/*---------------------------------------------------------------------- | AP4_SampleTable::GenerateStblAtom +---------------------------------------------------------------------*/ AP4_Result AP4_SampleTable::GenerateStblAtom(AP4_ContainerAtom*& stbl) { // create the stbl container stbl = new AP4_ContainerAtom(AP4_ATOM_TYPE_STBL); // create the stsd atom AP4_StsdAtom* stsd = new AP4_StsdAtom(this); // create the stsz atom AP4_StszAtom* stsz = new AP4_StszAtom(); // create the stsc atom AP4_StscAtom* stsc = new AP4_StscAtom(); // create the stts atom AP4_SttsAtom* stts = new AP4_SttsAtom(); // create the stss atom AP4_StssAtom* stss = new AP4_StssAtom(); // declare the ctts atom (may be created later) AP4_CttsAtom* ctts = NULL; // start chunk table AP4_Ordinal current_chunk_index = 0; AP4_Size current_chunk_size = 0; AP4_Position current_chunk_offset = 0; AP4_Cardinal current_samples_in_chunk = 0; AP4_Ordinal current_sample_description_index = 0; AP4_UI32 current_duration = 0; AP4_Cardinal current_duration_run = 0; AP4_UI32 current_cts_delta = 0; AP4_Cardinal current_cts_delta_run = 0; AP4_Array<AP4_Position> chunk_offsets; // process all the samples bool all_samples_are_sync = false; AP4_Cardinal sample_count = GetSampleCount(); for (AP4_Ordinal i=0; i<sample_count; i++) { AP4_Sample sample; GetSample(i, sample); // update DTS table AP4_UI32 new_duration = sample.GetDuration(); if (new_duration != current_duration && current_duration_run != 0) { // emit a new stts entry stts->AddEntry(current_duration_run, current_duration); // reset the run count current_duration_run = 0; } ++current_duration_run; current_duration = new_duration; // update CTS table AP4_UI32 new_cts_delta = sample.GetCtsDelta(); if (new_cts_delta != current_cts_delta && current_cts_delta_run != 0) { // create a ctts atom if we don't have one if (ctts == NULL) ctts = new AP4_CttsAtom(); //emit a new ctts entry ctts->AddEntry(current_cts_delta_run, current_cts_delta); // reset the run count current_cts_delta_run = 0; } ++current_cts_delta_run; current_cts_delta = new_cts_delta; // add an entry into the stsz atom stsz->AddEntry(sample.GetSize()); // update the sync sample table if (sample.IsSync()) { stss->AddEntry(i+1); if (i==0) all_samples_are_sync = true; } else { all_samples_are_sync = false; } // see in which chunk this sample is AP4_Ordinal chunk_index = 0; AP4_Ordinal position_in_chunk = 0; AP4_Result result = GetSampleChunkPosition(i, chunk_index, position_in_chunk); if (AP4_SUCCEEDED(result)) { if (chunk_index != current_chunk_index && current_samples_in_chunk != 0) { // new chunk chunk_offsets.Append(current_chunk_offset); current_chunk_offset += current_chunk_size; stsc->AddEntry(1, current_samples_in_chunk, current_sample_description_index+1); current_samples_in_chunk = 0; current_chunk_size = 0; } current_chunk_index = chunk_index; } // store the sample description index current_sample_description_index = sample.GetDescriptionIndex(); // adjust the current chunk info current_chunk_size += sample.GetSize(); ++current_samples_in_chunk; } // finish the stts table if (sample_count) stts->AddEntry(current_duration_run, current_duration); // finish the ctts table if we have one if (ctts) { AP4_ASSERT(current_cts_delta_run != 0); // add a ctts entry ctts->AddEntry(current_cts_delta_run, current_cts_delta); } // process any unfinished chunk if (current_samples_in_chunk != 0) { // new chunk chunk_offsets.Append(current_chunk_offset); stsc->AddEntry(1, current_samples_in_chunk, current_sample_description_index+1); } // attach the children of stbl stbl->AddChild(stsd); stbl->AddChild(stsz); stbl->AddChild(stsc); stbl->AddChild(stts); if (ctts) stbl->AddChild(ctts); if (!all_samples_are_sync && stss->GetEntries().ItemCount() != 0) { stbl->AddChild(stss); } else { delete stss; } // see if we need a co64 or an stco atom AP4_Size chunk_count = chunk_offsets.ItemCount(); if (current_chunk_offset <= 0xFFFFFFFF) { // make an array of 32-bit entries AP4_UI32* chunk_offsets_32 = new AP4_UI32[chunk_count]; for (unsigned int i=0; i<chunk_count; i++) { chunk_offsets_32[i] = (AP4_UI32)chunk_offsets[i]; } // create the stco atom AP4_StcoAtom* stco = new AP4_StcoAtom(&chunk_offsets_32[0], chunk_count); stbl->AddChild(stco); delete[] chunk_offsets_32; } else { // create the co64 atom AP4_Co64Atom* co64 = new AP4_Co64Atom(&chunk_offsets[0], chunk_count); stbl->AddChild(co64); } return AP4_SUCCESS; }
/*---------------------------------------------------------------------- | AP4_SampleTable::GenerateStblAtom +---------------------------------------------------------------------*/ AP4_Result AP4_SampleTable::GenerateStblAtom(AP4_ContainerAtom*& stbl) { // create the stbl container stbl = DNew AP4_ContainerAtom(AP4_ATOM_TYPE_STBL); // create the stsd atom AP4_StsdAtom* stsd = DNew AP4_StsdAtom(this); // create the stsz atom AP4_StszAtom* stsz = DNew AP4_StszAtom(); // create the stsc atom AP4_StscAtom* stsc = DNew AP4_StscAtom(); // start chunk table AP4_Cardinal samples_in_chunk = 0; AP4_Offset current_chunk_offset = 0; AP4_Size current_chunk_size = 0; AP4_Array<AP4_UI32> chunk_offsets; // process all the samples AP4_Cardinal sample_count = GetSampleCount(); for (AP4_Ordinal i=0; i<sample_count; i++) { AP4_Sample sample; GetSample(i, sample); // add an entry into the stsz atom stsz->AddEntry(sample.GetSize()); // adjust the current chunk info current_chunk_size += sample.GetSize(); // count the sample samples_in_chunk++; if (samples_in_chunk == 10) { // new chunk chunk_offsets.Append(current_chunk_offset); stsc->AddEntry(1, 10, 1); samples_in_chunk = 0; // adjust the chunk offset current_chunk_offset += current_chunk_size; current_chunk_size = 0; } } // process any unfinished chunk if (samples_in_chunk != 0) { // new chunk chunk_offsets.Append(current_chunk_offset); stsc->AddEntry(1, samples_in_chunk, 1); } // create the stco atom AP4_StcoAtom* stco = DNew AP4_StcoAtom(&chunk_offsets[0], chunk_offsets.ItemCount()); // create the stts atom (for now, we assume sample of equal duration) AP4_SttsAtom* stts = DNew AP4_SttsAtom(); stts->AddEntry(sample_count, 1000); // FIXME // attach the children of stbl stbl->AddChild(stsd); stbl->AddChild(stsz); stbl->AddChild(stsc); stbl->AddChild(stco); stbl->AddChild(stts); return AP4_SUCCESS; }