/*---------------------------------------------------------------------- | AP4_RtpPacket::Write +---------------------------------------------------------------------*/ AP4_Result AP4_RtpPacket::Write(AP4_ByteStream& stream) { // check the payload type if (m_PayloadType > 128) return AP4_FAILURE; // now write AP4_Result result = stream.WriteUI32(m_RelativeTime); if (AP4_FAILED(result)) return result; result = stream.WriteUI08(0x80 | m_PBit << 5 | m_XBit << 4); if (AP4_FAILED(result)) return result; result = stream.WriteUI08(m_MBit << 7 | m_PayloadType); if (AP4_FAILED(result)) return result; result = stream.WriteUI16(m_SequenceSeed); if (AP4_FAILED(result)) return result; result = stream.WriteUI08(0); if (AP4_FAILED(result)) return result; // deal with extra flag bool extra_flag = m_TimeStampOffset != 0; result = stream.WriteUI08(0x00 | extra_flag << 2 | m_BFrameFlag << 1 | m_RepeatFlag << 0); if (AP4_FAILED(result)) return result; // constructor count result = stream.WriteUI16(static_cast<AP4_UI16>(m_Constructors.ItemCount())); // write extra data if (extra_flag) { // extra_length result = stream.WriteUI32(16); // 4 (extra_length) + 12 (rtpo atom) if (AP4_FAILED(result)) return result; // rtpo atom result = stream.WriteUI32(12); // size if (AP4_FAILED(result)) return result; result = stream.WriteUI32(AP4_ATOM_TYPE('r','t','p','o')); if (AP4_FAILED(result)) return result; result = stream.WriteUI32(m_TimeStampOffset); if (AP4_FAILED(result)) return result; } // constructors AP4_List<AP4_RtpConstructor>::Item* it = m_Constructors.FirstItem(); while (it != NULL) { result = it->GetData()->Write(stream); if (AP4_FAILED(result)) return result; it = it->GetNext(); } return result; }
/*---------------------------------------------------------------------- | AP4_SchmAtom::Create +---------------------------------------------------------------------*/ AP4_SchmAtom* AP4_SchmAtom::Create(AP4_Size size, AP4_Array<AP4_Atom::Type>* context, AP4_ByteStream& stream) { AP4_UI32 version; AP4_UI32 flags; if (AP4_FAILED(AP4_Atom::ReadFullHeader(stream, version, flags))) return NULL; if (version != 0) return NULL; if (size < AP4_FULL_ATOM_HEADER_SIZE+6) return NULL; // check the context to see if this is a short form atom or not bool short_form = false; if (size < AP4_FULL_ATOM_HEADER_SIZE+8) short_form = true; if (context) { AP4_Size context_depth = context->ItemCount(); if (context_depth >= 2 && (*context)[context_depth-2] == AP4_ATOM_TYPE('m','r','l','n')) { short_form = true; } } return new AP4_SchmAtom(size, version, flags, short_form, stream); }
/*---------------------------------------------------------------------- | AP4_AtomFactory::CreateAtomFromStream +---------------------------------------------------------------------*/ AP4_Result AP4_AtomFactory::CreateAtomFromStream(AP4_ByteStream& stream, AP4_Size& bytes_available, AP4_Atom*& atom, AP4_Atom* parent) { AP4_Result result; // NULL by default atom = NULL; // check that there are enough bytes for at least a header if (bytes_available < 8) return AP4_ERROR_EOS; // remember current stream offset AP4_Offset start; stream.Tell(start); // read atom size AP4_UI64 size = 0; result = stream.ReadUI32((AP4_UI32&)size); if (AP4_FAILED(result)) { stream.Seek(start); return result; } if (size == 0) { // atom extends to end of file AP4_Size streamSize = 0; stream.GetSize(streamSize); if (streamSize >= start) { size = streamSize - start; } } // check the size (we don't handle extended size yet) if (size != 1 && size < 8 || size > bytes_available) { stream.Seek(start); return AP4_ERROR_INVALID_FORMAT; } // read atom type AP4_Atom::Type type; result = stream.ReadUI32(type); if (AP4_FAILED(result)) { stream.Seek(start); return result; } if (size == 1) { AP4_UI64 size_high; result = stream.ReadUI64(size_high); if (AP4_FAILED(result) ) { stream.Seek(start); return AP4_ERROR_INVALID_FORMAT; } size = size_high; } // create the atom switch (type) { case AP4_ATOM_TYPE_MOOV: atom = new AP4_MoovAtom(size, stream, *this); break; case AP4_ATOM_TYPE_MVHD: atom = new AP4_MvhdAtom(size, stream); break; case AP4_ATOM_TYPE_TRAK: atom = new AP4_TrakAtom(size, stream, *this); break; case AP4_ATOM_TYPE_HDLR: atom = new AP4_HdlrAtom(size, stream); break; case AP4_ATOM_TYPE_DREF: atom = new AP4_DrefAtom(size, stream, *this); break; case AP4_ATOM_TYPE_URL: atom = new AP4_UrlAtom(size, stream); break; case AP4_ATOM_TYPE_TKHD: atom = new AP4_TkhdAtom(size, stream); break; case AP4_ATOM_TYPE_MDHD: atom = new AP4_MdhdAtom(size, stream); break; case AP4_ATOM_TYPE_STSD: atom = new AP4_StsdAtom(size, stream, *this); break; case AP4_ATOM_TYPE_STSC: atom = new AP4_StscAtom(size, stream); break; case AP4_ATOM_TYPE_STCO: atom = new AP4_StcoAtom(size, stream); break; case AP4_ATOM_TYPE_CO64: atom = new AP4_Co64Atom(size, stream); break; case AP4_ATOM_TYPE_STSZ: atom = new AP4_StszAtom(size, stream); break; case AP4_ATOM_TYPE_STTS: atom = new AP4_SttsAtom(size, stream); break; case AP4_ATOM_TYPE_CTTS: atom = new AP4_CttsAtom(size, stream); break; case AP4_ATOM_TYPE_STSS: atom = new AP4_StssAtom(size, stream); break; case AP4_ATOM_TYPE_MP4S: atom = new AP4_Mp4sSampleEntry(size, stream, *this); break; case AP4_ATOM_TYPE_MP4A: atom = parent && parent->GetType() == AP4_ATOM_TYPE_STSD ? (AP4_Atom*)new AP4_Mp4aSampleEntry(size, stream, *this) : (AP4_Atom*)new AP4_UnknownAtom(type, size, false, stream); break; case AP4_ATOM_TYPE_MP4V: atom = new AP4_Mp4vSampleEntry(size, stream, *this); break; case AP4_ATOM_TYPE_AVC1: atom = new AP4_Avc1SampleEntry(size, stream, *this); break; case AP4_ATOM_TYPE_ENCA: atom = new AP4_EncaSampleEntry(size, stream, *this); break; case AP4_ATOM_TYPE_ENCV: atom = new AP4_EncvSampleEntry(size, stream, *this); break; case AP4_ATOM_TYPE_ESDS: atom = new AP4_EsdsAtom(size, stream); break; case AP4_ATOM_TYPE_VMHD: atom = new AP4_VmhdAtom(size, stream); break; case AP4_ATOM_TYPE_SMHD: atom = new AP4_SmhdAtom(size, stream); break; case AP4_ATOM_TYPE_NMHD: atom = new AP4_NmhdAtom(size, stream); break; case AP4_ATOM_TYPE_HMHD: atom = new AP4_HmhdAtom(size, stream); break; case AP4_ATOM_TYPE_FRMA: atom = new AP4_FrmaAtom(size, stream); break; case AP4_ATOM_TYPE_SCHM: atom = new AP4_SchmAtom(size, stream); break; case AP4_ATOM_TYPE_FTYP: atom = new AP4_FtypAtom(size, stream); break; case AP4_ATOM_TYPE_RTP: if (m_Context == AP4_ATOM_TYPE_HNTI) { atom = new AP4_RtpAtom(size, stream); } else { atom = new AP4_RtpHintSampleEntry(size, stream, *this); } break; case AP4_ATOM_TYPE_TIMS: atom = new AP4_TimsAtom(size, stream); break; case AP4_ATOM_TYPE_SDP: atom = new AP4_SdpAtom(size, stream); break; case AP4_ATOM_TYPE_IKMS: atom = new AP4_IkmsAtom(size, stream); break; case AP4_ATOM_TYPE_ISFM: atom = new AP4_IsfmAtom(size, stream); break; case AP4_ATOM_TYPE_HINT: atom = new AP4_TrefTypeAtom(type, size, stream); break; // container atoms case AP4_ATOM_TYPE_TREF: case AP4_ATOM_TYPE_HNTI: case AP4_ATOM_TYPE_STBL: case AP4_ATOM_TYPE_MDIA: case AP4_ATOM_TYPE_DINF: case AP4_ATOM_TYPE_MINF: case AP4_ATOM_TYPE_SCHI: case AP4_ATOM_TYPE_SINF: case AP4_ATOM_TYPE_UDTA: case AP4_ATOM_TYPE_ILST: case AP4_ATOM_TYPE_NAM: case AP4_ATOM_TYPE_ART: case AP4_ATOM_TYPE_WRT: case AP4_ATOM_TYPE_ALB: case AP4_ATOM_TYPE_DAY: case AP4_ATOM_TYPE_TOO: case AP4_ATOM_TYPE_CMT: case AP4_ATOM_TYPE_GEN: case AP4_ATOM_TYPE_TRKN: case AP4_ATOM_TYPE_EDTS: case AP4_ATOM_TYPE_WAVE: case AP4_ATOM_TYPE_CMOV: { AP4_UI32 context = m_Context; m_Context = type; // set the context for the children atom = new AP4_ContainerAtom(type, size, false, stream, *this); m_Context = context; // restore the previous context break; } // full container atoms case AP4_ATOM_TYPE_META: atom = new AP4_ContainerAtom(type, size, true, stream, *this); break; // other case AP4_ATOM_TYPE_AVCC: atom = new AP4_AvcCAtom(size, stream); break; case AP4_ATOM_TYPE_TEXT: atom = new AP4_TextSampleEntry(size, stream, *this); break; case AP4_ATOM_TYPE_TX3G: atom = new AP4_Tx3gSampleEntry(size, stream, *this); break; case AP4_ATOM_TYPE_FTAB: atom = new AP4_FtabAtom(size, stream); break; case AP4_ATOM_TYPE_RAW: { AP4_Offset pos; AP4_UI16 ch_count_test; stream.Tell(pos); stream.Seek(pos + 16); stream.ReadUI16(ch_count_test); stream.Seek(pos); if (ch_count_test == 0) { atom = new AP4_VisualSampleEntry(type, size, stream, *this); } else { atom = new AP4_AudioSampleEntry(type, size, stream, *this); } } break; case AP4_ATOM_TYPE_CVID: case AP4_ATOM_TYPE_SVQ1: case AP4_ATOM_TYPE_SVQ2: case AP4_ATOM_TYPE_SVQ3: case AP4_ATOM_TYPE_H261: case AP4_ATOM_TYPE_H263: case AP4_ATOM_TYPE_S263: case AP4_ATOM_TYPE_JPEG: case AP4_ATOM_TYPE_PNG: case AP4_ATOM_TYPE_RLE: case AP4_ATOM_TYPE_MJPA: case AP4_ATOM_TYPE_MJPB: case AP4_ATOM_TYPE_RPZA: case AP4_ATOM_TYPE_DIV3: case AP4_ATOM_TYPE_DIVX: case AP4_ATOM_TYPE_8BPS: case AP4_ATOM_TYPE_3IV1: case AP4_ATOM_TYPE_3IV2: case AP4_ATOM_TYPE_IV32: case AP4_ATOM_TYPE_IV41: case AP4_ATOM_TYPE_VP31: case AP4_ATOM_TYPE_YV12: case AP4_ATOM_TYPE_APCN: case AP4_ATOM_TYPE_APCH: case AP4_ATOM_TYPE_APCO: case AP4_ATOM_TYPE_APCS: atom = new AP4_VisualSampleEntry(type, size, stream, *this); break; // DV Video Subtypes - http://msdn.microsoft.com/en-us/library/windows/desktop/dd388646%28v=vs.85%29.aspx case AP4_ATOM_TYPE_DVC: case AP4_ATOM_TYPE_DVCP: atom = new AP4_VisualSampleEntry(AP4_ATOM_TYPE('d','v','s','d'), size, stream, *this); // MEDIASUBTYPE_dvsd (DV Video Decoder, ffdshow, LAV) break; case AP4_ATOM_TYPE_DVPP: atom = new AP4_VisualSampleEntry(AP4_ATOM_TYPE('d','v','2','5'), size, stream, *this); // MEDIASUBTYPE_dv25 (ffdshow, LAV) break; case AP4_ATOM_TYPE_DV5N: case AP4_ATOM_TYPE_DV5P: atom = new AP4_VisualSampleEntry(AP4_ATOM_TYPE('d','v','5','0'), size, stream, *this); // MEDIASUBTYPE_dv50 (ffdshow, LAV) break; case AP4_ATOM_TYPE_DVHQ: case AP4_ATOM_TYPE_DVH5: atom = new AP4_VisualSampleEntry(AP4_ATOM_TYPE('C','D','V','H'), size, stream, *this); // MEDIASUBTYPE_CDVH (LAV) break; case AP4_ATOM_TYPE_MJPG: case AP4_ATOM_TYPE_AVDJ: // uncommon fourcc case AP4_ATOM_TYPE_DMB1: // uncommon fourcc atom = new AP4_VisualSampleEntry(AP4_ATOM_TYPE_MJPG, size, stream, *this); break; case AP4_ATOM_TYPE_2VUY: // = 'UYVY' atom = new AP4_VisualSampleEntry(AP4_ATOM_TYPE('U','Y','V','Y'), size, stream, *this); break; case AP4_ATOM_TYPE_SAMR: case AP4_ATOM_TYPE__MP3: case AP4_ATOM_TYPE_IMA4: case AP4_ATOM_TYPE_QDMC: case AP4_ATOM_TYPE_QDM2: case AP4_ATOM_TYPE_NONE: case AP4_ATOM_TYPE_TWOS: case AP4_ATOM_TYPE_SOWT: case AP4_ATOM_TYPE_IN24: case AP4_ATOM_TYPE_IN32: case AP4_ATOM_TYPE_FL32: case AP4_ATOM_TYPE_FL64: case AP4_ATOM_TYPE_LPCM: case AP4_ATOM_TYPE_ALAW: case AP4_ATOM_TYPE_ULAW: case AP4_ATOM_TYPE_NMOS: case AP4_ATOM_TYPE_ALAC: case AP4_ATOM_TYPE_MAC3: case AP4_ATOM_TYPE_MAC6: atom = new AP4_AudioSampleEntry(type, size, stream, *this); break; case AP4_ATOM_TYPE__AC3: // AC3-in-MP4 from ISO Standard case AP4_ATOM_TYPE_SAC3: // AC3-in-MP4 from Nero Stuff >.< atom = new AP4_AC3SampleEntry(size, stream, *this); break; case AP4_ATOM_TYPE_EAC3: atom = new AP4_EAC3SampleEntry(size, stream, *this); break; case AP4_ATOM_TYPE_CHPL: atom = new AP4_ChplAtom(size, stream); break; case AP4_ATOM_TYPE_DATA: atom = new AP4_DataAtom(size, stream); break; case AP4_ATOM_TYPE_DCOM: atom = new AP4_DcomAtom(size, stream); break; case AP4_ATOM_TYPE_CMVD: atom = new AP4_CmvdAtom(size, stream, *this); break; case AP4_ATOM_TYPE_ENDA: atom = new AP4_EndaAtom(size, stream); break; case AP4_ATOM_TYPE_PASP: atom = new AP4_PaspAtom(size, stream); break; default: if(parent && parent->GetType() == AP4_ATOM_TYPE_STSD && (type & 0xffff0000) == AP4_ATOM_TYPE('m', 's', 0, 0)) { atom = new AP4_AudioSampleEntry(type, size, stream, *this); } else {// try all the external type handlers atom = NULL; AP4_List<TypeHandler>::Item* handler_item = m_TypeHandlers.FirstItem(); while (handler_item) { TypeHandler* handler = handler_item->GetData(); if (AP4_SUCCEEDED(handler->CreateAtom(type, size, stream, atom))) { break; } handler_item = handler_item->GetNext(); } if (atom == NULL) { // no custom handlers, create a generic atom atom = new AP4_UnknownAtom(type, size, false, stream); } } break; } // skip to the end of the atom bytes_available -= size; result = stream.Seek(start+size); if (AP4_FAILED(result)) { delete atom; atom = NULL; } return result; }
/*---------------------------------------------------------------------- | AP4_RtpPacket::AP4_RtpPacket +---------------------------------------------------------------------*/ AP4_RtpPacket::AP4_RtpPacket(AP4_ByteStream& stream) : m_ReferenceCount(1), m_TimeStampOffset(0) { AP4_UI08 octet; // relative time AP4_UI32 relative_time; stream.ReadUI32(relative_time); m_RelativeTime = relative_time; // pbit and xbit stream.ReadUI08(octet); m_PBit = (octet & 0x20) != 0; m_XBit = (octet & 0x10) != 0; // mbit and payload type stream.ReadUI08(octet); m_MBit = (octet & 0x80) != 0; m_PayloadType = octet & 0x7F; // sequence seed stream.ReadUI16(m_SequenceSeed); // extra, bframe and repeat flags stream.ReadUI08(octet); stream.ReadUI08(octet); // repeat on purpose bool extra_flag = (octet & 0x04) != 0; // bframe and repeat flags m_BFrameFlag = (octet & 0x02) != 0; m_RepeatFlag = (octet & 0x01) != 0; // constructor count AP4_UI16 constructor_count; stream.ReadUI16(constructor_count); // parse the packet extra data if (extra_flag) { // read the length AP4_UI32 extra_length; stream.ReadUI32(extra_length); // check it if (extra_length < 4) throw AP4_Exception(AP4_ERROR_INVALID_RTP_PACKET_EXTRA_DATA); // now read the entries extra_length -= 4; while (extra_length > 0) { AP4_UI32 entry_length; AP4_UI32 entry_tag; stream.ReadUI32(entry_length); stream.ReadUI32(entry_tag); // check the entry if (entry_length < 8) { throw AP4_Exception(AP4_ERROR_INVALID_RTP_PACKET_EXTRA_DATA); } // parse the single entry that's currently defined in the spec if (entry_tag == AP4_ATOM_TYPE('r','t','p','o') && entry_length == 12) { AP4_UI32 time_stamp_offset; stream.ReadUI32(time_stamp_offset); m_TimeStampOffset = time_stamp_offset; } else { // ignore it AP4_Offset cur_pos; stream.Tell(cur_pos); stream.Seek(cur_pos + entry_length - 8); // 8 = length + tag } extra_length -= entry_length; } } // constructors for (AP4_UI16 i=0; i<constructor_count; i++) { AP4_RtpConstructor* constructor = NULL; AP4_RtpConstructorFactory::CreateConstructorFromStream(stream, constructor); m_Constructors.Add(constructor); } }
/*---------------------------------------------------------------------- | AP4_MarlinIpmpParser:Parse +---------------------------------------------------------------------*/ AP4_Result AP4_MarlinIpmpParser::Parse(AP4_AtomParent& top_level, AP4_ByteStream& stream, AP4_List<SinfEntry>& sinf_entries, bool remove_od_data) { // check the file type AP4_FtypAtom* ftyp = AP4_DYNAMIC_CAST(AP4_FtypAtom, top_level.GetChild(AP4_ATOM_TYPE_FTYP)); if (ftyp == NULL || (ftyp->GetMajorBrand() != AP4_MARLIN_BRAND_MGSV && !ftyp->HasCompatibleBrand(AP4_MARLIN_BRAND_MGSV))) { return AP4_ERROR_INVALID_FORMAT; } // check the initial object descriptor and get the OD Track ID AP4_IodsAtom* iods = AP4_DYNAMIC_CAST(AP4_IodsAtom, top_level.FindChild("moov/iods")); AP4_UI32 od_track_id = 0; if (iods == NULL) return AP4_ERROR_INVALID_FORMAT; const AP4_ObjectDescriptor* od = iods->GetObjectDescriptor(); if (od == NULL) return AP4_ERROR_INVALID_FORMAT; AP4_EsIdIncDescriptor* es_id_inc = AP4_DYNAMIC_CAST(AP4_EsIdIncDescriptor, od->FindSubDescriptor(AP4_DESCRIPTOR_TAG_ES_ID_INC)); if (es_id_inc == NULL) return AP4_ERROR_INVALID_FORMAT; od_track_id = es_id_inc->GetTrackId(); // find the track pointed to by the descriptor AP4_MoovAtom* moov = AP4_DYNAMIC_CAST(AP4_MoovAtom, top_level.GetChild(AP4_ATOM_TYPE_MOOV)); if (moov == NULL) return AP4_ERROR_INVALID_FORMAT; AP4_TrakAtom* od_trak = NULL; AP4_List<AP4_TrakAtom>::Item* trak_item = moov->GetTrakAtoms().FirstItem(); while (trak_item) { AP4_TrakAtom* trak = trak_item->GetData(); if (trak) { if (trak->GetId() == od_track_id) { od_trak = trak; } else { sinf_entries.Add(new SinfEntry(trak->GetId(), NULL)); } } trak_item = trak_item->GetNext(); } // check that we have found the OD track if (od_trak == NULL) return AP4_ERROR_INVALID_FORMAT; // look for the 'mpod' trak references AP4_TrefTypeAtom* track_references; track_references = AP4_DYNAMIC_CAST(AP4_TrefTypeAtom, od_trak->FindChild("tref/mpod")); if (track_references == NULL) return AP4_ERROR_INVALID_FORMAT; // create an AP4_Track object from the trak atom and check that it has samples AP4_Track* od_track = new AP4_Track(*od_trak, stream, 0); if (od_track->GetSampleCount() < 1) { delete od_track; return AP4_ERROR_INVALID_FORMAT; } // get the first sample (in this version, we only look at a single OD command) AP4_Sample od_sample; AP4_Result result = od_track->GetSample(0, od_sample); if (AP4_FAILED(result)) { delete od_track; return AP4_ERROR_INVALID_FORMAT; } // adapt the sample data into a byte stream for parsing AP4_DataBuffer sample_data; od_sample.ReadData(sample_data); AP4_MemoryByteStream* sample_stream = new AP4_MemoryByteStream(sample_data); // look for one ObjectDescriptorUpdate command and // one IPMP_DescriptorUpdate command AP4_DescriptorUpdateCommand* od_update = NULL; AP4_DescriptorUpdateCommand* ipmp_update = NULL; do { AP4_Command* command = NULL; result = AP4_CommandFactory::CreateCommandFromStream(*sample_stream, command); if (AP4_SUCCEEDED(result)) { // found a command in the sample, check the type switch (command->GetTag()) { case AP4_COMMAND_TAG_OBJECT_DESCRIPTOR_UPDATE: if (od_update == NULL) { od_update = AP4_DYNAMIC_CAST(AP4_DescriptorUpdateCommand, command); } break; case AP4_COMMAND_TAG_IPMP_DESCRIPTOR_UPDATE: if (ipmp_update == NULL) { ipmp_update = AP4_DYNAMIC_CAST(AP4_DescriptorUpdateCommand, command); } break; default: break; } } } while (AP4_SUCCEEDED(result)); sample_stream->Release(); sample_stream = NULL; // check that we have what we need if (od_update == NULL || ipmp_update == NULL) { delete od_track; return AP4_ERROR_INVALID_FORMAT; } // process all the object descriptors in the od update for (AP4_List<AP4_Descriptor>::Item* od_item = od_update->GetDescriptors().FirstItem(); od_item; od_item = od_item->GetNext()) { od = AP4_DYNAMIC_CAST(AP4_ObjectDescriptor, od_item->GetData()); if (od == NULL) continue; // find which track this od references AP4_EsIdRefDescriptor* es_id_ref; es_id_ref = AP4_DYNAMIC_CAST(AP4_EsIdRefDescriptor, od->FindSubDescriptor(AP4_DESCRIPTOR_TAG_ES_ID_REF)); if (es_id_ref == NULL || es_id_ref->GetRefIndex() > track_references->GetTrackIds().ItemCount() || es_id_ref->GetRefIndex() == 0) { continue; } AP4_UI32 track_id = track_references->GetTrackIds()[es_id_ref->GetRefIndex()-1]; SinfEntry* sinf_entry = NULL; for (AP4_List<SinfEntry>::Item* sinf_entry_item = sinf_entries.FirstItem(); sinf_entry_item; sinf_entry_item = sinf_entry_item->GetNext()) { sinf_entry = sinf_entry_item->GetData(); if (sinf_entry->m_TrackId == track_id) { break; // match } else { sinf_entry = NULL; // no match } } if (sinf_entry == NULL) continue; // no matching entry if (sinf_entry->m_Sinf != NULL) continue; // entry already populated // see what ipmp descriptor this od points to AP4_IpmpDescriptorPointer* ipmpd_pointer; ipmpd_pointer = AP4_DYNAMIC_CAST(AP4_IpmpDescriptorPointer, od->FindSubDescriptor(AP4_DESCRIPTOR_TAG_IPMP_DESCRIPTOR_POINTER)); if (ipmpd_pointer == NULL) continue; // no pointer // find the ipmp descriptor referenced by the pointer AP4_IpmpDescriptor* ipmpd = NULL; for (AP4_List<AP4_Descriptor>::Item* ipmpd_item = ipmp_update->GetDescriptors().FirstItem(); ipmpd_item; ipmpd_item = ipmpd_item->GetNext()) { // check that this descriptor is of the right type ipmpd = AP4_DYNAMIC_CAST(AP4_IpmpDescriptor, ipmpd_item->GetData()); if (ipmpd == NULL || ipmpd->GetIpmpsType() != AP4_MARLIN_IPMPS_TYPE_MGSV) continue; // check the descriptor id if (ipmpd->GetDescriptorId() == ipmpd_pointer->GetDescriptorId()) { break; // match } else { ipmpd = NULL; // no match } } if (ipmpd == NULL) continue; // no matching entry // parse the ipmp data into one or more 'sinf' atoms, and keep the one with the // right type AP4_MemoryByteStream* data = new AP4_MemoryByteStream(ipmpd->GetData().GetData(), ipmpd->GetData().GetDataSize()); AP4_LargeSize bytes_available = ipmpd->GetData().GetDataSize(); do { AP4_Atom* atom = NULL; // setup the factory with a context so we can instantiate an 'schm' // atom with a slightly different format than the standard 'schm' AP4_AtomFactory* factory = &AP4_MarlinIpmpAtomFactory::Instance; factory->PushContext(AP4_ATOM_TYPE('m','r','l','n')); // parse the next atom in the stream result = factory->CreateAtomFromStream(*data, bytes_available, atom); factory->PopContext(); if (AP4_FAILED(result) || atom == NULL) break; // check that what we have parsed is indeed an 'sinf' of the right type if (atom->GetType() == AP4_ATOM_TYPE_SINF) { AP4_ContainerAtom* sinf = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom); AP4_SchmAtom* schm = AP4_DYNAMIC_CAST(AP4_SchmAtom, sinf->FindChild("schm")); if (schm->GetSchemeType() == AP4_PROTECTION_SCHEME_TYPE_MARLIN_ACBC && schm->GetSchemeVersion() == 0x0100) { // store the sinf in the entry for that track sinf_entry->m_Sinf = sinf; break; } } delete atom; } while (AP4_SUCCEEDED(result)); data->Release(); } // remove the iods atom and the OD track if required if (remove_od_data) { od_trak->Detach(); delete od_trak; iods->Detach(); delete iods; } // cleanup delete od_track; return AP4_SUCCESS; }
/*---------------------------------------------------------------------- | AP4_AtomFactory::CreateAtomFromStream +---------------------------------------------------------------------*/ AP4_Result AP4_AtomFactory::CreateAtomFromStream(AP4_ByteStream& stream, AP4_Size& bytes_available, AP4_Atom*& atom, AP4_Atom* parent) { AP4_Result result; // NULL by default atom = NULL; // check that there are enough bytes for at least a header if (bytes_available < 8) return AP4_ERROR_EOS; // remember current stream offset AP4_Offset start; stream.Tell(start); // read atom size AP4_UI32 size; result = stream.ReadUI32(size); if (AP4_FAILED(result)) { stream.Seek(start); return result; } if (size == 0) { // atom extends to end of file AP4_Size streamSize = 0; stream.GetSize(streamSize); if (streamSize >= start) { size = streamSize - start; } } // check the size (we don't handle extended size yet) if (size != 1 && size < 8 || size > bytes_available) { stream.Seek(start); return AP4_ERROR_INVALID_FORMAT; } // read atom type AP4_Atom::Type type; result = stream.ReadUI32(type); if (AP4_FAILED(result)) { stream.Seek(start); return result; } if (size == 1) { AP4_UI32 size_high; result = stream.ReadUI32(size_high); if (AP4_FAILED(result) ) { stream.Seek(start); return AP4_ERROR_INVALID_FORMAT; } result = stream.ReadUI32(size); if (AP4_FAILED(result)) { stream.Seek(start); return result; } if(size_high > 0) { size = (((ULONGLONG)size_high) << 32) | size; } } // create the atom switch (type) { case AP4_ATOM_TYPE_3DVF: case AP4_ATOM_TYPE_MOOV: atom = DNew AP4_MoovAtom(size, stream, *this); break; case AP4_ATOM_TYPE_MVHD: atom = DNew AP4_MvhdAtom(size, stream); break; case AP4_ATOM_TYPE_TRAK: atom = DNew AP4_TrakAtom(size, stream, *this); break; case AP4_ATOM_TYPE_HDLR: atom = DNew AP4_HdlrAtom(size, stream); break; case AP4_ATOM_TYPE_DREF: atom = DNew AP4_DrefAtom(size, stream, *this); break; case AP4_ATOM_TYPE_URL: atom = DNew AP4_UrlAtom(size, stream); break; case AP4_ATOM_TYPE_TKHD: atom = DNew AP4_TkhdAtom(size, stream); break; case AP4_ATOM_TYPE_MDHD: atom = DNew AP4_MdhdAtom(size, stream); break; case AP4_ATOM_TYPE_STSD: atom = DNew AP4_StsdAtom(size, stream, *this); break; case AP4_ATOM_TYPE_STSC: atom = DNew AP4_StscAtom(size, stream); break; case AP4_ATOM_TYPE_STCO: atom = DNew AP4_StcoAtom(size, stream); break; case AP4_ATOM_TYPE_CO64: atom = DNew AP4_Co64Atom(size, stream); break; case AP4_ATOM_TYPE_STSZ: atom = DNew AP4_StszAtom(size, stream); break; case AP4_ATOM_TYPE_STTS: atom = DNew AP4_SttsAtom(size, stream); break; case AP4_ATOM_TYPE_CTTS: atom = DNew AP4_CttsAtom(size, stream); break; case AP4_ATOM_TYPE_STSS: atom = DNew AP4_StssAtom(size, stream); break; case AP4_ATOM_TYPE_MP4S: atom = DNew AP4_Mp4sSampleEntry(size, stream, *this); break; case AP4_ATOM_TYPE_MP4A: atom = parent && parent->GetType() == AP4_ATOM_TYPE_STSD ? (AP4_Atom*)DNew AP4_Mp4aSampleEntry(size, stream, *this) : (AP4_Atom*)DNew AP4_UnknownAtom(type, size, false, stream); break; case AP4_ATOM_TYPE_MP4V: atom = DNew AP4_Mp4vSampleEntry(size, stream, *this); break; case AP4_ATOM_TYPE_AVC1: atom = DNew AP4_Avc1SampleEntry(size, stream, *this); break; case AP4_ATOM_TYPE_ENCA: atom = DNew AP4_EncaSampleEntry(size, stream, *this); break; case AP4_ATOM_TYPE_ENCV: atom = DNew AP4_EncvSampleEntry(size, stream, *this); break; case AP4_ATOM_TYPE_ESDS: atom = DNew AP4_EsdsAtom(size, stream); break; case AP4_ATOM_TYPE_VMHD: atom = DNew AP4_VmhdAtom(size, stream); break; case AP4_ATOM_TYPE_SMHD: atom = DNew AP4_SmhdAtom(size, stream); break; case AP4_ATOM_TYPE_NMHD: atom = DNew AP4_NmhdAtom(size, stream); break; case AP4_ATOM_TYPE_HMHD: atom = DNew AP4_HmhdAtom(size, stream); break; case AP4_ATOM_TYPE_FRMA: atom = DNew AP4_FrmaAtom(size, stream); break; case AP4_ATOM_TYPE_SCHM: atom = DNew AP4_SchmAtom(size, stream); break; case AP4_ATOM_TYPE_FTYP: atom = DNew AP4_FtypAtom(size, stream); break; case AP4_ATOM_TYPE_RTP: if (m_Context == AP4_ATOM_TYPE_HNTI) { atom = DNew AP4_RtpAtom(size, stream); } else { atom = DNew AP4_RtpHintSampleEntry(size, stream, *this); } break; case AP4_ATOM_TYPE_TIMS: atom = DNew AP4_TimsAtom(size, stream); break; case AP4_ATOM_TYPE_SDP: atom = DNew AP4_SdpAtom(size, stream); break; case AP4_ATOM_TYPE_IKMS: atom = DNew AP4_IkmsAtom(size, stream); break; case AP4_ATOM_TYPE_ISFM: atom = DNew AP4_IsfmAtom(size, stream); break; case AP4_ATOM_TYPE_HINT: atom = DNew AP4_TrefTypeAtom(type, size, stream); break; // container atoms case AP4_ATOM_TYPE_TREF: case AP4_ATOM_TYPE_HNTI: case AP4_ATOM_TYPE_STBL: case AP4_ATOM_TYPE_MDIA: case AP4_ATOM_TYPE_DINF: case AP4_ATOM_TYPE_MINF: case AP4_ATOM_TYPE_SCHI: case AP4_ATOM_TYPE_SINF: case AP4_ATOM_TYPE_UDTA: case AP4_ATOM_TYPE_ILST: case AP4_ATOM_TYPE_NAM: case AP4_ATOM_TYPE_ART: case AP4_ATOM_TYPE_WRT: case AP4_ATOM_TYPE_ALB: case AP4_ATOM_TYPE_DAY: case AP4_ATOM_TYPE_TOO: case AP4_ATOM_TYPE_CMT: case AP4_ATOM_TYPE_GEN: case AP4_ATOM_TYPE_TRKN: case AP4_ATOM_TYPE_EDTS: case AP4_ATOM_TYPE_WAVE: case AP4_ATOM_TYPE_CMOV: { AP4_UI32 context = m_Context; m_Context = type; // set the context for the children atom = DNew AP4_ContainerAtom(type, size, false, stream, *this); m_Context = context; // restore the previous context break; } // full container atoms case AP4_ATOM_TYPE_META: atom = DNew AP4_ContainerAtom(type, size, true, stream, *this); break; // other case AP4_ATOM_TYPE_AVCC: case AP4_ATOM_TYPE_MVCC: atom = DNew AP4_AvcCAtom(type, size, stream); break; case AP4_ATOM_TYPE_TEXT: atom = DNew AP4_TextSampleEntry(size, stream, *this); break; case AP4_ATOM_TYPE_TX3G: atom = DNew AP4_Tx3gSampleEntry(size, stream, *this); break; case AP4_ATOM_TYPE_FTAB: atom = DNew AP4_FtabAtom(size, stream); break; case AP4_ATOM_TYPE_CVID: case AP4_ATOM_TYPE_SVQ1: case AP4_ATOM_TYPE_SVQ2: case AP4_ATOM_TYPE_SVQ3: case AP4_ATOM_TYPE_H261: case AP4_ATOM_TYPE_H263: case AP4_ATOM_TYPE_S263: case AP4_ATOM_TYPE_JPEG: case AP4_ATOM_TYPE_PNG: case AP4_ATOM_TYPE_RLE: case AP4_ATOM_TYPE_MJPA: case AP4_ATOM_TYPE_MJPB: case AP4_ATOM_TYPE_MJPG: case AP4_ATOM_TYPE_DMB1: case AP4_ATOM_TYPE_RPZA: case AP4_ATOM_TYPE_DVC: case AP4_ATOM_TYPE_DIV3: case AP4_ATOM_TYPE_DIVX: case AP4_ATOM_TYPE_8BPS: case AP4_ATOM_TYPE_3IV1: case AP4_ATOM_TYPE_3IV2: case AP4_ATOM_TYPE_IV32: case AP4_ATOM_TYPE_VP31: case AP4_ATOM_TYPE_YV12: atom = DNew AP4_VisualSampleEntry(type, size, stream, *this); break; case AP4_ATOM_TYPE_SAMR: case AP4_ATOM_TYPE__MP3: case AP4_ATOM_TYPE_IMA4: case AP4_ATOM_TYPE_QDMC: case AP4_ATOM_TYPE_QDM2: case AP4_ATOM_TYPE_NONE: case AP4_ATOM_TYPE_RAW: case AP4_ATOM_TYPE_TWOS: case AP4_ATOM_TYPE_SOWT: case AP4_ATOM_TYPE_IN24: case AP4_ATOM_TYPE_IN32: case AP4_ATOM_TYPE_FL32: case AP4_ATOM_TYPE_FL64: case AP4_ATOM_TYPE_ALAW: case AP4_ATOM_TYPE_ULAW: atom = DNew AP4_AudioSampleEntry(type, size, stream, *this); break; case AP4_ATOM_TYPE__AC3: // AC3-in-MP4 from ISO Standard case AP4_ATOM_TYPE_SAC3: // AC3-in-MP4 from Nero Stuff >.< atom = DNew AP4_AC3SampleEntry(size, stream, *this); break; case AP4_ATOM_TYPE_EAC3: atom = DNew AP4_EAC3SampleEntry(size, stream, *this); break; case AP4_ATOM_TYPE_CHPL: atom = DNew AP4_ChplAtom(size, stream); break; case AP4_ATOM_TYPE_DATA: atom = DNew AP4_DataAtom(size, stream); break; case AP4_ATOM_TYPE_DCOM: atom = DNew AP4_DcomAtom(size, stream); break; case AP4_ATOM_TYPE_CMVD: atom = DNew AP4_CmvdAtom(size, stream, *this); break; case AP4_ATOM_TYPE_ENDA: atom = DNew AP4_EndaAtom(size, stream); break; case AP4_ATOM_TYPE_PASP: atom = DNew AP4_PaspAtom(size, stream); break; default: if(parent && parent->GetType() == AP4_ATOM_TYPE_STSD && (type & 0xffff0000) == AP4_ATOM_TYPE('m', 's', 0, 0)) { atom = DNew AP4_AudioSampleEntry(type, size, stream, *this); } else // try all the external type handlers { atom = NULL; AP4_List<TypeHandler>::Item* handler_item = m_TypeHandlers.FirstItem(); while (handler_item) { TypeHandler* handler = handler_item->GetData(); if (AP4_SUCCEEDED(handler->CreateAtom(type, size, stream, atom))) { break; } handler_item = handler_item->GetNext(); } if (atom == NULL) { // no custom handlers, create a generic atom atom = DNew AP4_UnknownAtom(type, size, false, stream); } } break; } // skip to the end of the atom bytes_available -= size; result = stream.Seek(start+size); if (AP4_FAILED(result)) { delete atom; atom = NULL; } return result; }
/*---------------------------------------------------------------------- | AP4_MoovAtom::AP4_MoovAtom +---------------------------------------------------------------------*/ AP4_MoovAtom::AP4_MoovAtom(AP4_Size size, AP4_ByteStream& stream, AP4_AtomFactory& atom_factory) : AP4_ContainerAtom(AP4_ATOM_TYPE_MOOV, size, false, stream, atom_factory), m_TimeScale(0) { if(AP4_ContainerAtom* cmov = dynamic_cast<AP4_ContainerAtom*>(GetChild(AP4_ATOM_TYPE_CMOV))) { AP4_DcomAtom* dcom = dynamic_cast<AP4_DcomAtom*>(cmov->GetChild(AP4_ATOM_TYPE_DCOM)); AP4_CmvdAtom* cmvd = dynamic_cast<AP4_CmvdAtom*>(cmov->GetChild(AP4_ATOM_TYPE_CMVD)); if(dcom && dcom->GetCompressorSubType() == AP4_ATOM_TYPE('z','l','i','b') && cmvd) { const AP4_DataBuffer& data = cmvd->GetDataBuffer(); z_stream d_stream; d_stream.zalloc = (alloc_func)0; d_stream.zfree = (free_func)0; d_stream.opaque = (voidpf)0; int res; if(Z_OK == (res = inflateInit(&d_stream))) { d_stream.next_in = (Bytef*)data.GetData(); d_stream.avail_in = data.GetDataSize(); unsigned char* dst = NULL; int n = 0; do { dst = (unsigned char*)realloc(dst, ++n*1000); d_stream.next_out = &dst[(n-1)*1000]; d_stream.avail_out = 1000; if(Z_OK != (res = inflate(&d_stream, Z_NO_FLUSH)) && Z_STREAM_END != res) { free(dst); dst = NULL; break; } } while(0 == d_stream.avail_out && 0 != d_stream.avail_in && Z_STREAM_END != res); inflateEnd(&d_stream); if(dst) { AP4_ByteStream* s = new AP4_MemoryByteStream(dst, d_stream.total_out); ReadChildren(atom_factory, *s, d_stream.total_out); s->Release(); free(dst); } if(AP4_MoovAtom* moov = dynamic_cast<AP4_MoovAtom*>(GetChild(AP4_ATOM_TYPE_MOOV))) { AP4_List<AP4_Atom> Children; for(AP4_List<AP4_Atom>::Item* item = moov->GetChildren().FirstItem(); item; item = item->GetNext()) { Children.Add(item->GetData()); } for(AP4_List<AP4_Atom>::Item* item = Children.FirstItem(); item; item = item->GetNext()) { AP4_Atom* atom = item->GetData(); atom->Detach(); atom->SetParent(this); m_Children.Add(atom); } moov->Detach(); delete moov; } } } } // collect all trak atoms m_Children.Apply(AP4_TrakAtomCollector(&m_TrakAtoms)); }