Example #1
0
/*----------------------------------------------------------------------
|       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;
}
Example #2
0
/*----------------------------------------------------------------------
|   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);
}
Example #3
0
/*----------------------------------------------------------------------
|       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;
}
Example #4
0
/*----------------------------------------------------------------------
|       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);
    }
}
Example #5
0
/*----------------------------------------------------------------------
|   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;
}
Example #6
0
/*----------------------------------------------------------------------
|       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;
}
Example #7
0
/*----------------------------------------------------------------------
|       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));    
}