isma.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  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 - 2004. All Rights Reserved.
  17. *
  18. * 3GPP features implementation is based on 3GPP's TS26.234-v5.60,
  19. * and was contributed by Ximpo Group Ltd.
  20. *
  21. * Portions created by Ximpo Group Ltd. are
  22. * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved.
  23. *
  24. * Contributor(s):
  25. * Dave Mackie [email protected]
  26. * Alix Marchandise-Franquet [email protected]
  27. * Ximpo Group Ltd. [email protected]
  28. */
  29. #include "mp4common.h"
  30. static const u_int8_t BifsV2Config[3] = {
  31. 0x00, 0x00, 0x60 // IsCommandStream = 1, PixelMetric = 1
  32. };
  33. void MP4File::MakeIsmaCompliant(bool addIsmaComplianceSdp)
  34. {
  35. ProtectWriteOperation("MP4MakeIsmaCompliant");
  36. if (m_useIsma) {
  37. // already done
  38. return;
  39. }
  40. // find first audio and/or video tracks
  41. MP4TrackId audioTrackId = MP4_INVALID_TRACK_ID;
  42. try {
  43. audioTrackId = FindTrackId(0, MP4_AUDIO_TRACK_TYPE);
  44. }
  45. catch (MP4Error* e) {
  46. delete e;
  47. }
  48. MP4TrackId videoTrackId = MP4_INVALID_TRACK_ID;
  49. try {
  50. videoTrackId = FindTrackId(0, MP4_VIDEO_TRACK_TYPE);
  51. }
  52. catch (MP4Error* e) {
  53. delete e;
  54. }
  55. if (audioTrackId == MP4_INVALID_TRACK_ID &&
  56. videoTrackId == MP4_INVALID_TRACK_ID) return;
  57. const char *audio_media_data_name, *video_media_data_name;
  58. uint8_t videoProfile = 0xff;
  59. if (audioTrackId != MP4_INVALID_TRACK_ID) {
  60. audio_media_data_name = MP4GetTrackMediaDataName(this, audioTrackId);
  61. if (!(ATOMID(audio_media_data_name) == ATOMID("mp4a") ||
  62. ATOMID(audio_media_data_name) == ATOMID("enca"))) {
  63. VERBOSE_ERROR(m_verbosity,
  64. printf("MakeIsmaCompliant:can't make ISMA compliant when file contains an %s track\n", audio_media_data_name);
  65. );
  66. return;
  67. }
  68. }
  69. //
  70. // Note - might have to check for avc1 here...
  71. if (videoTrackId != MP4_INVALID_TRACK_ID) {
  72. video_media_data_name = MP4GetTrackMediaDataName(this, videoTrackId);
  73. if (!(ATOMID(video_media_data_name) == ATOMID("mp4v") ||
  74. ATOMID(video_media_data_name) == ATOMID("encv"))) {
  75. VERBOSE_ERROR(m_verbosity,
  76. printf("MakeIsmaCompliant:can't make ISMA compliant when file contains an %s track\n", video_media_data_name);
  77. );
  78. return;
  79. }
  80. uint32_t verb = GetVerbosity();
  81. SetVerbosity(verb & ~MP4_DETAILS_ERROR);
  82. videoProfile = MP4GetVideoProfileLevel(this, videoTrackId);
  83. SetVerbosity(verb);
  84. }
  85. m_useIsma = true;
  86. u_int64_t fileMsDuration = 0;
  87. fileMsDuration =
  88. ConvertFromMovieDuration(GetDuration(), MP4_MSECS_TIME_SCALE);
  89. // delete any existing OD track
  90. if (m_odTrackId != MP4_INVALID_TRACK_ID) {
  91. DeleteTrack(m_odTrackId);
  92. }
  93. if (m_pRootAtom->FindAtomMP4("moov.iods") == NULL) {
  94. (void)AddChildAtom("moov", "iods");
  95. }
  96. (void)AddODTrack();
  97. SetODProfileLevel(0xFF);
  98. if (audioTrackId != MP4_INVALID_TRACK_ID) {
  99. AddTrackToOd(audioTrackId);
  100. MP4SetAudioProfileLevel(this, 0xf);
  101. }
  102. if (videoTrackId != MP4_INVALID_TRACK_ID) {
  103. AddTrackToOd(videoTrackId);
  104. MP4SetVideoProfileLevel(this, videoProfile);
  105. }
  106. // delete any existing scene track
  107. MP4TrackId sceneTrackId = MP4_INVALID_TRACK_ID;
  108. try {
  109. sceneTrackId = FindTrackId(0, MP4_SCENE_TRACK_TYPE);
  110. }
  111. catch (MP4Error *e) {
  112. delete e;
  113. }
  114. if (sceneTrackId != MP4_INVALID_TRACK_ID) {
  115. DeleteTrack(sceneTrackId);
  116. }
  117. // add scene track
  118. sceneTrackId = AddSceneTrack();
  119. SetSceneProfileLevel(0xFF);
  120. SetGraphicsProfileLevel(0xFF);
  121. SetTrackIntegerProperty(sceneTrackId,
  122. "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.objectTypeId",
  123. MP4SystemsV2ObjectType);
  124. SetTrackESConfiguration(sceneTrackId,
  125. BifsV2Config, sizeof(BifsV2Config));
  126. u_int8_t* pBytes = NULL;
  127. u_int64_t numBytes = 0;
  128. // write OD Update Command
  129. CreateIsmaODUpdateCommandFromFileForFile(
  130. m_odTrackId,
  131. audioTrackId,
  132. videoTrackId,
  133. &pBytes,
  134. &numBytes);
  135. WriteSample(m_odTrackId, pBytes, numBytes, fileMsDuration);
  136. MP4Free(pBytes);
  137. pBytes = NULL;
  138. // write BIFS Scene Replace Command
  139. CreateIsmaSceneCommand(
  140. MP4_IS_VALID_TRACK_ID(audioTrackId),
  141. MP4_IS_VALID_TRACK_ID(videoTrackId),
  142. &pBytes,
  143. &numBytes);
  144. WriteSample(sceneTrackId, pBytes, numBytes, fileMsDuration);
  145. MP4Free(pBytes);
  146. pBytes = NULL;
  147. // add session level sdp
  148. CreateIsmaIodFromFile(
  149. m_odTrackId,
  150. sceneTrackId,
  151. audioTrackId,
  152. videoTrackId,
  153. &pBytes,
  154. &numBytes);
  155. char* iodBase64 = MP4ToBase64(pBytes, numBytes);
  156. uint sdpBufLen = (uint)strlen(iodBase64) + 256;
  157. uint used;
  158. char* sdpBuf = (char*)MP4Calloc(sdpBufLen);
  159. if (addIsmaComplianceSdp) {
  160. strncpy(sdpBuf, "a=isma-compliance:1,1.0,1\015\012", sdpBufLen);
  161. }
  162. used = (uint)strlen(sdpBuf);
  163. sdpBufLen -= used;
  164. snprintf(&sdpBuf[used], sdpBufLen,
  165. "a=mpeg4-iod: \042data:application/mpeg4-iod;base64,%s\042\015\012",
  166. iodBase64);
  167. SetSessionSdp(sdpBuf);
  168. VERBOSE_ISMA(GetVerbosity(),
  169. printf("IOD SDP = %s\n", sdpBuf));
  170. MP4Free(iodBase64);
  171. iodBase64 = NULL;
  172. MP4Free(pBytes);
  173. pBytes = NULL;
  174. MP4Free(sdpBuf);
  175. sdpBuf = NULL;
  176. }
  177. static void CloneIntegerProperty(
  178. MP4Descriptor* pDest,
  179. MP4DescriptorProperty* pSrc,
  180. const char* name)
  181. {
  182. MP4IntegerProperty* pGetProperty;
  183. MP4IntegerProperty* pSetProperty;
  184. if (!pSrc->FindProperty(name, (MP4Property**)&pGetProperty)) return;
  185. if (!pDest->FindProperty(name, (MP4Property**)&pSetProperty)) return;
  186. pSetProperty->SetValue(pGetProperty->GetValue());
  187. }
  188. void MP4File::CreateIsmaIodFromFile(
  189. MP4TrackId odTrackId,
  190. MP4TrackId sceneTrackId,
  191. MP4TrackId audioTrackId,
  192. MP4TrackId videoTrackId,
  193. u_int8_t** ppBytes,
  194. u_int64_t* pNumBytes)
  195. {
  196. MP4Descriptor* pIod = new MP4IODescriptor();
  197. pIod->SetTag(MP4IODescrTag);
  198. pIod->Generate();
  199. MP4Atom* pIodsAtom = FindAtomMP4File("moov.iods");
  200. ASSERT(pIodsAtom);
  201. MP4DescriptorProperty* pSrcIod =
  202. (MP4DescriptorProperty*)pIodsAtom->GetProperty(2);
  203. CloneIntegerProperty(pIod, pSrcIod, "objectDescriptorId");
  204. CloneIntegerProperty(pIod, pSrcIod, "ODProfileLevelId");
  205. CloneIntegerProperty(pIod, pSrcIod, "sceneProfileLevelId");
  206. CloneIntegerProperty(pIod, pSrcIod, "audioProfileLevelId");
  207. CloneIntegerProperty(pIod, pSrcIod, "visualProfileLevelId");
  208. CloneIntegerProperty(pIod, pSrcIod, "graphicsProfileLevelId");
  209. // mutate esIds from MP4ESIDIncDescrTag to MP4ESDescrTag
  210. MP4DescriptorProperty* pEsProperty;
  211. if (!pIod->FindProperty("esIds", (MP4Property**)&pEsProperty)) return;
  212. pEsProperty->SetTags(MP4ESDescrTag);
  213. MP4IntegerProperty* pSetProperty;
  214. MP4IntegerProperty* pSceneESID;
  215. MP4IntegerProperty* pOdESID;
  216. // OD
  217. MP4Descriptor* pOdEsd =
  218. pEsProperty->AddDescriptor(MP4ESDescrTag);
  219. pOdEsd->Generate();
  220. if (!pOdEsd->FindProperty("ESID", (MP4Property**)&pOdESID)) return;
  221. // we set the OD ESID to a non-zero unique value
  222. pOdESID->SetValue(m_odTrackId);
  223. if (pOdEsd->FindProperty("URLFlag",
  224. (MP4Property**)&pSetProperty))
  225. pSetProperty->SetValue(1);
  226. u_int8_t* pBytes;
  227. u_int64_t numBytes;
  228. CreateIsmaODUpdateCommandFromFileForStream(
  229. audioTrackId,
  230. videoTrackId,
  231. &pBytes,
  232. &numBytes);
  233. VERBOSE_ISMA(GetVerbosity(),
  234. printf("OD data =\n"); MP4HexDump(pBytes, numBytes));
  235. char* odCmdBase64 = MP4ToBase64(pBytes, numBytes);
  236. uint urlBufLen = (uint)strlen(odCmdBase64) + 64;
  237. char* urlBuf = (char*)MP4Malloc(urlBufLen);
  238. snprintf(urlBuf, urlBufLen,
  239. "data:application/mpeg4-od-au;base64,%s",
  240. odCmdBase64);
  241. MP4StringProperty* pUrlProperty;
  242. if (pOdEsd->FindProperty("URL",
  243. (MP4Property**)&pUrlProperty))
  244. pUrlProperty->SetValue(urlBuf);
  245. VERBOSE_ISMA(GetVerbosity(),
  246. printf("OD data URL = \042%s\042\n", urlBuf));
  247. MP4Free(odCmdBase64);
  248. odCmdBase64 = NULL;
  249. MP4Free(pBytes);
  250. pBytes = NULL;
  251. MP4Free(urlBuf);
  252. urlBuf = NULL;
  253. MP4DescriptorProperty* pSrcDcd = NULL;
  254. // HACK temporarily point to scene decoder config
  255. (void)FindProperty(MakeTrackName(odTrackId,
  256. "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr"),
  257. (MP4Property**)&pSrcDcd);
  258. ASSERT(pSrcDcd);
  259. MP4Property* pOrgOdEsdProperty =
  260. pOdEsd->GetProperty(8);
  261. pOdEsd->SetProperty(8, pSrcDcd);
  262. // bufferSizeDB needs to be set appropriately
  263. MP4BitfieldProperty* pBufferSizeProperty = NULL;
  264. if (pOdEsd->FindProperty("decConfigDescr.bufferSizeDB",
  265. (MP4Property**)&pBufferSizeProperty)) {
  266. ASSERT(pBufferSizeProperty);
  267. pBufferSizeProperty->SetValue(numBytes);
  268. }
  269. // SL config needs to change from 2 (file) to 1 (null)
  270. if (pOdEsd->FindProperty("slConfigDescr.predefined",
  271. (MP4Property**)&pSetProperty))
  272. pSetProperty->SetValue(1);
  273. // Scene
  274. MP4Descriptor* pSceneEsd =
  275. pEsProperty->AddDescriptor(MP4ESDescrTag);
  276. pSceneEsd->Generate();
  277. if (pSceneEsd->FindProperty("ESID",
  278. (MP4Property**)&pSceneESID)) {
  279. // we set the Scene ESID to a non-zero unique value
  280. pSceneESID->SetValue(sceneTrackId);
  281. }
  282. if (pSceneEsd->FindProperty("URLFlag",
  283. (MP4Property**)&pSetProperty))
  284. pSetProperty->SetValue(1);
  285. CreateIsmaSceneCommand(
  286. MP4_IS_VALID_TRACK_ID(audioTrackId),
  287. MP4_IS_VALID_TRACK_ID(videoTrackId),
  288. &pBytes,
  289. &numBytes);
  290. VERBOSE_ISMA(GetVerbosity(),
  291. printf("Scene data =\n"); MP4HexDump(pBytes, numBytes));
  292. char *sceneCmdBase64 = MP4ToBase64(pBytes, numBytes);
  293. urlBuf = (char*)MP4Malloc(strlen(sceneCmdBase64) + 64);
  294. snprintf(urlBuf, strlen(sceneCmdBase64) + 64,
  295. "data:application/mpeg4-bifs-au;base64,%s",
  296. sceneCmdBase64);
  297. if (pSceneEsd->FindProperty("URL",
  298. (MP4Property**)&pUrlProperty))
  299. pUrlProperty->SetValue(urlBuf);
  300. VERBOSE_ISMA(GetVerbosity(),
  301. printf("Scene data URL = \042%s\042\n", urlBuf));
  302. MP4Free(sceneCmdBase64);
  303. sceneCmdBase64 = NULL;
  304. MP4Free(urlBuf);
  305. urlBuf = NULL;
  306. MP4Free(pBytes);
  307. pBytes = NULL;
  308. // HACK temporarily point to scene decoder config
  309. ASSERT(FindProperty(MakeTrackName(sceneTrackId,
  310. "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr"),
  311. (MP4Property**)&pSrcDcd));
  312. ASSERT(pSrcDcd);
  313. MP4Property* pOrgSceneEsdProperty =
  314. pSceneEsd->GetProperty(8);
  315. pSceneEsd->SetProperty(8, pSrcDcd);
  316. // bufferSizeDB needs to be set
  317. pBufferSizeProperty = NULL;
  318. if (pSceneEsd->FindProperty("decConfigDescr.bufferSizeDB",
  319. (MP4Property**)&pBufferSizeProperty)) {
  320. ASSERT(pBufferSizeProperty);
  321. pBufferSizeProperty->SetValue(numBytes);
  322. }
  323. // SL config needs to change from 2 (file) to 1 (null)
  324. if (pSceneEsd->FindProperty("slConfigDescr.predefined",
  325. (MP4Property**)&pSetProperty))
  326. pSetProperty->SetValue(1);
  327. // finally get the whole thing written to a memory
  328. pIod->WriteToMemory(this, ppBytes, pNumBytes);
  329. // now carefully replace esd properties before destroying
  330. pOdEsd->SetProperty(8, pOrgOdEsdProperty);
  331. pSceneEsd->SetProperty(8, pOrgSceneEsdProperty);
  332. pSceneESID->SetValue(0); // restore 0 value
  333. pOdESID->SetValue(0);
  334. delete pIod;
  335. VERBOSE_ISMA(GetVerbosity(),
  336. printf("IOD data =\n"); MP4HexDump(*ppBytes, *pNumBytes));
  337. }
  338. void MP4File::CreateIsmaIodFromParams(
  339. u_int8_t videoProfile,
  340. u_int32_t videoBitrate,
  341. u_int8_t* videoConfig,
  342. u_int32_t videoConfigLength,
  343. u_int8_t audioProfile,
  344. u_int32_t audioBitrate,
  345. u_int8_t* audioConfig,
  346. u_int32_t audioConfigLength,
  347. u_int8_t** ppIodBytes,
  348. u_int64_t* pIodNumBytes)
  349. {
  350. MP4IntegerProperty* pInt;
  351. u_int8_t* pBytes = NULL;
  352. u_int64_t numBytes;
  353. // Create the IOD
  354. MP4Descriptor* pIod = new MP4IODescriptor();
  355. pIod->SetTag(MP4IODescrTag);
  356. pIod->Generate();
  357. // Set audio and video profileLevels
  358. if (pIod->FindProperty("audioProfileLevelId",
  359. (MP4Property**)&pInt))
  360. pInt->SetValue(audioProfile);
  361. if (pIod->FindProperty("visualProfileLevelId",
  362. (MP4Property**)&pInt))
  363. pInt->SetValue(videoProfile);
  364. // Mutate esIds from MP4ESIDIncDescrTag to MP4ESDescrTag
  365. MP4DescriptorProperty* pEsProperty;
  366. if (!pIod->FindProperty("esIds", (MP4Property**)&pEsProperty)) return;
  367. pEsProperty->SetTags(MP4ESDescrTag);
  368. // Add ES Descriptors
  369. // Scene
  370. CreateIsmaSceneCommand(
  371. (audioProfile != 0xFF),
  372. (videoProfile != 0xFF),
  373. &pBytes,
  374. &numBytes);
  375. VERBOSE_ISMA(GetVerbosity(),
  376. printf("Scene data =\n"); MP4HexDump(pBytes, numBytes));
  377. char* sceneCmdBase64 = MP4ToBase64(pBytes, numBytes);
  378. char* urlBuf =
  379. (char*)MP4Malloc(strlen(sceneCmdBase64) + 64);
  380. snprintf(urlBuf, strlen(sceneCmdBase64) + 64,
  381. "data:application/mpeg4-bifs-au;base64,%s",
  382. sceneCmdBase64);
  383. VERBOSE_ISMA(GetVerbosity(),
  384. printf("Scene data URL = \042%s\042\n", urlBuf));
  385. /* MP4Descriptor* pSceneEsd = */
  386. CreateESD(
  387. pEsProperty,
  388. 201, // esid
  389. MP4SystemsV2ObjectType,
  390. MP4SceneDescriptionStreamType,
  391. numBytes, // bufferSize
  392. numBytes * 8, // bitrate
  393. BifsV2Config,
  394. sizeof(BifsV2Config),
  395. urlBuf);
  396. MP4Free(urlBuf);
  397. urlBuf = NULL;
  398. MP4Free(sceneCmdBase64);
  399. sceneCmdBase64 = NULL;
  400. MP4Free(pBytes);
  401. pBytes = NULL;
  402. // OD
  403. // Video
  404. MP4DescriptorProperty* pVideoEsdProperty =
  405. new MP4DescriptorProperty();
  406. pVideoEsdProperty->SetTags(MP4ESDescrTag);
  407. /* MP4Descriptor* pVideoEsd = */
  408. CreateESD(
  409. pVideoEsdProperty,
  410. 20, // esid
  411. MP4_MPEG4_VIDEO_TYPE,
  412. MP4VisualStreamType,
  413. videoBitrate / 8, // bufferSize
  414. videoBitrate,
  415. videoConfig,
  416. videoConfigLength,
  417. NULL);
  418. // Audio
  419. MP4DescriptorProperty* pAudioEsdProperty =
  420. new MP4DescriptorProperty();
  421. pAudioEsdProperty->SetTags(MP4ESDescrTag);
  422. /* MP4Descriptor* pAudioEsd = */
  423. CreateESD(
  424. pAudioEsdProperty,
  425. 10, // esid
  426. MP4_MPEG4_AUDIO_TYPE,
  427. MP4AudioStreamType,
  428. audioBitrate / 8, // bufferSize
  429. audioBitrate,
  430. audioConfig,
  431. audioConfigLength,
  432. NULL);
  433. CreateIsmaODUpdateCommandForStream(
  434. pAudioEsdProperty,
  435. pVideoEsdProperty,
  436. &pBytes,
  437. &numBytes);
  438. // cleanup temporary descriptor properties
  439. delete pAudioEsdProperty;
  440. delete pVideoEsdProperty;
  441. VERBOSE_ISMA(GetVerbosity(),
  442. printf("OD data = "U64" bytes\n", numBytes); MP4HexDump(pBytes, numBytes));
  443. char* odCmdBase64 = MP4ToBase64(pBytes, numBytes);
  444. urlBuf = (char*)MP4Malloc(strlen(odCmdBase64) + 64);
  445. if (urlBuf != NULL) {
  446. snprintf(urlBuf, strlen(odCmdBase64) + 64,
  447. "data:application/mpeg4-od-au;base64,%s",
  448. odCmdBase64);
  449. VERBOSE_ISMA(GetVerbosity(),
  450. printf("OD data URL = \042%s\042\n", urlBuf));
  451. /* MP4Descriptor* pOdEsd = */
  452. CreateESD(
  453. pEsProperty,
  454. 101,
  455. MP4SystemsV1ObjectType,
  456. MP4ObjectDescriptionStreamType,
  457. numBytes, // bufferSize
  458. numBytes * 8, // bitrate
  459. NULL, // config
  460. 0, // configLength
  461. urlBuf);
  462. MP4Free(urlBuf);
  463. urlBuf = NULL;
  464. }
  465. MP4Free(odCmdBase64);
  466. odCmdBase64 = NULL;
  467. MP4Free(pBytes);
  468. pBytes = NULL;
  469. // finally get the whole thing written to a memory
  470. pIod->WriteToMemory(this, ppIodBytes, pIodNumBytes);
  471. delete pIod;
  472. VERBOSE_ISMA(GetVerbosity(),
  473. printf("IOD data =\n"); MP4HexDump(*ppIodBytes, *pIodNumBytes));
  474. }
  475. void MP4File::CreateESD(
  476. MP4DescriptorProperty* pEsProperty,
  477. u_int32_t esid,
  478. u_int8_t objectType,
  479. u_int8_t streamType,
  480. u_int32_t bufferSize,
  481. u_int32_t bitrate,
  482. const u_int8_t* pConfig,
  483. u_int32_t configLength,
  484. char* url)
  485. {
  486. MP4IntegerProperty* pInt;
  487. MP4StringProperty* pString;
  488. MP4BytesProperty* pBytes;
  489. MP4BitfieldProperty* pBits;
  490. MP4Descriptor* pEsd =
  491. pEsProperty->AddDescriptor(MP4ESDescrTag);
  492. pEsd->Generate();
  493. if (pEsd->FindProperty("ESID",
  494. (MP4Property**)&pInt))
  495. pInt->SetValue(esid);
  496. if (pEsd->FindProperty("decConfigDescr.objectTypeId",
  497. (MP4Property**)&pInt))
  498. pInt->SetValue(objectType);
  499. if (pEsd->FindProperty("decConfigDescr.streamType",
  500. (MP4Property**)&pInt))
  501. pInt->SetValue(streamType);
  502. if (pEsd->FindProperty("decConfigDescr.bufferSizeDB",
  503. (MP4Property**)&pInt))
  504. pInt->SetValue(bufferSize);
  505. if (pEsd->FindProperty("decConfigDescr.maxBitrate",
  506. (MP4Property**)&pInt))
  507. pInt->SetValue(bitrate);
  508. if (pEsd->FindProperty("decConfigDescr.avgBitrate",
  509. (MP4Property**)&pInt))
  510. pInt->SetValue(bitrate);
  511. MP4DescriptorProperty* pConfigDescrProperty;
  512. if (pEsd->FindProperty("decConfigDescr.decSpecificInfo",
  513. (MP4Property**)&pConfigDescrProperty)) {
  514. MP4Descriptor* pConfigDescr =
  515. pConfigDescrProperty->AddDescriptor(MP4DecSpecificDescrTag);
  516. pConfigDescr->Generate();
  517. if (pConfigDescrProperty->FindProperty("decSpecificInfo[0].info",
  518. (MP4Property**)&pBytes))
  519. pBytes->SetValue(pConfig, configLength);
  520. }
  521. if (pEsd->FindProperty("slConfigDescr.predefined",
  522. (MP4Property**)&pInt))
  523. // changed 12/5/02 from plugfest to value 0
  524. pInt->SetValue(0);
  525. if (pEsd->FindProperty("slConfig.useAccessUnitEndFlag",
  526. (MP4Property **)&pBits))
  527. pBits->SetValue(1);
  528. if (url) {
  529. if (pEsd->FindProperty("URLFlag",
  530. (MP4Property**)&pInt))
  531. pInt->SetValue(1);
  532. if (pEsd->FindProperty("URL",
  533. (MP4Property**)&pString))
  534. pString->SetValue(url);
  535. }
  536. //return pEsd;
  537. }
  538. void MP4File::CreateIsmaODUpdateCommandFromFileForFile(
  539. MP4TrackId odTrackId,
  540. MP4TrackId audioTrackId,
  541. MP4TrackId videoTrackId,
  542. u_int8_t** ppBytes,
  543. u_int64_t* pNumBytes)
  544. {
  545. MP4Descriptor* pCommand = CreateODCommand(MP4ODUpdateODCommandTag);
  546. pCommand->Generate();
  547. for (u_int8_t i = 0; i < 2; i++) {
  548. MP4TrackId trackId;
  549. u_int16_t odId;
  550. if (i == 0) {
  551. trackId = audioTrackId;
  552. odId = 10;
  553. } else {
  554. trackId = videoTrackId;
  555. odId = 20;
  556. }
  557. if (trackId == MP4_INVALID_TRACK_ID) {
  558. continue;
  559. }
  560. MP4DescriptorProperty* pOdDescrProperty =
  561. (MP4DescriptorProperty*)(pCommand->GetProperty(0));
  562. pOdDescrProperty->SetTags(MP4FileODescrTag);
  563. MP4Descriptor* pOd =
  564. pOdDescrProperty->AddDescriptor(MP4FileODescrTag);
  565. pOd->Generate();
  566. MP4BitfieldProperty* pOdIdProperty = NULL;
  567. if (pOd->FindProperty("objectDescriptorId",
  568. (MP4Property**)&pOdIdProperty))
  569. pOdIdProperty->SetValue(odId);
  570. MP4DescriptorProperty* pEsIdsDescriptorProperty = NULL;
  571. ASSERT(pOd->FindProperty("esIds",
  572. (MP4Property**)&pEsIdsDescriptorProperty));
  573. ASSERT(pEsIdsDescriptorProperty);
  574. pEsIdsDescriptorProperty->SetTags(MP4ESIDRefDescrTag);
  575. MP4Descriptor *pRefDescriptor =
  576. pEsIdsDescriptorProperty->AddDescriptor(MP4ESIDRefDescrTag);
  577. pRefDescriptor->Generate();
  578. MP4Integer16Property* pRefIndexProperty = NULL;
  579. ASSERT(pRefDescriptor->FindProperty("refIndex",
  580. (MP4Property**)&pRefIndexProperty));
  581. ASSERT(pRefIndexProperty);
  582. u_int32_t mpodIndex = FindTrackReference(
  583. MakeTrackName(odTrackId, "tref.mpod"), trackId);
  584. ASSERT(mpodIndex != 0);
  585. pRefIndexProperty->SetValue(mpodIndex);
  586. }
  587. pCommand->WriteToMemory(this, ppBytes, pNumBytes);
  588. delete pCommand;
  589. }
  590. void MP4File::CreateIsmaODUpdateCommandFromFileForStream(
  591. MP4TrackId audioTrackId,
  592. MP4TrackId videoTrackId,
  593. u_int8_t** ppBytes,
  594. u_int64_t* pNumBytes)
  595. {
  596. MP4DescriptorProperty* pAudioEsd = NULL;
  597. MP4Integer8Property* pAudioSLConfigPredef = NULL;
  598. MP4BitfieldProperty* pAudioAccessUnitEndFlag = NULL;
  599. int oldAudioUnitEndFlagValue = 0;
  600. MP4DescriptorProperty* pVideoEsd = NULL;
  601. MP4Integer8Property* pVideoSLConfigPredef = NULL;
  602. MP4BitfieldProperty* pVideoAccessUnitEndFlag = NULL;
  603. int oldVideoUnitEndFlagValue = 0;
  604. MP4IntegerProperty* pAudioEsdId = NULL;
  605. MP4IntegerProperty* pVideoEsdId = NULL;
  606. if (audioTrackId != MP4_INVALID_TRACK_ID) {
  607. // changed mp4a to * to handle enca case
  608. MP4Atom* pEsdsAtom =
  609. FindAtomMP4File(MakeTrackName(audioTrackId,
  610. "mdia.minf.stbl.stsd.*.esds"));
  611. ASSERT(pEsdsAtom);
  612. pAudioEsd = (MP4DescriptorProperty*)(pEsdsAtom->GetProperty(2));
  613. // ESID is 0 for file, stream needs to be non-ze
  614. ASSERT(pAudioEsd->FindProperty("ESID",
  615. (MP4Property**)&pAudioEsdId));
  616. ASSERT(pAudioEsdId);
  617. pAudioEsdId->SetValue(audioTrackId);
  618. // SL config needs to change from 2 (file) to 1 (null)
  619. if (pAudioEsd->FindProperty("slConfigDescr.predefined",
  620. (MP4Property**)&pAudioSLConfigPredef)) {
  621. ASSERT(pAudioSLConfigPredef);
  622. pAudioSLConfigPredef->SetValue(0);
  623. }
  624. if (pAudioEsd->FindProperty("slConfigDescr.useAccessUnitEndFlag",
  625. (MP4Property **)&pAudioAccessUnitEndFlag)) {
  626. oldAudioUnitEndFlagValue =
  627. pAudioAccessUnitEndFlag->GetValue();
  628. pAudioAccessUnitEndFlag->SetValue(1);
  629. }
  630. }
  631. if (videoTrackId != MP4_INVALID_TRACK_ID) {
  632. // changed mp4v to * to handle encv case
  633. MP4Atom* pEsdsAtom =
  634. FindAtomMP4File(MakeTrackName(videoTrackId,
  635. "mdia.minf.stbl.stsd.*.esds"));
  636. ASSERT(pEsdsAtom);
  637. pVideoEsd = (MP4DescriptorProperty*)(pEsdsAtom->GetProperty(2));
  638. ASSERT(pVideoEsd->FindProperty("ESID",
  639. (MP4Property**)&pVideoEsdId));
  640. ASSERT(pVideoEsdId);
  641. pVideoEsdId->SetValue(videoTrackId);
  642. // SL config needs to change from 2 (file) to 1 (null)
  643. ASSERT(pVideoEsd->FindProperty("slConfigDescr.predefined",
  644. (MP4Property **)&pVideoSLConfigPredef));
  645. ASSERT(pVideoSLConfigPredef);
  646. pVideoSLConfigPredef->SetValue(0);
  647. if (pVideoEsd->FindProperty("slConfigDescr.useAccessUnitEndFlag",
  648. (MP4Property **)&pVideoAccessUnitEndFlag)) {
  649. oldVideoUnitEndFlagValue =
  650. pVideoAccessUnitEndFlag->GetValue();
  651. pVideoAccessUnitEndFlag->SetValue(1);
  652. }
  653. }
  654. CreateIsmaODUpdateCommandForStream(
  655. pAudioEsd, pVideoEsd, ppBytes, pNumBytes);
  656. VERBOSE_ISMA(GetVerbosity(),
  657. printf("After CreateImsaODUpdateCommandForStream len "U64" =\n", *pNumBytes); MP4HexDump(*ppBytes, *pNumBytes));
  658. // return SL config values to 2 (file)
  659. // return ESID values to 0
  660. if (pAudioSLConfigPredef) {
  661. pAudioSLConfigPredef->SetValue(2);
  662. }
  663. if (pAudioEsdId) {
  664. pAudioEsdId->SetValue(0);
  665. }
  666. if (pAudioAccessUnitEndFlag) {
  667. pAudioAccessUnitEndFlag->SetValue(oldAudioUnitEndFlagValue );
  668. }
  669. if (pVideoEsdId) {
  670. pVideoEsdId->SetValue(0);
  671. }
  672. if (pVideoSLConfigPredef) {
  673. pVideoSLConfigPredef->SetValue(2);
  674. }
  675. if (pVideoAccessUnitEndFlag) {
  676. pVideoAccessUnitEndFlag->SetValue(oldVideoUnitEndFlagValue );
  677. }
  678. }
  679. void MP4File::CreateIsmaODUpdateCommandForStream(
  680. MP4DescriptorProperty* pAudioEsdProperty,
  681. MP4DescriptorProperty* pVideoEsdProperty,
  682. u_int8_t** ppBytes,
  683. u_int64_t* pNumBytes)
  684. {
  685. MP4Descriptor* pAudioOd = NULL;
  686. MP4Descriptor* pVideoOd = NULL;
  687. MP4Descriptor* pCommand =
  688. CreateODCommand(MP4ODUpdateODCommandTag);
  689. pCommand->Generate();
  690. for (u_int8_t i = 0; i < 2; i++) {
  691. u_int16_t odId;
  692. MP4DescriptorProperty* pEsdProperty = NULL;
  693. if (i == 0) {
  694. odId = 10;
  695. pEsdProperty = pAudioEsdProperty;
  696. } else {
  697. odId = 20;
  698. pEsdProperty = pVideoEsdProperty;
  699. }
  700. if (pEsdProperty == NULL) {
  701. continue;
  702. }
  703. MP4DescriptorProperty* pOdDescrProperty =
  704. (MP4DescriptorProperty*)(pCommand->GetProperty(0));
  705. pOdDescrProperty->SetTags(MP4ODescrTag);
  706. MP4Descriptor* pOd =
  707. pOdDescrProperty->AddDescriptor(MP4ODescrTag);
  708. pOd->Generate();
  709. if (i == 0) {
  710. pAudioOd = pOd;
  711. } else {
  712. pVideoOd = pOd;
  713. }
  714. MP4BitfieldProperty* pOdIdProperty = NULL;
  715. if (pOd->FindProperty("objectDescriptorId",
  716. (MP4Property**)&pOdIdProperty)) {
  717. pOdIdProperty->SetValue(odId);
  718. }
  719. delete (MP4DescriptorProperty*)pOd->GetProperty(4);
  720. pOd->SetProperty(4, pEsdProperty);
  721. }
  722. // serialize OD command
  723. pCommand->WriteToMemory(this, ppBytes, pNumBytes);
  724. // detach from esd descriptor params
  725. if (pAudioOd) {
  726. pAudioOd->SetProperty(4, NULL);
  727. }
  728. if (pVideoOd) {
  729. pVideoOd->SetProperty(4, NULL);
  730. }
  731. // then destroy
  732. delete pCommand;
  733. }
  734. void MP4File::CreateIsmaSceneCommand(
  735. bool hasAudio,
  736. bool hasVideo,
  737. u_int8_t** ppBytes,
  738. u_int64_t* pNumBytes)
  739. {
  740. // from ISMA 1.0 Tech Spec Appendix E
  741. static const u_int8_t bifsAudioOnly[] = {
  742. 0xC0, 0x10, 0x12,
  743. 0x81, 0x30, 0x2A, 0x05, 0x6D, 0xC0
  744. };
  745. static const u_int8_t bifsVideoOnly[] = {
  746. 0xC0, 0x10, 0x12,
  747. 0x61, 0x04,
  748. 0x1F, 0xC0, 0x00, 0x00,
  749. 0x1F, 0xC0, 0x00, 0x00,
  750. 0x44, 0x28, 0x22, 0x82, 0x9F, 0x80
  751. };
  752. static const u_int8_t bifsAudioVideo[] = {
  753. 0xC0, 0x10, 0x12,
  754. 0x81, 0x30, 0x2A, 0x05, 0x6D, 0x26,
  755. 0x10, 0x41, 0xFC, 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00,
  756. 0x04, 0x42, 0x82, 0x28, 0x29, 0xF8
  757. };
  758. if (hasAudio && hasVideo) {
  759. *pNumBytes = sizeof(bifsAudioVideo);
  760. *ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes);
  761. memcpy(*ppBytes, bifsAudioVideo, sizeof(bifsAudioVideo));
  762. } else if (hasAudio) {
  763. *pNumBytes = sizeof(bifsAudioOnly);
  764. *ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes);
  765. memcpy(*ppBytes, bifsAudioOnly, sizeof(bifsAudioOnly));
  766. } else if (hasVideo) {
  767. *pNumBytes = sizeof(bifsVideoOnly);
  768. *ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes);
  769. memcpy(*ppBytes, bifsVideoOnly, sizeof(bifsVideoOnly));
  770. } else {
  771. *pNumBytes = 0;
  772. *ppBytes = NULL;
  773. }
  774. }