mp4file.cpp
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:58k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is MPEG4IP.
  13.  * 
  14.  * The Initial Developer of the Original Code is Cisco Systems Inc.
  15.  * Portions created by Cisco Systems Inc. are
  16.  * Copyright (C) Cisco Systems Inc. 2001.  All Rights Reserved.
  17.  * 
  18.  * Contributor(s): 
  19.  * Dave Mackie dmackie@cisco.com
  20.  */
  21. #include "mp4common.h"
  22. MP4File::MP4File(u_int32_t verbosity)
  23. {
  24. m_fileName = NULL;
  25. m_pFile = NULL;
  26. m_orgFileSize = 0;
  27. m_fileSize = 0;
  28. m_pRootAtom = NULL;
  29. m_odTrackId = MP4_INVALID_TRACK_ID;
  30. m_verbosity = verbosity;
  31. m_mode = 0;
  32. m_use64bits = false;
  33. m_useIsma = false;
  34. m_pModificationProperty = NULL;
  35. m_pTimeScaleProperty = NULL;
  36. m_pDurationProperty = NULL;
  37. m_memoryBuffer = NULL;
  38. m_memoryBufferSize = 0;
  39. m_memoryBufferPosition = 0;
  40. m_numReadBits = 0;
  41. m_bufReadBits = 0;
  42. m_numWriteBits = 0;
  43. m_bufWriteBits = 0;
  44. }
  45. MP4File::~MP4File()
  46. {
  47. MP4Free(m_fileName);
  48. delete m_pRootAtom;
  49. for (u_int32_t i = 0; i < m_pTracks.Size(); i++) {
  50. delete m_pTracks[i];
  51. }
  52. MP4Free(m_memoryBuffer); // just in case
  53. }
  54. void MP4File::Read(const char* fileName)
  55. {
  56. m_fileName = MP4Stralloc(fileName);
  57. m_mode = 'r';
  58. Open("rb");
  59. ReadFromFile();
  60. CacheProperties();
  61. }
  62. void MP4File::Create(const char* fileName, bool use64bits)
  63. {
  64. m_fileName = MP4Stralloc(fileName);
  65. m_mode = 'w';
  66. m_use64bits = use64bits;
  67. Open("wb+");
  68. // generate a skeletal atom tree
  69. m_pRootAtom = MP4Atom::CreateAtom(NULL);
  70. m_pRootAtom->SetFile(this);
  71. m_pRootAtom->Generate();
  72. CacheProperties();
  73. // create mdat, and insert it after ftyp, and before moov
  74. InsertChildAtom(m_pRootAtom, "mdat", 1);
  75. // start writing
  76. m_pRootAtom->BeginWrite();
  77. }
  78. void MP4File::Modify(const char* fileName)
  79. {
  80. m_fileName = MP4Stralloc(fileName);
  81. m_mode = 'r';
  82. Open("rb+");
  83. ReadFromFile();
  84. m_mode = 'w';
  85. // find the moov atom
  86. MP4Atom* pMoovAtom = m_pRootAtom->FindAtom("moov");
  87. u_int32_t numAtoms;
  88. if (pMoovAtom == NULL) {
  89. // there isn't one, odd but we can still proceed
  90. pMoovAtom = AddChildAtom(m_pRootAtom, "moov");
  91. } else {
  92. numAtoms = m_pRootAtom->GetNumberOfChildAtoms();
  93. // work backwards thru the top level atoms
  94. int32_t i;
  95. bool lastAtomIsMoov = true;
  96. MP4Atom* pLastAtom = NULL;
  97. for (i = numAtoms - 1; i >= 0; i--) {
  98. MP4Atom* pAtom = m_pRootAtom->GetChildAtom(i);
  99. const char* type = pAtom->GetType();
  100. // get rid of any trailing free or skips
  101. if (!strcmp(type, "free") || !strcmp(type, "skip")) {
  102. m_pRootAtom->DeleteChildAtom(pAtom);
  103. continue;
  104. }
  105. if (strcmp(type, "moov")) {
  106. if (pLastAtom == NULL) {
  107. pLastAtom = pAtom;
  108. lastAtomIsMoov = false;
  109. }
  110. continue;
  111. }
  112. // now at moov atom
  113. // multiple moov atoms?!?
  114. if (pAtom != pMoovAtom) {
  115. throw new MP4Error(
  116. "Badly formed mp4 file, multiple moov atoms", 
  117. "MP4Modify");
  118. }
  119. if (lastAtomIsMoov) {
  120. // position to start of moov atom,
  121. // effectively truncating file 
  122. // prior to adding new mdat
  123. SetPosition(pMoovAtom->GetStart());
  124. } else { // last atom isn't moov
  125. // need to place a free atom 
  126. MP4Atom* pFreeAtom = MP4Atom::CreateAtom("free");
  127. // in existing position of the moov atom
  128. m_pRootAtom->InsertChildAtom(pFreeAtom, i);
  129. m_pRootAtom->DeleteChildAtom(pMoovAtom);
  130. m_pRootAtom->AddChildAtom(pMoovAtom);
  131. // write free atom to disk
  132. SetPosition(pMoovAtom->GetStart());
  133. pFreeAtom->SetSize(pMoovAtom->GetSize());
  134. pFreeAtom->Write();
  135. // finally set our file position to the end of the last atom
  136. SetPosition(pLastAtom->GetEnd());
  137. }
  138. break;
  139. }
  140. ASSERT(i != -1);
  141. }
  142. CacheProperties(); // of moov atom
  143. numAtoms = m_pRootAtom->GetNumberOfChildAtoms();
  144. // insert another mdat prior to moov atom (the last atom)
  145. MP4Atom* pMdatAtom = InsertChildAtom(m_pRootAtom, "mdat", numAtoms - 1);
  146. // start writing new mdat
  147. pMdatAtom->BeginWrite();
  148. }
  149. void MP4File::Optimize(const char* orgFileName, const char* newFileName)
  150. {
  151. m_fileName = MP4Stralloc(orgFileName);
  152. m_mode = 'r';
  153. // first load meta-info into memory
  154. Open("rb");
  155. ReadFromFile();
  156. CacheProperties(); // of moov atom
  157. // now switch over to writing the new file
  158. MP4Free(m_fileName);
  159. // create a temporary file if necessary
  160. if (newFileName == NULL) {
  161. m_fileName = MP4Stralloc(TempFileName());
  162. } else {
  163. m_fileName = MP4Stralloc(newFileName);
  164. }
  165. FILE* pReadFile = m_pFile;
  166. m_pFile = NULL;
  167. m_mode = 'w';
  168. Open("wb");
  169. SetIntegerProperty("moov.mvhd.modificationTime", 
  170. MP4GetAbsTimestamp());
  171. // writing meta info in the optimal order
  172. ((MP4RootAtom*)m_pRootAtom)->BeginOptimalWrite();
  173. // write data in optimal order
  174. RewriteMdat(pReadFile, m_pFile);
  175. // finish writing
  176. ((MP4RootAtom*)m_pRootAtom)->FinishOptimalWrite();
  177. // cleanup
  178. fclose(m_pFile);
  179. m_pFile = NULL;
  180. fclose(pReadFile);
  181. // move temporary file into place
  182. if (newFileName == NULL) {
  183. Rename(m_fileName, orgFileName);
  184. }
  185. }
  186. void MP4File::RewriteMdat(FILE* pReadFile, FILE* pWriteFile)
  187. {
  188. u_int32_t numTracks = m_pTracks.Size();
  189. MP4ChunkId* chunkIds = new MP4ChunkId[numTracks];
  190. MP4ChunkId* maxChunkIds = new MP4ChunkId[numTracks];
  191. MP4Timestamp* nextChunkTimes = new MP4Timestamp[numTracks];
  192. for (u_int32_t i = 0; i < numTracks; i++) {
  193. chunkIds[i] = 1;
  194. maxChunkIds[i] = m_pTracks[i]->GetNumberOfChunks();
  195. nextChunkTimes[i] = MP4_INVALID_TIMESTAMP;
  196. }
  197. while (true) {
  198. u_int32_t nextTrackIndex = (u_int32_t)-1;
  199. MP4Timestamp nextTime = MP4_INVALID_TIMESTAMP;
  200. for (u_int32_t i = 0; i < numTracks; i++) {
  201. if (chunkIds[i] > maxChunkIds[i]) {
  202. continue;
  203. }
  204. if (nextChunkTimes[i] == MP4_INVALID_TIMESTAMP) {
  205. MP4Timestamp chunkTime =
  206. m_pTracks[i]->GetChunkTime(chunkIds[i]);
  207. nextChunkTimes[i] = MP4ConvertTime(chunkTime,
  208. m_pTracks[i]->GetTimeScale(), GetTimeScale());
  209. }
  210. // time is not earliest so far
  211. if (nextChunkTimes[i] > nextTime) {
  212. continue;
  213. }
  214. // prefer hint tracks to media tracks if times are equal
  215. if (nextChunkTimes[i] == nextTime 
  216.   && strcmp(m_pTracks[i]->GetType(), MP4_HINT_TRACK_TYPE)) {
  217. continue;
  218. }
  219. // this is our current choice of tracks
  220. nextTime = nextChunkTimes[i];
  221. nextTrackIndex = i;
  222. }
  223. if (nextTrackIndex == (u_int32_t)-1) {
  224. break;
  225. }
  226. // point into original mp4 file for read chunk call
  227. m_pFile = pReadFile;
  228. m_mode = 'r';
  229. u_int8_t* pChunk;
  230. u_int32_t chunkSize;
  231. m_pTracks[nextTrackIndex]->
  232. ReadChunk(chunkIds[nextTrackIndex], &pChunk, &chunkSize);
  233. // point back at the new mp4 file for write chunk
  234. m_pFile = pWriteFile;
  235. m_mode = 'w';
  236. m_pTracks[nextTrackIndex]->
  237. RewriteChunk(chunkIds[nextTrackIndex], pChunk, chunkSize);
  238. MP4Free(pChunk);
  239. chunkIds[nextTrackIndex]++;
  240. nextChunkTimes[nextTrackIndex] = MP4_INVALID_TIMESTAMP;
  241. }
  242. delete [] chunkIds;
  243. delete [] maxChunkIds;
  244. delete [] nextChunkTimes;
  245. }
  246. void MP4File::Open(const char* fmode)
  247. {
  248. ASSERT(m_pFile == NULL);
  249. #ifdef O_LARGEFILE
  250. // UGH! fopen doesn't open a file in 64-bit mode, period.
  251. // So we need to use open() and then fdopen()
  252. int fd;
  253. int flags = O_LARGEFILE;
  254. if (strchr(fmode, '+')) {
  255. flags |= O_CREAT | O_RDWR;
  256. if (fmode[0] == 'w') {
  257. flags |= O_TRUNC;
  258. }
  259. } else {
  260. if (fmode[0] == 'w') {
  261. flags |= O_CREAT | O_TRUNC | O_WRONLY;
  262. } else {
  263. flags |= O_RDONLY;
  264. }
  265. }
  266. fd = open(m_fileName, flags, 0666); 
  267. if (fd >= 0) {
  268. m_pFile = fdopen(fd, fmode);
  269. }
  270. #else
  271. m_pFile = fopen(m_fileName, fmode);
  272. #endif
  273. if (m_pFile == NULL) {
  274. throw new MP4Error(errno, "failed", "MP4Open");
  275. }
  276. if (m_mode == 'r') {
  277. struct stat s;
  278. if (fstat(fileno(m_pFile), &s) < 0) {
  279. throw new MP4Error(errno, "stat failed", "MP4Open");
  280. }
  281. m_orgFileSize = m_fileSize = s.st_size;
  282. } else {
  283. m_orgFileSize = m_fileSize = 0;
  284. }
  285. }
  286. void MP4File::ReadFromFile()
  287. {
  288. // ensure we start at beginning of file
  289. SetPosition(0);
  290. // create a new root atom
  291. ASSERT(m_pRootAtom == NULL);
  292. m_pRootAtom = MP4Atom::CreateAtom(NULL);
  293. u_int64_t fileSize = GetSize();
  294. m_pRootAtom->SetFile(this);
  295. m_pRootAtom->SetStart(0);
  296. m_pRootAtom->SetSize(fileSize);
  297. m_pRootAtom->SetEnd(fileSize);
  298. m_pRootAtom->Read();
  299. // create MP4Track's for any tracks in the file
  300. GenerateTracks();
  301. }
  302. void MP4File::GenerateTracks()
  303. {
  304. u_int32_t trackIndex = 0;
  305. while (true) {
  306. char trackName[32];
  307. snprintf(trackName, sizeof(trackName), "moov.trak[%u]", trackIndex);
  308. // find next trak atom
  309. MP4Atom* pTrakAtom = m_pRootAtom->FindAtom(trackName);
  310. // done, no more trak atoms
  311. if (pTrakAtom == NULL) {
  312. break;
  313. }
  314. // find track id property
  315. MP4Integer32Property* pTrackIdProperty = NULL;
  316. pTrakAtom->FindProperty(
  317. "trak.tkhd.trackId",
  318. (MP4Property**)&pTrackIdProperty);
  319. // find track type property
  320. MP4StringProperty* pTypeProperty = NULL;
  321. pTrakAtom->FindProperty(
  322. "trak.mdia.hdlr.handlerType",
  323. (MP4Property**)&pTypeProperty);
  324. // ensure we have the basics properties
  325. if (pTrackIdProperty && pTypeProperty) {
  326. m_trakIds.Add(pTrackIdProperty->GetValue());
  327. MP4Track* pTrack = NULL;
  328. try {
  329. if (!strcmp(pTypeProperty->GetValue(), MP4_HINT_TRACK_TYPE)) {
  330. pTrack = new MP4RtpHintTrack(this, pTrakAtom);
  331. } else {
  332. pTrack = new MP4Track(this, pTrakAtom);
  333. }
  334. m_pTracks.Add(pTrack);
  335. }
  336. catch (MP4Error* e) {
  337. VERBOSE_ERROR(m_verbosity, e->Print());
  338. delete e;
  339. }
  340. // remember when we encounter the OD track
  341. if (pTrack && !strcmp(pTrack->GetType(), MP4_OD_TRACK_TYPE)) {
  342. if (m_odTrackId == MP4_INVALID_TRACK_ID) {
  343. m_odTrackId = pTrackIdProperty->GetValue();
  344. } else {
  345. VERBOSE_READ(GetVerbosity(),
  346. printf("Warning: multiple OD tracks presentn"));
  347. }
  348. }
  349. } else {
  350. m_trakIds.Add(0);
  351. }
  352. trackIndex++;
  353. }
  354. }
  355. void MP4File::CacheProperties()
  356. {
  357. FindIntegerProperty("moov.mvhd.modificationTime", 
  358. (MP4Property**)&m_pModificationProperty);
  359. FindIntegerProperty("moov.mvhd.timeScale", 
  360. (MP4Property**)&m_pTimeScaleProperty);
  361. FindIntegerProperty("moov.mvhd.duration", 
  362. (MP4Property**)&m_pDurationProperty);
  363. }
  364. void MP4File::BeginWrite()
  365. {
  366. m_pRootAtom->BeginWrite();
  367. }
  368. void MP4File::FinishWrite()
  369. {
  370. // for all tracks, flush chunking buffers
  371. for (u_int32_t i = 0; i < m_pTracks.Size(); i++) {
  372. ASSERT(m_pTracks[i]);
  373. m_pTracks[i]->FinishWrite();
  374. }
  375. // ask root atom to write
  376. m_pRootAtom->FinishWrite();
  377. // check if file shrunk, e.g. we deleted a track
  378. if (GetSize() < m_orgFileSize) {
  379. // just use a free atom to mark unused space
  380. // MP4Optimize() should be used to clean up this space
  381. MP4Atom* pFreeAtom = MP4Atom::CreateAtom("free");
  382. ASSERT(pFreeAtom);
  383. pFreeAtom->SetFile(this);
  384. pFreeAtom->SetSize(MAX(m_orgFileSize - (m_fileSize + 8), 0));
  385. pFreeAtom->Write();
  386. delete pFreeAtom;
  387. }
  388. }
  389. MP4Duration MP4File::UpdateDuration(MP4Duration duration)
  390. {
  391. MP4Duration currentDuration = GetDuration();
  392. if (duration > currentDuration) {
  393. SetDuration(duration);
  394. return duration;
  395. }
  396. return currentDuration;
  397. }
  398. void MP4File::Dump(FILE* pDumpFile, bool dumpImplicits)
  399. {
  400. if (pDumpFile == NULL) {
  401. pDumpFile = stdout;
  402. }
  403. fprintf(pDumpFile, "Dumping %s meta-information...n", m_fileName);
  404. m_pRootAtom->Dump(pDumpFile, 0, dumpImplicits);
  405. }
  406. void MP4File::Close()
  407. {
  408. if (m_mode == 'w') {
  409. SetIntegerProperty("moov.mvhd.modificationTime", 
  410. MP4GetAbsTimestamp());
  411. FinishWrite();
  412. }
  413. fclose(m_pFile);
  414. m_pFile = NULL;
  415. }
  416. const char* MP4File::TempFileName()
  417. {
  418. // there are so many attempts in libc to get this right
  419. // that for portablity reasons, it's best just to roll our own
  420. #ifndef _WIN32
  421. static char tempFileName[64];
  422. u_int32_t i;
  423. for (i = getpid(); i < 0xFFFFFFFF; i++) {
  424. sprintf(tempFileName, "./tmp%u.mp4", i);
  425. if (access(tempFileName, F_OK) != 0) {
  426. break;
  427. }
  428. }
  429. if (i == 0xFFFFFFFF) {
  430. throw new MP4Error("can't create temporary file", "TempFileName");
  431. }
  432. #else
  433. static char tempFileName[MAX_PATH + 3];
  434. GetTempFileName(".", // dir. for temp. files 
  435. "mp4",                // temp. filename prefix 
  436. 0,                    // create unique name 
  437. tempFileName);        // buffer for name 
  438. #endif
  439. return tempFileName;
  440. }
  441. void MP4File::Rename(const char* oldFileName, const char* newFileName)
  442. {
  443. int rc;
  444. #ifdef _WIN32
  445. rc = remove(newFileName);
  446. if (rc == 0) {
  447. rc = rename(oldFileName, newFileName);
  448. }
  449. #else
  450. rc = rename(oldFileName, newFileName);
  451. #endif
  452. if (rc != 0) {
  453. throw new MP4Error(errno, "can't overwrite existing file", "Rename");
  454. }
  455. }
  456. void MP4File::ProtectWriteOperation(char* where)
  457. {
  458. if (m_mode == 'r') {
  459. throw new MP4Error("operation not permitted in read mode", where);
  460. }
  461. }
  462. MP4Track* MP4File::GetTrack(MP4TrackId trackId)
  463. {
  464. return m_pTracks[FindTrackIndex(trackId)];
  465. }
  466. MP4Atom* MP4File::FindAtom(const char* name)
  467. {
  468. MP4Atom* pAtom = NULL;
  469. if (!name || !strcmp(name, "")) {
  470. pAtom = m_pRootAtom;
  471. } else {
  472. pAtom = m_pRootAtom->FindAtom(name);
  473. }
  474. return pAtom;
  475. }
  476. MP4Atom* MP4File::AddChildAtom(
  477. const char* parentName, 
  478. const char* childName)
  479. {
  480. return AddChildAtom(FindAtom(parentName), childName);
  481. }
  482. MP4Atom* MP4File::AddChildAtom(
  483. MP4Atom* pParentAtom, 
  484. const char* childName)
  485. {
  486. return InsertChildAtom(pParentAtom, childName, 
  487. pParentAtom->GetNumberOfChildAtoms());
  488. }
  489. MP4Atom* MP4File::InsertChildAtom(
  490. const char* parentName, 
  491. const char* childName, 
  492. u_int32_t index)
  493. {
  494. return InsertChildAtom(FindAtom(parentName), childName, index); 
  495. }
  496. MP4Atom* MP4File::InsertChildAtom(
  497. MP4Atom* pParentAtom, 
  498. const char* childName, 
  499. u_int32_t index)
  500. {
  501. MP4Atom* pChildAtom = MP4Atom::CreateAtom(childName);
  502. ASSERT(pParentAtom);
  503. pParentAtom->InsertChildAtom(pChildAtom, index);
  504. pChildAtom->Generate();
  505. return pChildAtom;
  506. }
  507. MP4Atom* MP4File::AddDescendantAtoms(
  508. const char* ancestorName, 
  509. const char* descendantNames)
  510. {
  511. return AddDescendantAtoms(FindAtom(ancestorName), descendantNames);
  512. }
  513. MP4Atom* MP4File::AddDescendantAtoms(
  514. MP4Atom* pAncestorAtom, const char* descendantNames)
  515. {
  516. ASSERT(pAncestorAtom);
  517. MP4Atom* pParentAtom = pAncestorAtom;
  518. MP4Atom* pChildAtom = NULL;
  519. while (true) {
  520. char* childName = MP4NameFirst(descendantNames);
  521. if (childName == NULL) {
  522. break;
  523. }
  524. descendantNames = MP4NameAfterFirst(descendantNames);
  525. pChildAtom = pParentAtom->FindChildAtom(childName);
  526. if (pChildAtom == NULL) {
  527. pChildAtom = AddChildAtom(pParentAtom, childName);
  528. }
  529. pParentAtom = pChildAtom;
  530. MP4Free(childName);
  531. }
  532. return pChildAtom;
  533. }
  534. bool MP4File::FindProperty(const char* name, 
  535. MP4Property** ppProperty, u_int32_t* pIndex)
  536. {
  537. if (pIndex) {
  538. *pIndex = 0; // set the default answer for index
  539. }
  540. return m_pRootAtom->FindProperty(name, ppProperty, pIndex);
  541. }
  542. void MP4File::FindIntegerProperty(const char* name, 
  543. MP4Property** ppProperty, u_int32_t* pIndex)
  544. {
  545. if (!FindProperty(name, ppProperty, pIndex)) {
  546. throw new MP4Error("no such property - %s", "MP4File::FindIntegerProperty", name);
  547. }
  548. switch ((*ppProperty)->GetType()) {
  549. case Integer8Property:
  550. case Integer16Property:
  551. case Integer24Property:
  552. case Integer32Property:
  553. case Integer64Property:
  554. break;
  555. default:
  556.   throw new MP4Error("type mismatch - property %s type %d", "MP4File::FindIntegerProperty", name, (*ppProperty)->GetType());
  557. }
  558. }
  559. u_int64_t MP4File::GetIntegerProperty(const char* name)
  560. {
  561. MP4Property* pProperty;
  562. u_int32_t index;
  563. FindIntegerProperty(name, &pProperty, &index);
  564. return ((MP4IntegerProperty*)pProperty)->GetValue(index);
  565. }
  566. void MP4File::SetIntegerProperty(const char* name, u_int64_t value)
  567. {
  568. ProtectWriteOperation("SetIntegerProperty");
  569. MP4Property* pProperty = NULL;
  570. u_int32_t index = 0;
  571. FindIntegerProperty(name, &pProperty, &index);
  572. ((MP4IntegerProperty*)pProperty)->SetValue(value, index);
  573. }
  574. void MP4File::FindFloatProperty(const char* name, 
  575. MP4Property** ppProperty, u_int32_t* pIndex)
  576. {
  577. if (!FindProperty(name, ppProperty, pIndex)) {
  578. throw new MP4Error("no such property - %s", "MP4File::FindFloatProperty", name);
  579. }
  580. if ((*ppProperty)->GetType() != Float32Property) {
  581. throw new MP4Error("type mismatch - property %s type %d", 
  582.    "MP4File::FindFloatProperty",
  583.    name, 
  584.    (*ppProperty)->GetType());
  585. }
  586. }
  587. float MP4File::GetFloatProperty(const char* name)
  588. {
  589. MP4Property* pProperty;
  590. u_int32_t index;
  591. FindFloatProperty(name, &pProperty, &index);
  592. return ((MP4Float32Property*)pProperty)->GetValue(index);
  593. }
  594. void MP4File::SetFloatProperty(const char* name, float value)
  595. {
  596. ProtectWriteOperation("SetFloatProperty");
  597. MP4Property* pProperty;
  598. u_int32_t index;
  599. FindFloatProperty(name, &pProperty, &index);
  600. ((MP4Float32Property*)pProperty)->SetValue(value, index);
  601. }
  602. void MP4File::FindStringProperty(const char* name, 
  603. MP4Property** ppProperty, u_int32_t* pIndex)
  604. {
  605. if (!FindProperty(name, ppProperty, pIndex)) {
  606. throw new MP4Error("no such property - %s", "MP4File::FindStringProperty", name);
  607. }
  608. if ((*ppProperty)->GetType() != StringProperty) {
  609. throw new MP4Error("type mismatch - property %s type %d", "MP4File::FindStringProperty",
  610.    name, (*ppProperty)->GetType());
  611. }
  612. }
  613. const char* MP4File::GetStringProperty(const char* name)
  614. {
  615. MP4Property* pProperty;
  616. u_int32_t index;
  617. FindStringProperty(name, &pProperty, &index);
  618. return ((MP4StringProperty*)pProperty)->GetValue(index);
  619. }
  620. void MP4File::SetStringProperty(const char* name, const char* value)
  621. {
  622. ProtectWriteOperation("SetStringProperty");
  623. MP4Property* pProperty;
  624. u_int32_t index;
  625. FindStringProperty(name, &pProperty, &index);
  626. ((MP4StringProperty*)pProperty)->SetValue(value, index);
  627. }
  628. void MP4File::FindBytesProperty(const char* name, 
  629. MP4Property** ppProperty, u_int32_t* pIndex)
  630. {
  631. if (!FindProperty(name, ppProperty, pIndex)) {
  632. throw new MP4Error("no such property %s", "MP4File::FindBytesProperty", name);
  633. }
  634. if ((*ppProperty)->GetType() != BytesProperty) {
  635. throw new MP4Error("type mismatch - property %s - type %d", "MP4File::FindBytesProperty", name, (*ppProperty)->GetType());
  636. }
  637. }
  638. void MP4File::GetBytesProperty(const char* name, 
  639. u_int8_t** ppValue, u_int32_t* pValueSize)
  640. {
  641. MP4Property* pProperty;
  642. u_int32_t index;
  643. FindBytesProperty(name, &pProperty, &index);
  644. ((MP4BytesProperty*)pProperty)->GetValue(ppValue, pValueSize, index);
  645. }
  646. void MP4File::SetBytesProperty(const char* name, 
  647. const u_int8_t* pValue, u_int32_t valueSize)
  648. {
  649. ProtectWriteOperation("SetBytesProperty");
  650. MP4Property* pProperty;
  651. u_int32_t index;
  652. FindBytesProperty(name, &pProperty, &index);
  653. ((MP4BytesProperty*)pProperty)->SetValue(pValue, valueSize, index);
  654. }
  655. // track functions
  656. MP4TrackId MP4File::AddTrack(const char* type, u_int32_t timeScale)
  657. {
  658. ProtectWriteOperation("AddTrack");
  659. // create and add new trak atom
  660. MP4Atom* pTrakAtom = AddChildAtom("moov", "trak");
  661. // allocate a new track id
  662. MP4TrackId trackId = AllocTrackId();
  663. m_trakIds.Add(trackId);
  664. // set track id
  665. MP4Integer32Property* pInteger32Property = NULL;
  666. pTrakAtom->FindProperty(
  667. "trak.tkhd.trackId", (MP4Property**)&pInteger32Property);
  668. ASSERT(pInteger32Property);
  669. pInteger32Property->SetValue(trackId);
  670. // set track type
  671. const char* normType = MP4Track::NormalizeTrackType(type);
  672. // sanity check for user defined types
  673. if (strlen(normType) > 4) {
  674. VERBOSE_WARNING(m_verbosity, 
  675. printf("AddTrack: type truncated to four charactersn"));
  676. // StringProperty::SetValue() will do the actual truncation
  677. }
  678. MP4StringProperty* pStringProperty = NULL;
  679. pTrakAtom->FindProperty(
  680. "trak.mdia.hdlr.handlerType", (MP4Property**)&pStringProperty);
  681. ASSERT(pStringProperty);
  682. pStringProperty->SetValue(normType);
  683. // set track time scale
  684. pInteger32Property = NULL;
  685. pTrakAtom->FindProperty(
  686. "trak.mdia.mdhd.timeScale", (MP4Property**)&pInteger32Property);
  687. ASSERT(pInteger32Property);
  688. pInteger32Property->SetValue(timeScale ? timeScale : 1000);
  689. // now have enough to create MP4Track object
  690. MP4Track* pTrack = NULL;
  691. if (!strcmp(normType, MP4_HINT_TRACK_TYPE)) {
  692. pTrack = new MP4RtpHintTrack(this, pTrakAtom);
  693. } else {
  694. pTrack = new MP4Track(this, pTrakAtom);
  695. }
  696. m_pTracks.Add(pTrack);
  697. // mark non-hint tracks as enabled
  698. if (strcmp(normType, MP4_HINT_TRACK_TYPE)) {
  699. SetTrackIntegerProperty(trackId, "tkhd.flags", 1);
  700. }
  701. // mark track as contained in this file
  702. // LATER will provide option for external data references
  703. AddDataReference(trackId, NULL);
  704. return trackId;
  705. }
  706. void MP4File::AddTrackToIod(MP4TrackId trackId)
  707. {
  708. MP4DescriptorProperty* pDescriptorProperty = NULL;
  709. m_pRootAtom->FindProperty("moov.iods.esIds", 
  710. (MP4Property**)&pDescriptorProperty);
  711. ASSERT(pDescriptorProperty);
  712. MP4Descriptor* pDescriptor = 
  713. pDescriptorProperty->AddDescriptor(MP4ESIDIncDescrTag);
  714. ASSERT(pDescriptor);
  715. MP4Integer32Property* pIdProperty = NULL;
  716. pDescriptor->FindProperty("id", 
  717. (MP4Property**)&pIdProperty);
  718. ASSERT(pIdProperty);
  719. pIdProperty->SetValue(trackId);
  720. }
  721. void MP4File::RemoveTrackFromIod(MP4TrackId trackId)
  722. {
  723. MP4DescriptorProperty* pDescriptorProperty = NULL;
  724. m_pRootAtom->FindProperty("moov.iods.esIds",
  725. (MP4Property**)&pDescriptorProperty);
  726. ASSERT(pDescriptorProperty);
  727. for (u_int32_t i = 0; i < pDescriptorProperty->GetCount(); i++) {
  728. static char name[32];
  729. snprintf(name, sizeof(name), "esIds[%u].id", i);
  730. MP4Integer32Property* pIdProperty = NULL;
  731. pDescriptorProperty->FindProperty(name, 
  732. (MP4Property**)&pIdProperty);
  733. ASSERT(pIdProperty);
  734. if (pIdProperty->GetValue() == trackId) {
  735. pDescriptorProperty->DeleteDescriptor(i);
  736. break;
  737. }
  738. }
  739. }
  740. void MP4File::AddTrackToOd(MP4TrackId trackId)
  741. {
  742. if (!m_odTrackId) {
  743. return;
  744. }
  745. AddTrackReference(MakeTrackName(m_odTrackId, "tref.mpod"), trackId);
  746. }
  747. void MP4File::RemoveTrackFromOd(MP4TrackId trackId)
  748. {
  749. if (!m_odTrackId) {
  750. return;
  751. }
  752. RemoveTrackReference(MakeTrackName(m_odTrackId, "tref.mpod"), trackId);
  753. }
  754. void MP4File::GetTrackReferenceProperties(const char* trefName,
  755. MP4Property** ppCountProperty, MP4Property** ppTrackIdProperty)
  756. {
  757. char propName[1024];
  758. snprintf(propName, sizeof(propName), "%s.%s", trefName, "entryCount");
  759. m_pRootAtom->FindProperty(propName, ppCountProperty);
  760. ASSERT(*ppCountProperty);
  761. snprintf(propName, sizeof(propName), "%s.%s", trefName, "entries.trackId");
  762. m_pRootAtom->FindProperty(propName, ppTrackIdProperty);
  763. ASSERT(*ppTrackIdProperty);
  764. }
  765. void MP4File::AddTrackReference(const char* trefName, MP4TrackId refTrackId)
  766. {
  767. MP4Integer32Property* pCountProperty = NULL;
  768. MP4Integer32Property* pTrackIdProperty = NULL;
  769. GetTrackReferenceProperties(trefName,
  770. (MP4Property**)&pCountProperty, 
  771. (MP4Property**)&pTrackIdProperty);
  772. pTrackIdProperty->AddValue(refTrackId);
  773. pCountProperty->IncrementValue();
  774. }
  775. u_int32_t MP4File::FindTrackReference(const char* trefName, 
  776. MP4TrackId refTrackId)
  777. {
  778. MP4Integer32Property* pCountProperty = NULL;
  779. MP4Integer32Property* pTrackIdProperty = NULL;
  780. GetTrackReferenceProperties(trefName, 
  781. (MP4Property**)&pCountProperty, 
  782. (MP4Property**)&pTrackIdProperty);
  783. for (u_int32_t i = 0; i < pCountProperty->GetValue(); i++) {
  784. if (refTrackId == pTrackIdProperty->GetValue(i)) {
  785. return i + 1; // N.B. 1 not 0 based index
  786. }
  787. }
  788. return 0;
  789. }
  790. void MP4File::RemoveTrackReference(const char* trefName, MP4TrackId refTrackId)
  791. {
  792. MP4Integer32Property* pCountProperty = NULL;
  793. MP4Integer32Property* pTrackIdProperty = NULL;
  794. GetTrackReferenceProperties(trefName,
  795. (MP4Property**)&pCountProperty, 
  796. (MP4Property**)&pTrackIdProperty);
  797. for (u_int32_t i = 0; i < pCountProperty->GetValue(); i++) {
  798. if (refTrackId == pTrackIdProperty->GetValue(i)) {
  799. pTrackIdProperty->DeleteValue(i);
  800. pCountProperty->IncrementValue(-1);
  801. }
  802. }
  803. }
  804. void MP4File::AddDataReference(MP4TrackId trackId, const char* url)
  805. {
  806. MP4Atom* pDrefAtom = 
  807. FindAtom(MakeTrackName(trackId, "mdia.minf.dinf.dref"));
  808. ASSERT(pDrefAtom);
  809. MP4Integer32Property* pCountProperty = NULL;
  810. pDrefAtom->FindProperty("dref.entryCount", 
  811. (MP4Property**)&pCountProperty);
  812. ASSERT(pCountProperty);
  813. pCountProperty->IncrementValue();
  814. MP4Atom* pUrlAtom = AddChildAtom(pDrefAtom, "url ");
  815. if (url && url[0] != '') {
  816. pUrlAtom->SetFlags(pUrlAtom->GetFlags() & 0xFFFFFE);
  817. MP4StringProperty* pUrlProperty = NULL;
  818. pUrlAtom->FindProperty("url .location",
  819. (MP4Property**)&pUrlProperty);
  820. ASSERT(pUrlProperty);
  821. pUrlProperty->SetValue(url);
  822. } else {
  823. pUrlAtom->SetFlags(pUrlAtom->GetFlags() | 1);
  824. }
  825. }
  826. MP4TrackId MP4File::AddSystemsTrack(const char* type)
  827. {
  828. const char* normType = MP4Track::NormalizeTrackType(type); 
  829. // TBD if user type, fix name to four chars, and warn
  830. MP4TrackId trackId = AddTrack(type, MP4_MSECS_TIME_SCALE);
  831. InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "nmhd", 0);
  832. AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "mp4s");
  833. // stsd is a unique beast in that it has a count of the number 
  834. // of child atoms that needs to be incremented after we add the mp4s atom
  835. MP4Integer32Property* pStsdCountProperty;
  836. FindIntegerProperty(
  837. MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
  838. (MP4Property**)&pStsdCountProperty);
  839. pStsdCountProperty->IncrementValue();
  840. SetTrackIntegerProperty(trackId, 
  841. "mdia.minf.stbl.stsd.mp4s.esds.ESID", trackId);
  842. SetTrackIntegerProperty(trackId, 
  843. "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.objectTypeId", 
  844. MP4SystemsV1ObjectType);
  845. SetTrackIntegerProperty(trackId, 
  846. "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.streamType", 
  847. ConvertTrackTypeToStreamType(normType));
  848. return trackId;
  849. }
  850. MP4TrackId MP4File::AddODTrack()
  851. {
  852. // until a demonstrated need emerges
  853. // we limit ourselves to one object description track
  854. if (m_odTrackId != MP4_INVALID_TRACK_ID) {
  855. throw new MP4Error("object description track already exists",
  856. "AddObjectDescriptionTrack");
  857. }
  858. m_odTrackId = AddSystemsTrack(MP4_OD_TRACK_TYPE);
  859. AddTrackToIod(m_odTrackId);
  860. AddDescendantAtoms(MakeTrackName(m_odTrackId, NULL), "tref.mpod");
  861. return m_odTrackId;
  862. }
  863. MP4TrackId MP4File::AddSceneTrack()
  864. {
  865. MP4TrackId trackId = AddSystemsTrack(MP4_SCENE_TRACK_TYPE);
  866. AddTrackToIod(trackId);
  867. AddTrackToOd(trackId);
  868. return trackId;
  869. }
  870. MP4TrackId MP4File::AddAudioTrack(
  871. u_int32_t timeScale, 
  872. MP4Duration sampleDuration, 
  873. u_int8_t audioType)
  874. {
  875. MP4TrackId trackId = AddTrack(MP4_AUDIO_TRACK_TYPE, timeScale);
  876. AddTrackToOd(trackId);
  877. SetTrackFloatProperty(trackId, "tkhd.volume", 1.0);
  878. InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "smhd", 0);
  879. AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "mp4a");
  880. // stsd is a unique beast in that it has a count of the number 
  881. // of child atoms that needs to be incremented after we add the mp4a atom
  882. MP4Integer32Property* pStsdCountProperty;
  883. FindIntegerProperty(
  884. MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
  885. (MP4Property**)&pStsdCountProperty);
  886. pStsdCountProperty->IncrementValue();
  887. SetTrackIntegerProperty(trackId, 
  888. "mdia.minf.stbl.stsd.mp4a.timeScale", timeScale);
  889. SetTrackIntegerProperty(trackId, 
  890. "mdia.minf.stbl.stsd.mp4a.esds.ESID", trackId);
  891. SetTrackIntegerProperty(trackId, 
  892. "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.objectTypeId", 
  893. audioType);
  894. SetTrackIntegerProperty(trackId, 
  895. "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.streamType", 
  896. MP4AudioStreamType);
  897. m_pTracks[FindTrackIndex(trackId)]->
  898. SetFixedSampleDuration(sampleDuration);
  899. return trackId;
  900. }
  901. MP4TrackId MP4File::AddVideoTrack(
  902. u_int32_t timeScale, 
  903. MP4Duration sampleDuration, 
  904. u_int16_t width, 
  905. u_int16_t height, 
  906. u_int8_t videoType)
  907. {
  908. MP4TrackId trackId = AddTrack(MP4_VIDEO_TRACK_TYPE, timeScale);
  909. AddTrackToOd(trackId);
  910. SetTrackFloatProperty(trackId, "tkhd.width", width);
  911. SetTrackFloatProperty(trackId, "tkhd.height", height);
  912. InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "vmhd", 0);
  913. AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "mp4v");
  914. // stsd is a unique beast in that it has a count of the number 
  915. // of child atoms that needs to be incremented after we add the mp4v atom
  916. MP4Integer32Property* pStsdCountProperty;
  917. FindIntegerProperty(
  918. MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
  919. (MP4Property**)&pStsdCountProperty);
  920. pStsdCountProperty->IncrementValue();
  921. SetTrackIntegerProperty(trackId, 
  922. "mdia.minf.stbl.stsd.mp4v.width", width);
  923. SetTrackIntegerProperty(trackId, 
  924. "mdia.minf.stbl.stsd.mp4v.height", height);
  925. SetTrackIntegerProperty(trackId, 
  926. "mdia.minf.stbl.stsd.mp4v.esds.ESID", trackId);
  927. SetTrackIntegerProperty(trackId, 
  928. "mdia.minf.stbl.stsd.mp4v.esds.decConfigDescr.objectTypeId", 
  929. videoType);
  930. SetTrackIntegerProperty(trackId, 
  931. "mdia.minf.stbl.stsd.mp4v.esds.decConfigDescr.streamType", 
  932. MP4VisualStreamType);
  933. SetTrackIntegerProperty(trackId, 
  934. "mdia.minf.stbl.stsz.sampleSize", sampleDuration);
  935. m_pTracks[FindTrackIndex(trackId)]->
  936. SetFixedSampleDuration(sampleDuration);
  937. return trackId;
  938. }
  939. MP4TrackId MP4File::AddHintTrack(MP4TrackId refTrackId)
  940. {
  941. // validate reference track id
  942. FindTrackIndex(refTrackId);
  943. MP4TrackId trackId = 
  944. AddTrack(MP4_HINT_TRACK_TYPE, GetTrackTimeScale(refTrackId));
  945. InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "hmhd", 0);
  946. AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "rtp ");
  947. // stsd is a unique beast in that it has a count of the number 
  948. // of child atoms that needs to be incremented after we add the rtp atom
  949. MP4Integer32Property* pStsdCountProperty;
  950. FindIntegerProperty(
  951. MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
  952. (MP4Property**)&pStsdCountProperty);
  953. pStsdCountProperty->IncrementValue();
  954. SetTrackIntegerProperty(trackId, 
  955. "mdia.minf.stbl.stsd.rtp .tims.timeScale", 
  956. GetTrackTimeScale(trackId));
  957. AddDescendantAtoms(MakeTrackName(trackId, NULL), "tref.hint");
  958. AddTrackReference(MakeTrackName(trackId, "tref.hint"), refTrackId);
  959. AddDescendantAtoms(MakeTrackName(trackId, NULL), "udta.hnti.sdp ");
  960. AddDescendantAtoms(MakeTrackName(trackId, NULL), "udta.hinf");
  961. return trackId;
  962. }
  963. void MP4File::DeleteTrack(MP4TrackId trackId)
  964. {
  965. ProtectWriteOperation("MP4DeleteTrack");
  966. u_int32_t trakIndex = FindTrakAtomIndex(trackId);
  967. u_int16_t trackIndex = FindTrackIndex(trackId);
  968. MP4Track* pTrack = m_pTracks[trackIndex];
  969. MP4Atom* pTrakAtom = pTrack->GetTrakAtom();
  970. ASSERT(pTrakAtom);
  971. MP4Atom* pMoovAtom = FindAtom("moov");
  972. ASSERT(pMoovAtom);
  973. RemoveTrackFromIod(trackId);
  974. RemoveTrackFromOd(trackId);
  975. if (trackId == m_odTrackId) {
  976. m_odTrackId = 0;
  977. }
  978. pMoovAtom->DeleteChildAtom(pTrakAtom);
  979. m_trakIds.Delete(trakIndex);
  980. m_pTracks.Delete(trackIndex);
  981. delete pTrack;
  982. delete pTrakAtom;
  983. }
  984. u_int32_t MP4File::GetNumberOfTracks(const char* type, u_int8_t subType)
  985. {
  986. if (type == NULL) {
  987. return m_pTracks.Size();
  988. u_int16_t typeSeen = 0;
  989. const char* normType = MP4Track::NormalizeTrackType(type);
  990. for (u_int16_t i = 0; i < m_pTracks.Size(); i++) {
  991. if (!strcmp(normType, m_pTracks[i]->GetType())) {
  992. if (subType) {
  993. if (normType == MP4_AUDIO_TRACK_TYPE) {
  994. if (subType != GetTrackAudioType(m_pTracks[i]->GetId())) {
  995. continue;
  996. }
  997. } else if (normType == MP4_VIDEO_TRACK_TYPE) {
  998. if (subType != GetTrackVideoType(m_pTracks[i]->GetId())) {
  999. continue;
  1000. }
  1001. // else unknown subtype, ignore it
  1002. }
  1003. typeSeen++;
  1004. }
  1005. }
  1006. return typeSeen;
  1007. }
  1008. MP4TrackId MP4File::AllocTrackId()
  1009. {
  1010. MP4TrackId trackId = 
  1011. GetIntegerProperty("moov.mvhd.nextTrackId");
  1012. if (trackId <= 0xFFFF) {
  1013. // check that nextTrackid is correct
  1014. try {
  1015. FindTrackIndex(trackId);
  1016. // ERROR, this trackId is in use
  1017. }
  1018. catch (MP4Error* e) {
  1019. // OK, this trackId is not in use, proceed
  1020. delete e;
  1021. SetIntegerProperty("moov.mvhd.nextTrackId", trackId + 1);
  1022. return trackId;
  1023. }
  1024. }
  1025. // we need to search for a track id
  1026. for (trackId = 1; trackId <= 0xFFFF; trackId++) {
  1027. try {
  1028. FindTrackIndex(trackId);
  1029. // KEEP LOOKING, this trackId is in use
  1030. }
  1031. catch (MP4Error* e) {
  1032. // OK, this trackId is not in use, proceed
  1033. delete e;
  1034. return trackId;
  1035. }
  1036. }
  1037. // extreme case where mp4 file has 2^16 tracks in it
  1038. throw new MP4Error("too many exising tracks", "AddTrack");
  1039. return MP4_INVALID_TRACK_ID; // to keep MSVC happy
  1040. }
  1041. MP4TrackId MP4File::FindTrackId(
  1042. u_int16_t trackIndex, const char* type, u_int8_t subType)
  1043. {
  1044. if (type == NULL) {
  1045. return m_pTracks[trackIndex]->GetId();
  1046. u_int16_t typeSeen = 0;
  1047. const char* normType = MP4Track::NormalizeTrackType(type);
  1048. for (u_int16_t i = 0; i < m_pTracks.Size(); i++) {
  1049. if (!strcmp(normType, m_pTracks[i]->GetType())) {
  1050. if (subType) {
  1051. if (normType == MP4_AUDIO_TRACK_TYPE) {
  1052. if (subType != GetTrackAudioType(m_pTracks[i]->GetId())) {
  1053. continue;
  1054. }
  1055. } else if (normType == MP4_VIDEO_TRACK_TYPE) {
  1056. if (subType != GetTrackVideoType(m_pTracks[i]->GetId())) {
  1057. continue;
  1058. }
  1059. // else unknown subtype, ignore it
  1060. }
  1061. if (trackIndex == typeSeen) {
  1062. return m_pTracks[i]->GetId();
  1063. }
  1064. typeSeen++;
  1065. }
  1066. }
  1067. throw new MP4Error("Track index doesn't exist - track %d type %s", 
  1068.    "FindTrackId", 
  1069.    trackIndex, type); 
  1070. return MP4_INVALID_TRACK_ID; // satisfy MS compiler
  1071. }
  1072. u_int16_t MP4File::FindTrackIndex(MP4TrackId trackId)
  1073. {
  1074. for (u_int16_t i = 0; i < m_pTracks.Size(); i++) {
  1075. if (m_pTracks[i]->GetId() == trackId) {
  1076. return i;
  1077. }
  1078. }
  1079. throw new MP4Error("Track id %d doesn't exist", "FindTrackIndex", trackId); 
  1080. return (u_int16_t)-1; // satisfy MS compiler
  1081. }
  1082. u_int16_t MP4File::FindTrakAtomIndex(MP4TrackId trackId)
  1083. {
  1084. if (trackId) {
  1085. for (u_int32_t i = 0; i < m_trakIds.Size(); i++) {
  1086. if (m_trakIds[i] == trackId) {
  1087. return i;
  1088. }
  1089. }
  1090. }
  1091. throw new MP4Error("Track id %d doesn't exist", "FindTrakAtomIndex",
  1092.    trackId); 
  1093. return (u_int16_t)-1; // satisfy MS compiler
  1094. }
  1095. u_int32_t MP4File::GetSampleSize(MP4TrackId trackId, MP4SampleId sampleId)
  1096. {
  1097. return m_pTracks[FindTrackIndex(trackId)]->GetSampleSize(sampleId);
  1098. }
  1099. u_int32_t MP4File::GetTrackMaxSampleSize(MP4TrackId trackId)
  1100. {
  1101. return m_pTracks[FindTrackIndex(trackId)]->GetMaxSampleSize();
  1102. }
  1103. MP4SampleId MP4File::GetSampleIdFromTime(MP4TrackId trackId, 
  1104. MP4Timestamp when, bool wantSyncSample)
  1105. {
  1106. return m_pTracks[FindTrackIndex(trackId)]->
  1107. GetSampleIdFromTime(when, wantSyncSample);
  1108. }
  1109. MP4Timestamp MP4File::GetSampleTime(
  1110. MP4TrackId trackId, MP4SampleId sampleId)
  1111. {
  1112. MP4Timestamp timestamp;
  1113. m_pTracks[FindTrackIndex(trackId)]->
  1114. GetSampleTimes(sampleId, &timestamp, NULL);
  1115. return timestamp;
  1116. }
  1117. MP4Duration MP4File::GetSampleDuration(
  1118. MP4TrackId trackId, MP4SampleId sampleId)
  1119. {
  1120. MP4Duration duration;
  1121. m_pTracks[FindTrackIndex(trackId)]->
  1122. GetSampleTimes(sampleId, NULL, &duration);
  1123. return duration; 
  1124. }
  1125. MP4Duration MP4File::GetSampleRenderingOffset(
  1126. MP4TrackId trackId, MP4SampleId sampleId)
  1127. {
  1128. return m_pTracks[FindTrackIndex(trackId)]->
  1129. GetSampleRenderingOffset(sampleId);
  1130. }
  1131. bool MP4File::GetSampleSync(MP4TrackId trackId, MP4SampleId sampleId)
  1132. {
  1133. return m_pTracks[FindTrackIndex(trackId)]->IsSyncSample(sampleId);
  1134. }
  1135. void MP4File::ReadSample(MP4TrackId trackId, MP4SampleId sampleId,
  1136. u_int8_t** ppBytes, u_int32_t* pNumBytes, 
  1137. MP4Timestamp* pStartTime, MP4Duration* pDuration,
  1138. MP4Duration* pRenderingOffset, bool* pIsSyncSample)
  1139. {
  1140. m_pTracks[FindTrackIndex(trackId)]->
  1141. ReadSample(sampleId, ppBytes, pNumBytes, 
  1142. pStartTime, pDuration, pRenderingOffset, pIsSyncSample);
  1143. }
  1144. void MP4File::WriteSample(MP4TrackId trackId,
  1145. u_int8_t* pBytes, u_int32_t numBytes,
  1146. MP4Duration duration, MP4Duration renderingOffset, bool isSyncSample)
  1147. {
  1148. ProtectWriteOperation("MP4WriteSample");
  1149. m_pTracks[FindTrackIndex(trackId)]->
  1150. WriteSample(pBytes, numBytes, duration, renderingOffset, isSyncSample);
  1151. m_pModificationProperty->SetValue(MP4GetAbsTimestamp());
  1152. }
  1153. void MP4File::SetSampleRenderingOffset(MP4TrackId trackId, 
  1154. MP4SampleId sampleId, MP4Duration renderingOffset)
  1155. {
  1156. ProtectWriteOperation("MP4SetSampleRenderingOffset");
  1157. m_pTracks[FindTrackIndex(trackId)]->
  1158. SetSampleRenderingOffset(sampleId, renderingOffset);
  1159. m_pModificationProperty->SetValue(MP4GetAbsTimestamp());
  1160. }
  1161. char* MP4File::MakeTrackName(MP4TrackId trackId, const char* name)
  1162. {
  1163. u_int16_t trakIndex = FindTrakAtomIndex(trackId);
  1164. static char trakName[1024];
  1165. if (name == NULL || name[0] == '') {
  1166. snprintf(trakName, sizeof(trakName), 
  1167. "moov.trak[%u]", trakIndex);
  1168. } else {
  1169. snprintf(trakName, sizeof(trakName), 
  1170. "moov.trak[%u].%s", trakIndex, name);
  1171. }
  1172. return trakName;
  1173. }
  1174. u_int64_t MP4File::GetTrackIntegerProperty(MP4TrackId trackId, const char* name)
  1175. {
  1176. return GetIntegerProperty(MakeTrackName(trackId, name));
  1177. }
  1178. void MP4File::SetTrackIntegerProperty(MP4TrackId trackId, const char* name, 
  1179. int64_t value)
  1180. {
  1181. SetIntegerProperty(MakeTrackName(trackId, name), value);
  1182. }
  1183. float MP4File::GetTrackFloatProperty(MP4TrackId trackId, const char* name)
  1184. {
  1185. return GetFloatProperty(MakeTrackName(trackId, name));
  1186. }
  1187. void MP4File::SetTrackFloatProperty(MP4TrackId trackId, const char* name, 
  1188. float value)
  1189. {
  1190. SetFloatProperty(MakeTrackName(trackId, name), value);
  1191. }
  1192. const char* MP4File::GetTrackStringProperty(MP4TrackId trackId, const char* name)
  1193. {
  1194. return GetStringProperty(MakeTrackName(trackId, name));
  1195. }
  1196. void MP4File::SetTrackStringProperty(MP4TrackId trackId, const char* name,
  1197. const char* value)
  1198. {
  1199. SetStringProperty(MakeTrackName(trackId, name), value);
  1200. }
  1201. void MP4File::GetTrackBytesProperty(MP4TrackId trackId, const char* name, 
  1202. u_int8_t** ppValue, u_int32_t* pValueSize)
  1203. {
  1204. GetBytesProperty(MakeTrackName(trackId, name), ppValue, pValueSize);
  1205. }
  1206. void MP4File::SetTrackBytesProperty(MP4TrackId trackId, const char* name, 
  1207. const u_int8_t* pValue, u_int32_t valueSize)
  1208. {
  1209. SetBytesProperty(MakeTrackName(trackId, name), pValue, valueSize);
  1210. }
  1211. // file level convenience functions
  1212. MP4Duration MP4File::GetDuration()
  1213. {
  1214. return m_pDurationProperty->GetValue();
  1215. }
  1216. void MP4File::SetDuration(MP4Duration value)
  1217. {
  1218. m_pDurationProperty->SetValue(value);
  1219. }
  1220. u_int32_t MP4File::GetTimeScale()
  1221. {
  1222. return m_pTimeScaleProperty->GetValue();
  1223. }
  1224. void MP4File::SetTimeScale(u_int32_t value)
  1225. {
  1226. if (value == 0) {
  1227. throw new MP4Error("invalid value", "SetTimeScale");
  1228. }
  1229. m_pTimeScaleProperty->SetValue(value);
  1230. }
  1231. u_int8_t MP4File::GetODProfileLevel()
  1232. {
  1233. return GetIntegerProperty("moov.iods.ODProfileLevelId");
  1234. }
  1235. void MP4File::SetODProfileLevel(u_int8_t value)
  1236. {
  1237. SetIntegerProperty("moov.iods.ODProfileLevelId", value);
  1238. }
  1239.  
  1240. u_int8_t MP4File::GetSceneProfileLevel()
  1241. {
  1242. return GetIntegerProperty("moov.iods.sceneProfileLevelId");
  1243. }
  1244. void MP4File::SetSceneProfileLevel(u_int8_t value)
  1245. {
  1246. SetIntegerProperty("moov.iods.sceneProfileLevelId", value);
  1247. }
  1248.  
  1249. u_int8_t MP4File::GetVideoProfileLevel()
  1250. {
  1251. return GetIntegerProperty("moov.iods.visualProfileLevelId");
  1252. }
  1253. void MP4File::SetVideoProfileLevel(u_int8_t value)
  1254. {
  1255. SetIntegerProperty("moov.iods.visualProfileLevelId", value);
  1256. }
  1257.  
  1258. u_int8_t MP4File::GetAudioProfileLevel()
  1259. {
  1260. return GetIntegerProperty("moov.iods.audioProfileLevelId");
  1261. }
  1262. void MP4File::SetAudioProfileLevel(u_int8_t value)
  1263. {
  1264. SetIntegerProperty("moov.iods.audioProfileLevelId", value);
  1265. }
  1266.  
  1267. u_int8_t MP4File::GetGraphicsProfileLevel()
  1268. {
  1269. return GetIntegerProperty("moov.iods.graphicsProfileLevelId");
  1270. }
  1271. void MP4File::SetGraphicsProfileLevel(u_int8_t value)
  1272. {
  1273. SetIntegerProperty("moov.iods.graphicsProfileLevelId", value);
  1274. }
  1275.  
  1276. const char* MP4File::GetSessionSdp()
  1277. {
  1278. return GetStringProperty("moov.udta.hnti.rtp .sdpText");
  1279. }
  1280. void MP4File::SetSessionSdp(const char* sdpString)
  1281. {
  1282. AddDescendantAtoms("moov", "udta.hnti.rtp ");
  1283. SetStringProperty("moov.udta.hnti.rtp .sdpText", sdpString);
  1284. }
  1285. void MP4File::AppendSessionSdp(const char* sdpFragment)
  1286. {
  1287. const char* oldSdpString = NULL;
  1288. try {
  1289. oldSdpString = GetSessionSdp();
  1290. }
  1291. catch (MP4Error* e) {
  1292. delete e;
  1293. SetSessionSdp(sdpFragment);
  1294. return;
  1295. }
  1296. char* newSdpString =
  1297. (char*)MP4Malloc(strlen(oldSdpString) + strlen(sdpFragment) + 1);
  1298. strcpy(newSdpString, oldSdpString);
  1299. strcat(newSdpString, sdpFragment);
  1300. SetSessionSdp(newSdpString);
  1301. MP4Free(newSdpString);
  1302. }
  1303. // track level convenience functions
  1304. MP4SampleId MP4File::GetTrackNumberOfSamples(MP4TrackId trackId)
  1305. {
  1306. return m_pTracks[FindTrackIndex(trackId)]->GetNumberOfSamples();
  1307. }
  1308. const char* MP4File::GetTrackType(MP4TrackId trackId)
  1309. {
  1310. return m_pTracks[FindTrackIndex(trackId)]->GetType();
  1311. }
  1312. u_int32_t MP4File::GetTrackTimeScale(MP4TrackId trackId)
  1313. {
  1314. return m_pTracks[FindTrackIndex(trackId)]->GetTimeScale();
  1315. }
  1316. void MP4File::SetTrackTimeScale(MP4TrackId trackId, u_int32_t value)
  1317. {
  1318. if (value == 0) {
  1319. throw new MP4Error("invalid value", "SetTrackTimeScale");
  1320. }
  1321. SetTrackIntegerProperty(trackId, "mdia.mdhd.timeScale", value);
  1322. }
  1323. MP4Duration MP4File::GetTrackDuration(MP4TrackId trackId)
  1324. {
  1325. return GetTrackIntegerProperty(trackId, "mdia.mdhd.duration");
  1326. }
  1327. u_int8_t MP4File::GetTrackAudioType(MP4TrackId trackId)
  1328. {
  1329. return GetTrackIntegerProperty(trackId, 
  1330. "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.objectTypeId");
  1331. }
  1332. u_int8_t MP4File::GetTrackAudioMpeg4Type(MP4TrackId trackId)
  1333. {
  1334. // verify that track is an MPEG-4 audio track 
  1335. if (GetTrackAudioType(trackId) != MP4_MPEG4_AUDIO_TYPE) {
  1336. return MP4_MPEG4_INVALID_AUDIO_TYPE;
  1337. }
  1338. u_int8_t* pEsConfig = NULL;
  1339. u_int32_t esConfigSize;
  1340. // The Mpeg4 audio type (AAC, CELP, HXVC, ...)
  1341. // is the first 5 bits of the ES configuration
  1342. GetTrackESConfiguration(trackId, &pEsConfig, &esConfigSize);
  1343. if (esConfigSize < 1) {
  1344. return MP4_MPEG4_INVALID_AUDIO_TYPE;
  1345. }
  1346. u_int8_t mpeg4Type = (pEsConfig[0] >> 3);
  1347. free(pEsConfig);
  1348. return mpeg4Type;
  1349. }
  1350. u_int8_t MP4File::GetTrackVideoType(MP4TrackId trackId)
  1351. {
  1352. return GetTrackIntegerProperty(trackId, 
  1353. "mdia.minf.stbl.stsd.mp4v.esds.decConfigDescr.objectTypeId");
  1354. }
  1355. MP4Duration MP4File::GetTrackFixedSampleDuration(MP4TrackId trackId)
  1356. {
  1357. return m_pTracks[FindTrackIndex(trackId)]->GetFixedSampleDuration();
  1358. }
  1359. float MP4File::GetTrackVideoFrameRate(MP4TrackId trackId)
  1360. {
  1361. MP4SampleId numSamples =
  1362. GetTrackNumberOfSamples(trackId);
  1363. #ifdef _WIN32
  1364. int64_t
  1365. #else
  1366. u_int64_t 
  1367. #endif
  1368. msDuration =
  1369. ConvertFromTrackDuration(trackId, 
  1370. GetTrackDuration(trackId), MP4_MSECS_TIME_SCALE);
  1371. if (msDuration == 0) {
  1372. return 0.0;
  1373. }
  1374. return ((double)numSamples / (double)msDuration) * MP4_MSECS_TIME_SCALE;
  1375. }
  1376. void MP4File::GetTrackESConfiguration(MP4TrackId trackId, 
  1377. u_int8_t** ppConfig, u_int32_t* pConfigSize)
  1378. {
  1379. GetTrackBytesProperty(trackId, 
  1380. "mdia.minf.stbl.stsd.*[0].esds.decConfigDescr.decSpecificInfo[0].info",
  1381. ppConfig, pConfigSize);
  1382. }
  1383. void MP4File::SetTrackESConfiguration(MP4TrackId trackId, 
  1384. const u_int8_t* pConfig, u_int32_t configSize)
  1385. {
  1386. // get a handle on the track decoder config descriptor 
  1387. MP4DescriptorProperty* pConfigDescrProperty = NULL;
  1388. FindProperty(MakeTrackName(trackId, 
  1389. "mdia.minf.stbl.stsd.*[0].esds.decConfigDescr.decSpecificInfo"),
  1390. (MP4Property**)&pConfigDescrProperty);
  1391. if (pConfigDescrProperty == NULL) {
  1392. // probably trackId refers to a hint track
  1393. throw new MP4Error("no such property", "MP4SetTrackESConfiguration");
  1394. }
  1395. // lookup the property to store the configuration
  1396. MP4BytesProperty* pInfoProperty = NULL;
  1397. pConfigDescrProperty->FindProperty("decSpecificInfo[0].info",
  1398. (MP4Property**)&pInfoProperty);
  1399. // configuration being set for the first time
  1400. if (pInfoProperty == NULL) {
  1401. // need to create a new descriptor to hold it
  1402. MP4Descriptor* pConfigDescr =
  1403. pConfigDescrProperty->AddDescriptor(MP4DecSpecificDescrTag);
  1404. pConfigDescr->Generate();
  1405. pConfigDescrProperty->FindProperty(
  1406. "decSpecificInfo[0].info",
  1407. (MP4Property**)&pInfoProperty);
  1408. ASSERT(pInfoProperty);
  1409. }
  1410. // set the value
  1411. pInfoProperty->SetValue(pConfig, configSize);
  1412. }
  1413. const char* MP4File::GetHintTrackSdp(MP4TrackId hintTrackId)
  1414. {
  1415. return GetTrackStringProperty(hintTrackId, "udta.hnti.sdp .sdpText");
  1416. }
  1417. void MP4File::SetHintTrackSdp(MP4TrackId hintTrackId, const char* sdpString)
  1418. {
  1419. MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
  1420. if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
  1421. throw new MP4Error("track is not a hint track", 
  1422. "MP4SetHintTrackSdp");
  1423. }
  1424. AddDescendantAtoms(
  1425. MakeTrackName(hintTrackId, NULL), "udta.hnti.sdp ");
  1426. SetTrackStringProperty(hintTrackId, "udta.hnti.sdp .sdpText", sdpString);
  1427. }
  1428. void MP4File::AppendHintTrackSdp(MP4TrackId hintTrackId, 
  1429. const char* sdpFragment)
  1430. {
  1431. const char* oldSdpString = NULL;
  1432. try {
  1433. oldSdpString = GetHintTrackSdp(hintTrackId);
  1434. }
  1435. catch (MP4Error* e) {
  1436. delete e;
  1437. SetHintTrackSdp(hintTrackId, sdpFragment);
  1438. return;
  1439. }
  1440. char* newSdpString =
  1441. (char*)MP4Malloc(strlen(oldSdpString) + strlen(sdpFragment) + 1);
  1442. strcpy(newSdpString, oldSdpString);
  1443. strcat(newSdpString, sdpFragment);
  1444. SetHintTrackSdp(hintTrackId, newSdpString);
  1445. MP4Free(newSdpString);
  1446. }
  1447. void MP4File::GetHintTrackRtpPayload(
  1448. MP4TrackId hintTrackId,
  1449. char** ppPayloadName,
  1450. u_int8_t* pPayloadNumber,
  1451. u_int16_t* pMaxPayloadSize)
  1452. {
  1453. MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
  1454. if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
  1455. throw new MP4Error("track is not a hint track", 
  1456. "MP4GetHintTrackRtpPayload");
  1457. }
  1458. ((MP4RtpHintTrack*)pTrack)->GetPayload(
  1459. ppPayloadName, pPayloadNumber, pMaxPayloadSize);
  1460. }
  1461. void MP4File::SetHintTrackRtpPayload(MP4TrackId hintTrackId,
  1462. const char* payloadName, u_int8_t* pPayloadNumber, u_int16_t maxPayloadSize)
  1463. {
  1464. MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
  1465. if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
  1466. throw new MP4Error("track is not a hint track", 
  1467. "MP4SetHintTrackRtpPayload");
  1468. }
  1469. u_int8_t payloadNumber;
  1470. if (pPayloadNumber && *pPayloadNumber != 0) {
  1471. payloadNumber = *pPayloadNumber;
  1472. } else {
  1473. payloadNumber = AllocRtpPayloadNumber();
  1474. if (pPayloadNumber) {
  1475. *pPayloadNumber = payloadNumber;
  1476. }
  1477. }
  1478. ((MP4RtpHintTrack*)pTrack)->SetPayload(
  1479. payloadName, payloadNumber, maxPayloadSize);
  1480. }
  1481. u_int8_t MP4File::AllocRtpPayloadNumber()
  1482. {
  1483. MP4Integer32Array usedPayloads;
  1484. u_int32_t i;
  1485. // collect rtp payload numbers in use by existing tracks
  1486. for (i = 0; i < m_pTracks.Size(); i++) {
  1487. MP4Atom* pTrakAtom = m_pTracks[i]->GetTrakAtom();
  1488. MP4Integer32Property* pPayloadProperty = NULL;
  1489. pTrakAtom->FindProperty("trak.udta.hinf.payt.payloadNumber",
  1490. (MP4Property**)&pPayloadProperty);
  1491. if (pPayloadProperty) {
  1492. usedPayloads.Add(pPayloadProperty->GetValue());
  1493. }
  1494. }
  1495. // search dynamic payload range for an available slot
  1496. u_int8_t payload;
  1497. for (payload = 96; payload < 128; payload++) {
  1498. for (i = 0; i < usedPayloads.Size(); i++) {
  1499. if (payload == usedPayloads[i]) {
  1500. break;
  1501. }
  1502. }
  1503. if (i == usedPayloads.Size()) {
  1504. break;
  1505. }
  1506. }
  1507. if (payload >= 128) {
  1508. throw new MP4Error("no more available rtp payload numbers",
  1509. "AllocRtpPayloadNumber");
  1510. }
  1511. return payload;
  1512. }
  1513. MP4TrackId MP4File::GetHintTrackReferenceTrackId(
  1514. MP4TrackId hintTrackId)
  1515. {
  1516. MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
  1517. if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
  1518. throw new MP4Error("track is not a hint track", 
  1519. "MP4GetHintTrackReferenceTrackId");
  1520. }
  1521. MP4Track* pRefTrack = ((MP4RtpHintTrack*)pTrack)->GetRefTrack();
  1522. if (pRefTrack == NULL) {
  1523. return MP4_INVALID_TRACK_ID;
  1524. }
  1525. return pRefTrack->GetId();
  1526. }
  1527. void MP4File::ReadRtpHint(
  1528. MP4TrackId hintTrackId,
  1529. MP4SampleId hintSampleId,
  1530. u_int16_t* pNumPackets)
  1531. {
  1532. MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
  1533. if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
  1534. throw new MP4Error("track is not a hint track", "MP4ReadRtpHint");
  1535. }
  1536. ((MP4RtpHintTrack*)pTrack)->
  1537. ReadHint(hintSampleId, pNumPackets);
  1538. }
  1539. u_int16_t MP4File::GetRtpHintNumberOfPackets(
  1540. MP4TrackId hintTrackId)
  1541. {
  1542. MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
  1543. if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
  1544. throw new MP4Error("track is not a hint track", 
  1545. "MP4GetRtpHintNumberOfPackets");
  1546. }
  1547. return ((MP4RtpHintTrack*)pTrack)->GetHintNumberOfPackets();
  1548. }
  1549. int8_t MP4File::GetRtpPacketBFrame(
  1550. MP4TrackId hintTrackId,
  1551. u_int16_t packetIndex)
  1552. {
  1553. MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
  1554. if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
  1555. throw new MP4Error("track is not a hint track", 
  1556. "MP4GetRtpHintBFrame");
  1557. }
  1558. return ((MP4RtpHintTrack*)pTrack)->GetPacketBFrame(packetIndex);
  1559. }
  1560. int32_t MP4File::GetRtpPacketTransmitOffset(
  1561. MP4TrackId hintTrackId,
  1562. u_int16_t packetIndex)
  1563. {
  1564. MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
  1565. if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
  1566. throw new MP4Error("track is not a hint track", 
  1567. "MP4GetRtpPacketTransmitOffset");
  1568. }
  1569. return ((MP4RtpHintTrack*)pTrack)->GetPacketTransmitOffset(packetIndex);
  1570. }
  1571. void MP4File::ReadRtpPacket(
  1572. MP4TrackId hintTrackId,
  1573. u_int16_t packetIndex,
  1574. u_int8_t** ppBytes, 
  1575. u_int32_t* pNumBytes,
  1576. u_int32_t ssrc,
  1577. bool includeHeader,
  1578. bool includePayload)
  1579. {
  1580. MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
  1581. if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
  1582. throw new MP4Error("track is not a hint track", "MP4ReadPacket");
  1583. }
  1584. ((MP4RtpHintTrack*)pTrack)->ReadPacket(
  1585. packetIndex, ppBytes, pNumBytes,
  1586. ssrc, includeHeader, includePayload);
  1587. }
  1588. MP4Timestamp MP4File::GetRtpTimestampStart(
  1589. MP4TrackId hintTrackId)
  1590. {
  1591. MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
  1592. if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
  1593. throw new MP4Error("track is not a hint track", 
  1594. "MP4GetRtpTimestampStart");
  1595. }
  1596. return ((MP4RtpHintTrack*)pTrack)->GetRtpTimestampStart();
  1597. }
  1598. void MP4File::SetRtpTimestampStart(
  1599. MP4TrackId hintTrackId,
  1600. MP4Timestamp rtpStart)
  1601. {
  1602. MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
  1603. if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
  1604. throw new MP4Error("track is not a hint track", 
  1605. "MP4SetRtpTimestampStart");
  1606. }
  1607. ((MP4RtpHintTrack*)pTrack)->SetRtpTimestampStart(rtpStart);
  1608. }
  1609. void MP4File::AddRtpHint(MP4TrackId hintTrackId, 
  1610. bool isBframe, u_int32_t timestampOffset)
  1611. {
  1612. ProtectWriteOperation("MP4AddRtpHint");
  1613. MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
  1614. if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
  1615. throw new MP4Error("track is not a hint track", "MP4AddRtpHint");
  1616. }
  1617. ((MP4RtpHintTrack*)pTrack)->AddHint(isBframe, timestampOffset);
  1618. }
  1619. void MP4File::AddRtpPacket(
  1620. MP4TrackId hintTrackId, bool setMbit, int32_t transmitOffset)
  1621. {
  1622. ProtectWriteOperation("MP4AddRtpPacket");
  1623. MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
  1624. if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
  1625. throw new MP4Error("track is not a hint track", "MP4AddRtpPacket");
  1626. }
  1627. ((MP4RtpHintTrack*)pTrack)->AddPacket(setMbit, transmitOffset);
  1628. }
  1629. void MP4File::AddRtpImmediateData(MP4TrackId hintTrackId, 
  1630. const u_int8_t* pBytes, u_int32_t numBytes)
  1631. {
  1632. ProtectWriteOperation("MP4AddRtpImmediateData");
  1633. MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
  1634. if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
  1635. throw new MP4Error("track is not a hint track", 
  1636. "MP4AddRtpImmediateData");
  1637. }
  1638. ((MP4RtpHintTrack*)pTrack)->AddImmediateData(pBytes, numBytes);
  1639. }
  1640. void MP4File::AddRtpSampleData(MP4TrackId hintTrackId, 
  1641. MP4SampleId sampleId, u_int32_t dataOffset, u_int32_t dataLength)
  1642. {
  1643. ProtectWriteOperation("MP4AddRtpSampleData");
  1644. MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
  1645. if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
  1646. throw new MP4Error("track is not a hint track", 
  1647. "MP4AddRtpSampleData");
  1648. }
  1649. ((MP4RtpHintTrack*)pTrack)->AddSampleData(
  1650. sampleId, dataOffset, dataLength);
  1651. }
  1652. void MP4File::AddRtpESConfigurationPacket(MP4TrackId hintTrackId)
  1653. {
  1654. ProtectWriteOperation("MP4AddRtpESConfigurationPacket");
  1655. MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
  1656. if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
  1657. throw new MP4Error("track is not a hint track", 
  1658. "MP4AddRtpESConfigurationPacket");
  1659. }
  1660. ((MP4RtpHintTrack*)pTrack)->AddESConfigurationPacket();
  1661. }
  1662. void MP4File::WriteRtpHint(MP4TrackId hintTrackId,
  1663. MP4Duration duration, bool isSyncSample)
  1664. {
  1665. ProtectWriteOperation("MP4WriteRtpHint");
  1666. MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
  1667. if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
  1668. throw new MP4Error("track is not a hint track", 
  1669. "MP4WriteRtpHint");
  1670. }
  1671. ((MP4RtpHintTrack*)pTrack)->WriteHint(duration, isSyncSample);
  1672. }
  1673. u_int64_t MP4File::ConvertFromMovieDuration(
  1674. MP4Duration duration,
  1675. u_int32_t timeScale)
  1676. {
  1677. return MP4ConvertTime((u_int64_t)duration, 
  1678. GetTimeScale(), timeScale);
  1679. }
  1680. u_int64_t MP4File::ConvertFromTrackTimestamp(
  1681. MP4TrackId trackId, 
  1682. MP4Timestamp timeStamp,
  1683. u_int32_t timeScale)
  1684. {
  1685. return MP4ConvertTime((u_int64_t)timeStamp, 
  1686. GetTrackTimeScale(trackId), timeScale);
  1687. }
  1688. MP4Timestamp MP4File::ConvertToTrackTimestamp(
  1689. MP4TrackId trackId, 
  1690. u_int64_t timeStamp,
  1691. u_int32_t timeScale)
  1692. {
  1693. return (MP4Timestamp)MP4ConvertTime(timeStamp, 
  1694. timeScale, GetTrackTimeScale(trackId));
  1695. }
  1696. u_int64_t MP4File::ConvertFromTrackDuration(
  1697. MP4TrackId trackId, 
  1698. MP4Duration duration,
  1699. u_int32_t timeScale)
  1700. {
  1701. return MP4ConvertTime((u_int64_t)duration, 
  1702. GetTrackTimeScale(trackId), timeScale);
  1703. }
  1704. MP4Duration MP4File::ConvertToTrackDuration(
  1705. MP4TrackId trackId, 
  1706. u_int64_t duration,
  1707. u_int32_t timeScale)
  1708. {
  1709. return (MP4Duration)MP4ConvertTime(duration, 
  1710. timeScale, GetTrackTimeScale(trackId));
  1711. }
  1712. u_int8_t MP4File::ConvertTrackTypeToStreamType(const char* trackType)
  1713. {
  1714. u_int8_t streamType;
  1715. if (!strcmp(trackType, MP4_OD_TRACK_TYPE)) {
  1716. streamType = MP4ObjectDescriptionStreamType;
  1717. } else if (!strcmp(trackType, MP4_SCENE_TRACK_TYPE)) {
  1718. streamType = MP4SceneDescriptionStreamType;
  1719. } else if (!strcmp(trackType, MP4_CLOCK_TRACK_TYPE)) {
  1720. streamType = MP4ClockReferenceStreamType;
  1721. } else if (!strcmp(trackType, MP4_MPEG7_TRACK_TYPE)) {
  1722. streamType = MP4Mpeg7StreamType;
  1723. } else if (!strcmp(trackType, MP4_OCI_TRACK_TYPE)) {
  1724. streamType = MP4OCIStreamType;
  1725. } else if (!strcmp(trackType, MP4_IPMP_TRACK_TYPE)) {
  1726. streamType = MP4IPMPStreamType;
  1727. } else if (!strcmp(trackType, MP4_MPEGJ_TRACK_TYPE)) {
  1728. streamType = MP4MPEGJStreamType;
  1729. } else {
  1730. streamType = MP4UserPrivateStreamType;
  1731. }
  1732. return streamType;
  1733. }
  1734. // edit list
  1735. char* MP4File::MakeTrackEditName(
  1736. MP4TrackId trackId,
  1737. MP4EditId editId,
  1738. const char* name)
  1739. {
  1740. char* trakName = MakeTrackName(trackId, NULL);
  1741. static char editName[1024];
  1742. snprintf(editName, sizeof(editName), 
  1743. "%s.edts.elst.entries[%u].%s", 
  1744. trakName, editId - 1, name);
  1745. return editName;
  1746. }
  1747. MP4EditId MP4File::AddTrackEdit(
  1748. MP4TrackId trackId,
  1749. MP4EditId editId)
  1750. {
  1751. ProtectWriteOperation("AddTrackEdit");
  1752. return m_pTracks[FindTrackIndex(trackId)]->AddEdit(editId);
  1753. }
  1754. void MP4File::DeleteTrackEdit(
  1755. MP4TrackId trackId,
  1756. MP4EditId editId)
  1757. {
  1758. ProtectWriteOperation("DeleteTrackEdit");
  1759. m_pTracks[FindTrackIndex(trackId)]->DeleteEdit(editId);
  1760. }
  1761. u_int32_t MP4File::GetTrackNumberOfEdits(
  1762. MP4TrackId trackId)
  1763. {
  1764. return GetTrackIntegerProperty(trackId, "edts.elst.entryCount");
  1765. }
  1766. MP4Duration MP4File::GetTrackEditTotalDuration(
  1767. MP4TrackId trackId,
  1768. MP4EditId editId)
  1769. {
  1770. return m_pTracks[FindTrackIndex(trackId)]->GetEditTotalDuration(editId);
  1771. }
  1772. MP4Timestamp MP4File::GetTrackEditStart(
  1773. MP4TrackId trackId,
  1774. MP4EditId editId)
  1775. {
  1776. return m_pTracks[FindTrackIndex(trackId)]->GetEditStart(editId);
  1777. }
  1778. MP4Timestamp MP4File::GetTrackEditMediaStart(
  1779. MP4TrackId trackId,
  1780. MP4EditId editId)
  1781. {
  1782. return GetIntegerProperty(
  1783. MakeTrackEditName(trackId, editId, "mediaTime"));
  1784. }
  1785. void MP4File::SetTrackEditMediaStart(
  1786. MP4TrackId trackId,
  1787. MP4EditId editId,
  1788. MP4Timestamp startTime)
  1789. {
  1790. SetIntegerProperty(
  1791. MakeTrackEditName(trackId, editId, "mediaTime"),
  1792. startTime);
  1793. }
  1794. MP4Duration MP4File::GetTrackEditDuration(
  1795. MP4TrackId trackId,
  1796. MP4EditId editId)
  1797. {
  1798. return GetIntegerProperty(
  1799. MakeTrackEditName(trackId, editId, "segmentDuration"));
  1800. }
  1801. void MP4File::SetTrackEditDuration(
  1802. MP4TrackId trackId,
  1803. MP4EditId editId,
  1804. MP4Duration duration)
  1805. {
  1806. SetIntegerProperty(
  1807. MakeTrackEditName(trackId, editId, "segmentDuration"),
  1808. duration);
  1809. }
  1810. bool MP4File::GetTrackEditDwell(
  1811. MP4TrackId trackId,
  1812. MP4EditId editId)
  1813. {
  1814. return (GetIntegerProperty(
  1815. MakeTrackEditName(trackId, editId, "mediaRate")) == 0);
  1816. }
  1817. void MP4File::SetTrackEditDwell(
  1818. MP4TrackId trackId,
  1819. MP4EditId editId,
  1820. bool dwell)
  1821. {
  1822. SetIntegerProperty(
  1823. MakeTrackEditName(trackId, editId, "mediaRate"),
  1824. (dwell ? 0 : 1));
  1825. }
  1826. MP4SampleId MP4File::GetSampleIdFromEditTime(
  1827. MP4TrackId trackId,
  1828. MP4Timestamp when,
  1829. MP4Timestamp* pStartTime,
  1830. MP4Duration* pDuration)
  1831. {
  1832. return m_pTracks[FindTrackIndex(trackId)]->GetSampleIdFromEditTime(
  1833. when, pStartTime, pDuration);
  1834. }