PageRenderTime 45ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/src/isomedia/isom_write.c

https://github.com/svettom/gpac
C | 4599 lines | 3690 code | 618 blank | 291 comment | 1130 complexity | 93d72a81fa0a2b1d617caa77fb3fe382 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * GPAC - Multimedia Framework C SDK
  3. *
  4. * Authors: Jean Le Feuvre
  5. * Copyright (c) Telecom ParisTech 2000-2012
  6. * All rights reserved
  7. *
  8. * This file is part of GPAC / ISO Media File Format sub-project
  9. *
  10. * GPAC is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU Lesser General Public License as published by
  12. * the Free Software Foundation; either version 2, or (at your option)
  13. * any later version.
  14. *
  15. * GPAC is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public
  21. * License along with this library; see the file COPYING. If not, write to
  22. * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  23. *
  24. */
  25. #include "../../include/gpac/internal/isomedia_dev.h"
  26. #if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_WRITE)
  27. GF_Err CanAccessMovie(GF_ISOFile *movie, u32 Mode)
  28. {
  29. if (!movie) return GF_BAD_PARAM;
  30. if (movie->openMode < Mode) return GF_ISOM_INVALID_MODE;
  31. #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
  32. if (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY) return GF_ISOM_INVALID_MODE;
  33. #endif
  34. return GF_OK;
  35. }
  36. static GF_Err unpack_track(GF_TrackBox *trak)
  37. {
  38. GF_Err e = GF_OK;
  39. if (!trak->is_unpacked) {
  40. e = stbl_UnpackOffsets(trak->Media->information->sampleTable);
  41. trak->is_unpacked = 1;
  42. }
  43. return e;
  44. }
  45. GF_Err FlushCaptureMode(GF_ISOFile *movie)
  46. {
  47. GF_Err e;
  48. if (movie->openMode != GF_ISOM_OPEN_WRITE) return GF_OK;
  49. /*make sure nothing was added*/
  50. if (gf_bs_get_position(movie->editFileMap->bs)) return GF_OK;
  51. /*add all first boxes*/
  52. if (movie->brand) {
  53. e = gf_isom_box_size((GF_Box *)movie->brand);
  54. if (e) return e;
  55. e = gf_isom_box_write((GF_Box *)movie->brand, movie->editFileMap->bs);
  56. if (e) return e;
  57. }
  58. if (movie->pdin) {
  59. e = gf_isom_box_size((GF_Box *)movie->pdin);
  60. if (e) return e;
  61. e = gf_isom_box_write((GF_Box *)movie->pdin, movie->editFileMap->bs);
  62. if (e) return e;
  63. }
  64. /*we have a trick here: the data will be stored on the fly, so the first
  65. thing in the file is the MDAT. As we don't know if we have a large file (>4 GB) or not
  66. do as if we had one and write 16 bytes: 4 (type) + 4 (size) + 8 (largeSize)...*/
  67. gf_bs_write_int(movie->editFileMap->bs, 0, 128);
  68. return GF_OK;
  69. }
  70. static GF_Err CheckNoData(GF_ISOFile *movie)
  71. {
  72. if (movie->openMode != GF_ISOM_OPEN_WRITE) return GF_OK;
  73. if (gf_bs_get_position(movie->editFileMap->bs)) return GF_BAD_PARAM;
  74. return GF_OK;
  75. }
  76. /**************************************************************
  77. File Writing / Editing
  78. **************************************************************/
  79. //quick function to add an IOD/OD to the file if not present (iods is optional)
  80. GF_Err AddMovieIOD(GF_MovieBox *moov, u8 isIOD)
  81. {
  82. GF_Descriptor *od;
  83. GF_ObjectDescriptorBox *iods;
  84. //do we have an IOD ?? If not, create one.
  85. if (moov->iods) return GF_OK;
  86. if (isIOD) {
  87. od = gf_odf_desc_new(GF_ODF_ISOM_IOD_TAG);
  88. } else {
  89. od = gf_odf_desc_new(GF_ODF_ISOM_OD_TAG);
  90. }
  91. if (!od) return GF_OUT_OF_MEM;
  92. ((GF_IsomObjectDescriptor *)od)->objectDescriptorID = 1;
  93. iods = (GF_ObjectDescriptorBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_IODS);
  94. iods->descriptor = od;
  95. return moov_AddBox((GF_Box*)moov, (GF_Box *)iods);
  96. }
  97. //add a track to the root OD
  98. GF_EXPORT
  99. GF_Err gf_isom_add_track_to_root_od(GF_ISOFile *movie, u32 trackNumber)
  100. {
  101. GF_Err e;
  102. GF_ES_ID_Inc *inc;
  103. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  104. if (e) return e;
  105. gf_isom_insert_moov(movie);
  106. if (!movie->moov->iods) AddMovieIOD(movie->moov, 0);
  107. if (gf_isom_is_track_in_root_od(movie, trackNumber) == 1) return GF_OK;
  108. inc = (GF_ES_ID_Inc *) gf_odf_desc_new(GF_ODF_ESD_INC_TAG);
  109. inc->trackID = gf_isom_get_track_id(movie, trackNumber);
  110. if (!inc->trackID) {
  111. gf_odf_desc_del((GF_Descriptor *)inc);
  112. return movie->LastError;
  113. }
  114. if ( (movie->LastError = gf_isom_add_desc_to_root_od(movie, (GF_Descriptor *)inc) ) ) {
  115. return movie->LastError;
  116. }
  117. gf_odf_desc_del((GF_Descriptor *)inc);
  118. return GF_OK;
  119. }
  120. //remove the root OD
  121. GF_EXPORT
  122. GF_Err gf_isom_remove_root_od(GF_ISOFile *movie)
  123. {
  124. GF_Err e;
  125. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  126. if (e) return e;
  127. if (!movie->moov || !movie->moov->iods) return GF_OK;
  128. gf_isom_box_del((GF_Box *)movie->moov->iods);
  129. movie->moov->iods = NULL;
  130. return GF_OK;
  131. }
  132. //remove a track to the root OD
  133. GF_EXPORT
  134. GF_Err gf_isom_remove_track_from_root_od(GF_ISOFile *movie, u32 trackNumber)
  135. {
  136. GF_List *esds;
  137. GF_ES_ID_Inc *inc;
  138. u32 i;
  139. GF_Err e;
  140. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  141. if (e) return e;
  142. if (!movie->moov) return GF_OK;
  143. if (!gf_isom_is_track_in_root_od(movie, trackNumber)) return GF_OK;
  144. if (!movie->moov->iods) AddMovieIOD(movie->moov, 0);
  145. switch (movie->moov->iods->descriptor->tag) {
  146. case GF_ODF_ISOM_IOD_TAG:
  147. esds = ((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->ES_ID_IncDescriptors;
  148. break;
  149. case GF_ODF_ISOM_OD_TAG:
  150. esds = ((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->ES_ID_IncDescriptors;
  151. break;
  152. default:
  153. return GF_ISOM_INVALID_FILE;
  154. }
  155. //get the desc
  156. i=0;
  157. while ((inc = (GF_ES_ID_Inc*)gf_list_enum(esds, &i))) {
  158. if (inc->trackID == gf_isom_get_track_id(movie, trackNumber)) {
  159. gf_odf_desc_del((GF_Descriptor *)inc);
  160. gf_list_rem(esds, i-1);
  161. break;
  162. }
  163. }
  164. //we don't remove the iod for P&Ls and other potential info
  165. return GF_OK;
  166. }
  167. GF_EXPORT
  168. GF_Err gf_isom_set_creation_time(GF_ISOFile *movie, u64 time)
  169. {
  170. if (!movie || !movie->moov) return GF_BAD_PARAM;
  171. movie->moov->mvhd->creationTime = time;
  172. movie->moov->mvhd->modificationTime = time;
  173. return GF_OK;
  174. }
  175. GF_EXPORT
  176. GF_Err gf_isom_set_track_creation_time(GF_ISOFile *movie,u32 trackNumber, u64 time)
  177. {
  178. GF_TrackBox *trak;
  179. trak = gf_isom_get_track_from_file(movie, trackNumber);
  180. if (!trak) return GF_BAD_PARAM;
  181. trak->Header->creationTime = time;
  182. trak->Header->modificationTime = time;
  183. return GF_OK;
  184. }
  185. //sets the enable flag of a track
  186. GF_EXPORT
  187. GF_Err gf_isom_set_track_enabled(GF_ISOFile *movie, u32 trackNumber, u8 enableTrack)
  188. {
  189. GF_Err e;
  190. GF_TrackBox *trak;
  191. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  192. if (e) return e;
  193. trak = gf_isom_get_track_from_file(movie, trackNumber);
  194. if (!trak) return GF_BAD_PARAM;
  195. if (enableTrack) {
  196. trak->Header->flags |= 1;
  197. } else {
  198. trak->Header->flags &= ~1;
  199. }
  200. return GF_OK;
  201. }
  202. GF_EXPORT
  203. GF_Err gf_isom_set_media_language(GF_ISOFile *movie, u32 trackNumber, char *three_char_code)
  204. {
  205. GF_Err e;
  206. GF_TrackBox *trak;
  207. trak = gf_isom_get_track_from_file(movie, trackNumber);
  208. if (!trak) return GF_BAD_PARAM;
  209. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  210. if (e) return e;
  211. memcpy(trak->Media->mediaHeader->packedLanguage, three_char_code, sizeof(char)*3);
  212. if (!movie->keep_utc)
  213. trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
  214. return GF_OK;
  215. }
  216. static void gf_isom_set_root_iod(GF_ISOFile *movie)
  217. {
  218. GF_IsomInitialObjectDescriptor *iod;
  219. GF_IsomObjectDescriptor *od;
  220. gf_isom_insert_moov(movie);
  221. if (!movie->moov->iods) {
  222. AddMovieIOD(movie->moov, 1);
  223. return;
  224. }
  225. //if OD, switch to IOD
  226. if (movie->moov->iods->descriptor->tag == GF_ODF_ISOM_IOD_TAG) return;
  227. od = (GF_IsomObjectDescriptor *) movie->moov->iods->descriptor;
  228. iod = (GF_IsomInitialObjectDescriptor*)gf_malloc(sizeof(GF_IsomInitialObjectDescriptor));
  229. memset(iod, 0, sizeof(GF_IsomInitialObjectDescriptor));
  230. iod->ES_ID_IncDescriptors = od->ES_ID_IncDescriptors;
  231. od->ES_ID_IncDescriptors = NULL;
  232. //not used in root OD
  233. iod->ES_ID_RefDescriptors = NULL;
  234. iod->extensionDescriptors = od->extensionDescriptors;
  235. od->extensionDescriptors = NULL;
  236. iod->IPMP_Descriptors = od->IPMP_Descriptors;
  237. od->IPMP_Descriptors = NULL;
  238. iod->objectDescriptorID = od->objectDescriptorID;
  239. iod->OCIDescriptors = od->OCIDescriptors;
  240. od->OCIDescriptors = NULL;
  241. iod->tag = GF_ODF_ISOM_IOD_TAG;
  242. iod->URLString = od->URLString;
  243. od->URLString = NULL;
  244. gf_odf_desc_del((GF_Descriptor *) od);
  245. movie->moov->iods->descriptor = (GF_Descriptor *)iod;
  246. }
  247. GF_Err gf_isom_add_desc_to_root_od(GF_ISOFile *movie, GF_Descriptor *theDesc)
  248. {
  249. GF_Err e;
  250. GF_Descriptor *desc, *dupDesc;
  251. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  252. if (e) return e;
  253. gf_isom_insert_moov(movie);
  254. if (!movie->moov->iods) AddMovieIOD(movie->moov, 0);
  255. if (theDesc->tag==GF_ODF_IPMP_TL_TAG) gf_isom_set_root_iod(movie);
  256. desc = movie->moov->iods->descriptor;
  257. //the type of desc is handled at the OD/IOD level, we'll be notified
  258. //if the desc is not allowed
  259. switch (desc->tag) {
  260. case GF_ODF_ISOM_IOD_TAG:
  261. case GF_ODF_ISOM_OD_TAG:
  262. //duplicate the desc
  263. e = gf_odf_desc_copy(theDesc, &dupDesc);
  264. if (e) return e;
  265. //add it (MUST BE (I)OD level desc)
  266. movie->LastError = gf_odf_desc_add_desc(desc, dupDesc);
  267. if (movie->LastError) gf_odf_desc_del((GF_Descriptor *)dupDesc);
  268. break;
  269. default:
  270. movie->LastError = GF_ISOM_INVALID_FILE;
  271. break;
  272. }
  273. return movie->LastError;
  274. }
  275. GF_EXPORT
  276. GF_Err gf_isom_set_timescale(GF_ISOFile *movie, u32 timeScale)
  277. {
  278. GF_Err e;
  279. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  280. if (e) return e;
  281. gf_isom_insert_moov(movie);
  282. movie->moov->mvhd->timeScale = timeScale;
  283. movie->interleavingTime = timeScale;
  284. return GF_OK;
  285. }
  286. GF_EXPORT
  287. GF_Err gf_isom_set_pl_indication(GF_ISOFile *movie, u8 PL_Code, u8 ProfileLevel)
  288. {
  289. GF_IsomInitialObjectDescriptor *iod;
  290. GF_Err e;
  291. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  292. if (e) return e;
  293. gf_isom_set_root_iod(movie);
  294. iod = (GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor;
  295. switch (PL_Code) {
  296. case GF_ISOM_PL_AUDIO:
  297. iod->audio_profileAndLevel = ProfileLevel;
  298. break;
  299. case GF_ISOM_PL_GRAPHICS:
  300. iod->graphics_profileAndLevel = ProfileLevel;
  301. break;
  302. case GF_ISOM_PL_OD:
  303. iod->OD_profileAndLevel = ProfileLevel;
  304. break;
  305. case GF_ISOM_PL_SCENE:
  306. iod->scene_profileAndLevel = ProfileLevel;
  307. break;
  308. case GF_ISOM_PL_VISUAL:
  309. iod->visual_profileAndLevel = ProfileLevel;
  310. break;
  311. case GF_ISOM_PL_INLINE:
  312. iod->inlineProfileFlag = ProfileLevel ? 1 : 0;
  313. break;
  314. }
  315. return GF_OK;
  316. }
  317. GF_Err gf_isom_set_root_od_id(GF_ISOFile *movie, u32 OD_ID)
  318. {
  319. GF_Err e;
  320. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  321. if (e) return e;
  322. gf_isom_insert_moov(movie);
  323. if (!movie->moov->iods) AddMovieIOD(movie->moov, 0);
  324. switch (movie->moov->iods->descriptor->tag) {
  325. case GF_ODF_ISOM_OD_TAG:
  326. ((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->objectDescriptorID = OD_ID;
  327. break;
  328. case GF_ODF_ISOM_IOD_TAG:
  329. ((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->objectDescriptorID = OD_ID;
  330. break;
  331. default:
  332. return GF_ISOM_INVALID_FILE;
  333. }
  334. return GF_OK;
  335. }
  336. GF_Err gf_isom_set_root_od_url(GF_ISOFile *movie, char *url_string)
  337. {
  338. GF_Err e;
  339. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  340. if (e) return e;
  341. gf_isom_insert_moov(movie);
  342. if (!movie->moov->iods) AddMovieIOD(movie->moov, 0);
  343. switch (movie->moov->iods->descriptor->tag) {
  344. case GF_ODF_ISOM_OD_TAG:
  345. if (((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->URLString) gf_free(((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->URLString);
  346. ((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->URLString = url_string ? gf_strdup(url_string) : NULL;
  347. break;
  348. case GF_ODF_ISOM_IOD_TAG:
  349. if (((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->URLString) gf_free(((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->URLString);
  350. ((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->URLString = url_string ? gf_strdup(url_string) : NULL;
  351. break;
  352. default:
  353. return GF_ISOM_INVALID_FILE;
  354. }
  355. return GF_OK;
  356. }
  357. //creates a new Track. If trackID = 0, the trackID is chosen by the API
  358. //returns the track number or 0 if error
  359. GF_EXPORT
  360. u32 gf_isom_new_track(GF_ISOFile *movie, u32 trakID, u32 MediaType, u32 TimeScale)
  361. {
  362. GF_Err e;
  363. u64 now;
  364. u8 isHint;
  365. GF_TrackBox *trak;
  366. GF_TrackHeaderBox *tkhd;
  367. GF_MediaBox *mdia;
  368. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  369. if (e) {
  370. gf_isom_set_last_error(movie, e);
  371. return 0;
  372. }
  373. gf_isom_insert_moov(movie);
  374. isHint = 0;
  375. //we're creating a hint track... it's the same, but mode HAS TO BE EDIT
  376. if (MediaType == GF_ISOM_MEDIA_HINT) {
  377. // if (movie->openMode != GF_ISOM_OPEN_EDIT) return 0;
  378. isHint = 1;
  379. }
  380. mdia = NULL;
  381. tkhd = NULL;
  382. trak = NULL;
  383. if (trakID) {
  384. //check if we are in ES_ID boundaries
  385. if (!isHint && (trakID > 0xFFFF)) {
  386. gf_isom_set_last_error(movie, GF_BAD_PARAM);
  387. return 0;
  388. }
  389. //here we should look for available IDs ...
  390. if (!RequestTrack(movie->moov, trakID)) return 0;
  391. } else {
  392. trakID = movie->moov->mvhd->nextTrackID;
  393. if (!trakID) trakID = 1;
  394. /*ESIDs are on 16 bits*/
  395. if (! isHint && (trakID > 0xFFFF)) trakID = 1;
  396. while (1) {
  397. if (RequestTrack(movie->moov, trakID)) break;
  398. trakID += 1;
  399. if (trakID == 0xFFFFFFFF) break;
  400. }
  401. if (trakID == 0xFFFFFFFF) {
  402. gf_isom_set_last_error(movie, GF_BAD_PARAM);
  403. return 0;
  404. }
  405. if (! isHint && (trakID > 0xFFFF)) {
  406. gf_isom_set_last_error(movie, GF_BAD_PARAM);
  407. return 0;
  408. }
  409. }
  410. //OK, now create a track...
  411. trak = (GF_TrackBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_TRAK);
  412. if (!trak) {
  413. gf_isom_set_last_error(movie, GF_OUT_OF_MEM);
  414. return 0;
  415. }
  416. tkhd = (GF_TrackHeaderBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_TKHD);
  417. if (!tkhd) {
  418. gf_isom_set_last_error(movie, GF_OUT_OF_MEM);
  419. gf_isom_box_del((GF_Box *)trak);
  420. return 0;
  421. }
  422. now = gf_isom_get_mp4time();
  423. tkhd->creationTime = now;
  424. if (!movie->keep_utc)
  425. tkhd->modificationTime = now;
  426. //OK, set up the media trak
  427. e = NewMedia(&mdia, MediaType, TimeScale);
  428. if (e) {
  429. gf_isom_box_del((GF_Box *)mdia);
  430. gf_isom_box_del((GF_Box *)trak);
  431. gf_isom_box_del((GF_Box *)tkhd);
  432. return 0;
  433. }
  434. //OK, add this media to our track
  435. mdia->mediaTrack = trak;
  436. e = trak_AddBox((GF_Box*)trak, (GF_Box *) tkhd); if (e) goto err_exit;
  437. e = trak_AddBox((GF_Box*)trak, (GF_Box *) mdia); if (e) goto err_exit;
  438. tkhd->trackID = trakID;
  439. //some default properties for Audio, Visual or private tracks
  440. switch (MediaType) {
  441. case GF_ISOM_MEDIA_VISUAL:
  442. case GF_ISOM_MEDIA_SCENE:
  443. case GF_ISOM_MEDIA_TEXT:
  444. case GF_ISOM_MEDIA_SUBT:
  445. /*320-240 pix in 16.16*/
  446. tkhd->width = 0x01400000;
  447. tkhd->height = 0x00F00000;
  448. break;
  449. case GF_ISOM_MEDIA_AUDIO:
  450. tkhd->volume = 0x0100;
  451. break;
  452. }
  453. mdia->mediaHeader->creationTime = mdia->mediaHeader->modificationTime = now;
  454. trak->Header->creationTime = trak->Header->modificationTime = now;
  455. //OK, add our trak
  456. e = moov_AddBox((GF_Box*)movie->moov, (GF_Box *)trak); if (e) goto err_exit;
  457. //set the new ID available
  458. if (trakID+1> movie->moov->mvhd->nextTrackID)
  459. movie->moov->mvhd->nextTrackID = trakID+1;
  460. //and return our track number
  461. return gf_isom_get_track_by_id(movie, trakID);
  462. err_exit:
  463. if (tkhd) gf_isom_box_del((GF_Box *)tkhd);
  464. if (trak) gf_isom_box_del((GF_Box *)trak);
  465. if (mdia) gf_isom_box_del((GF_Box *)mdia);
  466. return 0;
  467. }
  468. //Create a new StreamDescription in the file. The URL and URN are used to describe external media
  469. GF_EXPORT
  470. GF_Err gf_isom_new_mpeg4_description(GF_ISOFile *movie,
  471. u32 trackNumber,
  472. GF_ESD *esd,
  473. char *URLname,
  474. char *URNname,
  475. u32 *outDescriptionIndex)
  476. {
  477. GF_TrackBox *trak;
  478. GF_Err e;
  479. u32 dataRefIndex;
  480. GF_ESD *new_esd;
  481. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  482. if (e) return e;
  483. trak = gf_isom_get_track_from_file(movie, trackNumber);
  484. if (!trak || !trak->Media ||
  485. !esd || !esd->decoderConfig ||
  486. !esd->slConfig) return GF_BAD_PARAM;
  487. //get or create the data ref
  488. e = Media_FindDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex);
  489. if (e) return e;
  490. if (!dataRefIndex) {
  491. e = Media_CreateDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex);
  492. if (e) return e;
  493. }
  494. //duplicate our desc
  495. e = gf_odf_desc_copy((GF_Descriptor *)esd, (GF_Descriptor **)&new_esd);
  496. if (e) return e;
  497. if (!movie->keep_utc)
  498. trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
  499. e = Track_SetStreamDescriptor(trak, 0, dataRefIndex, new_esd, outDescriptionIndex);
  500. if (e) {
  501. gf_odf_desc_del((GF_Descriptor *)new_esd);
  502. return e;
  503. }
  504. if (new_esd->URLString) {
  505. }
  506. return e;
  507. }
  508. //Add samples to a track. Use streamDescriptionIndex to specify the desired stream (if several)
  509. GF_EXPORT
  510. GF_Err gf_isom_add_sample(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_ISOSample *sample)
  511. {
  512. GF_Err e;
  513. GF_TrackBox *trak;
  514. GF_SampleEntryBox *entry;
  515. u32 dataRefIndex;
  516. u64 data_offset;
  517. u32 descIndex;
  518. GF_DataEntryURLBox *Dentry;
  519. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  520. if (e) return e;
  521. trak = gf_isom_get_track_from_file(movie, trackNumber);
  522. if (!trak) return GF_BAD_PARAM;
  523. e = FlushCaptureMode(movie);
  524. if (e) return e;
  525. e = unpack_track(trak);
  526. if (e) return e;
  527. //OK, add the sample
  528. //1- Get the streamDescriptionIndex and dataRefIndex
  529. //not specified, get the latest used...
  530. descIndex = StreamDescriptionIndex;
  531. if (!StreamDescriptionIndex) {
  532. descIndex = trak->Media->information->sampleTable->currentEntryIndex;
  533. }
  534. e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
  535. if (e) return e;
  536. if (!entry || !dataRefIndex) return GF_BAD_PARAM;
  537. //set the current to this one
  538. trak->Media->information->sampleTable->currentEntryIndex = descIndex;
  539. //get this dataRef and return false if not self contained
  540. Dentry = (GF_DataEntryURLBox*)gf_list_get(trak->Media->information->dataInformation->dref->other_boxes, dataRefIndex - 1);
  541. if (!Dentry || Dentry->flags != 1) return GF_BAD_PARAM;
  542. //Open our data map. We are adding stuff, so use EDIT
  543. e = gf_isom_datamap_open(trak->Media, dataRefIndex, 1);
  544. if (e) return e;
  545. //Get the offset...
  546. data_offset = gf_isom_datamap_get_offset(trak->Media->information->dataHandler);
  547. /*rewrite OD frame*/
  548. if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
  549. GF_ISOSample *od_sample = NULL;
  550. e = Media_ParseODFrame(trak->Media, sample, &od_sample);
  551. if (!e) e = Media_AddSample(trak->Media, data_offset, od_sample, descIndex, 0);
  552. if (!e) e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, od_sample->data, od_sample->dataLength);
  553. if (od_sample) gf_isom_sample_del(&od_sample);
  554. } else {
  555. e = Media_AddSample(trak->Media, data_offset, sample, descIndex, 0);
  556. if (!e && sample->dataLength) e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, sample->data, sample->dataLength);
  557. }
  558. if (e) return e;
  559. if (!movie->keep_utc)
  560. trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
  561. return SetTrackDuration(trak);
  562. }
  563. GF_Err gf_isom_add_sample_shadow(GF_ISOFile *movie, u32 trackNumber, GF_ISOSample *sample)
  564. {
  565. GF_Err e;
  566. GF_TrackBox *trak;
  567. GF_ISOSample *prev;
  568. GF_SampleEntryBox *entry;
  569. u32 dataRefIndex;
  570. u64 data_offset;
  571. u32 descIndex;
  572. u32 sampleNum, prevSampleNum;
  573. GF_DataEntryURLBox *Dentry;
  574. Bool offset_times = 0;
  575. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  576. if (e) return e;
  577. trak = gf_isom_get_track_from_file(movie, trackNumber);
  578. if (!trak || !sample) return GF_BAD_PARAM;
  579. e = FlushCaptureMode(movie);
  580. if (e) return e;
  581. e = unpack_track(trak);
  582. if (e) return e;
  583. e = findEntryForTime(trak->Media->information->sampleTable, sample->DTS, 0, &sampleNum, &prevSampleNum);
  584. if (e) return e;
  585. /*we need the EXACT match*/
  586. if (!sampleNum) return GF_BAD_PARAM;
  587. prev = gf_isom_get_sample_info(movie, trackNumber, sampleNum, &descIndex, NULL);
  588. if (!prev) return gf_isom_last_error(movie);
  589. /*for conformance*/
  590. if (sample->DTS==prev->DTS) offset_times = 1;
  591. gf_isom_sample_del(&prev);
  592. e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
  593. if (e) return e;
  594. if (!entry || !dataRefIndex) return GF_BAD_PARAM;
  595. trak->Media->information->sampleTable->currentEntryIndex = descIndex;
  596. //get this dataRef and return false if not self contained
  597. Dentry = (GF_DataEntryURLBox*)gf_list_get(trak->Media->information->dataInformation->dref->other_boxes, dataRefIndex - 1);
  598. if (!Dentry || Dentry->flags != 1) return GF_BAD_PARAM;
  599. //Open our data map. We are adding stuff, so use EDIT
  600. e = gf_isom_datamap_open(trak->Media, dataRefIndex, 1);
  601. if (e) return e;
  602. data_offset = gf_isom_datamap_get_offset(trak->Media->information->dataHandler);
  603. if (offset_times) sample->DTS += 1;
  604. /*REWRITE ANY OD STUFF*/
  605. if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
  606. GF_ISOSample *od_sample = NULL;
  607. e = Media_ParseODFrame(trak->Media, sample, &od_sample);
  608. if (!e) e = Media_AddSample(trak->Media, data_offset, od_sample, descIndex, sampleNum);
  609. if (!e) e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, od_sample->data, od_sample->dataLength);
  610. if (od_sample) gf_isom_sample_del(&od_sample);
  611. } else {
  612. e = Media_AddSample(trak->Media, data_offset, sample, descIndex, sampleNum);
  613. if (!e) e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, sample->data, sample->dataLength);
  614. }
  615. if (e) return e;
  616. if (offset_times) sample->DTS -= 1;
  617. //OK, update duration
  618. e = Media_SetDuration(trak);
  619. if (e) return e;
  620. if (!movie->keep_utc)
  621. trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
  622. return SetTrackDuration(trak);
  623. }
  624. GF_Err gf_isom_set_sample_rap(GF_ISOFile *movie, u32 trackNumber)
  625. {
  626. GF_SampleTableBox *stbl;
  627. GF_Err e;
  628. GF_TrackBox *trak;
  629. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  630. if (e) return e;
  631. trak = gf_isom_get_track_from_file(movie, trackNumber);
  632. if (!trak) return GF_BAD_PARAM;
  633. stbl = trak->Media->information->sampleTable;
  634. if (!stbl->SyncSample) stbl->SyncSample = (GF_SyncSampleBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STSS);
  635. return stbl_AddRAP(stbl->SyncSample, stbl->SampleSize->sampleCount);
  636. }
  637. GF_Err gf_isom_append_sample_data(GF_ISOFile *movie, u32 trackNumber, char *data, u32 data_size)
  638. {
  639. GF_Err e;
  640. GF_TrackBox *trak;
  641. GF_SampleEntryBox *entry;
  642. u32 dataRefIndex;
  643. u32 descIndex;
  644. GF_DataEntryURLBox *Dentry;
  645. if (!data_size) return GF_OK;
  646. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  647. if (e) return e;
  648. trak = gf_isom_get_track_from_file(movie, trackNumber);
  649. if (!trak) return GF_BAD_PARAM;
  650. if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) return GF_BAD_PARAM;
  651. //OK, add the sample
  652. descIndex = trak->Media->information->sampleTable->currentEntryIndex;
  653. e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
  654. if (e) return e;
  655. if (!entry || !dataRefIndex) return GF_BAD_PARAM;
  656. //get this dataRef and return false if not self contained
  657. Dentry = (GF_DataEntryURLBox*)gf_list_get(trak->Media->information->dataInformation->dref->other_boxes, dataRefIndex - 1);
  658. if (!Dentry || Dentry->flags != 1) return GF_BAD_PARAM;
  659. //Open our data map. We are adding stuff, so use EDIT
  660. e = gf_isom_datamap_open(trak->Media, dataRefIndex, 1);
  661. if (e) return e;
  662. //add the media data
  663. e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, data, data_size);
  664. if (e) return e;
  665. //update data size
  666. return stbl_SampleSizeAppend(trak->Media->information->sampleTable->SampleSize, data_size);
  667. }
  668. //Add sample reference to a track. The SampleOffset is the offset of the data in the referenced file
  669. //you must have created a StreamDescription with URL or URN specifying your referenced file
  670. //the data offset specifies the begining of the chunk
  671. //Use streamDescriptionIndex to specify the desired stream (if several)
  672. GF_EXPORT
  673. GF_Err gf_isom_add_sample_reference(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_ISOSample *sample, u64 dataOffset)
  674. {
  675. GF_TrackBox *trak;
  676. GF_SampleEntryBox *entry;
  677. u32 dataRefIndex;
  678. u32 descIndex;
  679. GF_DataEntryURLBox *Dentry;
  680. GF_Err e;
  681. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  682. if (e) return e;
  683. trak = gf_isom_get_track_from_file(movie, trackNumber);
  684. if (!trak) return GF_BAD_PARAM;
  685. e = unpack_track(trak);
  686. if (e) return e;
  687. //OD is not allowed as a data ref
  688. if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
  689. return GF_BAD_PARAM;
  690. }
  691. //OK, add the sample
  692. //1- Get the streamDescriptionIndex and dataRefIndex
  693. //not specified, get the latest used...
  694. descIndex = StreamDescriptionIndex;
  695. if (!StreamDescriptionIndex) {
  696. descIndex = trak->Media->information->sampleTable->currentEntryIndex;
  697. }
  698. e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
  699. if (e) return e;
  700. if (!entry || !dataRefIndex) return GF_BAD_PARAM;
  701. //set the current to this one
  702. trak->Media->information->sampleTable->currentEntryIndex = descIndex;
  703. //get this dataRef and return false if self contained
  704. Dentry =(GF_DataEntryURLBox*) gf_list_get(trak->Media->information->dataInformation->dref->other_boxes, dataRefIndex - 1);
  705. if (Dentry->flags == 1) return GF_BAD_PARAM;
  706. //add the meta data
  707. e = Media_AddSample(trak->Media, dataOffset, sample, descIndex, 0);
  708. if (e) return e;
  709. if (!movie->keep_utc)
  710. trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
  711. //OK, update duration
  712. e = Media_SetDuration(trak);
  713. if (e) return e;
  714. return SetTrackDuration(trak);
  715. }
  716. //set the duration of the last media sample. If not set, the duration of the last sample is the
  717. //duration of the previous one if any, or 1000 (default value).
  718. GF_EXPORT
  719. GF_Err gf_isom_set_last_sample_duration(GF_ISOFile *movie, u32 trackNumber, u32 duration)
  720. {
  721. GF_TrackBox *trak;
  722. GF_SttsEntry *ent;
  723. GF_TimeToSampleBox *stts;
  724. u64 mdur;
  725. GF_Err e;
  726. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  727. if (e) return e;
  728. trak = gf_isom_get_track_from_file(movie, trackNumber);
  729. if (!trak) return GF_BAD_PARAM;
  730. mdur = trak->Media->mediaHeader->duration;
  731. stts = trak->Media->information->sampleTable->TimeToSample;
  732. if (!stts->nb_entries) return GF_BAD_PARAM;
  733. //get the last entry
  734. ent = (GF_SttsEntry*) &stts->entries[stts->nb_entries-1];
  735. mdur -= ent->sampleDelta;
  736. mdur += duration;
  737. //we only have one sample
  738. if (ent->sampleCount == 1) {
  739. ent->sampleDelta = duration;
  740. } else {
  741. if (ent->sampleDelta == duration) return GF_OK;
  742. ent->sampleCount -= 1;
  743. if (stts->nb_entries==stts->alloc_size) {
  744. stts->alloc_size++;
  745. stts->entries = gf_realloc(stts->entries, sizeof(GF_SttsEntry)*stts->alloc_size);
  746. if (!stts->entries) return GF_OUT_OF_MEM;
  747. }
  748. stts->entries[stts->nb_entries].sampleCount = 1;
  749. stts->entries[stts->nb_entries].sampleDelta = duration;
  750. stts->nb_entries++;
  751. //and update the write cache
  752. stts->w_currentSampleNum = trak->Media->information->sampleTable->SampleSize->sampleCount;
  753. }
  754. if (!movie->keep_utc)
  755. trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
  756. trak->Media->mediaHeader->duration = mdur;
  757. return SetTrackDuration(trak);
  758. }
  759. //update a sample data in the media. Note that the sample MUST exists
  760. GF_Err gf_isom_update_sample(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber, GF_ISOSample *sample, Bool data_only)
  761. {
  762. GF_Err e;
  763. GF_TrackBox *trak;
  764. e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
  765. if (e) return e;
  766. trak = gf_isom_get_track_from_file(movie, trackNumber);
  767. if (!trak) return GF_BAD_PARAM;
  768. e = unpack_track(trak);
  769. if (e) return e;
  770. //block for hint tracks
  771. if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_HINT) return GF_BAD_PARAM;
  772. //REWRITE ANY OD STUFF
  773. if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
  774. GF_ISOSample *od_sample = NULL;
  775. e = Media_ParseODFrame(trak->Media, sample, &od_sample);
  776. if (!e) e = Media_UpdateSample(trak->Media, sampleNumber, od_sample, data_only);
  777. if (od_sample) gf_isom_sample_del(&od_sample);
  778. } else {
  779. e = Media_UpdateSample(trak->Media, sampleNumber, sample, data_only);
  780. }
  781. if (e) return e;
  782. if (!movie->keep_utc)
  783. trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
  784. return GF_OK;
  785. }
  786. //update a sample data in the media. Note that the sample MUST exists,
  787. //that sample->data MUST be NULL and sample->dataLength must be NON NULL;
  788. GF_Err gf_isom_update_sample_reference(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber, GF_ISOSample *sample, u64 data_offset)
  789. {
  790. GF_Err e;
  791. GF_TrackBox *trak;
  792. e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
  793. if (e) return e;
  794. trak = gf_isom_get_track_from_file(movie, trackNumber);
  795. if (!trak) return GF_BAD_PARAM;
  796. //block for hint tracks
  797. if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_HINT) return GF_BAD_PARAM;
  798. if (!sampleNumber || !sample) return GF_BAD_PARAM;
  799. e = unpack_track(trak);
  800. if (e) return e;
  801. //OD is not allowed as a data ref
  802. if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
  803. return GF_BAD_PARAM;
  804. }
  805. //OK, update it
  806. e = Media_UpdateSampleReference(trak->Media, sampleNumber, sample, data_offset);
  807. if (e) return e;
  808. if (!movie->keep_utc)
  809. trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
  810. return GF_OK;
  811. }
  812. //Remove a given sample
  813. GF_EXPORT
  814. GF_Err gf_isom_remove_sample(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber)
  815. {
  816. GF_Err e;
  817. GF_TrackBox *trak;
  818. e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
  819. if (e) return e;
  820. trak = gf_isom_get_track_from_file(movie, trackNumber);
  821. if (!trak || !sampleNumber || (sampleNumber > trak->Media->information->sampleTable->SampleSize->sampleCount) )
  822. return GF_BAD_PARAM;
  823. //block for hint tracks
  824. if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_HINT) return GF_BAD_PARAM;
  825. e = unpack_track(trak);
  826. if (e) return e;
  827. //remove DTS
  828. e = stbl_RemoveDTS(trak->Media->information->sampleTable, sampleNumber, trak->Media->mediaHeader->timeScale);
  829. if (e) return e;
  830. //remove CTS if any
  831. if (trak->Media->information->sampleTable->CompositionOffset) {
  832. e = stbl_RemoveCTS(trak->Media->information->sampleTable, sampleNumber);
  833. if (e) return e;
  834. }
  835. //remove size
  836. e = stbl_RemoveSize(trak->Media->information->sampleTable->SampleSize, sampleNumber);
  837. if (e) return e;
  838. //remove sampleToChunk and chunk
  839. e = stbl_RemoveChunk(trak->Media->information->sampleTable, sampleNumber);
  840. if (e) return e;
  841. //remove sync
  842. if (trak->Media->information->sampleTable->SyncSample) {
  843. e = stbl_RemoveRAP(trak->Media->information->sampleTable, sampleNumber);
  844. if (e) return e;
  845. }
  846. //remove sample dep
  847. if (trak->Media->information->sampleTable->SampleDep) {
  848. e = stbl_RemoveRedundant(trak->Media->information->sampleTable, sampleNumber);
  849. if (e) return e;
  850. }
  851. //remove shadow
  852. if (trak->Media->information->sampleTable->ShadowSync) {
  853. e = stbl_RemoveShadow(trak->Media->information->sampleTable->ShadowSync, sampleNumber);
  854. if (e) return e;
  855. }
  856. //remove padding
  857. e = stbl_RemovePaddingBits(trak->Media->information->sampleTable, sampleNumber);
  858. if (e) return e;
  859. return SetTrackDuration(trak);
  860. }
  861. GF_EXPORT
  862. GF_Err gf_isom_set_final_name(GF_ISOFile *movie, char *filename)
  863. {
  864. GF_Err e;
  865. if (!movie ) return GF_BAD_PARAM;
  866. //if mode is not OPEN_EDIT file was created under the right name
  867. e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
  868. if (e) return e;
  869. if (filename) {
  870. //we don't allow file overwriting
  871. if ( (movie->openMode == GF_ISOM_OPEN_EDIT)
  872. && movie->fileName && !strcmp(filename, movie->fileName))
  873. return GF_BAD_PARAM;
  874. if (movie->finalName) gf_free(movie->finalName);
  875. movie->finalName = gf_strdup(filename);
  876. if (!movie->finalName) return GF_OUT_OF_MEM;
  877. }
  878. return GF_OK;
  879. }
  880. //Add a system descriptor to the ESD of a stream(EDIT or WRITE mode only)
  881. GF_Err gf_isom_add_desc_to_description(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_Descriptor *theDesc)
  882. {
  883. GF_IPIPtr *ipiD;
  884. GF_Err e;
  885. u16 tmpRef;
  886. GF_TrackBox *trak;
  887. GF_Descriptor *desc;
  888. GF_ESD *esd;
  889. GF_TrackReferenceBox *tref;
  890. GF_TrackReferenceTypeBox *dpnd;
  891. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  892. if (e) return e;
  893. trak = gf_isom_get_track_from_file(movie, trackNumber);
  894. if (!trak) return GF_BAD_PARAM;
  895. /*GETS NATIVE DESCRIPTOR ONLY*/
  896. e = Media_GetESD(trak->Media, StreamDescriptionIndex, &esd, 1);
  897. if (e) return e;
  898. //duplicate the desc
  899. e = gf_odf_desc_copy(theDesc, &desc);
  900. if (e) return e;
  901. //and add it to the ESD EXCEPT IPI PTR (we need to translate from ES_ID to TrackID!!!
  902. if (!movie->keep_utc)
  903. trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
  904. switch (desc->tag) {
  905. case GF_ODF_IPI_PTR_TAG:
  906. goto insertIPI;
  907. default:
  908. return gf_odf_desc_add_desc((GF_Descriptor *)esd, desc);
  909. }
  910. insertIPI:
  911. if (esd->ipiPtr) {
  912. gf_odf_desc_del((GF_Descriptor *) esd->ipiPtr);
  913. esd->ipiPtr = NULL;
  914. }
  915. ipiD = (GF_IPIPtr *) desc;
  916. //find a tref
  917. if (!trak->References) {
  918. tref = (GF_TrackReferenceBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_TREF);
  919. e = trak_AddBox((GF_Box*)trak, (GF_Box *)tref);
  920. if (e) return e;
  921. }
  922. tref = trak->References;
  923. e = Track_FindRef(trak, GF_ISOM_REF_IPI, &dpnd);
  924. if (e) return e;
  925. if (!dpnd) {
  926. tmpRef = 0;
  927. dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_REFT);
  928. dpnd->reference_type = GF_ISOM_BOX_TYPE_IPIR;
  929. e = tref_AddBox((GF_Box*)tref, (GF_Box *) dpnd);
  930. if (e) return e;
  931. e = reftype_AddRefTrack(dpnd, ipiD->IPI_ES_Id, &tmpRef);
  932. if (e) return e;
  933. //and replace the tag and value...
  934. ipiD->IPI_ES_Id = tmpRef;
  935. ipiD->tag = GF_ODF_ISOM_IPI_PTR_TAG;
  936. } else {
  937. //Watch out! ONLY ONE IPI dependancy is allowed per stream
  938. dpnd->trackIDCount = 1;
  939. dpnd->trackIDs[0] = ipiD->IPI_ES_Id;
  940. //and replace the tag and value...
  941. ipiD->IPI_ES_Id = 1;
  942. ipiD->tag = GF_ODF_ISOM_IPI_PTR_TAG;
  943. }
  944. //and add the desc to the esd...
  945. return gf_odf_desc_add_desc((GF_Descriptor *)esd, desc);
  946. }
  947. //use carefully. Very usefull when you made a lot of changes (IPMP, IPI, OCI, ...)
  948. //THIS WILL REPLACE THE WHOLE DESCRIPTOR ...
  949. GF_EXPORT
  950. GF_Err gf_isom_change_mpeg4_description(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_ESD *newESD)
  951. {
  952. GF_Err e;
  953. GF_ESD *esd;
  954. GF_TrackBox *trak;
  955. GF_SampleEntryBox *entry;
  956. GF_SampleDescriptionBox *stsd;
  957. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  958. if (e) return e;
  959. trak = gf_isom_get_track_from_file(movie, trackNumber);
  960. if (!trak) return GF_BAD_PARAM;
  961. stsd = trak->Media->information->sampleTable->SampleDescription;
  962. if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
  963. if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->other_boxes)) {
  964. return movie->LastError = GF_BAD_PARAM;
  965. }
  966. entry = (GF_SampleEntryBox *)gf_list_get(stsd->other_boxes, StreamDescriptionIndex - 1);
  967. //no support for generic sample entries (eg, no MPEG4 descriptor)
  968. if (entry == NULL) return GF_BAD_PARAM;
  969. if (!movie->keep_utc)
  970. trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
  971. //duplicate our desc
  972. e = gf_odf_desc_copy((GF_Descriptor *)newESD, (GF_Descriptor **)&esd);
  973. if (e) return e;
  974. return Track_SetStreamDescriptor(trak, StreamDescriptionIndex, entry->dataReferenceIndex, esd, NULL);
  975. }
  976. GF_EXPORT
  977. GF_Err gf_isom_set_visual_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 Width, u32 Height)
  978. {
  979. GF_Err e;
  980. GF_TrackBox *trak;
  981. GF_SampleEntryBox *entry;
  982. GF_SampleDescriptionBox *stsd;
  983. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  984. if (e) return e;
  985. trak = gf_isom_get_track_from_file(movie, trackNumber);
  986. if (!trak) return GF_BAD_PARAM;
  987. stsd = trak->Media->information->sampleTable->SampleDescription;
  988. if (!stsd) {
  989. return movie->LastError = GF_ISOM_INVALID_FILE;
  990. }
  991. if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->other_boxes)) {
  992. return movie->LastError = GF_BAD_PARAM;
  993. }
  994. entry = (GF_SampleEntryBox *)gf_list_get(stsd->other_boxes, StreamDescriptionIndex - 1);
  995. //no support for generic sample entries (eg, no MPEG4 descriptor)
  996. if (entry == NULL) return GF_BAD_PARAM;
  997. if (!movie->keep_utc)
  998. trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
  999. //valid for MPEG visual, JPG and 3GPP H263
  1000. switch (entry->type) {
  1001. case GF_ISOM_BOX_TYPE_MP4V:
  1002. case GF_ISOM_SUBTYPE_3GP_H263:
  1003. case GF_ISOM_BOX_TYPE_AVC1:
  1004. case GF_ISOM_BOX_TYPE_AVC2:
  1005. case GF_ISOM_BOX_TYPE_AVC3:
  1006. case GF_ISOM_BOX_TYPE_AVC4:
  1007. case GF_ISOM_BOX_TYPE_SVC1:
  1008. case GF_ISOM_BOX_TYPE_HVC1:
  1009. case GF_ISOM_BOX_TYPE_HEV1:
  1010. ((GF_VisualSampleEntryBox*)entry)->Width = Width;
  1011. ((GF_VisualSampleEntryBox*)entry)->Height = Height;
  1012. trak->Header->width = Width<<16;
  1013. trak->Header->height = Height<<16;
  1014. return GF_OK;
  1015. /*check BIFS*/
  1016. default:
  1017. if (trak->Media->handler->handlerType==GF_ISOM_MEDIA_SCENE) {
  1018. trak->Header->width = Width<<16;
  1019. trak->Header->height = Height<<16;
  1020. return GF_OK;
  1021. }
  1022. return GF_BAD_PARAM;
  1023. }
  1024. }
  1025. GF_Err gf_isom_set_pixel_aspect_ratio(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 hSpacing, u32 vSpacing)
  1026. {
  1027. GF_Err e;
  1028. GF_TrackBox *trak;
  1029. GF_SampleEntryBox *entry;
  1030. GF_VisualSampleEntryBox*vent;
  1031. GF_SampleDescriptionBox *stsd;
  1032. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  1033. if (e) return e;
  1034. trak = gf_isom_get_track_from_file(movie, trackNumber);
  1035. if (!trak) return GF_BAD_PARAM;
  1036. stsd = trak->Media->information->sampleTable->SampleDescription;
  1037. if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
  1038. if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->other_boxes)) {
  1039. return movie->LastError = GF_BAD_PARAM;
  1040. }
  1041. entry = (GF_SampleEntryBox *)gf_list_get(stsd->other_boxes, StreamDescriptionIndex - 1);
  1042. //no support for generic sample entries (eg, no MPEG4 descriptor)
  1043. if (entry == NULL) return GF_BAD_PARAM;
  1044. if (!movie->keep_utc)
  1045. trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
  1046. switch (entry->type) {
  1047. case GF_ISOM_BOX_TYPE_MP4V:
  1048. case GF_ISOM_SUBTYPE_3GP_H263:
  1049. case GF_ISOM_BOX_TYPE_AVC1:
  1050. case GF_ISOM_BOX_TYPE_AVC2:
  1051. case GF_ISOM_BOX_TYPE_AVC3:
  1052. case GF_ISOM_BOX_TYPE_AVC4:
  1053. case GF_ISOM_BOX_TYPE_SVC1:
  1054. case GF_ISOM_BOX_TYPE_HVC1:
  1055. case GF_ISOM_BOX_TYPE_HEV1:
  1056. break;
  1057. default:
  1058. return GF_BAD_PARAM;
  1059. }
  1060. vent = (GF_VisualSampleEntryBox*)entry;
  1061. if (!hSpacing || !vSpacing) {
  1062. if (vent->pasp) gf_isom_box_del((GF_Box*)vent->pasp);
  1063. vent->pasp = NULL;
  1064. return GF_OK;
  1065. }
  1066. if (!vent->pasp) vent->pasp = (GF_PixelAspectRatioBox*)gf_isom_box_new(GF_ISOM_BOX_TYPE_PASP);
  1067. vent->pasp->hSpacing = hSpacing;
  1068. vent->pasp->vSpacing = vSpacing;
  1069. return GF_OK;
  1070. }
  1071. GF_EXPORT
  1072. GF_Err gf_isom_set_audio_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 sampleRate, u32 nbChannels, u8 bitsPerSample)
  1073. {
  1074. GF_Err e;
  1075. GF_TrackBox *trak;
  1076. GF_SampleEntryBox *entry;
  1077. GF_SampleDescriptionBox *stsd;
  1078. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  1079. if (e) return e;
  1080. trak = gf_isom_get_track_from_file(movie, trackNumber);
  1081. if (!trak) return GF_BAD_PARAM;
  1082. stsd = trak->Media->information->sampleTable->SampleDescription;
  1083. if (!stsd) {
  1084. return movie->LastError = GF_ISOM_INVALID_FILE;
  1085. }
  1086. if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->other_boxes)) {
  1087. return movie->LastError = GF_BAD_PARAM;
  1088. }
  1089. entry = (GF_SampleEntryBox *)gf_list_get(stsd->other_boxes, StreamDescriptionIndex - 1);
  1090. //no support for generic sample entries (eg, no MPEG4 descriptor)
  1091. if (entry == NULL) return GF_BAD_PARAM;
  1092. if (!movie->keep_utc)
  1093. trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
  1094. switch (entry->type) {
  1095. case GF_ISOM_BOX_TYPE_MP4A:
  1096. case GF_ISOM_SUBTYPE_3GP_AMR:
  1097. case GF_ISOM_SUBTYPE_3GP_AMR_WB:
  1098. case GF_ISOM_SUBTYPE_3GP_EVRC:
  1099. case GF_ISOM_SUBTYPE_3GP_QCELP:
  1100. case GF_ISOM_SUBTYPE_3GP_SMV:
  1101. ((GF_AudioSampleEntryBox*)entry)->samplerate_hi = sampleRate;
  1102. ((GF_AudioSampleEntryBox*)entry)->samplerate_lo = 0;
  1103. ((GF_AudioSampleEntryBox*)entry)->channel_count = nbChannels;
  1104. ((GF_AudioSampleEntryBox*)entry)->bitspersample = bitsPerSample;
  1105. return GF_OK;
  1106. case GF_ISOM_SUBTYPE_AC3:
  1107. case GF_ISOM_SUBTYPE_SAC3:
  1108. ((GF_AC3SampleEntryBox*)entry)->samplerate_hi = sampleRate;
  1109. ((GF_AC3SampleEntryBox*)entry)->samplerate_lo = 0;
  1110. ((GF_AC3SampleEntryBox*)entry)->channel_count = nbChannels;
  1111. ((GF_AC3SampleEntryBox*)entry)->bitspersample = bitsPerSample;
  1112. return GF_OK;
  1113. /*check BIFS*/
  1114. default:
  1115. return GF_BAD_PARAM;
  1116. }
  1117. }
  1118. //set the storage mode of a file (FLAT, STREAMABLE, INTERLEAVED)
  1119. GF_EXPORT
  1120. GF_Err gf_isom_set_storage_mode(GF_ISOFile *movie, u8 storageMode)
  1121. {
  1122. GF_Err e;
  1123. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  1124. if (e) return e;
  1125. switch (storageMode) {
  1126. case GF_ISOM_STORE_FLAT:
  1127. case GF_ISOM_STORE_STREAMABLE:
  1128. case GF_ISOM_STORE_INTERLEAVED:
  1129. case GF_ISOM_STORE_DRIFT_INTERLEAVED:
  1130. case GF_ISOM_STORE_TIGHT:
  1131. movie->storageMode = storageMode;
  1132. return GF_OK;
  1133. default:
  1134. return GF_BAD_PARAM;
  1135. }
  1136. }
  1137. //update or insert a new edit segment in the track time line. Edits are used to modify
  1138. //the media normal timing. EditTime and EditDuration are expressed in Movie TimeScale
  1139. //If a segment with EditTime already exists, IT IS ERASED
  1140. GF_EXPORT
  1141. GF_Err gf_isom_set_edit_segment(GF_ISOFile *movie, u32 trackNumber, u64 EditTime, u64 EditDuration, u64 MediaTime, u8 EditMode)
  1142. {
  1143. GF_TrackBox *trak;
  1144. GF_EditBox *edts;
  1145. GF_EditListBox *elst;
  1146. GF_EdtsEntry *ent, *newEnt;
  1147. u32 i;
  1148. GF_Err e;
  1149. u64 startTime;
  1150. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  1151. if (e) return e;
  1152. trak = gf_isom_get_track_from_file(movie, trackNumber);
  1153. if (!trak) return GF_BAD_PARAM;
  1154. edts = trak->editBox;
  1155. if (! edts) {
  1156. edts = (GF_EditBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_EDTS);
  1157. if (!edts) return GF_OUT_OF_MEM;
  1158. trak_AddBox((GF_Box*)trak, (GF_Box *)edts);
  1159. }
  1160. elst = edts->editList;
  1161. if (!elst) {
  1162. elst = (GF_EditListBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_ELST);
  1163. if (!elst) return GF_OUT_OF_MEM;
  1164. edts_AddBox((GF_Box*)edts, (GF_Box *)elst);
  1165. }
  1166. startTime = 0;
  1167. ent = NULL;
  1168. //get the prev entry to this startTime if any
  1169. i=0;
  1170. while ((ent = (GF_EdtsEntry *)gf_list_enum(elst->entryList, &i))) {
  1171. if ( (startTime <= EditTime) && (startTime + ent->segmentDuration > EditTime) )
  1172. goto found;
  1173. startTime += ent->segmentDuration;
  1174. }
  1175. //not found, add a new entry and adjust the prev one if any
  1176. if (!ent) {
  1177. newEnt = CreateEditEntry(EditDuration, MediaTime, EditMode);
  1178. if (!newEnt) return GF_OUT_OF_MEM;
  1179. gf_list_add(elst->entryList, newEnt);
  1180. return SetTrackDuration(trak);
  1181. }
  1182. startTime -= ent->segmentDuration;
  1183. found:
  1184. //if same time, we erase the current one...
  1185. if (startTime == EditTime) {
  1186. ent->segmentDuration = EditDuration;
  1187. switch (EditMode) {
  1188. case GF_ISOM_EDIT_EMPTY:
  1189. ent->mediaRate = 1<<16;
  1190. ent->mediaTime = -1;
  1191. break;
  1192. case GF_ISOM_EDIT_DWELL:
  1193. ent->mediaRate = 0;
  1194. ent->mediaTime = MediaTime;
  1195. break;
  1196. default:
  1197. ent->mediaRate = 1<<16;
  1198. ent->mediaTime = MediaTime;
  1199. break;
  1200. }
  1201. return SetTrackDuration(trak);
  1202. }
  1203. //adjust so that the prev ent leads to EntryTime
  1204. //Note: we don't change the next one as it is unknown to us in
  1205. //a lot of case (the author's changes)
  1206. ent->segmentDuration = EditTime - startTime;
  1207. newEnt = CreateEditEntry(EditDuration, MediaTime, EditMode);
  1208. if (!newEnt) return GF_OUT_OF_MEM;
  1209. //is it the last entry ???
  1210. if (i >= gf_list_count(elst->entryList) - 1) {
  1211. //add the new entry at the end
  1212. gf_list_add(elst->entryList, newEnt);
  1213. return SetTrackDuration(trak);
  1214. } else {
  1215. //insert after the current entry (which is i)
  1216. gf_list_insert(elst->entryList, newEnt, i+1);
  1217. return SetTrackDuration(trak);
  1218. }
  1219. }
  1220. //remove the edit segments for the whole track
  1221. GF_EXPORT
  1222. GF_Err gf_isom_remove_edit_segments(GF_ISOFile *movie, u32 trackNumber)
  1223. {
  1224. GF_Err e;
  1225. GF_TrackBox *trak;
  1226. GF_EdtsEntry *ent;
  1227. trak = gf_isom_get_track_from_file(movie, trackNumber);
  1228. if (!trak) return GF_BAD_PARAM;
  1229. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  1230. if (e) return e;
  1231. if (!trak->editBox || !trak->editBox->editList) return GF_OK;
  1232. while (gf_list_count(trak->editBox->editList->entryList)) {
  1233. ent = (GF_EdtsEntry*)gf_list_get(trak->editBox->editList->entryList, 0);
  1234. gf_free(ent);
  1235. e = gf_list_rem(trak->editBox->editList->entryList, 0);
  1236. if (e) return e;
  1237. }
  1238. //then delete the GF_EditBox...
  1239. gf_isom_box_del((GF_Box *)trak->editBox);
  1240. trak->editBox = NULL;
  1241. return SetTrackDuration(trak);
  1242. }
  1243. //remove the edit segments for the whole track
  1244. GF_Err gf_isom_remove_edit_segment(GF_ISOFile *movie, u32 trackNumber, u32 seg_index)
  1245. {
  1246. GF_Err e;
  1247. GF_TrackBox *trak;
  1248. GF_EdtsEntry *ent, *next_ent;
  1249. trak = gf_isom_get_track_from_file(movie, trackNumber);
  1250. if (!trak || !seg_index) return GF_BAD_PARAM;
  1251. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  1252. if (e) return e;
  1253. if (!trak->editBox || !trak->editBox->editList) return GF_OK;
  1254. if (gf_list_count(trak->editBox->editList->entryList)<=1) return gf_isom_remove_edit_segments(movie, trackNumber);
  1255. ent = (GF_EdtsEntry*) gf_list_get(trak->editBox->editList->entryList, seg_index-1);
  1256. gf_list_rem(trak->editBox->editList->entryList, seg_index-1);
  1257. next_ent = (GF_EdtsEntry *)gf_list_get(trak->editBox->editList->entryList, seg_index-1);
  1258. if (next_ent) next_ent->segmentDuration += ent->segmentDuration;
  1259. gf_free(ent);
  1260. return SetTrackDuration(trak);
  1261. }
  1262. GF_EXPORT
  1263. GF_Err gf_isom_append_edit_segment(GF_ISOFile *movie, u32 trackNumber, u64 EditDuration, u64 MediaTime, u8 EditMode)
  1264. {
  1265. GF_Err e;
  1266. GF_TrackBox *trak;
  1267. GF_EdtsEntry *ent;
  1268. trak = gf_isom_get_track_from_file(movie, trackNumber);
  1269. if (!trak) return GF_BAD_PARAM;
  1270. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  1271. if (e) return e;
  1272. if (!trak->editBox) {
  1273. GF_EditBox *edts = (GF_EditBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_EDTS);
  1274. if (!edts) return GF_OUT_OF_MEM;
  1275. trak_AddBox((GF_Box*)trak, (GF_Box *)edts);
  1276. }
  1277. if (!trak->editBox->editList) {
  1278. GF_EditListBox *elst = (GF_EditListBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_ELST);
  1279. if (!elst) return GF_OUT_OF_MEM;
  1280. edts_AddBox((GF_Box*)trak->editBox, (GF_Box *)elst);
  1281. }
  1282. ent = (GF_EdtsEntry *)gf_malloc(sizeof(GF_EdtsEntry));
  1283. if (!ent) return GF_OUT_OF_MEM;
  1284. ent->segmentDuration = EditDuration;
  1285. switch (EditMode) {
  1286. case GF_ISOM_EDIT_EMPTY:
  1287. ent->mediaRate = 1<<16;
  1288. ent->mediaTime = -1;
  1289. break;
  1290. case GF_ISOM_EDIT_DWELL:
  1291. ent->mediaRate = 0;
  1292. ent->mediaTime = MediaTime;
  1293. break;
  1294. default:
  1295. ent->mediaRate = 1<<16;
  1296. ent->mediaTime = MediaTime;
  1297. break;
  1298. }
  1299. gf_list_add(trak->editBox->editList->entryList, ent);
  1300. return SetTrackDuration(trak);
  1301. }
  1302. GF_EXPORT
  1303. GF_Err gf_isom_append_edit_segment2(GF_ISOFile *movie, u32 trackNumber, u64 EditDuration, u64 MediaTime, u32 MediaRate, u8 EditMode)
  1304. {
  1305. GF_Err e;
  1306. GF_TrackBox *trak;
  1307. GF_EdtsEntry *ent;
  1308. trak = gf_isom_get_track_from_file(movie, trackNumber);
  1309. if (!trak) return GF_BAD_PARAM;
  1310. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  1311. if (e) return e;
  1312. if (!trak->editBox) {
  1313. GF_EditBox *edts = (GF_EditBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_EDTS);
  1314. if (!edts) return GF_OUT_OF_MEM;
  1315. trak_AddBox((GF_Box*)trak, (GF_Box *)edts);
  1316. }
  1317. if (!trak->editBox->editList) {
  1318. GF_EditListBox *elst = (GF_EditListBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_ELST);
  1319. if (!elst) return GF_OUT_OF_MEM;
  1320. edts_AddBox((GF_Box*)trak->editBox, (GF_Box *)elst);
  1321. }
  1322. ent = (GF_EdtsEntry *)gf_malloc(sizeof(GF_EdtsEntry));
  1323. if (!ent) return GF_OUT_OF_MEM;
  1324. ent->segmentDuration = EditDuration;
  1325. ent->mediaTime = (EditMode == GF_ISOM_EDIT_EMPTY) ? -1 : MediaTime;
  1326. ent->mediaRate = MediaRate;
  1327. gf_list_add(trak->editBox->editList->entryList, ent);
  1328. return SetTrackDuration(trak);
  1329. }
  1330. GF_EXPORT
  1331. GF_Err gf_isom_modify_edit_segment(GF_ISOFile *movie, u32 trackNumber, u32 seg_index, u64 EditDuration, u64 MediaTime, u8 EditMode)
  1332. {
  1333. GF_Err e;
  1334. GF_TrackBox *trak;
  1335. GF_EdtsEntry *ent;
  1336. trak = gf_isom_get_track_from_file(movie, trackNumber);
  1337. if (!trak || !seg_index) return GF_BAD_PARAM;
  1338. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  1339. if (e) return e;
  1340. if (!trak->editBox || !trak->editBox->editList) return GF_OK;
  1341. if (gf_list_count(trak->editBox->editList->entryList)<seg_index) return GF_BAD_PARAM;
  1342. ent = (GF_EdtsEntry*) gf_list_get(trak->editBox->editList->entryList, seg_index-1);
  1343. ent->segmentDuration = EditDuration;
  1344. switch (EditMode) {
  1345. case GF_ISOM_EDIT_EMPTY:
  1346. ent->mediaRate = 1<<16;
  1347. ent->mediaTime = -1;
  1348. break;
  1349. case GF_ISOM_EDIT_DWELL:
  1350. ent->mediaRate = 0;
  1351. ent->mediaTime = MediaTime;
  1352. break;
  1353. default:
  1354. ent->mediaRate = 1<<16;
  1355. ent->mediaTime = MediaTime;
  1356. break;
  1357. }
  1358. return SetTrackDuration(trak);
  1359. }
  1360. GF_EXPORT
  1361. GF_Err gf_isom_modify_edit_segment2(GF_ISOFile *movie, u32 trackNumber, u32 seg_index, u64 EditDuration, u64 MediaTime, u32 MediaRate, u8 EditMode)
  1362. {
  1363. GF_Err e;
  1364. GF_TrackBox *trak;
  1365. GF_EdtsEntry *ent;
  1366. trak = gf_isom_get_track_from_file(movie, trackNumber);
  1367. if (!trak || !seg_index) return GF_BAD_PARAM;
  1368. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  1369. if (e) return e;
  1370. if (!trak->editBox || !trak->editBox->editList) return GF_OK;
  1371. if (gf_list_count(trak->editBox->editList->entryList)<seg_index) return GF_BAD_PARAM;
  1372. ent = (GF_EdtsEntry*) gf_list_get(trak->editBox->editList->entryList, seg_index-1);
  1373. ent->segmentDuration = EditDuration;
  1374. ent->mediaTime = (EditMode == GF_ISOM_EDIT_EMPTY) ? -1 : MediaTime;
  1375. ent->mediaRate = MediaRate;
  1376. return SetTrackDuration(trak);
  1377. }
  1378. //removes the desired track
  1379. GF_EXPORT
  1380. GF_Err gf_isom_remove_track(GF_ISOFile *movie, u32 trackNumber)
  1381. {
  1382. GF_Err e;
  1383. GF_TrackBox *the_trak, *trak;
  1384. GF_TrackReferenceTypeBox *tref;
  1385. u32 i, j, k, *newRefs, descIndex;
  1386. u8 found;
  1387. GF_ISOSample *samp;
  1388. the_trak = gf_isom_get_track_from_file(movie, trackNumber);
  1389. if (!the_trak) return GF_BAD_PARAM;
  1390. e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
  1391. if (e) return e;
  1392. if (movie->moov->iods && movie->moov->iods->descriptor) {
  1393. GF_Descriptor *desc;
  1394. GF_ES_ID_Inc *inc;
  1395. GF_List *ESDs;
  1396. desc = movie->moov->iods->descriptor;
  1397. if (desc->tag == GF_ODF_ISOM_IOD_TAG) {
  1398. ESDs = ((GF_IsomInitialObjectDescriptor *)desc)->ES_ID_IncDescriptors;
  1399. } else if (desc->tag == GF_ODF_ISOM_OD_TAG) {
  1400. ESDs = ((GF_IsomObjectDescriptor *)desc)->ES_ID_IncDescriptors;
  1401. } else {
  1402. return GF_ISOM_INVALID_FILE;
  1403. }
  1404. //remove the track ref from the root OD if any
  1405. i=0;
  1406. while ((inc = (GF_ES_ID_Inc *)gf_list_enum(ESDs, &i))) {
  1407. if (inc->trackID == the_trak->Header->trackID) {
  1408. gf_odf_desc_del((GF_Descriptor *)inc);
  1409. i--;
  1410. gf_list_rem(ESDs, i);
  1411. }
  1412. }
  1413. }
  1414. //remove the track from the movie
  1415. gf_list_del_item(movie->moov->trackList, the_trak);
  1416. //rewrite any OD tracks
  1417. i=0;
  1418. whil

Large files files are truncated, but you can click here to view the full file