bool genericSetItem( MP4File& file, const MP4ItmfItem* item ) { if( !item || !item->__handle ) return false; MP4Atom* ilst = file.FindAtom( "moov.udta.meta.ilst" ); if( !ilst ) return false; MP4ItemAtom* const old = static_cast<MP4ItemAtom*>(item->__handle); const uint32_t childCount = ilst->GetNumberOfChildAtoms(); uint32_t fidx = numeric_limits<uint32_t>::max(); for( uint32_t i = 0; i < childCount; i++ ) { MP4Atom* atom = ilst->GetChildAtom( i ); if( atom == old ) { fidx = i; break; } } if( fidx == numeric_limits<uint32_t>::max() ) return false; ilst->DeleteChildAtom( old ); delete old; MP4ItemAtom& itemAtom = *(MP4ItemAtom*)MP4Atom::CreateAtom( file, ilst, item->code ); ilst->InsertChildAtom( &itemAtom, fidx ); return __itemModelToAtom( *item, itemAtom ); }
void MP4SoundAtom::Read() { MP4Atom *parent = GetParentAtom(); if (ATOMID(parent->GetType()) != ATOMID("stsd")) { // Quicktime has an interesting thing - they'll put an mp4a atom // which is blank inside a wave atom, which is inside an mp4a atom // we have a mp4a inside an wave inside an mp4a - delete all properties m_pProperties.Delete(8); m_pProperties.Delete(7); m_pProperties.Delete(6); m_pProperties.Delete(5); m_pProperties.Delete(4); m_pProperties.Delete(3); m_pProperties.Delete(2); m_pProperties.Delete(1); m_pProperties.Delete(0); if (ATOMID(GetType()) == ATOMID("alac")) { AddProperty(new MP4BytesProperty("decoderConfig", m_size)); ReadProperties(); } if (m_pChildAtomInfos.Size() > 0) { ReadChildAtoms(); } } else { ReadProperties(0, 3); // read first 3 properties AddProperties(((MP4IntegerProperty *)m_pProperties[2])->GetValue()); ReadProperties(3); // continue if (m_pChildAtomInfos.Size() > 0) { ReadChildAtoms(); } } Skip(); }
void MP4D263Atom::Write() { // Check whether we have valid values in the bitr atom // (if it exists, of course) MP4Atom* bitrAtom = FindAtom("d263.bitr"); if (bitrAtom) { uint32_t avgBitrate; uint32_t maxBitrate; MP4Integer32Property* pProp; bitrAtom->FindProperty("bitr.avgBitrate", (MP4Property**)&pProp, NULL); ASSERT(pProp); avgBitrate = pProp->GetValue(); bitrAtom->FindProperty("bitr.maxBitrate", (MP4Property**)&pProp, NULL); ASSERT(pProp); maxBitrate = pProp->GetValue(); if (!maxBitrate && !avgBitrate) { DeleteChildAtom(bitrAtom); } } MP4Atom::Write(); }
MP4ItmfItemList* genericGetItemsByCode( MP4File& file, const string& code ) { MP4Atom* ilst = file.FindAtom( "moov.udta.meta.ilst" ); if( !ilst ) return __itemListAlloc(); // pass 1: filter by code and populate indexList const uint32_t childCount = ilst->GetNumberOfChildAtoms(); vector<uint32_t> indexList; for( uint32_t i = 0; i < childCount; i++ ) { if( ATOMID( ilst->GetChildAtom( i )->GetType() ) != ATOMID( code.c_str() )) continue; indexList.push_back( i ); } if( indexList.size() < 1 ) return __itemListAlloc(); MP4ItmfItemList& list = *__itemListAlloc(); __itemListResize( list, (uint32_t)indexList.size() ); // pass 2: process each atom const vector<uint32_t>::size_type max = indexList.size(); for( vector<uint32_t>::size_type i = 0; i < max; i++ ) { uint32_t& aidx = indexList[i]; __itemAtomToModel( *(MP4ItemAtom*)ilst->GetChildAtom( aidx ), list.elements[i] ); } return &list; }
void MP4File::Make3GPCompliant(const char* fileName, char* majorBrand, u_int32_t minorVersion, char** supportedBrands, u_int32_t supportedBrandsCount, bool deleteIodsAtom) { char brand[5] = "3gp5"; char* _3gpSupportedBrands[1] = { (char*)&brand }; if (majorBrand) { if (!supportedBrands || !supportedBrandsCount) { throw new MP4Error("Invalid parameters", "MP4File::Make3GPCompliant"); } } MakeFtypAtom( majorBrand ? majorBrand : (char*)brand, majorBrand ? minorVersion : _3GP_MINOR_VERSION, majorBrand ? supportedBrands : (char**)_3gpSupportedBrands, majorBrand ? supportedBrandsCount : 1); if (deleteIodsAtom) { // Delete the iods atom, if it exists.... MP4Atom* iodsAtom = m_pRootAtom->FindAtom("moov.iods"); if (iodsAtom) { MP4Atom* moovAtom = m_pRootAtom->FindAtom("moov"); ASSERT(moovAtom); moovAtom->DeleteChildAtom(iodsAtom); } } }
void MP4RootAtom::FinishOptimalWrite() { // finish writing mdat m_pChildAtoms[GetLastMdatIndex()]->FinishWrite(m_pFile->Use64Bits("mdat")); // find moov atom u_int32_t size = m_pChildAtoms.Size(); MP4Atom* pMoovAtom = NULL; u_int32_t i; for (i = 0; i < size; i++) { if (!strcmp("moov", m_pChildAtoms[i]->GetType())) { pMoovAtom = m_pChildAtoms[i]; break; } } ASSERT(i < size); // rewrite moov so that updated chunkOffsets are written to disk m_pFile->SetPosition(pMoovAtom->GetStart()); u_int64_t oldSize = pMoovAtom->GetSize(); pMoovAtom->Write(); // sanity check u_int64_t newSize = pMoovAtom->GetSize(); ASSERT(oldSize == newSize); }
void MP4Track::UpdateSyncSamples(MP4SampleId sampleId, bool isSyncSample) { if (isSyncSample) { // if stss atom exists, add entry if (m_pStssCountProperty) { m_pStssSampleProperty->AddValue(sampleId); m_pStssCountProperty->IncrementValue(); } // else nothing to do (yet) } else { // !isSyncSample // if stss atom doesn't exist, create one if (m_pStssCountProperty == NULL) { MP4Atom* pStssAtom = AddAtom("trak.mdia.minf.stbl", "stss"); pStssAtom->FindProperty( "stss.entryCount", (MP4Property**)&m_pStssCountProperty); pStssAtom->FindProperty( "stss.entries.sampleNumber", (MP4Property**)&m_pStssSampleProperty); // set values for all samples that came before this one for (MP4SampleId sid = 1; sid < sampleId; sid++) { m_pStssSampleProperty->AddValue(sid); m_pStssCountProperty->IncrementValue(); } } // else nothing to do } }
void MP4Track::UpdateRenderingOffsets(MP4SampleId sampleId, MP4Duration renderingOffset) { // if ctts atom doesn't exist if (m_pCttsCountProperty == NULL) { // no rendering offset, so nothing to do if (renderingOffset == 0) { return; } // else create a ctts atom MP4Atom* pCttsAtom = AddAtom("trak.mdia.minf.stbl", "ctts"); // and get handles on the properties pCttsAtom->FindProperty( "ctts.entryCount", (MP4Property**)&m_pCttsCountProperty); pCttsAtom->FindProperty( "ctts.entries.sampleCount", (MP4Property**)&m_pCttsSampleCountProperty); pCttsAtom->FindProperty( "ctts.entries.sampleOffset", (MP4Property**)&m_pCttsSampleOffsetProperty); // if this is not the first sample if (sampleId > 1) { // add a ctts entry for all previous samples // with rendering offset equal to zero m_pCttsSampleCountProperty->AddValue(sampleId - 1); m_pCttsSampleOffsetProperty->AddValue(0); m_pCttsCountProperty->IncrementValue();; } } // ctts atom exists (now) u_int32_t numCtts = m_pCttsCountProperty->GetValue(); // if renderingOffset == renderingOffset of last entry if (numCtts && renderingOffset == m_pCttsSampleOffsetProperty->GetValue(numCtts-1)) { // increment last entry sampleCount m_pCttsSampleCountProperty->IncrementValue(1, numCtts-1); } else { // add ctts entry, sampleCount = 1, sampleOffset = renderingOffset m_pCttsSampleCountProperty->AddValue(1); m_pCttsSampleOffsetProperty->AddValue(renderingOffset); m_pCttsCountProperty->IncrementValue(); } }
void MP4HntiAtom::Read() { MP4Atom* grandParent = m_pParentAtom->GetParentAtom(); ASSERT(grandParent); if (ATOMID(grandParent->GetType()) == ATOMID("trak")) { ExpectChildAtom("sdp ", Optional, OnlyOne); } else { ExpectChildAtom("rtp ", Optional, OnlyOne); } MP4Atom::Read(); }
MP4Atom* MP4Track::AddAtom(char* parentName, char* childName) { MP4Atom* pChildAtom = MP4Atom::CreateAtom(childName); MP4Atom* pParentAtom = m_pTrakAtom->FindAtom(parentName); ASSERT(pParentAtom); pParentAtom->AddChildAtom(pChildAtom); pChildAtom->Generate(); return pChildAtom; }
MP4ItmfItemList* genericGetItemsByMeaning( MP4File& file, const string& meaning, const string& name ) { MP4Atom* ilst = file.FindAtom( "moov.udta.meta.ilst" ); if( !ilst ) return __itemListAlloc(); // pass 1: filter by code and populate indexList const uint32_t childCount = ilst->GetNumberOfChildAtoms(); vector<uint32_t> indexList; for( uint32_t i = 0; i < childCount; i++ ) { MP4Atom& atom = *ilst->GetChildAtom( i ); if( ATOMID( atom.GetType() ) != ATOMID( "----" )) continue; // filter-out meaning mismatch MP4MeanAtom* meanAtom = (MP4MeanAtom*)atom.FindAtom( "----.mean" ); if( !meanAtom ) continue; if( meanAtom->value.CompareToString( meaning )) continue; if( !name.empty() ) { // filter-out name mismatch MP4MeanAtom* nameAtom = (MP4MeanAtom*)atom.FindAtom( "----.name" ); if( !nameAtom ) continue; if( nameAtom->value.CompareToString( name )) continue; } indexList.push_back( i ); } if( indexList.size() < 1 ) return __itemListAlloc(); MP4ItmfItemList& list = *__itemListAlloc(); __itemListResize( list, (uint32_t)indexList.size() ); // pass 2: process each atom const vector<uint32_t>::size_type max = indexList.size(); for( vector<uint32_t>::size_type i = 0; i < max; i++ ) { uint32_t& aidx = indexList[i]; __itemAtomToModel( *(MP4ItemAtom*)ilst->GetChildAtom( aidx ), list.elements[i] ); } return &list; }
void MP4Meta2Atom::Read () { MP4Atom *parent = GetParentAtom(); if (ATOMID(parent->GetType()) == ATOMID("udta")) { // add data property AddReserved("reserved2", 4); /* 0 */ AddProperty( new MP4BytesProperty("metadata")); /* 1 */ ((MP4BytesProperty*)m_pProperties[1])->SetValueSize(m_size - 4); } else { ExpectChildAtom("data", Required, OnlyOne); } MP4Atom::Read(); }
bool genericRemoveItem( MP4File& file, const MP4ItmfItem* item ) { if( !item || !item->__handle ) return false; MP4Atom* ilst = file.FindAtom( "moov.udta.meta.ilst" ); if( !ilst ) return false; MP4ItemAtom* const old = static_cast<MP4ItemAtom*>(item->__handle); ilst->DeleteChildAtom( old ); delete old; return true; }
bool PictureAspectRatioBox::remove( MP4FileHandle file, uint16_t trackIndex ) { MP4Atom* coding; if( findCoding( file, trackIndex, coding )) throw new MP4Exception( "supported coding not found" ); MP4Atom* pasp; if( findPictureAspectRatioBox( file, *coding, pasp )) throw new MP4Exception( "pasp-box not found" ); coding->DeleteChildAtom( pasp ); delete pasp; return false; }
void MP4StblAtom::Generate() { // as usual MP4Atom::Generate(); // but we also need one of the chunk offset atoms MP4Atom* pChunkOffsetAtom; if (m_File.Use64Bits(GetType())) { pChunkOffsetAtom = CreateAtom(m_File, this, "co64"); } else { pChunkOffsetAtom = CreateAtom(m_File, this, "stco"); } AddChildAtom(pChunkOffsetAtom); // and ask it to self generate pChunkOffsetAtom->Generate(); }
bool genericAddItem( MP4File& file, const MP4ItmfItem* item ) { if( !item ) return false; MP4Atom* ilst = file.FindAtom( "moov.udta.meta.ilst" ); if( !ilst ) { file.AddDescendantAtoms( "moov", "udta.meta.ilst" ); ilst = file.FindAtom( "moov.udta.meta.ilst" ); ASSERT( ilst ); } MP4ItemAtom& itemAtom = *(MP4ItemAtom*)MP4Atom::CreateAtom( file, ilst, item->code ); ilst->AddChildAtom( &itemAtom ); return __itemModelToAtom( *item, itemAtom ); }
MP4ItmfItemList* genericGetItems( MP4File& file ) { MP4Atom* ilst = file.FindAtom( "moov.udta.meta.ilst" ); if( !ilst ) return __itemListAlloc(); const uint32_t itemCount = ilst->GetNumberOfChildAtoms(); if( itemCount < 1 ) return __itemListAlloc(); MP4ItmfItemList& list = *__itemListAlloc(); __itemListResize( list, itemCount ); for( uint32_t i = 0; i < list.size; i++ ) __itemAtomToModel( *(MP4ItemAtom*)ilst->GetChildAtom( i ), list.elements[i] ); return &list; }
bool fileFetchSummaryInfo( MP4FileHandle file, FileSummaryInfo& info ) { if( file == MP4_INVALID_FILE_HANDLE ) return true; MP4File& mp4 = *((MP4File*)file); MP4Atom* root = mp4.FindAtom( "" ); if( !root ) return true; MP4FtypAtom* ftyp = (MP4FtypAtom*)root->FindAtom( "ftyp" ); if( !ftyp ) return true; info.major_brand = ftyp->majorBrand.GetValue(); info.minor_version = ftyp->minorVersion.GetValue(); const uint32_t cbmax = ftyp->compatibleBrands.GetCount(); for( uint32_t i = 0; i < cbmax; i++ ) { string s = ftyp->compatibleBrands.GetValue( i ); // remove spaces so brand set is presentable string stripped; const string::size_type max = s.length(); for( string::size_type pos = 0; pos < max; pos++ ) { if( s[pos] != ' ' ) stripped += s[pos]; } if( stripped.empty() ) continue; info.compatible_brands.insert( stripped ); } info.nlargesize = 0; info.nversion1 = 0; info.nspecial = 0; searchFor64bit( *root, info ); return false; }
void searchFor64bit( MP4Atom& atom, FileSummaryInfo& info ) { const uint32_t max = atom.GetNumberOfChildAtoms(); for( uint32_t i = 0; i < max; i++ ) { MP4Atom& child = *atom.GetChildAtom( i ); if( child.GetLargesizeMode() ) info.nlargesize++; MP4Integer8Property* version; if( child.FindProperty( "version", (MP4Property**)&version ) && version->GetValue() == 1 ) info.nversion1++; if( !strcmp( child.GetType(), "co64" )) info.nspecial++; searchFor64bit( child, info ); } }
bool PictureAspectRatioBox::set( MP4FileHandle file, uint16_t trackIndex, const Item& item ) { MP4Atom* coding; if( findCoding( file, trackIndex, coding )) throw new MP4Exception( "supported coding not found" ); MP4Atom* pasp; if( findPictureAspectRatioBox( file, *coding, pasp )) throw new MP4Exception( "pasp-box not found" ); MP4Integer16Property* hSpacing; MP4Integer16Property* vSpacing; if( pasp->FindProperty( "pasp.hSpacing", (MP4Property**)&hSpacing )) hSpacing->SetValue( item.hSpacing ); if( pasp->FindProperty( "pasp.vSpacing", (MP4Property**)&vSpacing )) vSpacing->SetValue( item.vSpacing ); return false; }
bool MP4Track::InitEditListProperties() { m_pElstCountProperty = NULL; m_pElstMediaTimeProperty = NULL; m_pElstDurationProperty = NULL; m_pElstRateProperty = NULL; m_pElstReservedProperty = NULL; MP4Atom* pElstAtom = m_pTrakAtom->FindAtom("trak.edts.elst"); if (!pElstAtom) { return false; } pElstAtom->FindProperty( "elst.entryCount", (MP4Property**)&m_pElstCountProperty); pElstAtom->FindProperty( "elst.entries.mediaTime", (MP4Property**)&m_pElstMediaTimeProperty); pElstAtom->FindProperty( "elst.entries.segmentDuration", (MP4Property**)&m_pElstDurationProperty); pElstAtom->FindProperty( "elst.entries.mediaRate", (MP4Property**)&m_pElstRateProperty); pElstAtom->FindProperty( "elst.entries.reserved", (MP4Property**)&m_pElstReservedProperty); return m_pElstCountProperty && m_pElstMediaTimeProperty && m_pElstDurationProperty && m_pElstRateProperty && m_pElstReservedProperty; }
void MP4File::CreateIsmaIodFromFile( MP4TrackId odTrackId, MP4TrackId sceneTrackId, MP4TrackId audioTrackId, MP4TrackId videoTrackId, u_int8_t** ppBytes, u_int64_t* pNumBytes) { MP4Descriptor* pIod = new MP4IODescriptor(); pIod->SetTag(MP4IODescrTag); pIod->Generate(); MP4Atom* pIodsAtom = FindAtom("moov.iods"); ASSERT(pIodsAtom); MP4DescriptorProperty* pSrcIod = (MP4DescriptorProperty*)pIodsAtom->GetProperty(2); CloneIntegerProperty(pIod, pSrcIod, "objectDescriptorId"); CloneIntegerProperty(pIod, pSrcIod, "ODProfileLevelId"); CloneIntegerProperty(pIod, pSrcIod, "sceneProfileLevelId"); CloneIntegerProperty(pIod, pSrcIod, "audioProfileLevelId"); CloneIntegerProperty(pIod, pSrcIod, "visualProfileLevelId"); CloneIntegerProperty(pIod, pSrcIod, "graphicsProfileLevelId"); // mutate esIds from MP4ESIDIncDescrTag to MP4ESDescrTag MP4DescriptorProperty* pEsProperty; pIod->FindProperty("esIds", (MP4Property**)&pEsProperty); pEsProperty->SetTags(MP4ESDescrTag); MP4IntegerProperty* pSetProperty; MP4IntegerProperty* pSceneESID; MP4IntegerProperty* pOdESID; // OD MP4Descriptor* pOdEsd = pEsProperty->AddDescriptor(MP4ESDescrTag); pOdEsd->Generate(); pOdEsd->FindProperty("ESID", (MP4Property**)&pOdESID); // we set the OD ESID to a non-zero unique value pOdESID->SetValue(m_odTrackId); pOdEsd->FindProperty("URLFlag", (MP4Property**)&pSetProperty); pSetProperty->SetValue(1); u_int8_t* pBytes; u_int64_t numBytes; CreateIsmaODUpdateCommandFromFileForStream( audioTrackId, videoTrackId, &pBytes, &numBytes); VERBOSE_ISMA(GetVerbosity(), printf("OD data =\n"); MP4HexDump(pBytes, numBytes)); char* odCmdBase64 = MP4ToBase64(pBytes, numBytes); char* urlBuf = (char*)MP4Malloc(strlen(odCmdBase64) + 64); sprintf(urlBuf, "data:application/mpeg4-od-au;base64,%s", odCmdBase64); MP4StringProperty* pUrlProperty; pOdEsd->FindProperty("URL", (MP4Property**)&pUrlProperty); pUrlProperty->SetValue(urlBuf); VERBOSE_ISMA(GetVerbosity(), printf("OD data URL = \042%s\042\n", urlBuf)); MP4Free(odCmdBase64); odCmdBase64 = NULL; MP4Free(pBytes); pBytes = NULL; MP4Free(urlBuf); urlBuf = NULL; MP4DescriptorProperty* pSrcDcd = NULL; // HACK temporarily point to scene decoder config FindProperty(MakeTrackName(odTrackId, "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr"), (MP4Property**)&pSrcDcd); ASSERT(pSrcDcd); MP4Property* pOrgOdEsdProperty = pOdEsd->GetProperty(8); pOdEsd->SetProperty(8, pSrcDcd); // bufferSizeDB needs to be set appropriately MP4BitfieldProperty* pBufferSizeProperty = NULL; pOdEsd->FindProperty("decConfigDescr.bufferSizeDB", (MP4Property**)&pBufferSizeProperty); ASSERT(pBufferSizeProperty); pBufferSizeProperty->SetValue(numBytes); // SL config needs to change from 2 (file) to 1 (null) pOdEsd->FindProperty("slConfigDescr.predefined", (MP4Property**)&pSetProperty); pSetProperty->SetValue(1); // Scene MP4Descriptor* pSceneEsd = pEsProperty->AddDescriptor(MP4ESDescrTag); pSceneEsd->Generate(); pSceneEsd->FindProperty("ESID", (MP4Property**)&pSceneESID); // we set the Scene ESID to a non-zero unique value pSceneESID->SetValue(sceneTrackId); pSceneEsd->FindProperty("URLFlag", (MP4Property**)&pSetProperty); pSetProperty->SetValue(1); CreateIsmaSceneCommand( MP4_IS_VALID_TRACK_ID(audioTrackId), MP4_IS_VALID_TRACK_ID(videoTrackId), &pBytes, &numBytes); VERBOSE_ISMA(GetVerbosity(), printf("Scene data =\n"); MP4HexDump(pBytes, numBytes)); char *sceneCmdBase64 = MP4ToBase64(pBytes, numBytes); urlBuf = (char*)MP4Malloc(strlen(sceneCmdBase64) + 64); sprintf(urlBuf, "data:application/mpeg4-bifs-au;base64,%s", sceneCmdBase64); pSceneEsd->FindProperty("URL", (MP4Property**)&pUrlProperty); pUrlProperty->SetValue(urlBuf); VERBOSE_ISMA(GetVerbosity(), printf("Scene data URL = \042%s\042\n", urlBuf)); MP4Free(sceneCmdBase64); sceneCmdBase64 = NULL; MP4Free(urlBuf); urlBuf = NULL; MP4Free(pBytes); pBytes = NULL; // HACK temporarily point to scene decoder config FindProperty(MakeTrackName(sceneTrackId, "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr"), (MP4Property**)&pSrcDcd); ASSERT(pSrcDcd); MP4Property* pOrgSceneEsdProperty = pSceneEsd->GetProperty(8); pSceneEsd->SetProperty(8, pSrcDcd); // bufferSizeDB needs to be set pBufferSizeProperty = NULL; pSceneEsd->FindProperty("decConfigDescr.bufferSizeDB", (MP4Property**)&pBufferSizeProperty); ASSERT(pBufferSizeProperty); pBufferSizeProperty->SetValue(numBytes); // SL config needs to change from 2 (file) to 1 (null) pSceneEsd->FindProperty("slConfigDescr.predefined", (MP4Property**)&pSetProperty); pSetProperty->SetValue(1); // finally get the whole thing written to a memory pIod->WriteToMemory(this, ppBytes, pNumBytes); // now carefully replace esd properties before destroying pOdEsd->SetProperty(8, pOrgOdEsdProperty); pSceneEsd->SetProperty(8, pOrgSceneEsdProperty); pSceneESID->SetValue(0); // restore 0 value pOdESID->SetValue(0); delete pIod; VERBOSE_ISMA(GetVerbosity(), printf("IOD data =\n"); MP4HexDump(*ppBytes, *pNumBytes)); }
void MP4File::MakeFtypAtom(char* majorBrand, u_int32_t minorVersion, char** supportedBrands, u_int32_t supportedBrandsCount) { bool rewriteNeeded = false; u_int32_t currentSupportedBrandsCount; u_int32_t i; MP4Atom* ftypAtom = m_pRootAtom->FindAtom("ftyp"); if (ftypAtom == NULL) { ftypAtom = InsertChildAtom(m_pRootAtom, "ftyp", 0); } if (majorBrand == NULL) return; MP4StringProperty* pMajorBrandProperty; if (!ftypAtom->FindProperty( "ftyp.majorBrand", (MP4Property**)&pMajorBrandProperty)) return; pMajorBrandProperty->SetValue(majorBrand); MP4Integer32Property* pMinorVersionProperty; if (!ftypAtom->FindProperty( "ftype.minorVersion", (MP4Property**)&pMinorVersionProperty)) return; pMinorVersionProperty->SetValue(minorVersion); MP4Integer32Property* pCompatibleBrandsCountProperty; if (!ftypAtom->FindProperty( "ftyp.compatibleBrandsCount", (MP4Property**)&pCompatibleBrandsCountProperty)) return; currentSupportedBrandsCount = pCompatibleBrandsCountProperty->GetValue(); MP4TableProperty* pCompatibleBrandsProperty; if (!ftypAtom->FindProperty( "ftyp.compatibleBrands", (MP4Property**)&pCompatibleBrandsProperty)) return; MP4StringProperty* pBrandProperty = (MP4StringProperty*) pCompatibleBrandsProperty->GetProperty(0); ASSERT(pBrandProperty); for (i = 0 ; i < ((currentSupportedBrandsCount > supportedBrandsCount) ? supportedBrandsCount : currentSupportedBrandsCount) ; i++) { pBrandProperty->SetValue(supportedBrands[i], i); } if (i < supportedBrandsCount) { for ( ; i < supportedBrandsCount ; i++) { pBrandProperty->AddValue(supportedBrands[i]); } } if (currentSupportedBrandsCount != supportedBrandsCount) { rewriteNeeded = true; pBrandProperty->SetCount(supportedBrandsCount); pCompatibleBrandsCountProperty->SetReadOnly(false); pCompatibleBrandsCountProperty->SetValue(supportedBrandsCount); pCompatibleBrandsCountProperty->SetReadOnly(true); } }
FILE* MP4Track::GetSampleFile(MP4SampleId sampleId) { u_int32_t stscIndex = GetSampleStscIndex(sampleId); u_int32_t stsdIndex = m_pStscSampleDescrIndexProperty->GetValue(stscIndex); // check if the answer will be the same as last time if (m_lastStsdIndex && stsdIndex == m_lastStsdIndex) { return m_lastSampleFile; } MP4Atom* pStsdAtom = m_pTrakAtom->FindAtom("trak.mdia.minf.stbl.stsd"); ASSERT(pStsdAtom); MP4Atom* pStsdEntryAtom = pStsdAtom->GetChildAtom(stsdIndex - 1); ASSERT(pStsdEntryAtom); MP4Integer16Property* pDrefIndexProperty = NULL; pStsdEntryAtom->FindProperty( "*.dataReferenceIndex", (MP4Property**)&pDrefIndexProperty); if (pDrefIndexProperty == NULL) { throw new MP4Error("invalid stsd entry", "GetSampleFile"); } u_int32_t drefIndex = pDrefIndexProperty->GetValue(); MP4Atom* pDrefAtom = m_pTrakAtom->FindAtom("trak.mdia.minf.dinf.dref"); ASSERT(pDrefAtom); MP4Atom* pUrlAtom = pDrefAtom->GetChildAtom(drefIndex - 1); ASSERT(pUrlAtom); FILE* pFile; if (pUrlAtom->GetFlags() & 1) { pFile = NULL; // self-contained } else { #ifndef USE_FILE_CALLBACKS MP4StringProperty* pLocationProperty = NULL; pUrlAtom->FindProperty( "*.location", (MP4Property**)&pLocationProperty); ASSERT(pLocationProperty); const char* url = pLocationProperty->GetValue(); VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(), printf("dref url = %s\n", url)); pFile = (FILE*)-1; // attempt to open url if it's a file url // currently this is the only thing we understand if (!strncmp(url, "file:", 5)) { const char* fileName = url + 5; if (!strncmp(fileName, "//", 2)) { fileName = strchr(fileName + 2, '/'); } if (fileName) { pFile = fopen(fileName, "rb"); if (!pFile) { pFile = (FILE*)-1; } } } #else throw new MP4Error(errno, "Function not supported when using callbacks", "GetSampleFile"); #endif } if (m_lastSampleFile) { #ifndef USE_FILE_CALLBACKS fclose(m_lastSampleFile); #else throw new MP4Error(errno, "Function not supported when using callbacks", "GetSampleFile"); #endif } // cache the answer m_lastStsdIndex = stsdIndex; m_lastSampleFile = pFile; return pFile; }
void MP4File::Make3GPCompliant(const char* fileName, char* majorBrand, u_int32_t minorVersion, char** supportedBrands, u_int32_t supportedBrandsCount, bool deleteIodsAtom) { char brand[5] = "3gp5"; char* _3gpSupportedBrands[1] = { (char*)&brand }; if (majorBrand) { if (!supportedBrands || !supportedBrandsCount) { throw new MP4Error("Invalid parameters", "MP4File::Make3GPCompliant"); } } m_fileName = MP4Stralloc(fileName); m_mode = 'r'; // first load meta-info into memory Open("rb"); ReadFromFile(); CacheProperties(); // of moov atom // now switch over to writing the new file MP4Free(m_fileName); // create a temporary file m_fileName = MP4Stralloc(TempFileName()); MakeFtypAtom( majorBrand ? majorBrand : (char*)brand, majorBrand ? minorVersion : _3GP_MINOR_VERSION, majorBrand ? supportedBrands : (char**)_3gpSupportedBrands, majorBrand ? supportedBrandsCount : 1); if (deleteIodsAtom) { // Delete the iods atom, if it exists.... MP4Atom* iodsAtom = m_pRootAtom->FindAtom("moov.iods"); if (iodsAtom) { MP4Atom* moovAtom = m_pRootAtom->FindAtom("moov"); ASSERT(moovAtom); moovAtom->DeleteChildAtom(iodsAtom); } } FILE* pReadFile = m_pFile; m_pFile = NULL; m_mode = 'w'; Open("wb"); SetIntegerProperty("moov.mvhd.modificationTime", MP4GetAbsTimestamp()); // writing meta info in the optimal order ((MP4RootAtom*)m_pRootAtom)->BeginOptimalWrite(); // write data in optimal order RewriteMdat(pReadFile, m_pFile); // finish writing ((MP4RootAtom*)m_pRootAtom)->FinishOptimalWrite(); // cleanup fclose(m_pFile); m_pFile = NULL; fclose(pReadFile); // move temporary file into place Rename(m_fileName, fileName); }
void MP4File::CreateIsmaODUpdateCommandFromFileForStream( MP4TrackId audioTrackId, MP4TrackId videoTrackId, u_int8_t** ppBytes, u_int64_t* pNumBytes) { MP4DescriptorProperty* pAudioEsd = NULL; MP4Integer8Property* pAudioSLConfigPredef = NULL; MP4BitfieldProperty* pAudioAccessUnitEndFlag = NULL; int oldAudioUnitEndFlagValue = 0; MP4DescriptorProperty* pVideoEsd = NULL; MP4Integer8Property* pVideoSLConfigPredef = NULL; MP4BitfieldProperty* pVideoAccessUnitEndFlag = NULL; int oldVideoUnitEndFlagValue = 0; MP4IntegerProperty* pAudioEsdId = NULL; MP4IntegerProperty* pVideoEsdId = NULL; if (audioTrackId != MP4_INVALID_TRACK_ID) { // changed mp4a to * to handle enca case MP4Atom* pEsdsAtom = FindAtom(MakeTrackName(audioTrackId, "mdia.minf.stbl.stsd.*.esds")); ASSERT(pEsdsAtom); pAudioEsd = (MP4DescriptorProperty*)(pEsdsAtom->GetProperty(2)); // ESID is 0 for file, stream needs to be non-ze pAudioEsd->FindProperty("ESID", (MP4Property**)&pAudioEsdId); ASSERT(pAudioEsdId); pAudioEsdId->SetValue(audioTrackId); // SL config needs to change from 2 (file) to 1 (null) pAudioEsd->FindProperty("slConfigDescr.predefined", (MP4Property**)&pAudioSLConfigPredef); ASSERT(pAudioSLConfigPredef); pAudioSLConfigPredef->SetValue(0); pAudioEsd->FindProperty("slConfigDescr.useAccessUnitEndFlag", (MP4Property **)&pAudioAccessUnitEndFlag); oldAudioUnitEndFlagValue = pAudioAccessUnitEndFlag->GetValue(); pAudioAccessUnitEndFlag->SetValue(1); } if (videoTrackId != MP4_INVALID_TRACK_ID) { // changed mp4v to * to handle encv case MP4Atom* pEsdsAtom = FindAtom(MakeTrackName(videoTrackId, "mdia.minf.stbl.stsd.*.esds")); ASSERT(pEsdsAtom); pVideoEsd = (MP4DescriptorProperty*)(pEsdsAtom->GetProperty(2)); pVideoEsd->FindProperty("ESID", (MP4Property**)&pVideoEsdId); ASSERT(pVideoEsdId); pVideoEsdId->SetValue(videoTrackId); // SL config needs to change from 2 (file) to 1 (null) pVideoEsd->FindProperty("slConfigDescr.predefined", (MP4Property**)&pVideoSLConfigPredef); ASSERT(pVideoSLConfigPredef); pVideoSLConfigPredef->SetValue(0); pVideoEsd->FindProperty("slConfigDescr.useAccessUnitEndFlag", (MP4Property **)&pVideoAccessUnitEndFlag); oldVideoUnitEndFlagValue = pVideoAccessUnitEndFlag->GetValue(); pVideoAccessUnitEndFlag->SetValue(1); } CreateIsmaODUpdateCommandForStream( pAudioEsd, pVideoEsd, ppBytes, pNumBytes); VERBOSE_ISMA(GetVerbosity(), printf("After CreateImsaODUpdateCommandForStream len %llu =\n", *pNumBytes); MP4HexDump(*ppBytes, *pNumBytes)); // return SL config values to 2 (file) // return ESID values to 0 if (pAudioSLConfigPredef) { pAudioSLConfigPredef->SetValue(2); } if (pAudioEsdId) { pAudioEsdId->SetValue(0); } if (pAudioAccessUnitEndFlag) { pAudioAccessUnitEndFlag->SetValue(oldAudioUnitEndFlagValue ); } if (pVideoEsdId) { pVideoEsdId->SetValue(0); } if (pVideoSLConfigPredef) { pVideoSLConfigPredef->SetValue(2); } if (pVideoAccessUnitEndFlag) { pVideoAccessUnitEndFlag->SetValue(oldVideoUnitEndFlagValue ); } }