/*---------------------------------------------------------------------- | AP4_Processor::ProcessFragments +---------------------------------------------------------------------*/ AP4_Result AP4_Processor::ProcessFragment( AP4_ContainerAtom* moof, AP4_SidxAtom* sidx, AP4_Position sidx_position, AP4_ByteStream& output, AP4_Array<AP4_Position>& moof_positions, AP4_Array<AP4_Position>& mdat_positions) { unsigned int fragment_index = 0; //AP4_UI64 mdat_payload_offset = atom_offset+atom->GetSize()+AP4_ATOM_HEADER_SIZE; AP4_Sample sample; AP4_DataBuffer sample_data_in; AP4_DataBuffer sample_data_out; AP4_Result result = AP4_SUCCESS; // parse the moof //AP4_MovieFragment* fragment = new AP4_MovieFragment(moof); // process all the traf atoms AP4_Array<AP4_Processor::FragmentHandler*> handlers; AP4_Array<AP4_FragmentSampleTable*> sample_tables; for (; AP4_Atom* child = moof->GetChild(AP4_ATOM_TYPE_TRAF, handlers.ItemCount());) { AP4_TrafAtom* traf = AP4_DYNAMIC_CAST(AP4_TrafAtom, child); PERTRACK &track_data(m_TrackData[traf->GetInternalTrackId()]); AP4_TrakAtom* trak = track_data.track_handler->GetTrakAtom(); AP4_TrexAtom* trex = track_data.track_handler->GetTrexAtom(); // create the handler for this traf AP4_Processor::FragmentHandler* handler = CreateFragmentHandler(trak, trex, traf, *(m_StreamData[track_data.streamId].stream), moof_positions[track_data.streamId]); if (handler) { result = handler->ProcessFragment(); if (AP4_FAILED(result)) return result; } handlers.Append(handler); // create a sample table object so we can read the sample data AP4_FragmentSampleTable* sample_table = new AP4_FragmentSampleTable( traf, trex, traf->GetInternalTrackId(), m_StreamData[track_data.streamId].stream, moof_positions[traf->GetInternalTrackId()], mdat_positions[traf->GetInternalTrackId()], 0); sample_tables.Append(sample_table); // let the handler look at the samples before we process them if (handler) result = handler->PrepareForSamples(sample_table); if (AP4_FAILED(result)) return result; } output.Buffer(); // write the moof AP4_UI64 moof_out_start = 0; output.Tell(moof_out_start); moof->Write(output); // remember the location of this fragment FragmentMapEntry map_entry = { moof_positions[0], moof_out_start }; fragment_map_.Append(map_entry); // write an mdat header AP4_Position mdat_out_start; AP4_UI64 mdat_size = AP4_ATOM_HEADER_SIZE; output.Tell(mdat_out_start); output.WriteUI32(0); output.WriteUI32(AP4_ATOM_TYPE_MDAT); // process all track runs for (unsigned int i=0; i<handlers.ItemCount(); i++) { AP4_Processor::FragmentHandler* handler = handlers[i]; // get the track ID AP4_ContainerAtom* traf = AP4_DYNAMIC_CAST(AP4_ContainerAtom, moof->GetChild(AP4_ATOM_TYPE_TRAF, i)); if (traf == NULL) continue; AP4_TfhdAtom* tfhd = AP4_DYNAMIC_CAST(AP4_TfhdAtom, traf->GetChild(AP4_ATOM_TYPE_TFHD)); // compute the base data offset AP4_UI64 base_data_offset; if (tfhd->GetFlags() & AP4_TFHD_FLAG_BASE_DATA_OFFSET_PRESENT) { base_data_offset = mdat_out_start+AP4_ATOM_HEADER_SIZE; } else { base_data_offset = moof_out_start; } // build a list of all trun atoms AP4_Array<AP4_TrunAtom*> truns; for (AP4_List<AP4_Atom>::Item* child_item = traf->GetChildren().FirstItem(); child_item; child_item = child_item->GetNext()) { AP4_Atom* child_atom = child_item->GetData(); if (child_atom->GetType() == AP4_ATOM_TYPE_TRUN) { AP4_TrunAtom* trun = AP4_DYNAMIC_CAST(AP4_TrunAtom, child_atom); truns.Append(trun); } } AP4_Ordinal trun_index = 0; AP4_Ordinal trun_sample_index = 0; AP4_TrunAtom* trun = truns[0]; trun->SetDataOffset((AP4_SI32)((mdat_out_start+mdat_size)-base_data_offset)); // write the mdat for (unsigned int j=0; j<sample_tables[i]->GetSampleCount(); j++, trun_sample_index++) { // advance the trun index if necessary if (trun_sample_index >= trun->GetEntries().ItemCount()) { trun = truns[++trun_index]; trun->SetDataOffset((AP4_SI32)((mdat_out_start+mdat_size)-base_data_offset)); trun_sample_index = 0; } // get the next sample result = sample_tables[i]->GetSample(j, sample); if (AP4_FAILED(result)) return result; sample.ReadData(sample_data_in); m_TrackData[sample_tables[i]->GetInteralTrackId()].dts = sample.GetDts(); // process the sample data if (handler) { result = handler->ProcessSample(sample_data_in, sample_data_out); if (AP4_FAILED(result)) return result; // write the sample data result = output.Write(sample_data_out.GetData(), sample_data_out.GetDataSize()); if (AP4_FAILED(result)) return result; // update the mdat size mdat_size += sample_data_out.GetDataSize(); // update the trun entry trun->UseEntries()[trun_sample_index].sample_size = sample_data_out.GetDataSize(); } else { // write the sample data (unmodified) result = output.Write(sample_data_in.GetData(), sample_data_in.GetDataSize()); if (AP4_FAILED(result)) return result; // update the mdat size mdat_size += sample_data_in.GetDataSize(); } } if (handler) { // update the tfhd header if (tfhd->GetFlags() & AP4_TFHD_FLAG_BASE_DATA_OFFSET_PRESENT) { tfhd->SetBaseDataOffset(mdat_out_start+AP4_ATOM_HEADER_SIZE); } if (tfhd->GetFlags() & AP4_TFHD_FLAG_DEFAULT_SAMPLE_SIZE_PRESENT) { tfhd->SetDefaultSampleSize(trun->GetEntries()[0].sample_size); } // give the handler a chance to update the atoms handler->FinishFragment(); } } // update the mdat header AP4_Position mdat_out_end; output.Tell(mdat_out_end); #if defined(AP4_DEBUG) AP4_ASSERT(mdat_out_end-mdat_out_start == mdat_size); #endif if (AP4_FAILED(result = output.Seek(mdat_out_start))) return result; output.WriteUI32((AP4_UI32)mdat_size); output.Seek(mdat_out_end); // update the moof if needed if (AP4_FAILED(result = output.Seek(moof_out_start))) return result; moof->Write(output); output.Seek(mdat_out_end); // update the sidx if we have one if (sidx && fragment_index < sidx->GetReferences().ItemCount()) { if (fragment_index == 0) { sidx->SetFirstOffset(moof_out_start-(sidx_position+sidx->GetSize())); } AP4_LargeSize fragment_size = mdat_out_end-moof_out_start; AP4_SidxAtom::Reference& sidx_ref = sidx->UseReferences()[fragment_index]; sidx_ref.m_ReferencedSize = (AP4_UI32)fragment_size; } // cleanup //delete fragment; for (unsigned int i=0; i<handlers.ItemCount(); i++) { delete handlers[i]; } for (unsigned int i=0; i<sample_tables.ItemCount(); i++) { delete sample_tables[i]; } if (AP4_FAILED(result = output.Flush())) return result; return AP4_SUCCESS; }