Ejemplo n.º 1
0
/*----------------------------------------------------------------------
|   AP4_Track::GetHandlerType
+---------------------------------------------------------------------*/
AP4_UI32
AP4_Track::GetHandlerType()
{
    if (m_TrakAtom) {
        AP4_HdlrAtom* hdlr = AP4_DYNAMIC_CAST(AP4_HdlrAtom, m_TrakAtom->FindChild("mdia/hdlr"));
        if (hdlr) {
            return hdlr->GetHandlerType();
        }
    }
    return 0;
}
Ejemplo n.º 2
0
/*----------------------------------------------------------------------
|       AP4_Track::AP4_Track
+---------------------------------------------------------------------*/
AP4_Track::AP4_Track(AP4_TrakAtom&   atom, 
                     AP4_ByteStream& sample_stream, 
                     AP4_UI32        movie_time_scale) :
    m_TrakAtom(&atom),
    m_TrakAtomIsOwned(false),
    m_Type(TYPE_UNKNOWN),
    m_SampleTable(NULL),
    m_SampleTableIsOwned(true),
    m_MovieTimeScale(movie_time_scale),
    m_MediaTimeScale(0)
{
    // find the handler type
    AP4_Atom* sub = atom.FindChild("mdia/hdlr");
    if (sub) {
        AP4_HdlrAtom* hdlr = dynamic_cast<AP4_HdlrAtom*>(sub);
        if (hdlr) {
            AP4_Atom::Type type = hdlr->GetHandlerType();
            if (type == AP4_HANDLER_TYPE_SOUN) {
                m_Type = TYPE_AUDIO;
            } else if (type == AP4_HANDLER_TYPE_VIDE) {
                m_Type = TYPE_VIDEO;
            } else if (type == AP4_HANDLER_TYPE_TEXT) {
                m_Type = TYPE_TEXT;
            } else if (type == AP4_HANDLER_TYPE_TX3G) {
                m_Type = TYPE_TEXT;
            } else if (type == AP4_HANDLER_TYPE_SUBP) {
                m_Type = TYPE_SUBP;
            } else if (type == AP4_HANDLER_TYPE_HINT) {
                m_Type = TYPE_HINT;
            }
        }
    }

    // get the media time scale
    sub = atom.FindChild("mdia/mdhd");
    if (sub) {
        AP4_MdhdAtom* mdhd = dynamic_cast<AP4_MdhdAtom*>(sub);
        if (mdhd) {
            m_MediaTimeScale = mdhd->GetTimeScale();
        }
    }

    // create a facade for the stbl atom
    AP4_ContainerAtom* stbl = dynamic_cast<AP4_ContainerAtom*>(
        atom.FindChild("mdia/minf/stbl"));
    if (stbl) {
        m_SampleTable = DNew AP4_AtomSampleTable(stbl, sample_stream);
    }
}
Ejemplo n.º 3
0
/*----------------------------------------------------------------------
|   AP4_Track::AP4_Track
+---------------------------------------------------------------------*/
AP4_Track::AP4_Track(AP4_TrakAtom&   atom, 
                     AP4_ByteStream& sample_stream, 
                     AP4_UI32        movie_time_scale) :
    m_TrakAtom(&atom),
    m_TrakAtomIsOwned(false),
    m_Type(TYPE_UNKNOWN),
    m_SampleTable(NULL),
    m_SampleTableIsOwned(true),
    m_MovieTimeScale(movie_time_scale)
{
    // find the handler type
    AP4_Atom* sub = atom.FindChild("mdia/hdlr");
    if (sub) {
        AP4_HdlrAtom* hdlr = AP4_DYNAMIC_CAST(AP4_HdlrAtom, sub);
        if (hdlr) {
            AP4_UI32 type = hdlr->GetHandlerType();
            if (type == AP4_HANDLER_TYPE_SOUN) {
                m_Type = TYPE_AUDIO;
            } else if (type == AP4_HANDLER_TYPE_VIDE) {
                m_Type = TYPE_VIDEO;
            } else if (type == AP4_HANDLER_TYPE_HINT) {
                m_Type = TYPE_HINT;
            } else if (type == AP4_HANDLER_TYPE_ODSM ||
                       type == AP4_HANDLER_TYPE_SDSM) {
                m_Type = TYPE_SYSTEM;
            } else if (type == AP4_HANDLER_TYPE_TEXT ||
                       type == AP4_HANDLER_TYPE_TX3G) {
                m_Type = TYPE_TEXT;
            } else if (type == AP4_HANDLER_TYPE_JPEG) {
                m_Type = TYPE_JPEG;
            } else if (type == AP4_HANDLER_TYPE_SUBT) {
                m_Type = TYPE_SUBTITLES;
            }
        }
    }

    // create a facade for the stbl atom
    AP4_ContainerAtom* stbl = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom.FindChild("mdia/minf/stbl"));
    if (stbl) {
        m_SampleTable = new AP4_AtomSampleTable(stbl, sample_stream);
    }
}
Ejemplo n.º 4
0
/*----------------------------------------------------------------------
|   AP4_OmaDcfEncryptingProcessor:CreateTrackHandler
+---------------------------------------------------------------------*/
AP4_Processor::TrackHandler*
AP4_OmaDcfEncryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak)
{
    // find the stsd atom
    AP4_StsdAtom* stsd = AP4_DYNAMIC_CAST(AP4_StsdAtom, trak->FindChild("mdia/minf/stbl/stsd"));

    // avoid tracks with no stsd atom (should not happen)
    if (stsd == NULL) return NULL;

    // only look at the first sample description
    AP4_SampleEntry* entry = stsd->GetSampleEntry(0);
    if (entry == NULL) return NULL;

    // create a handler for this track if we have a key for it and we know
    // how to map the type
    const AP4_DataBuffer* key;
    const AP4_DataBuffer* iv;
    AP4_UI32              format = 0;
    if (AP4_SUCCEEDED(m_KeyMap.GetKeyAndIv(trak->GetId(), key, iv))) {
        switch (entry->GetType()) {
        case AP4_ATOM_TYPE_MP4A:
            format = AP4_ATOM_TYPE_ENCA;
            break;

        case AP4_ATOM_TYPE_MP4V:
        case AP4_ATOM_TYPE_AVC1:
        case AP4_ATOM_TYPE_AVC2:
        case AP4_ATOM_TYPE_AVC3:
        case AP4_ATOM_TYPE_AVC4:
        case AP4_ATOM_TYPE_HEV1:
        case AP4_ATOM_TYPE_HVC1:
            format = AP4_ATOM_TYPE_ENCV;
            break;

        default: {
            // try to find if this is audio or video
            AP4_HdlrAtom* hdlr = AP4_DYNAMIC_CAST(AP4_HdlrAtom, trak->FindChild("mdia/hdlr"));
            if (hdlr) {
                switch (hdlr->GetHandlerType()) {
                case AP4_HANDLER_TYPE_SOUN:
                    format = AP4_ATOM_TYPE_ENCA;
                    break;

                case AP4_HANDLER_TYPE_VIDE:
                    format = AP4_ATOM_TYPE_ENCV;
                    break;
                }
            }
            break;
        }
        }
        if (format) {
            const char*    content_id = m_PropertyMap.GetProperty(trak->GetId(), "ContentId");
            const char*    rights_issuer_url = m_PropertyMap.GetProperty(trak->GetId(), "RightsIssuerUrl");
            AP4_DataBuffer textual_headers;
            AP4_Result     result = m_PropertyMap.GetTextualHeaders(trak->GetId(), textual_headers);
            if (AP4_FAILED(result)) textual_headers.SetDataSize(0);

            // create the block cipher
            AP4_BlockCipher*            block_cipher = NULL;
            AP4_BlockCipher::CtrParams  ctr_params;
            AP4_BlockCipher::CipherMode cipher_mode;
            const void*                 cipher_params = NULL;
            if (m_CipherMode == AP4_OMA_DCF_CIPHER_MODE_CBC) {
                cipher_mode = AP4_BlockCipher::CBC;
            } else if (m_CipherMode == AP4_OMA_DCF_CIPHER_MODE_CTR) {
                cipher_mode = AP4_BlockCipher::CTR;
                ctr_params.counter_size = 16;
                cipher_params = &ctr_params;
            } else {
                return NULL;
            }
            result = m_BlockCipherFactory->CreateCipher(AP4_BlockCipher::AES_128,
                     AP4_BlockCipher::ENCRYPT,
                     cipher_mode,
                     cipher_params,
                     key->GetData(),
                     key->GetDataSize(),
                     block_cipher);
            if (AP4_FAILED(result)) return NULL;
            return new AP4_OmaDcfTrackEncrypter(m_CipherMode,
                                                block_cipher,
                                                iv->GetData(),
                                                entry,
                                                format,
                                                content_id,
                                                rights_issuer_url,
                                                textual_headers.GetData(),
                                                textual_headers.GetDataSize());
        }
    }

    return NULL;
}
Ejemplo n.º 5
0
/*----------------------------------------------------------------------
|   AP4_MarlinIpmpEncryptingProcessor::Initialize
+---------------------------------------------------------------------*/
AP4_Result 
AP4_MarlinIpmpEncryptingProcessor::Initialize(
    AP4_AtomParent&                  top_level,
    AP4_ByteStream&                  /*stream*/,
    AP4_Processor::ProgressListener* /*listener = NULL*/)
{
    // get the moov atom
    AP4_MoovAtom* moov = AP4_DYNAMIC_CAST(AP4_MoovAtom, top_level.GetChild(AP4_ATOM_TYPE_MOOV));
    if (moov == NULL) return AP4_ERROR_INVALID_FORMAT;
    
    // deal with the file type
    AP4_FtypAtom* ftyp = AP4_DYNAMIC_CAST(AP4_FtypAtom, top_level.GetChild(AP4_ATOM_TYPE_FTYP));
    if (ftyp) {
        // remove the atom, it will be replaced with a new one
        top_level.RemoveChild(ftyp);
        
        // keep the existing brand and compatible brands
        AP4_Array<AP4_UI32> compatible_brands;
        compatible_brands.EnsureCapacity(ftyp->GetCompatibleBrands().ItemCount()+1);
        for (unsigned int i=0; i<ftyp->GetCompatibleBrands().ItemCount(); i++) {
            compatible_brands.Append(ftyp->GetCompatibleBrands()[i]);
        }
        
        // add the MGSV compatible brand if it is not already there
        if (!ftyp->HasCompatibleBrand(AP4_MARLIN_BRAND_MGSV)) {
            compatible_brands.Append(AP4_MARLIN_BRAND_MGSV);
        }

        // create a replacement for the major brand
        AP4_FtypAtom* new_ftyp = new AP4_FtypAtom(AP4_MARLIN_BRAND_MGSV,
                                                  0x13c078c, //AP4_MARLIN_BRAND_MGSV_MAJOR_VERSION,
                                                  &compatible_brands[0],
                                                  compatible_brands.ItemCount());
        delete ftyp;
        ftyp = new_ftyp;
    } else {
        AP4_UI32 isom = AP4_FTYP_BRAND_ISOM;
        ftyp = new AP4_FtypAtom(AP4_MARLIN_BRAND_MGSV, 0, &isom, 1);
    }
    
    // insert the ftyp atom as the first child
    top_level.AddChild(ftyp, 0);

    // create and 'mpod' track reference atom
    AP4_TrefTypeAtom* mpod = new AP4_TrefTypeAtom(AP4_ATOM_TYPE_MPOD);
    
    // look for an available track ID, starting at 1
    unsigned int od_track_id       = 0;
    unsigned int od_track_position = 0;
    for (AP4_List<AP4_TrakAtom>::Item* trak_item = moov->GetTrakAtoms().FirstItem();
                                       trak_item;
                                       trak_item = trak_item->GetNext()) {
        AP4_TrakAtom* trak = trak_item->GetData();
        if (trak) {
            od_track_position++;
            if (trak->GetId() >= od_track_id) {
                od_track_id = trak->GetId()+1;
            }
            
            // if the track is encrypted, reference it in the mpod
            if (m_KeyMap.GetKey(trak->GetId())) {
                mpod->AddTrackId(trak->GetId());
            }
            
            //m_SinfEntries.Add(new SinfEntry(trak->GetId(), NULL));
        }   
    }
    
    // check that there was at least one track in the file
    if (od_track_id == 0) return AP4_ERROR_INVALID_FORMAT;
    
    // create an initial object descriptor
    AP4_InitialObjectDescriptor* iod = 
        // FIXME: get real values from the property map
        new AP4_InitialObjectDescriptor(AP4_DESCRIPTOR_TAG_MP4_IOD,
                                        1022, // object descriptor id
                                        false, 
                                        0xFE,    // OD profile level (0xFE = No OD profile specified)
                                        0xFF,    // scene profile level
                                        0xFE,    // audio profile level
                                        0xFE,    // visual profile level
                                        0xFF);   // graphics profile

    // create an ES_ID_Inc subdescriptor and add it to the initial object descriptor
    AP4_EsIdIncDescriptor* es_id_inc = new AP4_EsIdIncDescriptor(od_track_id);
    iod->AddSubDescriptor(es_id_inc);
    
    // create an iods atom to hold the initial object descriptor
    AP4_IodsAtom* iods = new AP4_IodsAtom(iod);
    
    // add the iods atom to the moov atom (try to put it just after mvhd)
    int iods_position = 0;
    int item_position = 0;
    for (AP4_List<AP4_Atom>::Item* moov_item = moov->GetChildren().FirstItem();
                                   moov_item;
                                   moov_item = moov_item->GetNext()) {
         ++item_position;
         if (moov_item->GetData()->GetType() == AP4_ATOM_TYPE_MVHD) {
            iods_position = item_position;
            break;
         }
    }
    AP4_Result result = moov->AddChild(iods, iods_position);
    if (AP4_FAILED(result)) {
        delete iods;
        return result;
    }
    
    // create a sample table for the OD track
    AP4_SyntheticSampleTable* od_sample_table = new AP4_SyntheticSampleTable();
    
    // create the sample description for the OD track 
    AP4_MpegSystemSampleDescription* od_sample_description;
    od_sample_description = new AP4_MpegSystemSampleDescription(AP4_STREAM_TYPE_OD,
                                                                AP4_OTI_MPEG4_SYSTEM,
                                                                NULL,
                                                                32768, // buffer size
                                                                1024,  // max bitrate
                                                                512);  // avg bitrate
    od_sample_table->AddSampleDescription(od_sample_description, true);
    
    // create the OD descriptor update 
    AP4_DescriptorUpdateCommand od_update(AP4_COMMAND_TAG_OBJECT_DESCRIPTOR_UPDATE);
    for (unsigned int i=0; i<mpod->GetTrackIds().ItemCount(); i++) {
        AP4_ObjectDescriptor* od = new AP4_ObjectDescriptor(AP4_DESCRIPTOR_TAG_MP4_OD, 256+i); // descriptor id = 256+i
        od->AddSubDescriptor(new AP4_EsIdRefDescriptor(i+1));     // index into mpod (1-based)
        od->AddSubDescriptor(new AP4_IpmpDescriptorPointer(i+1)); // descriptor id = i+1
        od_update.AddDescriptor(od);
    }
    
    // create the IPMP descriptor update 
    AP4_DescriptorUpdateCommand ipmp_update(AP4_COMMAND_TAG_IPMP_DESCRIPTOR_UPDATE);
    for (unsigned int i=0; i<mpod->GetTrackIds().ItemCount(); i++) {
        // create the ipmp descriptor
        AP4_IpmpDescriptor* ipmp_descriptor = new AP4_IpmpDescriptor(i+1, AP4_MARLIN_IPMPS_TYPE_MGSV);

        // create the sinf container
        AP4_ContainerAtom* sinf = new AP4_ContainerAtom(AP4_ATOM_TYPE_SINF);

        // add the scheme type atom
        sinf->AddChild(new AP4_SchmAtom(m_UseGroupKey?
                                        AP4_PROTECTION_SCHEME_TYPE_MARLIN_ACGK:
                                        AP4_PROTECTION_SCHEME_TYPE_MARLIN_ACBC, 
                                        0x0100, NULL, true));

        // create the 'schi' container
        AP4_ContainerAtom* schi = new AP4_ContainerAtom(AP4_ATOM_TYPE_SCHI);

        // add the content ID 
        const char* content_id = m_PropertyMap.GetProperty(mpod->GetTrackIds()[i], "ContentId");
        if (content_id) {
            // add the content ID (8id_)
            schi->AddChild(new AP4_NullTerminatedStringAtom(AP4_ATOM_TYPE_8ID_, content_id));
        }
                
        // find what the track type is (necessary for the next step) and the key
        const AP4_DataBuffer* key = NULL;
        AP4_Track::Type track_type = AP4_Track::TYPE_UNKNOWN;
        for (AP4_List<AP4_TrakAtom>::Item* trak_item = moov->GetTrakAtoms().FirstItem();
                                           trak_item;
                                           trak_item = trak_item->GetNext()) {
            AP4_TrakAtom* trak = trak_item->GetData();
            if (trak->GetId() == mpod->GetTrackIds()[i]) {
                // find the handler type
                AP4_Atom* sub = trak->FindChild("mdia/hdlr");
                if (sub) {
                    AP4_HdlrAtom* hdlr = AP4_DYNAMIC_CAST(AP4_HdlrAtom, sub);
                    if (hdlr) {
                        AP4_UI32 type = hdlr->GetHandlerType();
                        if (type == AP4_HANDLER_TYPE_SOUN) {
                            track_type = AP4_Track::TYPE_AUDIO;
                        } else if (type == AP4_HANDLER_TYPE_VIDE) {
                            track_type = AP4_Track::TYPE_VIDEO;
                        }
                    }
                }
                
                // find the key
                key = m_KeyMap.GetKey(trak->GetId());
                break;
            }
        }
        
        // group key
        if (m_UseGroupKey && key) {
            // find the group key
            const AP4_DataBuffer* group_key = m_KeyMap.GetKey(0);
            if (group_key) {
                AP4_DataBuffer wrapped_key;
                result = AP4_AesKeyWrap(group_key->GetData(), key->GetData(), key->GetDataSize(), wrapped_key);
                if (AP4_FAILED(result)) return result;
                AP4_UnknownAtom* gkey = new AP4_UnknownAtom(AP4_ATOM_TYPE_GKEY, 
                                                            wrapped_key.GetData(), 
                                                            wrapped_key.GetDataSize());
                schi->AddChild(gkey);
            }
        }
                
        // create and add the security attributes (satr)
        if (track_type != AP4_Track::TYPE_UNKNOWN && key != NULL && key != NULL) {
            AP4_ContainerAtom* satr = new AP4_ContainerAtom(AP4_ATOM_TYPE_SATR);
            switch (track_type) {
                case AP4_Track::TYPE_AUDIO:
                    satr->AddChild(new AP4_NullTerminatedStringAtom(AP4_ATOM_TYPE_STYP, AP4_MARLIN_IPMP_STYP_AUDIO));
                    break;
                case AP4_Track::TYPE_VIDEO:
                    satr->AddChild(new AP4_NullTerminatedStringAtom(AP4_ATOM_TYPE_STYP, AP4_MARLIN_IPMP_STYP_VIDEO));
                    break;
                default:
                    break;
            }
            
            // add the signed attributes, if any
            const char* signed_attributes = m_PropertyMap.GetProperty(mpod->GetTrackIds()[i], "SignedAttributes");
            if (signed_attributes) {
                // decode the hex-encoded data
                unsigned int size = (unsigned int)AP4_StringLength(signed_attributes)/2;
                AP4_DataBuffer attributes_atoms;
                attributes_atoms.SetDataSize(size);
                if (AP4_SUCCEEDED(AP4_ParseHex(signed_attributes, attributes_atoms.UseData(), size))) {
                    // parse all the atoms encoded in the data and add them to the 'schi' container
                    AP4_MemoryByteStream* mbs = new AP4_MemoryByteStream(attributes_atoms.GetData(), 
                                                                         attributes_atoms.GetDataSize());
                    do {
                        AP4_Atom* atom = NULL;
                        result = AP4_DefaultAtomFactory::Instance.CreateAtomFromStream(*mbs, atom);
                        if (AP4_SUCCEEDED(result) && atom) {
                            satr->AddChild(atom);
                        }
                    } while (AP4_SUCCEEDED(result));
                    mbs->Release();
                }
            }

            // compute the hmac
            AP4_MemoryByteStream* mbs = new AP4_MemoryByteStream();
            satr->Write(*mbs);
            AP4_Hmac* digester = NULL;
            AP4_Hmac::Create(AP4_Hmac::SHA256, key->GetData(), key->GetDataSize(), digester);
            digester->Update(mbs->GetData(), mbs->GetDataSize());
            AP4_DataBuffer hmac_value;
            digester->Final(hmac_value);
            AP4_Atom* hmac = new AP4_UnknownAtom(AP4_ATOM_TYPE_HMAC, hmac_value.GetData(), hmac_value.GetDataSize());
            
            schi->AddChild(satr);
            schi->AddChild(hmac);
            
            mbs->Release();
        }
            
        sinf->AddChild(schi);
         
        // serialize the sinf atom to a buffer and set it as the ipmp data
        AP4_MemoryByteStream* sinf_data = new AP4_MemoryByteStream((AP4_Size)sinf->GetSize());
        sinf->Write(*sinf_data);
        ipmp_descriptor->SetData(sinf_data->GetData(), sinf_data->GetDataSize());
        sinf_data->Release();
        
        ipmp_update.AddDescriptor(ipmp_descriptor);
    }
    
    // add the sample with the descriptors and updates
    AP4_MemoryByteStream* sample_data = new AP4_MemoryByteStream();
    od_update.Write(*sample_data);
    ipmp_update.Write(*sample_data);
    od_sample_table->AddSample(*sample_data, 0, sample_data->GetDataSize(), 0, 0, 0, 0, true);
    
    // create the OD track
    AP4_TrakAtom* od_track = new AP4_TrakAtom(od_sample_table,
                                              AP4_HANDLER_TYPE_ODSM,
                                              "Bento4 Marlin OD Handler",
                                              od_track_id,
                                              0, 0,
                                              1, 1000, 1, 0, "und",
                                              0, 0);
    
    // add an entry in the processor's stream table to indicate that the 
    // media data for the OD track is not in the file stream, but in our
    // memory stream.
    m_ExternalTrackData.Add(new ExternalTrackData(od_track_id, sample_data));
    sample_data->Release();
    
    // add a tref track reference atom
    AP4_ContainerAtom* tref = new AP4_ContainerAtom(AP4_ATOM_TYPE_TREF);
    tref->AddChild(mpod);
    od_track->AddChild(tref, 1); // add after 'tkhd'
    
    // add the track to the moov atoms (just after the last track)
    moov->AddChild(od_track, od_track_position);
    
    return AP4_SUCCESS;
}