12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728 |
- /*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is MPEG4IP.
- *
- * The Initial Developer of the Original Code is Cisco Systems Inc.
- * Portions created by Cisco Systems Inc. are
- * Copyright (C) Cisco Systems Inc. 2001 - 2005. All Rights Reserved.
- *
- * 3GPP features implementation is based on 3GPP's TS26.234-v5.60,
- * and was contributed by Ximpo Group Ltd.
- *
- * Portions created by Ximpo Group Ltd. are
- * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved.
- *
- * Contributor(s):
- * Dave Mackie [email protected]
- * Alix Marchandise-Franquet [email protected]
- * Ximpo Group Ltd. [email protected]
- * Bill May [email protected]
- */
- #include "mp4common.h"
- MP4File::MP4File(u_int32_t verbosity)
- {
- m_fileName = NULL;
- m_pFile = NULL;
- m_virtual_IO = NULL;
- m_orgFileSize = 0;
- m_fileSize = 0;
- m_pRootAtom = NULL;
- m_odTrackId = MP4_INVALID_TRACK_ID;
- m_verbosity = verbosity;
- m_mode = 0;
- m_createFlags = 0;
- m_useIsma = false;
- m_pModificationProperty = NULL;
- m_pTimeScaleProperty = NULL;
- m_pDurationProperty = NULL;
- m_memoryBuffer = NULL;
- m_memoryBufferSize = 0;
- m_memoryBufferPosition = 0;
- m_numReadBits = 0;
- m_bufReadBits = 0;
- m_numWriteBits = 0;
- m_bufWriteBits = 0;
- m_editName = NULL;
- #ifndef _WIN32
- m_tempFileName[0] = '\0';
- #endif
- m_trakName[0] = '\0';
- m_tempFileName[0] = '\0';
- }
- MP4File::~MP4File()
- {
- MP4Free(m_fileName);
- if (m_pFile != NULL) {
- // not closed ?
- m_virtual_IO->Close(m_pFile);
- m_pFile = NULL;
- }
- delete m_pRootAtom;
- for (u_int32_t i = 0; i < m_pTracks.Size(); i++) {
- delete m_pTracks[i];
- }
- MP4Free(m_memoryBuffer); // just in case
- CHECK_AND_FREE(m_editName);
-
- }
- void MP4File::Read(const MP4_FILENAME_CHAR* fileName)
- {
- m_fileName = MP4Stralloc(fileName);
- m_mode = 'r';
- #ifdef _WIN32
- Open(L"rb");
- #else
- Open("rb");
- #endif
- ReadFromFile();
- CacheProperties();
- }
- // benski>
- void MP4File::ReadEx(const MP4_FILENAME_CHAR *fileName, void *user, Virtual_IO *virtual_IO)
- {
- m_fileName = MP4Stralloc(fileName);
- m_mode = 'r';
- m_pFile = user;
- m_virtual_IO = virtual_IO;
- ASSERT(m_pFile);
- ASSERT(m_virtual_IO)
-
- m_orgFileSize = m_fileSize = m_virtual_IO->GetFileLength(m_pFile);
- ReadFromFile();
- CacheProperties();
- }
- void MP4File::Create(const MP4_FILENAME_CHAR *fileName, u_int32_t flags,
- int add_ftyp, int add_iods,
- char* majorBrand, u_int32_t minorVersion,
- char** supportedBrands, u_int32_t supportedBrandsCount)
- {
- m_fileName = MP4Stralloc(fileName);
- m_mode = 'w';
- m_createFlags = flags;
- #ifdef _WIN32
- Open(L"wb+");
- #else
- Open("wb+");
- #endif
- // generate a skeletal atom tree
- m_pRootAtom = MP4Atom::CreateAtom(NULL);
- m_pRootAtom->SetFile(this);
- m_pRootAtom->Generate();
- if (add_ftyp != 0) {
- MakeFtypAtom(majorBrand, minorVersion,
- supportedBrands, supportedBrandsCount);
- }
- CacheProperties();
- // create mdat, and insert it after ftyp, and before moov
- (void)InsertChildAtom(m_pRootAtom, "mdat",
- add_ftyp != 0 ? 1 : 0);
- // start writing
- m_pRootAtom->BeginWrite();
- if (add_iods != 0) {
- (void)AddChildAtom("moov", "iods");
- }
- }
- bool MP4File::Use64Bits (const char *atomName)
- {
- uint32_t atomid = ATOMID(atomName);
- if (atomid == ATOMID("mdat") || atomid == ATOMID("stbl")) {
- return (m_createFlags & MP4_CREATE_64BIT_DATA) == MP4_CREATE_64BIT_DATA;
- }
- if (atomid == ATOMID("mvhd") ||
- atomid == ATOMID("tkhd") ||
- atomid == ATOMID("mdhd")) {
- return (m_createFlags & MP4_CREATE_64BIT_TIME) == MP4_CREATE_64BIT_TIME;
- }
- return false;
- }
- void MP4File::Check64BitStatus (const char *atomName)
- {
- uint32_t atomid = ATOMID(atomName);
- if (atomid == ATOMID("mdat") || atomid == ATOMID("stbl")) {
- m_createFlags |= MP4_CREATE_64BIT_DATA;
- } else if (atomid == ATOMID("mvhd") ||
- atomid == ATOMID("tkhd") ||
- atomid == ATOMID("mdhd")) {
- m_createFlags |= MP4_CREATE_64BIT_TIME;
- }
- }
-
- void MP4File::Modify(const MP4_FILENAME_CHAR* fileName)
- {
- m_fileName = MP4Stralloc(fileName);
- m_mode = 'r';
- #ifdef _WIN32
- Open(L"rb+");
- #else
- Open("rb+");
- #endif
- ReadFromFile();
- m_mode = 'w';
- // find the moov atom
- MP4Atom* pMoovAtom = m_pRootAtom->FindAtomMP4("moov");
- u_int32_t numAtoms;
- if (pMoovAtom == NULL) {
- // there isn't one, odd but we can still proceed
- pMoovAtom = AddChildAtom(m_pRootAtom, "moov");
- } else {
- numAtoms = m_pRootAtom->GetNumberOfChildAtoms();
- // work backwards thru the top level atoms
- int32_t i;
- bool lastAtomIsMoov = true;
- MP4Atom* pLastAtom = NULL;
- for (i = numAtoms - 1; i >= 0; i--) {
- MP4Atom* pAtom = m_pRootAtom->GetChildAtom(i);
- const char* type = pAtom->GetType();
-
- // get rid of any trailing free or skips
- if (!strcmp(type, "free") || !strcmp(type, "skip")) {
- m_pRootAtom->DeleteChildAtom(pAtom);
- continue;
- }
- if (strcmp(type, "moov")) {
- if (pLastAtom == NULL) {
- pLastAtom = pAtom;
- lastAtomIsMoov = false;
- }
- continue;
- }
- // now at moov atom
- // multiple moov atoms?!?
- if (pAtom != pMoovAtom) {
- throw new MP4Error(
- "Badly formed mp4 file, multiple moov atoms",
- "MP4Modify");
- }
- if (lastAtomIsMoov) {
- // position to start of moov atom,
- // effectively truncating file
- // prior to adding new mdat
- SetPosition(pMoovAtom->GetStart());
- } else { // last atom isn't moov
- // need to place a free atom
- MP4Atom* pFreeAtom = MP4Atom::CreateAtom("free");
- // in existing position of the moov atom
- m_pRootAtom->InsertChildAtom(pFreeAtom, i);
- m_pRootAtom->DeleteChildAtom(pMoovAtom);
- m_pRootAtom->AddChildAtom(pMoovAtom);
- // write free atom to disk
- SetPosition(pMoovAtom->GetStart());
- pFreeAtom->SetSize(pMoovAtom->GetSize());
- pFreeAtom->Write();
- // finally set our file position to the end of the last atom
- SetPosition(pLastAtom->GetEnd());
- }
- break;
- }
- ASSERT(i != -1);
- }
- CacheProperties(); // of moov atom
- numAtoms = m_pRootAtom->GetNumberOfChildAtoms();
- // insert another mdat prior to moov atom (the last atom)
- MP4Atom* pMdatAtom = InsertChildAtom(m_pRootAtom, "mdat", numAtoms - 1);
- // start writing new mdat
- pMdatAtom->BeginWrite(Use64Bits("mdat"));
- }
- void MP4File::Optimize(const MP4_FILENAME_CHAR* orgFileName, const MP4_FILENAME_CHAR* newFileName)
- {
- m_fileName = MP4Stralloc(orgFileName);
- m_mode = 'r';
- // first load meta-info into memory
- #ifdef _WIN32
- Open(L"rb");
- #else
- Open("rb");
- #endif
- ReadFromFile();
- CacheProperties(); // of moov atom
- // now switch over to writing the new file
- MP4Free(m_fileName);
- // create a temporary file if necessary
- if (newFileName == NULL) {
- m_fileName = MP4Stralloc(TempFileName());
- } else {
- m_fileName = MP4Stralloc(newFileName);
- }
- void* pReadFile = m_pFile;
- Virtual_IO *pReadIO = m_virtual_IO;
- m_pFile = NULL;
- m_mode = 'w';
- #ifdef _WIN32
- Open(L"wb");
- #else
- Open("wb");
- #endif
- 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, pReadIO, m_virtual_IO);
- // finish writing
- ((MP4RootAtom*)m_pRootAtom)->FinishOptimalWrite();
- // cleanup
- m_virtual_IO->Close(m_pFile);
- m_pFile = NULL;
- pReadIO->Close(pReadFile);
- // move temporary file into place
- if (newFileName == NULL) {
- Rename(m_fileName, orgFileName);
- }
- }
- void MP4File::RewriteMdat(void* pReadFile, void* pWriteFile,
- Virtual_IO *readIO, Virtual_IO *writeIO)
- {
- u_int32_t numTracks = m_pTracks.Size();
- MP4ChunkId* chunkIds = new MP4ChunkId[numTracks];
- MP4ChunkId* maxChunkIds = new MP4ChunkId[numTracks];
- MP4Timestamp* nextChunkTimes = new MP4Timestamp[numTracks];
- for (u_int32_t i = 0; i < numTracks; i++) {
- chunkIds[i] = 1;
- maxChunkIds[i] = m_pTracks[i]->GetNumberOfChunks();
- nextChunkTimes[i] = MP4_INVALID_TIMESTAMP;
- }
- while (true) {
- u_int32_t nextTrackIndex = (u_int32_t)-1;
- MP4Timestamp nextTime = MP4_INVALID_TIMESTAMP;
- for (u_int32_t i = 0; i < numTracks; i++) {
- if (chunkIds[i] > maxChunkIds[i]) {
- continue;
- }
- if (nextChunkTimes[i] == MP4_INVALID_TIMESTAMP) {
- MP4Timestamp chunkTime =
- m_pTracks[i]->GetChunkTime(chunkIds[i]);
- nextChunkTimes[i] = MP4ConvertTime(chunkTime,
- m_pTracks[i]->GetTimeScale(), GetTimeScale());
- }
- // time is not earliest so far
- if (nextChunkTimes[i] > nextTime) {
- continue;
- }
- // prefer hint tracks to media tracks if times are equal
- if (nextChunkTimes[i] == nextTime
- && strcmp(m_pTracks[i]->GetType(), MP4_HINT_TRACK_TYPE)) {
- continue;
- }
- // this is our current choice of tracks
- nextTime = nextChunkTimes[i];
- nextTrackIndex = i;
- }
- if (nextTrackIndex == (u_int32_t)-1) {
- break;
- }
- // point into original mp4 file for read chunk call
- m_pFile = pReadFile;
- m_virtual_IO = readIO;
- m_mode = 'r';
- u_int8_t* pChunk=0;
- u_int32_t chunkSize;
- m_pTracks[nextTrackIndex]->
- ReadChunk(chunkIds[nextTrackIndex], &pChunk, &chunkSize);
- // point back at the new mp4 file for write chunk
- m_pFile = pWriteFile;
- m_virtual_IO = writeIO;
- m_mode = 'w';
- m_pTracks[nextTrackIndex]->
- RewriteChunk(chunkIds[nextTrackIndex], pChunk, chunkSize);
- MP4Free(pChunk);
- chunkIds[nextTrackIndex]++;
- nextChunkTimes[nextTrackIndex] = MP4_INVALID_TIMESTAMP;
- }
- delete [] chunkIds;
- delete [] maxChunkIds;
- delete [] nextChunkTimes;
- }
- void MP4File::Open(const MP4_FILENAME_CHAR *fmode)
- {
- ASSERT(m_pFile == NULL);
- FILE *openFile = NULL;
- #ifdef O_LARGEFILE
- // UGH! fopen doesn't open a file in 64-bit mode, period.
- // So we need to use open() and then fdopen()
- int fd;
- int flags = O_LARGEFILE;
- if (strchr(fmode, '+')) {
- flags |= O_CREAT | O_RDWR;
- if (fmode[0] == 'w') {
- flags |= O_TRUNC;
- }
- } else {
- if (fmode[0] == 'w') {
- flags |= O_CREAT | O_TRUNC | O_WRONLY;
- } else {
- flags |= O_RDONLY;
- }
- }
- fd = open(m_fileName, flags, 0666);
- if (fd >= 0) {
- openFile = fdopen(fd, fmode);
- }
- #elif defined(_WIN32)
- openFile = _wfopen(m_fileName, fmode);
- #else
- openFile = fopen(m_fileName, fmode);
- #endif
- m_pFile = openFile;
- if (m_pFile == NULL) {
- throw new MP4Error(errno, "failed", "MP4Open");
- }
-
- m_virtual_IO = &FILE_virtual_IO;
- if (m_mode == 'r') {
- m_orgFileSize = m_fileSize = m_virtual_IO->GetFileLength(m_pFile); // benski
- } else {
- m_orgFileSize = m_fileSize = 0;
- }
- }
- void MP4File::ReadFromFile()
- {
- // ensure we start at beginning of file
- SetPosition(0);
- // create a new root atom
- ASSERT(m_pRootAtom == NULL);
- m_pRootAtom = MP4Atom::CreateAtom(NULL);
- u_int64_t fileSize = GetSize();
- m_pRootAtom->SetFile(this);
- m_pRootAtom->SetStart(0);
- m_pRootAtom->SetSize(fileSize);
- m_pRootAtom->SetEnd(fileSize);
- m_pRootAtom->Read();
- // create MP4Track's for any tracks in the file
- GenerateTracks();
- }
- void MP4File::GenerateTracks()
- {
- u_int32_t trackIndex = 0;
- while (true) {
- char trackName[32];
- snprintf(trackName, sizeof(trackName), "moov.trak[%u]", trackIndex);
- // find next trak atom
- MP4Atom* pTrakAtom = m_pRootAtom->FindAtomMP4(trackName);
- // done, no more trak atoms
- if (pTrakAtom == NULL) {
- break;
- }
- // find track id property
- MP4Integer32Property* pTrackIdProperty = NULL;
- (void)pTrakAtom->FindProperty(
- "trak.tkhd.trackId",
- (MP4Property**)&pTrackIdProperty);
- // find track type property
- MP4StringProperty* pTypeProperty = NULL;
- (void)pTrakAtom->FindProperty(
- "trak.mdia.hdlr.handlerType",
- (MP4Property**)&pTypeProperty);
- // ensure we have the basics properties
- if (pTrackIdProperty && pTypeProperty) {
- m_trakIds.Add(pTrackIdProperty->GetValue());
- MP4Track* pTrack = NULL;
- try {
- const char* value = pTypeProperty->GetValue();
- if (value && !strcmp(value, MP4_HINT_TRACK_TYPE)) {
- pTrack = new MP4RtpHintTrack(this, pTrakAtom);
- } else {
- pTrack = new MP4Track(this, pTrakAtom);
- }
- m_pTracks.Add(pTrack);
- }
- catch (MP4Error* e) {
- VERBOSE_ERROR(m_verbosity, e->Print());
- delete e;
- }
- // remember when we encounter the OD track
- const char* track = (pTrack ? pTrack->GetType() : 0);
- if (pTrack && !strcmp(track, MP4_OD_TRACK_TYPE)) {
- if (m_odTrackId == MP4_INVALID_TRACK_ID) {
- m_odTrackId = pTrackIdProperty->GetValue();
- } else {
- VERBOSE_READ(GetVerbosity(),
- printf("Warning: multiple OD tracks present\n"));
- }
- }
- } else {
- m_trakIds.Add(0);
- }
- trackIndex++;
- }
- }
- void MP4File::CacheProperties()
- {
- FindIntegerProperty("moov.mvhd.modificationTime",
- (MP4Property**)&m_pModificationProperty);
- FindIntegerProperty("moov.mvhd.timeScale",
- (MP4Property**)&m_pTimeScaleProperty);
- FindIntegerProperty("moov.mvhd.duration",
- (MP4Property**)&m_pDurationProperty);
- }
- void MP4File::BeginWrite()
- {
- m_pRootAtom->BeginWrite();
- }
- void MP4File::FinishWrite()
- {
- // for all tracks, flush chunking buffers
- for (u_int32_t i = 0; i < m_pTracks.Size(); i++) {
- ASSERT(m_pTracks[i]);
- m_pTracks[i]->FinishWrite();
- }
- // ask root atom to write
- m_pRootAtom->FinishWrite();
- // check if file shrunk, e.g. we deleted a track
- if (GetSize() < m_orgFileSize) {
- // just use a free atom to mark unused space
- // MP4Optimize() should be used to clean up this space
- MP4Atom* pFreeAtom = MP4Atom::CreateAtom("free");
- ASSERT(pFreeAtom);
- pFreeAtom->SetFile(this);
- int64_t size = m_orgFileSize - (m_fileSize + 8);
- if (size < 0) size = 0;
- pFreeAtom->SetSize(size);
- pFreeAtom->Write();
- delete pFreeAtom;
- }
- }
- void MP4File::UpdateDuration(MP4Duration duration)
- {
- MP4Duration currentDuration = GetDuration();
- if (duration > currentDuration) {
- SetDuration(duration);
- }
- }
- void MP4File::Close()
- {
- if (m_mode == 'w') {
- SetIntegerProperty("moov.mvhd.modificationTime",
- MP4GetAbsTimestamp());
- FinishWrite();
- }
- m_virtual_IO->Close(m_pFile);
- m_pFile = NULL;
- }
- const MP4_FILENAME_CHAR* MP4File::TempFileName()
- {
- // there are so many attempts in libc to get this right
- // that for portablity reasons, it's best just to roll our own
- #ifndef _WIN32
- u_int32_t i;
- for (i = getpid(); i < 0xFFFFFFFF; i++) {
- snprintf(m_tempFileName, sizeof(m_tempFileName),
- "./tmp%u.mp4", i);
- if (access(m_tempFileName, F_OK) != 0) {
- break;
- }
- }
- if (i == 0xFFFFFFFF) {
- throw new MP4Error("can't create temporary file", "TempFileName");
- }
- #else
- wchar_t tmppath[MAX_PATH-14];
- GetTempPathW(MAX_PATH-14,tmppath);
- GetTempFileNameW(tmppath, // dir. for temp. files
- L"mp4", // temp. filename prefix
- 0, // create unique name
- m_tempFileName); // buffer for name
- #endif
- return m_tempFileName;
- }
- void MP4File::Rename(const MP4_FILENAME_CHAR* oldFileName, const MP4_FILENAME_CHAR* newFileName)
- {
- int rc;
- #ifdef _WIN32
- rc=0;
- DeleteFileW(newFileName);
- if (MoveFileW(oldFileName,newFileName) == 0) // if the function fails
- {
- if (!CopyFileW(oldFileName,newFileName, FALSE))
- rc=1;
- else
- DeleteFileW(oldFileName);
- }
- /* benski> CUT:
- rc = remove(newFileName);
- if (rc == 0) {
- rc = rename(oldFileName, newFileName);
- }
- */
- #else
- rc = rename(oldFileName, newFileName);
- #endif
- if (rc != 0) {
- throw new MP4Error(errno, "can't overwrite existing file", "Rename");
- }
- }
- void MP4File::ProtectWriteOperation(char* where)
- {
- if (m_mode == 'r') {
- throw new MP4Error("operation not permitted in read mode", where);
- }
- }
- MP4Track* MP4File::GetTrack(MP4TrackId trackId)
- {
- return m_pTracks[FindTrackIndex(trackId)];
- }
- MP4Atom* MP4File::FindAtomMP4File(const char* name)
- {
- MP4Atom* pAtom = NULL;
- if (!name || !strcmp(name, "")) {
- pAtom = m_pRootAtom;
- } else {
- pAtom = m_pRootAtom->FindAtomMP4(name);
- }
- return pAtom;
- }
- MP4Atom* MP4File::AddChildAtom(
- const char* parentName,
- const char* childName)
- {
- return AddChildAtom(FindAtomMP4File(parentName), childName);
- }
- MP4Atom* MP4File::AddChildAtom(
- MP4Atom* pParentAtom,
- const char* childName)
- {
- return InsertChildAtom(pParentAtom, childName,
- pParentAtom->GetNumberOfChildAtoms());
- }
- MP4Atom* MP4File::InsertChildAtom(
- const char* parentName,
- const char* childName,
- u_int32_t index)
- {
- return InsertChildAtom(FindAtomMP4File(parentName), childName, index);
- }
- MP4Atom* MP4File::InsertChildAtom(
- MP4Atom* pParentAtom,
- const char* childName,
- u_int32_t index)
- {
- MP4Atom* pChildAtom = MP4Atom::CreateAtom(childName);
- ASSERT(pParentAtom);
- pParentAtom->InsertChildAtom(pChildAtom, index);
- pChildAtom->Generate();
- return pChildAtom;
- }
- MP4Atom* MP4File::AddDescendantAtoms(
- const char* ancestorName,
- const char* descendantNames)
- {
- return AddDescendantAtoms(FindAtomMP4File(ancestorName), descendantNames);
- }
- MP4Atom* MP4File::AddDescendantAtoms(
- MP4Atom* pAncestorAtom, const char* descendantNames)
- {
- ASSERT(pAncestorAtom);
- MP4Atom* pParentAtom = pAncestorAtom;
- MP4Atom* pChildAtom = NULL;
- while (true) {
- char* childName = MP4NameFirst(descendantNames);
- if (childName == NULL) {
- break;
- }
- descendantNames = MP4NameAfterFirst(descendantNames);
- pChildAtom = pParentAtom->FindChildAtom(childName);
- if (pChildAtom == NULL) {
- pChildAtom = AddChildAtom(pParentAtom, childName);
- }
- pParentAtom = pChildAtom;
- MP4Free(childName);
- }
- return pChildAtom;
- }
- bool MP4File::FindProperty(const char* name,
- MP4Property** ppProperty, u_int32_t* pIndex)
- {
- if (pIndex) {
- *pIndex = 0; // set the default answer for index
- }
- return m_pRootAtom->FindProperty(name, ppProperty, pIndex);
- }
- void MP4File::FindIntegerProperty(const char* name,
- MP4Property** ppProperty, u_int32_t* pIndex)
- {
- if (!FindProperty(name, ppProperty, pIndex)) {
- throw new MP4Error("no such property - %s", "MP4File::FindIntegerProperty", name);
- }
- switch ((*ppProperty)->GetType()) {
- case Integer8Property:
- case Integer16Property:
- case Integer24Property:
- case Integer32Property:
- case Integer64Property:
- break;
- default:
- throw new MP4Error("type mismatch - property %s type %d", "MP4File::FindIntegerProperty", name, (*ppProperty)->GetType());
- }
- }
- u_int64_t MP4File::GetIntegerProperty(const char* name)
- {
- MP4Property* pProperty;
- u_int32_t index;
- FindIntegerProperty(name, &pProperty, &index);
- return ((MP4IntegerProperty*)pProperty)->GetValue(index);
- }
- void MP4File::SetIntegerProperty(const char* name, u_int64_t value)
- {
- ProtectWriteOperation("SetIntegerProperty");
- MP4Property* pProperty = NULL;
- u_int32_t index = 0;
- FindIntegerProperty(name, &pProperty, &index);
- ((MP4IntegerProperty*)pProperty)->SetValue(value, index);
- }
- void MP4File::FindFloatProperty(const char* name,
- MP4Property** ppProperty, u_int32_t* pIndex)
- {
- if (!FindProperty(name, ppProperty, pIndex)) {
- throw new MP4Error("no such property - %s", "MP4File::FindFloatProperty", name);
- }
- if ((*ppProperty)->GetType() != Float32Property) {
- throw new MP4Error("type mismatch - property %s type %d",
- "MP4File::FindFloatProperty",
- name,
- (*ppProperty)->GetType());
- }
- }
- float MP4File::GetFloatProperty(const char* name)
- {
- MP4Property* pProperty;
- u_int32_t index;
- FindFloatProperty(name, &pProperty, &index);
- return ((MP4Float32Property*)pProperty)->GetValue(index);
- }
- void MP4File::SetFloatProperty(const char* name, float value)
- {
- ProtectWriteOperation("SetFloatProperty");
- MP4Property* pProperty;
- u_int32_t index;
- FindFloatProperty(name, &pProperty, &index);
- ((MP4Float32Property*)pProperty)->SetValue(value, index);
- }
- void MP4File::FindStringProperty(const char* name,
- MP4Property** ppProperty, u_int32_t* pIndex)
- {
- if (!FindProperty(name, ppProperty, pIndex)) {
- throw new MP4Error("no such property - %s", "MP4File::FindStringProperty", name);
- }
- if ((*ppProperty)->GetType() != StringProperty) {
- throw new MP4Error("type mismatch - property %s type %d", "MP4File::FindStringProperty",
- name, (*ppProperty)->GetType());
- }
- }
- const char* MP4File::GetStringProperty(const char* name)
- {
- MP4Property* pProperty;
- u_int32_t index;
- FindStringProperty(name, &pProperty, &index);
- return ((MP4StringProperty*)pProperty)->GetValue(index);
- }
- void MP4File::SetStringProperty(const char* name, const char* value)
- {
- ProtectWriteOperation("SetStringProperty");
- MP4Property* pProperty;
- u_int32_t index;
- FindStringProperty(name, &pProperty, &index);
- ((MP4StringProperty*)pProperty)->SetValue(value, index);
- }
- void MP4File::FindBytesProperty(const char* name,
- MP4Property** ppProperty, u_int32_t* pIndex)
- {
- if (!FindProperty(name, ppProperty, pIndex)) {
- throw new MP4Error("no such property %s", "MP4File::FindBytesProperty", name);
- }
- if ((*ppProperty)->GetType() != BytesProperty) {
- throw new MP4Error("type mismatch - property %s - type %d", "MP4File::FindBytesProperty", name, (*ppProperty)->GetType());
- }
- }
- void MP4File::GetBytesProperty(const char* name,
- u_int8_t** ppValue, u_int32_t* pValueSize)
- {
- MP4Property* pProperty;
- u_int32_t index;
- FindBytesProperty(name, &pProperty, &index);
- ((MP4BytesProperty*)pProperty)->GetValue(ppValue, pValueSize, index);
- }
- void MP4File::SetBytesProperty(const char* name,
- const u_int8_t* pValue, u_int32_t valueSize)
- {
- ProtectWriteOperation("SetBytesProperty");
- MP4Property* pProperty;
- u_int32_t index;
- FindBytesProperty(name, &pProperty, &index);
- ((MP4BytesProperty*)pProperty)->SetValue(pValue, valueSize, index);
- }
- // track functions
- MP4TrackId MP4File::AddTrack(const char* type, u_int32_t timeScale)
- {
- ProtectWriteOperation("AddTrack");
- // create and add new trak atom
- MP4Atom* pTrakAtom = AddChildAtom("moov", "trak");
- // allocate a new track id
- MP4TrackId trackId = AllocTrackId();
- m_trakIds.Add(trackId);
- // set track id
- MP4Integer32Property* pInteger32Property = NULL;
- (void)pTrakAtom->FindProperty("trak.tkhd.trackId",
- (MP4Property**)&pInteger32Property);
- ASSERT(pInteger32Property);
- pInteger32Property->SetValue(trackId);
- // set track type
- const char* normType = MP4NormalizeTrackType(type, m_verbosity);
- // sanity check for user defined types
- if (strlen(normType) > 4) {
- VERBOSE_WARNING(m_verbosity,
- printf("AddTrack: type truncated to four characters\n"));
- // StringProperty::SetValue() will do the actual truncation
- }
- MP4StringProperty* pStringProperty = NULL;
- (void)pTrakAtom->FindProperty("trak.mdia.hdlr.handlerType",
- (MP4Property**)&pStringProperty);
- ASSERT(pStringProperty);
- pStringProperty->SetValue(normType);
- // set track time scale
- pInteger32Property = NULL;
- (void)pTrakAtom->FindProperty("trak.mdia.mdhd.timeScale",
- (MP4Property**)&pInteger32Property);
- ASSERT(pInteger32Property);
- pInteger32Property->SetValue(timeScale ? timeScale : 1000);
- // now have enough to create MP4Track object
- MP4Track* pTrack = NULL;
- if (!strcmp(normType, MP4_HINT_TRACK_TYPE)) {
- pTrack = new MP4RtpHintTrack(this, pTrakAtom);
- } else {
- pTrack = new MP4Track(this, pTrakAtom);
- }
- m_pTracks.Add(pTrack);
- // mark non-hint tracks as enabled
- if (strcmp(normType, MP4_HINT_TRACK_TYPE)) {
- SetTrackIntegerProperty(trackId, "tkhd.flags", 1);
- }
- // mark track as contained in this file
- // LATER will provide option for external data references
- AddDataReference(trackId, NULL);
- return trackId;
- }
- void MP4File::AddTrackToIod(MP4TrackId trackId)
- {
- MP4DescriptorProperty* pDescriptorProperty = NULL;
- (void)m_pRootAtom->FindProperty("moov.iods.esIds",
- (MP4Property**)&pDescriptorProperty);
- ASSERT(pDescriptorProperty);
- MP4Descriptor* pDescriptor =
- pDescriptorProperty->AddDescriptor(MP4ESIDIncDescrTag);
- ASSERT(pDescriptor);
- MP4Integer32Property* pIdProperty = NULL;
- (void)pDescriptor->FindProperty("id",
- (MP4Property**)&pIdProperty);
- ASSERT(pIdProperty);
- pIdProperty->SetValue(trackId);
- }
- void MP4File::RemoveTrackFromIod(MP4TrackId trackId, bool shallHaveIods)
- {
- MP4DescriptorProperty* pDescriptorProperty = NULL;
- if (!m_pRootAtom->FindProperty("moov.iods.esIds",
- (MP4Property**)&pDescriptorProperty))
- return;
- #if 0
- // we may not have iods
- if (shallHaveIods) {
- ASSERT(pDescriptorProperty);
- } else {
- if (!pDescriptorProperty) {
- return;
- }
- }
- #else
- if (pDescriptorProperty == NULL) {
- return;
- }
- #endif
- for (u_int32_t i = 0; i < pDescriptorProperty->GetCount(); i++) {
- /* static */char name[32];
- snprintf(name, sizeof(name), "esIds[%u].id", i);
- MP4Integer32Property* pIdProperty = NULL;
- (void)pDescriptorProperty->FindProperty(name,
- (MP4Property**)&pIdProperty);
- // wmay ASSERT(pIdProperty);
- if (pIdProperty != NULL &&
- pIdProperty->GetValue() == trackId) {
- pDescriptorProperty->DeleteDescriptor(i);
- break;
- }
- }
- }
- void MP4File::AddTrackToOd(MP4TrackId trackId)
- {
- if (!m_odTrackId) {
- return;
- }
- AddTrackReference(MakeTrackName(m_odTrackId, "tref.mpod"), trackId);
- }
- void MP4File::RemoveTrackFromOd(MP4TrackId trackId)
- {
- if (!m_odTrackId) {
- return;
- }
- RemoveTrackReference(MakeTrackName(m_odTrackId, "tref.mpod"), trackId);
- }
- void MP4File::GetTrackReferenceProperties(const char* trefName,
- MP4Property** ppCountProperty, MP4Property** ppTrackIdProperty)
- {
- char propName[1024];
- snprintf(propName, sizeof(propName), "%s.%s", trefName, "entryCount");
- (void)m_pRootAtom->FindProperty(propName, ppCountProperty);
- ASSERT(*ppCountProperty);
- snprintf(propName, sizeof(propName), "%s.%s", trefName, "entries.trackId");
- (void)m_pRootAtom->FindProperty(propName, ppTrackIdProperty);
- ASSERT(*ppTrackIdProperty);
- }
- void MP4File::AddTrackReference(const char* trefName, MP4TrackId refTrackId)
- {
- MP4Integer32Property* pCountProperty = NULL;
- MP4Integer32Property* pTrackIdProperty = NULL;
- GetTrackReferenceProperties(trefName,
- (MP4Property**)&pCountProperty,
- (MP4Property**)&pTrackIdProperty);
- pTrackIdProperty->AddValue(refTrackId);
- pCountProperty->IncrementValue();
- }
- u_int32_t MP4File::FindTrackReference(const char* trefName,
- MP4TrackId refTrackId)
- {
- MP4Integer32Property* pCountProperty = NULL;
- MP4Integer32Property* pTrackIdProperty = NULL;
- GetTrackReferenceProperties(trefName,
- (MP4Property**)&pCountProperty,
- (MP4Property**)&pTrackIdProperty);
- for (u_int32_t i = 0; i < pCountProperty->GetValue(); i++) {
- if (refTrackId == pTrackIdProperty->GetValue(i)) {
- return i + 1; // N.B. 1 not 0 based index
- }
- }
- return 0;
- }
- void MP4File::RemoveTrackReference(const char* trefName, MP4TrackId refTrackId)
- {
- MP4Integer32Property* pCountProperty = NULL;
- MP4Integer32Property* pTrackIdProperty = NULL;
- GetTrackReferenceProperties(trefName,
- (MP4Property**)&pCountProperty,
- (MP4Property**)&pTrackIdProperty);
- for (u_int32_t i = 0; i < pCountProperty->GetValue(); i++) {
- if (refTrackId == pTrackIdProperty->GetValue(i)) {
- pTrackIdProperty->DeleteValue(i);
- pCountProperty->IncrementValue(-1);
- }
- }
- }
- void MP4File::AddDataReference(MP4TrackId trackId, const char* url)
- {
- MP4Atom* pDrefAtom =
- FindAtomMP4File(MakeTrackName(trackId, "mdia.minf.dinf.dref"));
- ASSERT(pDrefAtom);
- MP4Integer32Property* pCountProperty = NULL;
- (void)pDrefAtom->FindProperty("dref.entryCount",
- (MP4Property**)&pCountProperty);
- ASSERT(pCountProperty);
- pCountProperty->IncrementValue();
- MP4Atom* pUrlAtom = AddChildAtom(pDrefAtom, "url ");
- if (url && url[0] != '\0') {
- pUrlAtom->SetFlags(pUrlAtom->GetFlags() & 0xFFFFFE);
- MP4StringProperty* pUrlProperty = NULL;
- (void)pUrlAtom->FindProperty("url .location",
- (MP4Property**)&pUrlProperty);
- ASSERT(pUrlProperty);
- pUrlProperty->SetValue(url);
- } else {
- pUrlAtom->SetFlags(pUrlAtom->GetFlags() | 1);
- }
- }
- MP4TrackId MP4File::AddSystemsTrack(const char* type)
- {
- const char* normType = MP4NormalizeTrackType(type, m_verbosity);
- // TBD if user type, fix name to four chars, and warn
- MP4TrackId trackId = AddTrack(type, MP4_MSECS_TIME_SCALE);
- (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "nmhd", 0);
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "mp4s");
- // stsd is a unique beast in that it has a count of the number
- // of child atoms that needs to be incremented after we add the mp4s atom
- MP4Integer32Property* pStsdCountProperty;
- FindIntegerProperty(
- MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
- (MP4Property**)&pStsdCountProperty);
- pStsdCountProperty->IncrementValue();
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4s.esds.ESID",
- #if 0
- // note - for a file, these values need to
- // be 0 - wmay - 04/16/2003
- trackId
- #else
- 0
- #endif
- );
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.objectTypeId",
- MP4SystemsV1ObjectType);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.streamType",
- ConvertTrackTypeToStreamType(normType));
- return trackId;
- }
- MP4TrackId MP4File::AddODTrack()
- {
- // until a demonstrated need emerges
- // we limit ourselves to one object description track
- if (m_odTrackId != MP4_INVALID_TRACK_ID) {
- throw new MP4Error("object description track already exists",
- "AddObjectDescriptionTrack");
- }
- m_odTrackId = AddSystemsTrack(MP4_OD_TRACK_TYPE);
- AddTrackToIod(m_odTrackId);
- (void)AddDescendantAtoms(MakeTrackName(m_odTrackId, NULL), "tref.mpod");
- return m_odTrackId;
- }
- MP4TrackId MP4File::AddSceneTrack()
- {
- MP4TrackId trackId = AddSystemsTrack(MP4_SCENE_TRACK_TYPE);
- AddTrackToIod(trackId);
- AddTrackToOd(trackId);
- return trackId;
- }
- // NULL terminated list of brands which require the IODS atom
- char *brandsWithIods[] = { "mp42",
- "isom",
- NULL};
- bool MP4File::ShallHaveIods()
- {
- u_int32_t compatibleBrandsCount;
- MP4StringProperty *pMajorBrandProperty;
-
- MP4Atom* ftypAtom = m_pRootAtom->FindAtomMP4("ftyp");
- if (ftypAtom == NULL) return false;
-
- // Check the major brand
- (void)ftypAtom->FindProperty(
- "ftyp.majorBrand",
- (MP4Property**)&pMajorBrandProperty);
- ASSERT(pMajorBrandProperty);
- for(u_int32_t j = 0 ; brandsWithIods[j] != NULL ; j++) {
- if (!strcasecmp( ((MP4StringProperty*)pMajorBrandProperty)->GetValue(),
- brandsWithIods[j]))
- return true;
- }
- // Check the compatible brands
- MP4Integer32Property* pCompatibleBrandsCountProperty;
- (void)ftypAtom->FindProperty(
- "ftyp.compatibleBrandsCount",
- (MP4Property**)&pCompatibleBrandsCountProperty);
- ASSERT(pCompatibleBrandsCountProperty);
-
- compatibleBrandsCount = pCompatibleBrandsCountProperty->GetValue();
-
- MP4TableProperty* pCompatibleBrandsProperty;
- (void)ftypAtom->FindProperty(
- "ftyp.compatibleBrands",
- (MP4Property**)&pCompatibleBrandsProperty);
-
- MP4StringProperty* pBrandProperty = (MP4StringProperty*)pCompatibleBrandsProperty->GetProperty(0);
- ASSERT(pBrandProperty);
- for(u_int32_t i = 0 ; i < compatibleBrandsCount ; i++) {
- for(u_int32_t j = 0 ; brandsWithIods[j] != NULL ; j++) {
- if (!strcasecmp(pBrandProperty->GetValue(i), brandsWithIods[j]))
- return true;
- }
- }
- return false;
- }
- void MP4File::SetAmrVendor(
- MP4TrackId trackId,
- u_int32_t vendor)
- {
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.*.damr.vendor",
- vendor);
- }
- void MP4File::SetAmrDecoderVersion(
- MP4TrackId trackId,
- u_int8_t decoderVersion)
- {
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.*.damr.decoderVersion",
- decoderVersion);
- }
- void MP4File::SetAmrModeSet(
- MP4TrackId trackId,
- u_int16_t modeSet)
- {
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.*.damr.modeSet",
- modeSet);
- }
- uint16_t MP4File::GetAmrModeSet(MP4TrackId trackId)
- {
- return GetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.*.damr.modeSet");
- }
- MP4TrackId MP4File::AddAmrAudioTrack(
- u_int32_t timeScale,
- u_int16_t modeSet,
- u_int8_t modeChangePeriod,
- u_int8_t framesPerSample,
- bool isAmrWB)
- {
-
- u_int32_t fixedSampleDuration = (timeScale * 20)/1000; // 20mSec/Sample
-
- MP4TrackId trackId = AddTrack(MP4_AUDIO_TRACK_TYPE, timeScale);
-
- AddTrackToOd(trackId);
-
- SetTrackFloatProperty(trackId, "tkhd.volume", 1.0);
-
- (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "smhd", 0);
-
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), isAmrWB ? "sawb" : "samr");
-
- // stsd is a unique beast in that it has a count of the number
- // of child atoms that needs to be incremented after we add the mp4a atom
- MP4Integer32Property* pStsdCountProperty;
- FindIntegerProperty(
- MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
- (MP4Property**)&pStsdCountProperty);
- pStsdCountProperty->IncrementValue();
-
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.*.timeScale",
- timeScale);
-
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.*.damr.modeSet",
- modeSet);
-
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.*.damr.modeChangePeriod",
- modeChangePeriod);
-
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.*.damr.framesPerSample",
- framesPerSample);
-
-
- m_pTracks[FindTrackIndex(trackId)]->
- SetFixedSampleDuration(fixedSampleDuration);
- return trackId;
- }
- MP4TrackId MP4File::AddAudioTrack(
- u_int32_t timeScale,
- MP4Duration sampleDuration,
- u_int8_t audioType)
- {
- MP4TrackId trackId = AddTrack(MP4_AUDIO_TRACK_TYPE, timeScale);
- AddTrackToOd(trackId);
- SetTrackFloatProperty(trackId, "tkhd.volume", 1.0);
- (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "smhd", 0);
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "mp4a");
- // stsd is a unique beast in that it has a count of the number
- // of child atoms that needs to be incremented after we add the mp4a atom
- MP4Integer32Property* pStsdCountProperty;
- FindIntegerProperty(
- MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
- (MP4Property**)&pStsdCountProperty);
- pStsdCountProperty->IncrementValue();
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4a.timeScale", timeScale);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4a.esds.ESID",
- #if 0
- // note - for a file, these values need to
- // be 0 - wmay - 04/16/2003
- trackId
- #else
- 0
- #endif
- );
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.objectTypeId",
- audioType);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.streamType",
- MP4AudioStreamType);
- m_pTracks[FindTrackIndex(trackId)]->
- SetFixedSampleDuration(sampleDuration);
- return trackId;
- }
- MP4TrackId MP4File::AddEncAudioTrack(u_int32_t timeScale,
- MP4Duration sampleDuration,
- u_int8_t audioType,
- u_int32_t scheme_type,
- u_int16_t scheme_version,
- u_int8_t key_ind_len,
- u_int8_t iv_len,
- bool selective_enc,
- const char *kms_uri,
- bool use_ismacryp
- )
- {
- u_int32_t original_fmt = 0;
- MP4TrackId trackId = AddTrack(MP4_AUDIO_TRACK_TYPE, timeScale);
- AddTrackToOd(trackId);
- SetTrackFloatProperty(trackId, "tkhd.volume", 1.0);
- (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "smhd", 0);
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "enca");
- // stsd is a unique beast in that it has a count of the number
- // of child atoms that needs to be incremented after we add the enca atom
- MP4Integer32Property* pStsdCountProperty;
- FindIntegerProperty(MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
- (MP4Property**)&pStsdCountProperty);
- pStsdCountProperty->IncrementValue();
- /* set all the ismacryp-specific values */
- // original format is mp4a
- if (use_ismacryp) {
- original_fmt = ATOMID("mp4a");
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.enca.sinf.frma.data-format",
- original_fmt);
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.enca.sinf"),
- "schm");
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.enca.sinf"),
- "schi");
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.enca.sinf.schi"),
- "iKMS");
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.enca.sinf.schi"),
- "iSFM");
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.enca.sinf.schm.scheme_type",
- scheme_type);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.enca.sinf.schm.scheme_version",
- scheme_version);
-
- SetTrackStringProperty(trackId,
- "mdia.minf.stbl.stsd.enca.sinf.schi.iKMS.kms_URI",
- kms_uri);
- #if 0
- if (kms_uri != NULL) {
- free((void *)kms_uri);
- }
- #endif
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.enca.sinf.schi.iSFM.selective-encryption",
- selective_enc);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.enca.sinf.schi.iSFM.key-indicator-length",
- key_ind_len);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.enca.sinf.schi.iSFM.IV-length",
- iv_len);
- /* end ismacryp */
- }
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.enca.timeScale", timeScale);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.enca.esds.ESID",
- #if 0
- // note - for a file, these values need to
- // be 0 - wmay - 04/16/2003
- trackId
- #else
- 0
- #endif
- );
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.enca.esds.decConfigDescr.objectTypeId",
- audioType);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.enca.esds.decConfigDescr.streamType",
- MP4AudioStreamType);
- m_pTracks[FindTrackIndex(trackId)]->
- SetFixedSampleDuration(sampleDuration);
- return trackId;
- }
- MP4TrackId MP4File::AddCntlTrackDefault (uint32_t timeScale,
- MP4Duration sampleDuration,
- const char *type)
- {
- MP4TrackId trackId = AddTrack(MP4_CNTL_TRACK_TYPE, timeScale);
- (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "nmhd", 0);
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), type);
- // stsd is a unique beast in that it has a count of the number
- // of child atoms that needs to be incremented after we add the mp4v atom
- MP4Integer32Property* pStsdCountProperty;
- FindIntegerProperty(
- MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
- (MP4Property**)&pStsdCountProperty);
- pStsdCountProperty->IncrementValue();
-
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsz.sampleSize", sampleDuration);
-
- m_pTracks[FindTrackIndex(trackId)]->
- SetFixedSampleDuration(sampleDuration);
-
- return trackId;
- }
- MP4TrackId MP4File::AddHrefTrack (uint32_t timeScale,
- MP4Duration sampleDuration,
- const char *base_url)
- {
- MP4TrackId trackId = AddCntlTrackDefault(timeScale, sampleDuration, "href");
- if (base_url != NULL) {
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.href"),
- "burl");
- SetTrackStringProperty(trackId, "mdia.minf.stbl.stsd.href.burl.base_url",
- base_url);
- }
- return trackId;
- }
-
- MP4TrackId MP4File::AddVideoTrackDefault(
- u_int32_t timeScale,
- MP4Duration sampleDuration,
- u_int16_t width,
- u_int16_t height,
- const char *videoType)
- {
- MP4TrackId trackId = AddTrack(MP4_VIDEO_TRACK_TYPE, timeScale);
- AddTrackToOd(trackId);
- SetTrackFloatProperty(trackId, "tkhd.width", width);
- SetTrackFloatProperty(trackId, "tkhd.height", height);
- (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "vmhd", 0);
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), videoType);
- // stsd is a unique beast in that it has a count of the number
- // of child atoms that needs to be incremented after we add the mp4v atom
- MP4Integer32Property* pStsdCountProperty;
- FindIntegerProperty(
- MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
- (MP4Property**)&pStsdCountProperty);
- pStsdCountProperty->IncrementValue();
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsz.sampleSize", sampleDuration);
- m_pTracks[FindTrackIndex(trackId)]->
- SetFixedSampleDuration(sampleDuration);
- return trackId;
- }
- MP4TrackId MP4File::AddMP4VideoTrack(
- u_int32_t timeScale,
- MP4Duration sampleDuration,
- u_int16_t width,
- u_int16_t height,
- u_int8_t videoType)
- {
- MP4TrackId trackId = AddVideoTrackDefault(timeScale,
- sampleDuration,
- width,
- height,
- "mp4v");
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4v.width", width);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4v.height", height);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4v.esds.ESID",
- #if 0
- // note - for a file, these values need to
- // be 0 - wmay - 04/16/2003
- trackId
- #else
- 0
- #endif
- );
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4v.esds.decConfigDescr.objectTypeId",
- videoType);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4v.esds.decConfigDescr.streamType",
- MP4VisualStreamType);
- return trackId;
- }
- // ismacrypted
- MP4TrackId MP4File::AddEncVideoTrack(u_int32_t timeScale,
- MP4Duration sampleDuration,
- u_int16_t width,
- u_int16_t height,
- u_int8_t videoType,
- mp4v2_ismacrypParams *icPp,
- const char *oFormat
- )
- {
- u_int32_t original_fmt = 0;
- MP4TrackId trackId = AddVideoTrackDefault(timeScale,
- sampleDuration,
- width,
- height,
- "encv");
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.encv.width", width);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.encv.height", height);
- /* set all the ismacryp-specific values */
- original_fmt = ATOMID(oFormat);
-
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.encv.sinf.frma.data-format",
- original_fmt);
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf"),
- "schm");
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf"),
- "schi");
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi"),
- "iKMS");
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi"),
- "iSFM");
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.encv.sinf.schm.scheme_type",
- icPp->scheme_type);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.encv.sinf.schm.scheme_version",
- icPp->scheme_version);
-
- SetTrackStringProperty(trackId,
- "mdia.minf.stbl.stsd.encv.sinf.schi.iKMS.kms_URI",
- icPp->kms_uri);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.encv.sinf.schi.iSFM.selective-encryption",
- icPp->selective_enc);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.encv.sinf.schi.iSFM.key-indicator-length",
- icPp->key_ind_len);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.encv.sinf.schi.iSFM.IV-length",
- icPp->iv_len);
- #if 0
- if (icPp->kms_uri != NULL) {
- free(icPp->kms_uri);
- }
- #endif
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.encv.esds.ESID",
- #if 0
- // note - for a file, these values need to
- // be 0 - wmay - 04/16/2003
- trackId
- #else
- 0
- #endif
- );
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.encv.esds.decConfigDescr.objectTypeId",
- videoType);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.encv.esds.decConfigDescr.streamType",
- MP4VisualStreamType);
- return trackId;
- }
- MP4TrackId MP4File::AddH264VideoTrack(
- u_int32_t timeScale,
- MP4Duration sampleDuration,
- u_int16_t width,
- u_int16_t height,
- uint8_t AVCProfileIndication,
- uint8_t profile_compat,
- uint8_t AVCLevelIndication,
- uint8_t sampleLenFieldSizeMinusOne)
- {
- MP4TrackId trackId = AddVideoTrackDefault(timeScale,
- sampleDuration,
- width,
- height,
- "avc1");
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.avc1.width", width);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.avc1.height", height);
- //FIXME - check this
- // shouldn't need this
- #if 0
- AddChildAtom(MakeTrackName(trackId,
- "mdia.minf.stbl.stsd.avc1"),
- "avcC");
- #endif
-
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.avc1.avcC.AVCProfileIndication",
- AVCProfileIndication);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.avc1.avcC.profile_compatibility",
- profile_compat);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.avc1.avcC.AVCLevelIndication",
- AVCLevelIndication);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.avc1.avcC.lengthSizeMinusOne",
- sampleLenFieldSizeMinusOne);
-
- return trackId;
- }
- MP4TrackId MP4File::AddEncH264VideoTrack(
- u_int32_t timeScale,
- MP4Duration sampleDuration,
- u_int16_t width,
- u_int16_t height,
- MP4Atom *srcAtom,
- mp4v2_ismacrypParams *icPp)
- {
- u_int32_t original_fmt = 0;
- MP4Atom *avcCAtom;
- MP4TrackId trackId = AddVideoTrackDefault(timeScale,
- sampleDuration,
- width,
- height,
- "encv");
- SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.width", width);
- SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.height", height);
-
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv"), "avcC");
-
- // create default values
- avcCAtom = FindAtomMP4File(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.avcC"));
-
- // export source atom
- ((MP4AvcCAtom *) srcAtom)->Clone((MP4AvcCAtom *)avcCAtom);
-
- /* set all the ismacryp-specific values */
-
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf"), "schm");
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf"), "schi");
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi"), "iKMS");
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi"), "iSFM");
- // per ismacrypt E&A V1.1 section 9.1.2.1 'avc1' is renamed '264b'
- // avc1 must not appear as a sample entry name or original format name
- original_fmt = ATOMID("264b");
- SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.frma.data-format",
- original_fmt);
- SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.schm.scheme_type",
- icPp->scheme_type);
- SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.schm.scheme_version",
- icPp->scheme_version);
-
- SetTrackStringProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi.iKMS.kms_URI",
- icPp->kms_uri);
- SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi.iSFM.selective-encryption",
- icPp->selective_enc);
- SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi.iSFM.key-indicator-length",
- icPp->key_ind_len);
- SetTrackIntegerProperty(trackId, "mdia.minf.stbl.stsd.encv.sinf.schi.iSFM.IV-length",
- icPp->iv_len);
- return trackId;
- }
- void MP4File::AddH264SequenceParameterSet (MP4TrackId trackId,
- const uint8_t *pSequence,
- uint16_t sequenceLen)
- {
- const char *format;
- MP4Atom *avcCAtom;
- // get 4cc media format - can be avc1 or encv for ismacrypted track
- format = GetTrackMediaDataName(trackId);
- if (!strcasecmp(format, "avc1"))
- avcCAtom = FindAtomMP4File(MakeTrackName(trackId, "mdia.minf.stbl.stsd.avc1.avcC"));
- else if (!strcasecmp(format, "encv"))
- avcCAtom = FindAtomMP4File(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.avcC"));
- else
- // huh? unknown track format
- return;
- MP4BitfieldProperty *pCount;
- MP4Integer16Property *pLength;
- MP4BytesProperty *pUnit;
- if ((avcCAtom->FindProperty("avcC.numOfSequenceParameterSets",
- (MP4Property **)&pCount) == false) ||
- (avcCAtom->FindProperty("avcC.sequenceEntries.sequenceParameterSetLength",
- (MP4Property **)&pLength) == false) ||
- (avcCAtom->FindProperty("avcC.sequenceEntries.sequenceParameterSetNALUnit",
- (MP4Property **)&pUnit) == false)) {
- VERBOSE_ERROR(m_verbosity, WARNING("Could not find avcC properties"));
- return;
- }
- uint32_t count = pCount->GetValue();
-
- if (count > 0) {
- // see if we already exist
- for (uint32_t index = 0; index < count; index++) {
- if (pLength->GetValue(index) == sequenceLen) {
- uint8_t *seq;
- uint32_t seqlen;
- pUnit->GetValue(&seq, &seqlen, index);
- if (memcmp(seq, pSequence, sequenceLen) == 0) {
- free(seq);
- return;
- }
- free(seq);
- }
- }
- }
- pLength->AddValue(sequenceLen);
- pUnit->AddValue(pSequence, sequenceLen);
- pCount->IncrementValue();
- return;
- }
- void MP4File::AddH264PictureParameterSet (MP4TrackId trackId,
- const uint8_t *pPict,
- uint16_t pictLen)
- {
- MP4Atom *avcCAtom =
- FindAtomMP4File(MakeTrackName(trackId,
- "mdia.minf.stbl.stsd.avc1.avcC"));
- MP4Integer8Property *pCount;
- MP4Integer16Property *pLength;
- MP4BytesProperty *pUnit;
- if ((avcCAtom->FindProperty("avcC.numOfPictureParameterSets",
- (MP4Property **)&pCount) == false) ||
- (avcCAtom->FindProperty("avcC.pictureEntries.pictureParameterSetLength",
- (MP4Property **)&pLength) == false) ||
- (avcCAtom->FindProperty("avcC.pictureEntries.pictureParameterSetNALUnit",
- (MP4Property **)&pUnit) == false)) {
- VERBOSE_ERROR(m_verbosity,
- WARNING("Could not find avcC picture table properties"));
- return;
- }
- uint32_t count = pCount->GetValue();
-
- if (count > 0) {
- // see if we already exist
- for (uint32_t index = 0; index < count; index++) {
- if (pLength->GetValue(index) == pictLen) {
- uint8_t *seq;
- uint32_t seqlen;
- pUnit->GetValue(&seq, &seqlen, index);
- if (memcmp(seq, pPict, pictLen) == 0) {
- VERBOSE_WRITE(m_verbosity,
- fprintf(stderr, "picture matches %d\n", index));
- free(seq);
- return;
- }
- free(seq);
- }
- }
- }
- pLength->AddValue(pictLen);
- pUnit->AddValue(pPict, pictLen);
- pCount->IncrementValue();
- VERBOSE_WRITE(m_verbosity,
- fprintf(stderr, "new picture added %d\n", pCount->GetValue()));
- return;
- }
- void MP4File::SetH263Vendor(
- MP4TrackId trackId,
- u_int32_t vendor)
- {
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.s263.d263.vendor",
- vendor);
- }
- void MP4File::SetH263DecoderVersion(
- MP4TrackId trackId,
- u_int8_t decoderVersion)
- {
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.s263.d263.decoderVersion",
- decoderVersion);
- }
- void MP4File::SetH263Bitrates(
- MP4TrackId trackId,
- u_int32_t avgBitrate,
- u_int32_t maxBitrate)
- {
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.s263.d263.bitr.avgBitrate",
- avgBitrate);
-
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.s263.d263.bitr.maxBitrate",
- maxBitrate);
- }
- MP4TrackId MP4File::AddH263VideoTrack(
- u_int32_t timeScale,
- MP4Duration sampleDuration,
- u_int16_t width,
- u_int16_t height,
- u_int8_t h263Level,
- u_int8_t h263Profile,
- u_int32_t avgBitrate,
- u_int32_t maxBitrate)
- {
- MP4TrackId trackId = AddVideoTrackDefault(timeScale,
- sampleDuration,
- width,
- height,
- "s263");
-
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.s263.width", width);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.s263.height", height);
-
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.s263.d263.h263Level", h263Level);
-
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.s263.d263.h263Profile", h263Profile);
- // Add the bitr atom
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.s263.d263"),
- "bitr");
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.s263.d263.bitr.avgBitrate", avgBitrate);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.s263.d263.bitr.maxBitrate", maxBitrate);
-
-
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsz.sampleSize", sampleDuration);
-
- return trackId;
- }
- MP4TrackId MP4File::AddHintTrack(MP4TrackId refTrackId)
- {
- // validate reference track id
- (void)FindTrackIndex(refTrackId);
- MP4TrackId trackId =
- AddTrack(MP4_HINT_TRACK_TYPE, GetTrackTimeScale(refTrackId));
- (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "hmhd", 0);
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "rtp ");
- // stsd is a unique beast in that it has a count of the number
- // of child atoms that needs to be incremented after we add the rtp atom
- MP4Integer32Property* pStsdCountProperty;
- FindIntegerProperty(
- MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
- (MP4Property**)&pStsdCountProperty);
- pStsdCountProperty->IncrementValue();
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.rtp .tims.timeScale",
- GetTrackTimeScale(trackId));
- (void)AddDescendantAtoms(MakeTrackName(trackId, NULL), "tref.hint");
- AddTrackReference(MakeTrackName(trackId, "tref.hint"), refTrackId);
- (void)AddDescendantAtoms(MakeTrackName(trackId, NULL), "udta.hnti.sdp ");
- (void)AddDescendantAtoms(MakeTrackName(trackId, NULL), "udta.hinf");
- return trackId;
- }
- MP4TrackId MP4File::AddTextTrack(MP4TrackId refTrackId)
- {
- // validate reference track id
- (void)FindTrackIndex(refTrackId);
- MP4TrackId trackId =
- AddTrack(MP4_TEXT_TRACK_TYPE, GetTrackTimeScale(refTrackId));
- (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "gmhd", 0);
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "text");
- // stsd is a unique beast in that it has a count of the number
- // of child atoms that needs to be incremented after we add the text atom
- MP4Integer32Property* pStsdCountProperty;
- FindIntegerProperty(
- MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
- (MP4Property**)&pStsdCountProperty);
- pStsdCountProperty->IncrementValue();
- return trackId;
- }
- MP4TrackId MP4File::AddChapterTextTrack(MP4TrackId refTrackId, u_int32_t timescale)
- {
- // validate reference track id
- (void)FindTrackIndex(refTrackId);
- if (0 == timescale) {
- timescale = GetTrackTimeScale(refTrackId);
- }
-
- MP4TrackId trackId = AddTrack(MP4_TEXT_TRACK_TYPE, timescale);
- (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "gmhd", 0);
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "text");
- // stsd is a unique beast in that it has a count of the number
- // of child atoms that needs to be incremented after we add the text atom
- MP4Integer32Property* pStsdCountProperty;
- FindIntegerProperty(
- MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
- (MP4Property**)&pStsdCountProperty);
- pStsdCountProperty->IncrementValue();
- // add a "text" atom to the generic media header
- // this is different to the stsd "text" atom added above
- // truth be told, it's not clear what this second "text" atom does,
- // but all iTunes Store movies (with chapter markers) have it,
- // as do all movies with chapter tracks made by hand in QuickTime Pro
- (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.gmhd"), "text");
- // disable the chapter text track
- // it won't display anyway, as it has zero display size,
- // but nonetheless it's good to disable it
- // the track still operates as a chapter track when disabled
- MP4Atom *pTkhdAtom = FindAtomMP4File(MakeTrackName(trackId, "tkhd"));
- if (pTkhdAtom) {
- pTkhdAtom->SetFlags(0xE);
- }
- // add a "chapter" track reference to our reference track,
- // pointing to this new chapter track
- (void)AddDescendantAtoms(MakeTrackName(refTrackId, NULL), "tref.chap");
- AddTrackReference(MakeTrackName(refTrackId, "tref.chap"), trackId);
- return trackId;
- }
- void MP4File::AddChapter(MP4TrackId chapterTrackId, MP4Duration chapterDuration, u_int32_t chapterNr, const char * chapterTitle)
- {
- if (0 == chapterTrackId) {
- throw new MP4Error("No chapter track given","AddChapter");
- }
-
- uint32_t sampleLength = 0;
- uint8_t sample[1040] = {0};
- int stringLen = 0;
- char *string = (char *)&(sample[2]);
-
- if( chapterTitle != NULL )
- {
- stringLen = (int)strlen(chapterTitle);
- strncpy( string, chapterTitle, MIN(stringLen, 1023) );
- }
-
- if( stringLen == 0 || stringLen >= 1024 )
- {
- snprintf( string, 1023, "Chapter %03i", chapterNr );
- stringLen = (int)strlen(string);
- }
-
- sampleLength = stringLen + 2 + 12; // Account for text length code and other marker
-
- // 2-byte length marker
- sample[0] = (stringLen >> 8) & 0xff;
- sample[1] = stringLen & 0xff;
-
- int x = 2 + stringLen;
-
- // Modifier Length Marker
- sample[x] = 0x00;
- sample[x+1] = 0x00;
- sample[x+2] = 0x00;
- sample[x+3] = 0x0C;
-
- // Modifier Type Code
- sample[x+4] = 'e';
- sample[x+5] = 'n';
- sample[x+6] = 'c';
- sample[x+7] = 'd';
-
- // Modifier Value
- sample[x+8] = 0x00;
- sample[x+9] = 0x00;
- sample[x+10] = (256 >> 8) & 0xff;
- sample[x+11] = 256 & 0xff;
-
- WriteSample(chapterTrackId, sample, sampleLength, chapterDuration);
- }
-
- void MP4File::AddChapter(MP4Timestamp chapterStart, const char * chapterTitle)
- {
- MP4Atom * pChpl = FindAtomMP4File("moov.udta.chpl");
- if (!pChpl) {
- pChpl = AddDescendantAtoms("", "moov.udta.chpl");
- }
-
- char buffer[256];
- int bufferLen = 0;
-
- MP4Integer32Property * pCount = (MP4Integer32Property*)pChpl->GetProperty(3);
- pCount->IncrementValue();
- u_int32_t count = pCount->GetValue();
-
- if (0 == chapterTitle) {
- snprintf( buffer, 255, "Chapter %03i", count );
- } else {
- int len = MIN(255, (int)strlen(chapterTitle));
- strncpy( buffer, chapterTitle, len );
- buffer[len] = 0;
- }
- bufferLen = (int)strlen(buffer);
-
- MP4TableProperty * pTable;
- if (pChpl->FindProperty("chpl.chapters", (MP4Property **)&pTable)) {
- MP4Integer64Property * pStartTime = (MP4Integer64Property *) pTable->GetProperty(0);
- MP4StringProperty * pName = (MP4StringProperty *) pTable->GetProperty(1);
- if (pStartTime && pTable) {
- pStartTime->AddValue(chapterStart);
- pName->AddValue(buffer);
- }
- }
- }
-
- void MP4File::ConvertChapters(boolean toQT)
- {
- if (toQT) {
- MP4Chapters_t * chapters = 0;
- u_int32_t chapterCount = 0;
- const char * name = 0;
- MP4Duration chapterDurationSum = 0;
-
- GetChaptersList(&chapters, &chapterCount, false);
- if (0 == chapterCount) {
- throw new MP4Error("Could not find chapter markers", "ConvertChapters");
- }
-
- // remove chapter track if there is an existing one
- DeleteChapters();
-
- // create the chapter track
- MP4TrackId refTrack = FindTrackId(0, MP4_AUDIO_TRACK_TYPE);
- MP4TrackId chapterTrack = AddChapterTextTrack(refTrack, MP4_MILLISECONDS_TIME_SCALE);
-
- // calculate the duration of the chapter track
- MP4Duration chapterTrackDuration = MP4ConvertTime(GetTrackDuration(refTrack),
- GetTrackTimeScale(refTrack),
- MP4_MILLISECONDS_TIME_SCALE);
-
- for (u_int32_t chapterIndex = 0 ; chapterIndex < chapterCount; ++chapterIndex) {
- // calculate the duration
- MP4Duration duration = chapters[chapterIndex].duration;
-
- // sum up the chapter duration
- chapterDurationSum += duration;
-
- // create and write the chapter track sample for the previous chapter
- AddChapter( chapterTrack, duration, chapterIndex+1, chapters[chapterIndex].title );
- }
-
- MP4Free(chapters);
- } else {
- MP4Chapters_t * chapters = 0;
- u_int32_t chapterCount = 0;
-
- GetChaptersList(&chapters, &chapterCount);
- if (0 == chapterCount) {
- throw new MP4Error("Could not find chapter markers", "ConvertChapters");
- }
-
- // remove existing chapters
- DeleteChapters(0, false);
-
- MP4Duration startTime = 0;
- for (u_int32_t i = 0; i < chapterCount; ++i) {
- const char * title = chapters[i].title;
- MP4Duration duration = chapters[i].duration;
-
- AddChapter(startTime, title);
- startTime += duration * MILLI2HUNDREDNANO;
- }
-
- MP4Free(chapters);
- }
- }
-
- void MP4File::DeleteChapters(MP4TrackId chapterTrackId, boolean deleteQT)
- {
- if (!deleteQT) {
- MP4Atom * pChpl = FindAtomMP4File("moov.udta.chpl");
- if (pChpl) {
- MP4Atom * pParent = pChpl->GetParentAtom();
- pParent->DeleteChildAtom(pChpl);
- }
- return;
- }
-
- char trackName[128] = {0};
-
- // no text track given, find a suitable
- if (0 == chapterTrackId) {
- chapterTrackId = FindChapterTrack(trackName, 127);
- } else {
- FindChapterReferenceTrack(chapterTrackId, trackName, 127);
- }
-
- if (0 != chapterTrackId && 0 != trackName[0]) {
- // remove the reference
- RemoveTrackReference(trackName, chapterTrackId);
-
- // remove the chapter track
- DeleteTrack(chapterTrackId);
- }
- }
-
- void MP4File::GetChaptersList(MP4Chapters_t ** chapterList,
- u_int32_t * chapterCount,
- boolean getQT)
- {
- *chapterList = 0;
- *chapterCount = 0;
-
- if (!getQT) {
- MP4Atom * pChpl = FindAtomMP4File("moov.udta.chpl");
- if (!pChpl) {
- throw new MP4Error("Atom moov.udta.chpl does not exist ", "GetChaptersList");
- }
-
- MP4Integer32Property * pCounter = 0;
- MP4TableProperty * pTable = 0;
- MP4Integer64Property * pStartTime = 0;
- MP4StringProperty * pName = 0;
- MP4Duration chapterDurationSum = 0;
- const char * name = 0;
-
- if (!pChpl->FindProperty("chpl.chaptercount", (MP4Property **)&pCounter)) {
- throw new MP4Error("Chapter count does not exist ", "GetChaptersList");
- }
-
- u_int32_t counter = pCounter->GetValue();
- if (0 == counter) {
- return;
- }
-
- if (!pChpl->FindProperty("chpl.chapters", (MP4Property **)&pTable)) {
- throw new MP4Error("Chapter list does not exist ", "GetChaptersList");
- }
-
- if (0 == (pStartTime = (MP4Integer64Property *) pTable->GetProperty(0))) {
- throw new MP4Error("List of Chapter starttimes does not exist ", "GetChaptersList");
- }
- if (0 == (pName = (MP4StringProperty *) pTable->GetProperty(1))) {
- throw new MP4Error("List of Chapter titles does not exist ", "GetChaptersList");
- }
-
- MP4Chapters_t * chapters = (MP4Chapters_t*)MP4Malloc(sizeof(MP4Chapters_t) * counter);
-
- // get the name of the first chapter
- name = pName->GetValue();
-
- // process remaining chapters
- u_int32_t i, j;
- for (i = 0, j = 1; i < counter; ++i, ++j) {
- // insert the chapter title
- u_int32_t len = MIN((u_int32_t)strlen(name), CHAPTERTITLELEN);
- strncpy(chapters[i].title, name, len);
- chapters[i].title[len] = 0;
-
- // calculate the duration
- MP4Duration duration = 0;
- if (j < counter) {
- duration = MP4ConvertTime(pStartTime->GetValue(j),
- (MP4_NANOSECONDS_TIME_SCALE / 100),
- MP4_MILLISECONDS_TIME_SCALE) - chapterDurationSum;
-
- // now get the name of the chapter (to be written next)
- name = pName->GetValue(j);
- } else {
- // last chapter
- duration = MP4ConvertTime(GetDuration(), GetTimeScale(), MP4_MILLISECONDS_TIME_SCALE) - chapterDurationSum;
- }
-
- // sum up the chapter duration
- chapterDurationSum += duration;
-
- // insert the chapter duration
- chapters[i].duration = duration;
- }
-
- *chapterList = chapters;
- *chapterCount = counter;
-
- // ok, we're done
- return;
- }
-
-
- u_int8_t * sample = 0;
- u_int32_t sampleSize = 0;
- MP4Timestamp startTime = 0;
- MP4Duration duration = 0;
-
- // get the chapter track
- MP4TrackId chapterTrackId = FindChapterTrack();
- if (0 == chapterTrackId) {
- throw new MP4Error("Could not find a chapter track", "GetChaptersList");
- }
-
- // get infos about the chapters
- MP4Track * pChapterTrack = GetTrack(chapterTrackId);
- u_int32_t counter = pChapterTrack->GetNumberOfSamples();
- u_int32_t timescale = pChapterTrack->GetTimeScale();
-
- MP4Chapters_t * chapters = (MP4Chapters_t*)MP4Malloc(sizeof(MP4Chapters_t) * counter);
-
- // process all chapter sample
- for (u_int32_t i = 0; i < counter; ++i) {
- // get the sample corresponding to the starttime
- MP4SampleId sampleId = pChapterTrack->GetSampleIdFromTime(startTime + duration, true);
- pChapterTrack->ReadSample(sampleId, &sample, &sampleSize);
-
- // get the starttime and duration
- pChapterTrack->GetSampleTimes(sampleId, &startTime, &duration);
-
- // we know that sample+2 contains the title
- const char * title = (const char *)&(sample[2]);
- int len = MIN((int)strlen(title), CHAPTERTITLELEN);
- strncpy(chapters[i].title, title, len);
- chapters[i].title[len] = 0;
-
- // write the duration (in milliseconds)
- chapters[i].duration = MP4ConvertTime(duration, timescale, MP4_MILLISECONDS_TIME_SCALE);
-
- // we're done with this sample
- MP4Free(sample);
- sample = 0;
- }
-
- *chapterList = chapters;
- *chapterCount = counter;
- }
-
- MP4TrackId MP4File::FindChapterTrack(char * trackName, int trackNameSize)
- {
- for (u_int32_t i = 0; i < m_pTracks.Size(); i++) {
- if (!strcmp(MP4_TEXT_TRACK_TYPE, m_pTracks[i]->GetType())) {
- MP4TrackId refTrackId = FindChapterReferenceTrack(m_pTracks[i]->GetId(), trackName, trackNameSize);
- if (0 != refTrackId) {
- return m_pTracks[i]->GetId();
- }
- }
- }
- return 0;
- }
-
- MP4TrackId MP4File::FindChapterReferenceTrack(MP4TrackId chapterTrackId, char * trackName, size_t trackNameSize)
- {
- for (u_int32_t i = 0; i < m_pTracks.Size(); i++) {
- if (!strcmp(MP4_AUDIO_TRACK_TYPE, m_pTracks[i]->GetType())) {
- MP4TrackId refTrackId = m_pTracks[i]->GetId();
- char * name = MakeTrackName(refTrackId, "tref.chap");
- if (FindTrackReference(name, chapterTrackId)) {
- if (0 != trackName) {
- strncpy(trackName, name, MIN(strlen(name),trackNameSize));
- }
- return m_pTracks[i]->GetId();
- }
- }
- }
- return 0;
- }
-
- void MP4File::DeleteTrack(MP4TrackId trackId)
- {
- ProtectWriteOperation("MP4DeleteTrack");
- u_int32_t trakIndex = FindTrakAtomIndex(trackId);
- u_int16_t trackIndex = FindTrackIndex(trackId);
- MP4Track* pTrack = m_pTracks[trackIndex];
- MP4Atom* pTrakAtom = pTrack->GetTrakAtom();
- ASSERT(pTrakAtom);
- MP4Atom* pMoovAtom = FindAtomMP4File("moov");
- ASSERT(pMoovAtom);
- RemoveTrackFromIod(trackId, ShallHaveIods());
- RemoveTrackFromOd(trackId);
- if (trackId == m_odTrackId) {
- m_odTrackId = 0;
- }
- pMoovAtom->DeleteChildAtom(pTrakAtom);
- m_trakIds.Delete(trakIndex);
- m_pTracks.Delete(trackIndex);
- delete pTrack;
- delete pTrakAtom;
- }
- u_int32_t MP4File::GetNumberOfTracks(const char* type, u_int8_t subType)
- {
- if (type == NULL) {
- return m_pTracks.Size();
- }
- u_int32_t typeSeen = 0;
- const char* normType = MP4NormalizeTrackType(type, m_verbosity);
- for (u_int32_t i = 0; i < m_pTracks.Size(); i++) {
- if (!strcmp(normType, m_pTracks[i]->GetType())) {
- if (subType) {
- if (normType == MP4_AUDIO_TRACK_TYPE) {
- if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) {
- continue;
- }
- } else if (normType == MP4_VIDEO_TRACK_TYPE) {
- if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) {
- continue;
- }
- }
- // else unknown subtype, ignore it
- }
- typeSeen++;
- }
- }
- return typeSeen;
- }
- MP4TrackId MP4File::AllocTrackId()
- {
- MP4TrackId trackId =
- GetIntegerProperty("moov.mvhd.nextTrackId");
- if (trackId <= 0xFFFF) {
- // check that nextTrackid is correct
- try {
- (void)FindTrackIndex(trackId);
- // ERROR, this trackId is in use
- }
- catch (MP4Error* e) {
- // OK, this trackId is not in use, proceed
- delete e;
- SetIntegerProperty("moov.mvhd.nextTrackId", trackId + 1);
- return trackId;
- }
- }
- // we need to search for a track id
- for (trackId = 1; trackId <= 0xFFFF; trackId++) {
- try {
- (void)FindTrackIndex(trackId);
- // KEEP LOOKING, this trackId is in use
- }
- catch (MP4Error* e) {
- // OK, this trackId is not in use, proceed
- delete e;
- return trackId;
- }
- }
- // extreme case where mp4 file has 2^16 tracks in it
- throw new MP4Error("too many existing tracks", "AddTrack");
- return MP4_INVALID_TRACK_ID; // to keep MSVC happy
- }
- MP4TrackId MP4File::FindTrackId(u_int16_t trackIndex,
- const char* type, u_int8_t subType)
- {
- if (type == NULL) {
- return m_pTracks[trackIndex]->GetId();
- }
- u_int32_t typeSeen = 0;
- const char* normType = MP4NormalizeTrackType(type, m_verbosity);
- for (u_int32_t i = 0; i < m_pTracks.Size(); i++) {
- if (!strcmp(normType, m_pTracks[i]->GetType())) {
- if (subType) {
- if (normType == MP4_AUDIO_TRACK_TYPE) {
- if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) {
- continue;
- }
- } else if (normType == MP4_VIDEO_TRACK_TYPE) {
- if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) {
- continue;
- }
- }
- // else unknown subtype, ignore it
- }
- if (trackIndex == typeSeen) {
- return m_pTracks[i]->GetId();
- }
- typeSeen++;
- }
- }
- throw new MP4Error("Track index doesn't exist - track %d type %s",
- "FindTrackId",
- trackIndex, type);
- return MP4_INVALID_TRACK_ID; // satisfy MS compiler
- }
- u_int16_t MP4File::FindTrackIndex(MP4TrackId trackId)
- {
- for (u_int32_t i = 0; i < m_pTracks.Size() && i <= 0xFFFF; i++) {
- if (m_pTracks[i]->GetId() == trackId) {
- return (u_int16_t)i;
- }
- }
-
- throw new MP4Error("Track id %d doesn't exist", "FindTrackIndex", trackId);
- return (u_int16_t)-1; // satisfy MS compiler
- }
- u_int16_t MP4File::FindTrakAtomIndex(MP4TrackId trackId)
- {
- if (trackId) {
- for (u_int32_t i = 0; i < m_trakIds.Size(); i++) {
- if (m_trakIds[i] == trackId) {
- return i;
- }
- }
- }
- throw new MP4Error("Track id %d doesn't exist", "FindTrakAtomIndex",
- trackId);
- return (u_int16_t)-1; // satisfy MS compiler
- }
- u_int32_t MP4File::GetSampleSize(MP4TrackId trackId, MP4SampleId sampleId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->GetSampleSize(sampleId);
- }
- u_int32_t MP4File::GetTrackMaxSampleSize(MP4TrackId trackId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->GetMaxSampleSize();
- }
- MP4SampleId MP4File::GetSampleIdFromTime(MP4TrackId trackId,
- MP4Timestamp when, bool wantSyncSample, bool rewind)
- {
- return m_pTracks[FindTrackIndex(trackId)]->
- GetSampleIdFromTime(when, wantSyncSample, rewind);
- }
- MP4ChunkId MP4File::GetChunkIdFromTime(MP4TrackId trackId, MP4Timestamp when)
- {
- return m_pTracks[FindTrackIndex(trackId)]->
- GetChunkIdFromTime(when);
- }
- MP4Timestamp MP4File::GetSampleTime(
- MP4TrackId trackId, MP4SampleId sampleId)
- {
- MP4Timestamp timestamp;
- m_pTracks[FindTrackIndex(trackId)]->
- GetSampleTimes(sampleId, ×tamp, NULL);
- return timestamp;
- }
- MP4Duration MP4File::GetSampleDuration(
- MP4TrackId trackId, MP4SampleId sampleId)
- {
- MP4Duration duration;
- m_pTracks[FindTrackIndex(trackId)]->
- GetSampleTimes(sampleId, NULL, &duration);
- return duration;
- }
- MP4Duration MP4File::GetSampleRenderingOffset(
- MP4TrackId trackId, MP4SampleId sampleId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->
- GetSampleRenderingOffset(sampleId);
- }
- bool MP4File::GetSampleSync(MP4TrackId trackId, MP4SampleId sampleId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->IsSyncSample(sampleId);
- }
- void MP4File::ReadSample(MP4TrackId trackId, MP4SampleId sampleId,
- u_int8_t** ppBytes, u_int32_t* pNumBytes,
- MP4Timestamp* pStartTime, MP4Duration* pDuration,
- MP4Duration* pRenderingOffset, bool* pIsSyncSample)
- {
- m_pTracks[FindTrackIndex(trackId)]->
- ReadSample(sampleId, ppBytes, pNumBytes,
- pStartTime, pDuration, pRenderingOffset, pIsSyncSample);
- }
- void MP4File::ReadChunk(MP4TrackId trackId, MP4ChunkId sampleId,
- u_int8_t** ppBytes, u_int32_t* pNumBytes,
- MP4Timestamp* pStartTime, MP4Duration* pDuration)
- {
- m_pTracks[FindTrackIndex(trackId)]->
- ReadChunk(sampleId, ppBytes, pNumBytes, pStartTime, pDuration);
- }
- void MP4File::WriteSample(MP4TrackId trackId,
- const u_int8_t* pBytes, u_int32_t numBytes,
- MP4Duration duration, MP4Duration renderingOffset, bool isSyncSample)
- {
- ProtectWriteOperation("MP4WriteSample");
- m_pTracks[FindTrackIndex(trackId)]->
- WriteSample(pBytes, numBytes, duration, renderingOffset, isSyncSample);
- m_pModificationProperty->SetValue(MP4GetAbsTimestamp());
- }
- void MP4File::SetSampleRenderingOffset(MP4TrackId trackId,
- MP4SampleId sampleId, MP4Duration renderingOffset)
- {
- ProtectWriteOperation("MP4SetSampleRenderingOffset");
- m_pTracks[FindTrackIndex(trackId)]->
- SetSampleRenderingOffset(sampleId, renderingOffset);
- m_pModificationProperty->SetValue(MP4GetAbsTimestamp());
- }
- char* MP4File::MakeTrackName(MP4TrackId trackId, const char* name)
- {
- u_int16_t trakIndex = FindTrakAtomIndex(trackId);
- if (name == NULL || name[0] == '\0') {
- snprintf(m_trakName, sizeof(m_trakName),
- "moov.trak[%u]", trakIndex);
- } else {
- snprintf(m_trakName, sizeof(m_trakName),
- "moov.trak[%u].%s", trakIndex, name);
- }
- return m_trakName;
- }
- MP4Atom *MP4File::FindTrackAtom (MP4TrackId trackId, const char *name)
- {
- return FindAtomMP4File(MakeTrackName(trackId, name));
- }
- u_int64_t MP4File::GetTrackIntegerProperty(MP4TrackId trackId, const char* name)
- {
- return GetIntegerProperty(MakeTrackName(trackId, name));
- }
- void MP4File::SetTrackIntegerProperty(MP4TrackId trackId, const char* name,
- int64_t value)
- {
- SetIntegerProperty(MakeTrackName(trackId, name), value);
- }
- float MP4File::GetTrackFloatProperty(MP4TrackId trackId, const char* name)
- {
- return GetFloatProperty(MakeTrackName(trackId, name));
- }
- void MP4File::SetTrackFloatProperty(MP4TrackId trackId, const char* name,
- float value)
- {
- SetFloatProperty(MakeTrackName(trackId, name), value);
- }
- const char* MP4File::GetTrackStringProperty(MP4TrackId trackId, const char* name)
- {
- return GetStringProperty(MakeTrackName(trackId, name));
- }
- void MP4File::SetTrackStringProperty(MP4TrackId trackId, const char* name,
- const char* value)
- {
- SetStringProperty(MakeTrackName(trackId, name), value);
- }
- void MP4File::GetTrackBytesProperty(MP4TrackId trackId, const char* name,
- u_int8_t** ppValue, u_int32_t* pValueSize)
- {
- GetBytesProperty(MakeTrackName(trackId, name), ppValue, pValueSize);
- }
- void MP4File::SetTrackBytesProperty(MP4TrackId trackId, const char* name,
- const u_int8_t* pValue, u_int32_t valueSize)
- {
- SetBytesProperty(MakeTrackName(trackId, name), pValue, valueSize);
- }
- // file level convenience functions
- MP4Duration MP4File::GetDuration()
- {
- return m_pDurationProperty->GetValue();
- }
- void MP4File::SetDuration(MP4Duration value)
- {
- m_pDurationProperty->SetValue(value);
- }
- u_int32_t MP4File::GetTimeScale()
- {
- return m_pTimeScaleProperty->GetValue();
- }
- void MP4File::SetTimeScale(u_int32_t value)
- {
- if (value == 0) {
- throw new MP4Error("invalid value", "SetTimeScale");
- }
- m_pTimeScaleProperty->SetValue(value);
- }
- u_int8_t MP4File::GetODProfileLevel()
- {
- return GetIntegerProperty("moov.iods.ODProfileLevelId");
- }
- void MP4File::SetODProfileLevel(u_int8_t value)
- {
- SetIntegerProperty("moov.iods.ODProfileLevelId", value);
- }
-
- u_int8_t MP4File::GetSceneProfileLevel()
- {
- return GetIntegerProperty("moov.iods.sceneProfileLevelId");
- }
- void MP4File::SetSceneProfileLevel(u_int8_t value)
- {
- SetIntegerProperty("moov.iods.sceneProfileLevelId", value);
- }
-
- u_int8_t MP4File::GetVideoProfileLevel()
- {
- return GetIntegerProperty("moov.iods.visualProfileLevelId");
- }
- void MP4File::SetVideoProfileLevel(u_int8_t value)
- {
- SetIntegerProperty("moov.iods.visualProfileLevelId", value);
- }
-
- u_int8_t MP4File::GetAudioProfileLevel()
- {
- return GetIntegerProperty("moov.iods.audioProfileLevelId");
- }
- void MP4File::SetAudioProfileLevel(u_int8_t value)
- {
- SetIntegerProperty("moov.iods.audioProfileLevelId", value);
- }
-
- u_int8_t MP4File::GetGraphicsProfileLevel()
- {
- return GetIntegerProperty("moov.iods.graphicsProfileLevelId");
- }
- void MP4File::SetGraphicsProfileLevel(u_int8_t value)
- {
- SetIntegerProperty("moov.iods.graphicsProfileLevelId", value);
- }
-
- const char* MP4File::GetSessionSdp()
- {
- return GetStringProperty("moov.udta.hnti.rtp .sdpText");
- }
- void MP4File::SetSessionSdp(const char* sdpString)
- {
- (void)AddDescendantAtoms("moov", "udta.hnti.rtp ");
- SetStringProperty("moov.udta.hnti.rtp .sdpText", sdpString);
- }
- void MP4File::AppendSessionSdp(const char* sdpFragment)
- {
- const char* oldSdpString = NULL;
- try {
- oldSdpString = GetSessionSdp();
- }
- catch (MP4Error* e) {
- delete e;
- SetSessionSdp(sdpFragment);
- return;
- }
- char* newSdpString =
- (char*)MP4Malloc(strlen(oldSdpString) + strlen(sdpFragment) + 1);
- strcpy(newSdpString, oldSdpString);
- strcat(newSdpString, sdpFragment);
- SetSessionSdp(newSdpString);
- MP4Free(newSdpString);
- }
- //
- // ismacrypt API - retrieve OriginalFormatBox
- //
- // parameters are assumed to have been sanity tested in mp4.cpp
- // don't call this unless media data name is 'encv',
- // results may otherwise be unpredictable.
- //
- // input:
- // trackID - valid encv track ID for this file
- // buflen - length of oFormat, minimum is 5 (4cc plus null terminator)
- //
- // output:
- // oFormat - buffer to return null terminated string containing
- // track original format
- // return:
- // 0 - original format returned OK
- // 1 - buffer length error or problem retrieving track property
- //
- //
- bool MP4File::GetTrackMediaDataOriginalFormat(MP4TrackId trackId,
- char *originalFormat, u_int32_t buflen)
- {
- u_int32_t format;
- if (buflen < 5)
- return false;
- format = GetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.*.sinf.frma.data-format");
- IDATOM(format, originalFormat);
- return true;
- }
-
- // track level convenience functions
- MP4SampleId MP4File::GetTrackNumberOfSamples(MP4TrackId trackId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->GetNumberOfSamples();
- }
- MP4ChunkId MP4File::GetTrackNumberOfChunks(MP4TrackId trackId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->GetNumberOfChunks();
- }
- const char* MP4File::GetTrackType(MP4TrackId trackId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->GetType();
- }
- const char *MP4File::GetTrackMediaDataName (MP4TrackId trackId)
- {
- MP4Atom *pChild;
- MP4Atom *pAtom =
- FindAtomMP4File(MakeTrackName(trackId,
- "mdia.minf.stbl.stsd"));
- if (!pAtom || pAtom->GetNumberOfChildAtoms() != 1) {
- VERBOSE_ERROR(m_verbosity,
- fprintf(stderr, "track %d has more than 1 child atoms in stsd\n", trackId));
- return NULL;
- }
- pChild = pAtom->GetChildAtom(0);
- return pChild->GetType();
- }
-
- u_int32_t MP4File::GetTrackTimeScale(MP4TrackId trackId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->GetTimeScale();
- }
- void MP4File::SetTrackTimeScale(MP4TrackId trackId, u_int32_t value)
- {
- if (value == 0) {
- throw new MP4Error("invalid value", "SetTrackTimeScale");
- }
- SetTrackIntegerProperty(trackId, "mdia.mdhd.timeScale", value);
- }
- MP4Duration MP4File::GetTrackDuration(MP4TrackId trackId)
- {
- return GetTrackIntegerProperty(trackId, "mdia.mdhd.duration");
- }
- u_int8_t MP4File::GetTrackEsdsObjectTypeId(MP4TrackId trackId)
- {
- // changed mp4a to * to handle enca case
- try {
- return GetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.*.esds.decConfigDescr.objectTypeId");
- } catch (MP4Error *e) {
- delete e;
- return GetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.*.*.esds.decConfigDescr.objectTypeId");
- }
- }
- u_int8_t MP4File::GetTrackAudioMpeg4Type(MP4TrackId trackId)
- {
- // verify that track is an MPEG-4 audio track
- if (GetTrackEsdsObjectTypeId(trackId) != MP4_MPEG4_AUDIO_TYPE) {
- return MP4_MPEG4_INVALID_AUDIO_TYPE;
- }
- u_int8_t* pEsConfig = NULL;
- u_int32_t esConfigSize;
- // The Mpeg4 audio type (AAC, CELP, HXVC, ...)
- // is the first 5 bits of the ES configuration
- GetTrackESConfiguration(trackId, &pEsConfig, &esConfigSize);
- if (esConfigSize < 1) {
- free(pEsConfig);
- return MP4_MPEG4_INVALID_AUDIO_TYPE;
- }
- u_int8_t mpeg4Type = ((pEsConfig[0] >> 3) & 0x1f);
- // TTTT TXXX XXX potentially 6 bits of extension.
- if (mpeg4Type == 0x1f) {
- if (esConfigSize < 2) {
- free(pEsConfig);
- return MP4_MPEG4_INVALID_AUDIO_TYPE;
- }
- mpeg4Type = 32 +
- (((pEsConfig[0] & 0x7) << 3) | ((pEsConfig[1] >> 5) & 0x7));
- }
- free(pEsConfig);
- return mpeg4Type;
- }
- MP4Duration MP4File::GetTrackFixedSampleDuration(MP4TrackId trackId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->GetFixedSampleDuration();
- }
- double MP4File::GetTrackVideoFrameRate(MP4TrackId trackId)
- {
- MP4SampleId numSamples =
- GetTrackNumberOfSamples(trackId);
- u_int64_t
- msDuration =
- ConvertFromTrackDuration(trackId,
- GetTrackDuration(trackId), MP4_MSECS_TIME_SCALE);
- if (msDuration == 0) {
- return 0.0;
- }
- return ((double)numSamples / UINT64_TO_DOUBLE(msDuration)) * MP4_MSECS_TIME_SCALE;
- }
- int MP4File::GetTrackAudioChannels (MP4TrackId trackId)
- {
- return GetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.*[0].channels");
- }
- // true if media track encrypted according to ismacryp
- bool MP4File::IsIsmaCrypMediaTrack(MP4TrackId trackId)
- {
- if (GetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.*.sinf.frma.data-format")
- != (u_int64_t)-1) {
- return true;
- }
- return false;
- }
- void MP4File::GetTrackESConfiguration(MP4TrackId trackId,
- u_int8_t** ppConfig, u_int32_t* pConfigSize)
- {
- try {
- GetTrackBytesProperty(trackId,
- "mdia.minf.stbl.stsd.*[0].esds.decConfigDescr.decSpecificInfo[0].info",
- ppConfig, pConfigSize);
- } catch (MP4Error *e) {
- delete e;
- GetTrackBytesProperty(trackId,
- "mdia.minf.stbl.stsd.*[0].*.esds.decConfigDescr.decSpecificInfo[0].info",
- ppConfig, pConfigSize);
- }
- }
- void MP4File::GetTrackVideoMetadata(MP4TrackId trackId,
- u_int8_t** ppConfig, u_int32_t* pConfigSize)
- {
- GetTrackBytesProperty(trackId,
- "mdia.minf.stbl.stsd.*[0].*.metadata",
- ppConfig, pConfigSize);
- }
- void MP4File::SetTrackESConfiguration(MP4TrackId trackId,
- const u_int8_t* pConfig, u_int32_t configSize)
- {
- // get a handle on the track decoder config descriptor
- MP4DescriptorProperty* pConfigDescrProperty = NULL;
- if (FindProperty(MakeTrackName(trackId,
- "mdia.minf.stbl.stsd.*[0].esds.decConfigDescr.decSpecificInfo"),
- (MP4Property**)&pConfigDescrProperty) == false ||
- pConfigDescrProperty == NULL) {
- // probably trackId refers to a hint track
- throw new MP4Error("no such property", "MP4SetTrackESConfiguration");
- }
- // lookup the property to store the configuration
- MP4BytesProperty* pInfoProperty = NULL;
- (void)pConfigDescrProperty->FindProperty("decSpecificInfo[0].info",
- (MP4Property**)&pInfoProperty);
- // configuration being set for the first time
- if (pInfoProperty == NULL) {
- // need to create a new descriptor to hold it
- MP4Descriptor* pConfigDescr =
- pConfigDescrProperty->AddDescriptor(MP4DecSpecificDescrTag);
- pConfigDescr->Generate();
- (void)pConfigDescrProperty->FindProperty(
- "decSpecificInfo[0].info",
- (MP4Property**)&pInfoProperty);
- ASSERT(pInfoProperty);
- }
- // set the value
- pInfoProperty->SetValue(pConfig, configSize);
- }
- void MP4File::GetTrackH264SeqPictHeaders (MP4TrackId trackId,
- uint8_t ***pppSeqHeader,
- uint32_t **ppSeqHeaderSize,
- uint8_t ***pppPictHeader,
- uint32_t **ppPictHeaderSize)
- {
- uint32_t count;
- const char *format;
- MP4Atom *avcCAtom;
- *pppSeqHeader = NULL; *pppPictHeader = NULL;
- *ppSeqHeaderSize = NULL; *ppPictHeaderSize = NULL;
- // get 4cc media format - can be avc1 or encv for ismacrypted track
- format = GetTrackMediaDataName (trackId);
- if (!strcasecmp(format, "avc1"))
- avcCAtom = FindAtomMP4File(MakeTrackName(trackId, "mdia.minf.stbl.stsd.avc1.avcC"));
- else if (!strcasecmp(format, "encv"))
- avcCAtom = FindAtomMP4File(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.avcC"));
- else
- // huh? unknown track format
- return;
- MP4BitfieldProperty *pSeqCount;
- MP4IntegerProperty *pSeqLen, *pPictCount, *pPictLen;
- MP4BytesProperty *pSeqVal, *pPictVal;
- if ((avcCAtom->FindProperty("avcC.numOfSequenceParameterSets",
- (MP4Property **)&pSeqCount) == false) ||
- (avcCAtom->FindProperty("avcC.sequenceEntries.sequenceParameterSetLength",
- (MP4Property **)&pSeqLen) == false) ||
- (avcCAtom->FindProperty("avcC.sequenceEntries.sequenceParameterSetNALUnit",
- (MP4Property **)&pSeqVal) == false)) {
- VERBOSE_ERROR(m_verbosity, WARNING("Could not find avcC properties"));
- return ;
- }
- uint8_t **ppSeqHeader =
- (uint8_t **)malloc((pSeqCount->GetValue() + 1) * sizeof(uint8_t *));
- if (ppSeqHeader == NULL) return;
- *pppSeqHeader = ppSeqHeader;
- uint32_t *pSeqHeaderSize =
- (uint32_t *)malloc((pSeqCount->GetValue() + 1) * sizeof(uint32_t *));
- if (pSeqHeaderSize == NULL) return;
- *ppSeqHeaderSize = pSeqHeaderSize;
- for (count = 0; count < pSeqCount->GetValue(); count++) {
- pSeqVal->GetValue(&(ppSeqHeader[count]), &(pSeqHeaderSize[count]),
- count);
- }
- ppSeqHeader[count] = NULL;
- pSeqHeaderSize[count] = 0;
- if ((avcCAtom->FindProperty("avcC.numOfPictureParameterSets",
- (MP4Property **)&pPictCount) == false) ||
- (avcCAtom->FindProperty("avcC.pictureEntries.pictureParameterSetLength",
- (MP4Property **)&pPictLen) == false) ||
- (avcCAtom->FindProperty("avcC.pictureEntries.pictureParameterSetNALUnit",
- (MP4Property **)&pPictVal) == false)) {
- VERBOSE_ERROR(m_verbosity,
- WARNING("Could not find avcC picture table properties"));
- return ;
- }
- uint8_t
- **ppPictHeader =
- (uint8_t **)malloc((pPictCount->GetValue() + 1) * sizeof(uint8_t *));
- if (ppPictHeader == NULL) return;
- uint32_t *pPictHeaderSize =
- (uint32_t *)malloc((pPictCount->GetValue() + 1)* sizeof(uint32_t *));
- if (pPictHeaderSize == NULL) {
- free(ppPictHeader);
- return;
- }
- *pppPictHeader = ppPictHeader;
- *ppPictHeaderSize = pPictHeaderSize;
- for (count = 0; count < pPictCount->GetValue(); count++) {
- pPictVal->GetValue(&(ppPictHeader[count]), &(pPictHeaderSize[count]),
- count);
- }
- ppPictHeader[count] = NULL;
- pPictHeaderSize[count] = 0;
- return ;
- }
- const char* MP4File::GetHintTrackSdp(MP4TrackId hintTrackId)
- {
- return GetTrackStringProperty(hintTrackId, "udta.hnti.sdp .sdpText");
- }
- void MP4File::SetHintTrackSdp(MP4TrackId hintTrackId, const char* sdpString)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4SetHintTrackSdp");
- }
- (void)AddDescendantAtoms(
- MakeTrackName(hintTrackId, NULL), "udta.hnti.sdp ");
- SetTrackStringProperty(hintTrackId, "udta.hnti.sdp .sdpText", sdpString);
- }
- void MP4File::AppendHintTrackSdp(MP4TrackId hintTrackId,
- const char* sdpFragment)
- {
- const char* oldSdpString = NULL;
- try {
- oldSdpString = GetHintTrackSdp(hintTrackId);
- }
- catch (MP4Error* e) {
- delete e;
- SetHintTrackSdp(hintTrackId, sdpFragment);
- return;
- }
- char* newSdpString =
- (char*)MP4Malloc(strlen(oldSdpString) + strlen(sdpFragment) + 1);
- strcpy(newSdpString, oldSdpString);
- strcat(newSdpString, sdpFragment);
- SetHintTrackSdp(hintTrackId, newSdpString);
- MP4Free(newSdpString);
- }
- void MP4File::GetHintTrackRtpPayload(
- MP4TrackId hintTrackId,
- char** ppPayloadName,
- u_int8_t* pPayloadNumber,
- u_int16_t* pMaxPayloadSize,
- char **ppEncodingParams)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4GetHintTrackRtpPayload");
- }
- ((MP4RtpHintTrack*)pTrack)->GetPayload(
- ppPayloadName, pPayloadNumber, pMaxPayloadSize, ppEncodingParams);
- }
- void MP4File::SetHintTrackRtpPayload(MP4TrackId hintTrackId,
- const char* payloadName, u_int8_t* pPayloadNumber, u_int16_t maxPayloadSize,
- const char *encoding_params,
- bool include_rtp_map,
- bool include_mpeg4_esid)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4SetHintTrackRtpPayload");
- }
- u_int8_t payloadNumber;
- if (pPayloadNumber && *pPayloadNumber != MP4_SET_DYNAMIC_PAYLOAD) {
- payloadNumber = *pPayloadNumber;
- } else {
- payloadNumber = AllocRtpPayloadNumber();
- if (pPayloadNumber) {
- *pPayloadNumber = payloadNumber;
- }
- }
- ((MP4RtpHintTrack*)pTrack)->SetPayload(
- payloadName, payloadNumber, maxPayloadSize, encoding_params,
- include_rtp_map, include_mpeg4_esid);
- }
- u_int8_t MP4File::AllocRtpPayloadNumber()
- {
- MP4Integer32Array usedPayloads;
- u_int32_t i;
- // collect rtp payload numbers in use by existing tracks
- for (i = 0; i < m_pTracks.Size(); i++) {
- MP4Atom* pTrakAtom = m_pTracks[i]->GetTrakAtom();
- MP4Integer32Property* pPayloadProperty = NULL;
- if (pTrakAtom->FindProperty("trak.udta.hinf.payt.payloadNumber",
- (MP4Property**)&pPayloadProperty) &&
- pPayloadProperty) {
- usedPayloads.Add(pPayloadProperty->GetValue());
- }
- }
- // search dynamic payload range for an available slot
- u_int8_t payload;
- for (payload = 96; payload < 128; payload++) {
- for (i = 0; i < usedPayloads.Size(); i++) {
- if (payload == usedPayloads[i]) {
- break;
- }
- }
- if (i == usedPayloads.Size()) {
- break;
- }
- }
- if (payload >= 128) {
- throw new MP4Error("no more available rtp payload numbers",
- "AllocRtpPayloadNumber");
- }
- return payload;
- }
- MP4TrackId MP4File::GetHintTrackReferenceTrackId(
- MP4TrackId hintTrackId)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4GetHintTrackReferenceTrackId");
- }
- MP4Track* pRefTrack = ((MP4RtpHintTrack*)pTrack)->GetRefTrack();
- if (pRefTrack == NULL) {
- return MP4_INVALID_TRACK_ID;
- }
- return pRefTrack->GetId();
- }
- void MP4File::ReadRtpHint(
- MP4TrackId hintTrackId,
- MP4SampleId hintSampleId,
- u_int16_t* pNumPackets)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track", "MP4ReadRtpHint");
- }
- ((MP4RtpHintTrack*)pTrack)->
- ReadHint(hintSampleId, pNumPackets);
- }
- u_int16_t MP4File::GetRtpHintNumberOfPackets(
- MP4TrackId hintTrackId)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4GetRtpHintNumberOfPackets");
- }
- return ((MP4RtpHintTrack*)pTrack)->GetHintNumberOfPackets();
- }
- int8_t MP4File::GetRtpPacketBFrame(
- MP4TrackId hintTrackId,
- u_int16_t packetIndex)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4GetRtpHintBFrame");
- }
- return ((MP4RtpHintTrack*)pTrack)->GetPacketBFrame(packetIndex);
- }
- int32_t MP4File::GetRtpPacketTransmitOffset(
- MP4TrackId hintTrackId,
- u_int16_t packetIndex)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4GetRtpPacketTransmitOffset");
- }
- return ((MP4RtpHintTrack*)pTrack)->GetPacketTransmitOffset(packetIndex);
- }
- void MP4File::ReadRtpPacket(
- MP4TrackId hintTrackId,
- u_int16_t packetIndex,
- u_int8_t** ppBytes,
- u_int32_t* pNumBytes,
- u_int32_t ssrc,
- bool includeHeader,
- bool includePayload)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track", "MP4ReadPacket");
- }
- ((MP4RtpHintTrack*)pTrack)->ReadPacket(
- packetIndex, ppBytes, pNumBytes,
- ssrc, includeHeader, includePayload);
- }
- MP4Timestamp MP4File::GetRtpTimestampStart(
- MP4TrackId hintTrackId)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4GetRtpTimestampStart");
- }
- return ((MP4RtpHintTrack*)pTrack)->GetRtpTimestampStart();
- }
- void MP4File::SetRtpTimestampStart(
- MP4TrackId hintTrackId,
- MP4Timestamp rtpStart)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4SetRtpTimestampStart");
- }
- ((MP4RtpHintTrack*)pTrack)->SetRtpTimestampStart(rtpStart);
- }
- void MP4File::AddRtpHint(MP4TrackId hintTrackId,
- bool isBframe, u_int32_t timestampOffset)
- {
- ProtectWriteOperation("MP4AddRtpHint");
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track", "MP4AddRtpHint");
- }
- ((MP4RtpHintTrack*)pTrack)->AddHint(isBframe, timestampOffset);
- }
- void MP4File::AddRtpPacket(
- MP4TrackId hintTrackId, bool setMbit, int32_t transmitOffset)
- {
- ProtectWriteOperation("MP4AddRtpPacket");
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track", "MP4AddRtpPacket");
- }
- ((MP4RtpHintTrack*)pTrack)->AddPacket(setMbit, transmitOffset);
- }
- void MP4File::AddRtpImmediateData(MP4TrackId hintTrackId,
- const u_int8_t* pBytes, u_int32_t numBytes)
- {
- ProtectWriteOperation("MP4AddRtpImmediateData");
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4AddRtpImmediateData");
- }
- ((MP4RtpHintTrack*)pTrack)->AddImmediateData(pBytes, numBytes);
- }
- void MP4File::AddRtpSampleData(MP4TrackId hintTrackId,
- MP4SampleId sampleId, u_int32_t dataOffset, u_int32_t dataLength)
- {
- ProtectWriteOperation("MP4AddRtpSampleData");
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4AddRtpSampleData");
- }
- ((MP4RtpHintTrack*)pTrack)->AddSampleData(
- sampleId, dataOffset, dataLength);
- }
- void MP4File::AddRtpESConfigurationPacket(MP4TrackId hintTrackId)
- {
- ProtectWriteOperation("MP4AddRtpESConfigurationPacket");
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4AddRtpESConfigurationPacket");
- }
- ((MP4RtpHintTrack*)pTrack)->AddESConfigurationPacket();
- }
- void MP4File::WriteRtpHint(MP4TrackId hintTrackId,
- MP4Duration duration, bool isSyncSample)
- {
- ProtectWriteOperation("MP4WriteRtpHint");
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4WriteRtpHint");
- }
- ((MP4RtpHintTrack*)pTrack)->WriteHint(duration, isSyncSample);
- }
- u_int64_t MP4File::ConvertFromMovieDuration(
- MP4Duration duration,
- u_int32_t timeScale)
- {
- return MP4ConvertTime((u_int64_t)duration,
- GetTimeScale(), timeScale);
- }
- u_int64_t MP4File::ConvertFromTrackTimestamp(
- MP4TrackId trackId,
- MP4Timestamp timeStamp,
- u_int32_t timeScale)
- {
- return MP4ConvertTime(timeStamp,
- GetTrackTimeScale(trackId), timeScale);
- }
- MP4Timestamp MP4File::ConvertToTrackTimestamp(
- MP4TrackId trackId,
- u_int64_t timeStamp,
- u_int32_t timeScale)
- {
- return (MP4Timestamp)MP4ConvertTime(timeStamp,
- timeScale, GetTrackTimeScale(trackId));
- }
- u_int64_t MP4File::ConvertFromTrackDuration(
- MP4TrackId trackId,
- MP4Duration duration,
- u_int32_t timeScale)
- {
- return MP4ConvertTime((u_int64_t)duration,
- GetTrackTimeScale(trackId), timeScale);
- }
- MP4Duration MP4File::ConvertToTrackDuration(
- MP4TrackId trackId,
- u_int64_t duration,
- u_int32_t timeScale)
- {
- return (MP4Duration)MP4ConvertTime(duration,
- timeScale, GetTrackTimeScale(trackId));
- }
- u_int8_t MP4File::ConvertTrackTypeToStreamType(const char* trackType)
- {
- u_int8_t streamType;
- if (!strcmp(trackType, MP4_OD_TRACK_TYPE)) {
- streamType = MP4ObjectDescriptionStreamType;
- } else if (!strcmp(trackType, MP4_SCENE_TRACK_TYPE)) {
- streamType = MP4SceneDescriptionStreamType;
- } else if (!strcmp(trackType, MP4_CLOCK_TRACK_TYPE)) {
- streamType = MP4ClockReferenceStreamType;
- } else if (!strcmp(trackType, MP4_MPEG7_TRACK_TYPE)) {
- streamType = MP4Mpeg7StreamType;
- } else if (!strcmp(trackType, MP4_OCI_TRACK_TYPE)) {
- streamType = MP4OCIStreamType;
- } else if (!strcmp(trackType, MP4_IPMP_TRACK_TYPE)) {
- streamType = MP4IPMPStreamType;
- } else if (!strcmp(trackType, MP4_MPEGJ_TRACK_TYPE)) {
- streamType = MP4MPEGJStreamType;
- } else {
- streamType = MP4UserPrivateStreamType;
- }
- return streamType;
- }
- // edit list
- char* MP4File::MakeTrackEditName(
- MP4TrackId trackId,
- MP4EditId editId,
- const char* name)
- {
- char* trakName = MakeTrackName(trackId, NULL);
- if (m_editName == NULL) {
- m_editName = (char *)malloc(1024);
- if (m_editName == NULL) return NULL;
- }
- snprintf(m_editName, 1024,
- "%s.edts.elst.entries[%u].%s",
- trakName, editId - 1, name);
- return m_editName;
- }
- MP4EditId MP4File::AddTrackEdit(
- MP4TrackId trackId,
- MP4EditId editId)
- {
- ProtectWriteOperation("AddTrackEdit");
- return m_pTracks[FindTrackIndex(trackId)]->AddEdit(editId);
- }
- void MP4File::DeleteTrackEdit(
- MP4TrackId trackId,
- MP4EditId editId)
- {
- ProtectWriteOperation("DeleteTrackEdit");
- m_pTracks[FindTrackIndex(trackId)]->DeleteEdit(editId);
- }
- u_int32_t MP4File::GetTrackNumberOfEdits(
- MP4TrackId trackId)
- {
- return GetTrackIntegerProperty(trackId, "edts.elst.entryCount");
- }
- MP4Duration MP4File::GetTrackEditTotalDuration(
- MP4TrackId trackId,
- MP4EditId editId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->GetEditTotalDuration(editId);
- }
- MP4Timestamp MP4File::GetTrackEditStart(
- MP4TrackId trackId,
- MP4EditId editId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->GetEditStart(editId);
- }
- MP4Timestamp MP4File::GetTrackEditMediaStart(
- MP4TrackId trackId,
- MP4EditId editId)
- {
- return GetIntegerProperty(
- MakeTrackEditName(trackId, editId, "mediaTime"));
- }
- void MP4File::SetTrackEditMediaStart(
- MP4TrackId trackId,
- MP4EditId editId,
- MP4Timestamp startTime)
- {
- SetIntegerProperty(
- MakeTrackEditName(trackId, editId, "mediaTime"),
- startTime);
- }
- MP4Duration MP4File::GetTrackEditDuration(
- MP4TrackId trackId,
- MP4EditId editId)
- {
- return GetIntegerProperty(
- MakeTrackEditName(trackId, editId, "segmentDuration"));
- }
- void MP4File::SetTrackEditDuration(
- MP4TrackId trackId,
- MP4EditId editId,
- MP4Duration duration)
- {
- SetIntegerProperty(
- MakeTrackEditName(trackId, editId, "segmentDuration"),
- duration);
- }
- bool MP4File::GetTrackEditDwell(
- MP4TrackId trackId,
- MP4EditId editId)
- {
- return (GetIntegerProperty(
- MakeTrackEditName(trackId, editId, "mediaRate")) == 0);
- }
- void MP4File::SetTrackEditDwell(
- MP4TrackId trackId,
- MP4EditId editId,
- bool dwell)
- {
- SetIntegerProperty(
- MakeTrackEditName(trackId, editId, "mediaRate"),
- (dwell ? 0 : 1));
- }
- MP4SampleId MP4File::GetSampleIdFromEditTime(
- MP4TrackId trackId,
- MP4Timestamp when,
- MP4Timestamp* pStartTime,
- MP4Duration* pDuration)
- {
- return m_pTracks[FindTrackIndex(trackId)]->GetSampleIdFromEditTime(
- when, pStartTime, pDuration);
- }
|