/*----------------------------------------------------------------------
|       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 = 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:
        atom = DNew AP4_AvcCAtom(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_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_DVC:
    case AP4_ATOM_TYPE_DV5P:
    case AP4_ATOM_TYPE_DVCP:
    case AP4_ATOM_TYPE_DVPP:
        atom = DNew AP4_VisualSampleEntry(type, size, stream, *this);
        break;

    case AP4_ATOM_TYPE_MJPG:
    case AP4_ATOM_TYPE_AVDJ://uncommon fourcc
    case AP4_ATOM_TYPE_DMB1://uncommon fourcc
        atom = DNew AP4_VisualSampleEntry(AP4_ATOM_TYPE_MJPG, 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_LPCM:
    case AP4_ATOM_TYPE_ALAW:
    case AP4_ATOM_TYPE_ULAW:
    case AP4_ATOM_TYPE_NMOS:
    case AP4_ATOM_TYPE_ALAC:
        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;
}
Exemple #2
0
/*----------------------------------------------------------------------
|       AP4_TrakAtom::AP4_TrakAtom
+---------------------------------------------------------------------*/
AP4_TrakAtom::AP4_TrakAtom(AP4_SampleTable* sample_table,
                           AP4_Atom::Type   hdlr_type,
                           const char*      hdlr_name, 
                           AP4_UI32         track_id,
                           AP4_UI64         creation_time,
                           AP4_UI64         modification_time,
                           AP4_UI64         track_duration,
                           AP4_UI32         media_time_scale,
                           AP4_UI64         media_duration,
                           AP4_UI16         volume,
                           const char*      language,
                           AP4_UI32         width,
                           AP4_UI32         height) :
    AP4_ContainerAtom(AP4_ATOM_TYPE_TRAK)
{
    AP4_Result result;

    // create a tkhd atom
    m_TkhdAtom = DNew AP4_TkhdAtom(creation_time, 
                                  modification_time, 
                                  track_id,
                                  track_duration, 
                                  volume, 
                                  width, 
                                  height);

    // create an edts

    // create a mdia atom
    AP4_ContainerAtom* mdia = DNew AP4_ContainerAtom(AP4_ATOM_TYPE_MDIA);

    // create a hdlr atom for the mdia atom
    m_HdlrAtom = DNew AP4_HdlrAtom(hdlr_type, hdlr_name);

    // create a minf atom 
    AP4_ContainerAtom* minf = DNew AP4_ContainerAtom(AP4_ATOM_TYPE_MINF);

    // create a media header atom for minf (vmhd, smhd, hmhd or nmhd)
    AP4_Atom* minf_header;
    switch (hdlr_type) {
        case AP4_HANDLER_TYPE_VIDE:
            minf_header = DNew AP4_VmhdAtom(0, 0, 0, 0);
            break;

        case AP4_HANDLER_TYPE_SOUN:
            minf_header = DNew AP4_SmhdAtom(0);
            break;

        default:
            minf_header = DNew AP4_NmhdAtom();
            break;
    }

    // create a dinf atom for minf
    AP4_ContainerAtom* dinf = DNew AP4_ContainerAtom(AP4_ATOM_TYPE_DINF);

    // create a url atom as a ref for dref
    AP4_Atom* url = DNew AP4_UrlAtom(); // local ref

    // create a dref atom for dinf
    AP4_DrefAtom* dref = DNew AP4_DrefAtom(&url, 1);

    // create a stbl atom for minf
    AP4_ContainerAtom* stbl;
    result = sample_table->GenerateStblAtom(stbl);
    if (AP4_FAILED(result)) stbl = NULL;
    
    // populate the dinf atom
    dinf->AddChild(dref);

    // populate the minf atom
    minf->AddChild(minf_header);
    minf->AddChild(dinf);
    if (stbl) minf->AddChild(stbl);

    // create a mdhd atom for the mdia atom
    AP4_MdhdAtom* mdhd = DNew AP4_MdhdAtom(creation_time,
                                          modification_time,
                                          media_time_scale,
                                          media_duration,
                                          language);

    // populate the mdia atom
    mdia->AddChild(mdhd);
    mdia->AddChild(m_HdlrAtom);
    mdia->AddChild(minf);

    // attach the children
    AddChild(m_TkhdAtom);
    AddChild(mdia);
}