Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2021
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 :
26 : #include <gpac/internal/isomedia_dev.h>
27 : #include <gpac/constants.h>
28 : #include <gpac/iso639.h>
29 :
30 :
31 : #if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_WRITE)
32 :
33 3289 : GF_Err CanAccessMovie(GF_ISOFile *movie, GF_ISOOpenMode Mode)
34 : {
35 1047755 : if (!movie) return GF_BAD_PARAM;
36 1058203 : if (movie->openMode < Mode) return GF_ISOM_INVALID_MODE;
37 :
38 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
39 1047975 : if (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY) return GF_ISOM_INVALID_MODE;
40 : #endif
41 3289 : return GF_OK;
42 : }
43 :
44 561877 : static GF_Err unpack_track(GF_TrackBox *trak)
45 : {
46 : GF_Err e = GF_OK;
47 561877 : if (!trak->is_unpacked) {
48 1320 : e = stbl_UnpackOffsets(trak->Media->information->sampleTable);
49 1320 : if (e) return e;
50 1320 : e = stbl_unpackCTS(trak->Media->information->sampleTable);
51 1320 : trak->is_unpacked = GF_TRUE;
52 : }
53 : return e;
54 : }
55 :
56 :
57 556443 : GF_Err FlushCaptureMode(GF_ISOFile *movie)
58 : {
59 : GF_Err e;
60 556443 : if (movie->openMode != GF_ISOM_OPEN_WRITE) {
61 554866 : if (!movie->editFileMap) return GF_ISOM_INVALID_MODE;
62 554866 : return GF_OK;
63 : }
64 : /*make sure nothing was added*/
65 1577 : if (gf_bs_get_position(movie->editFileMap->bs)) return GF_OK;
66 :
67 9 : if (!strcmp(movie->fileName, "_gpac_isobmff_redirect")) {
68 1 : if (!movie->on_block_out) {
69 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISOBMFF] Missing output block callback, cannot write\n"));
70 : return GF_BAD_PARAM;
71 : }
72 :
73 1 : gf_bs_del(movie->editFileMap->bs);
74 1 : movie->editFileMap->bs = gf_bs_new_cbk(movie->on_block_out, movie->on_block_out_usr_data, movie->on_block_out_block_size);
75 : }
76 :
77 : /*add all first boxes*/
78 9 : if (movie->brand) {
79 9 : e = gf_isom_box_size((GF_Box *)movie->brand);
80 9 : if (e) return e;
81 9 : e = gf_isom_box_write((GF_Box *)movie->brand, movie->editFileMap->bs);
82 9 : if (e) return e;
83 : }
84 9 : if (movie->pdin) {
85 0 : e = gf_isom_box_size((GF_Box *)movie->pdin);
86 0 : if (e) return e;
87 0 : e = gf_isom_box_write((GF_Box *)movie->pdin, movie->editFileMap->bs);
88 0 : if (e) return e;
89 : }
90 9 : movie->mdat->bsOffset = gf_bs_get_position(movie->editFileMap->bs);
91 :
92 : /*we have a trick here: the data will be stored on the fly, so the first
93 : thing in the file is the MDAT. As we don't know if we have a large file (>4 GB) or not
94 : do as if we had one and write 16 bytes: 4 (type) + 4 (size) + 8 (largeSize)...*/
95 9 : gf_bs_write_long_int(movie->editFileMap->bs, 0, 64);
96 9 : gf_bs_write_long_int(movie->editFileMap->bs, 0, 64);
97 9 : return GF_OK;
98 : }
99 :
100 : static GF_Err CheckNoData(GF_ISOFile *movie)
101 : {
102 10226 : if (movie->openMode != GF_ISOM_OPEN_WRITE) return GF_OK;
103 5995 : if (gf_bs_get_position(movie->editFileMap->bs)) return GF_BAD_PARAM;
104 : return GF_OK;
105 : }
106 :
107 : /**************************************************************
108 : File Writing / Editing
109 : **************************************************************/
110 : //quick function to add an IOD/OD to the file if not present (iods is optional)
111 511 : GF_Err AddMovieIOD(GF_MovieBox *moov, u8 isIOD)
112 : {
113 : GF_Descriptor *od;
114 : GF_ObjectDescriptorBox *iods;
115 :
116 : //do we have an IOD ?? If not, create one.
117 511 : if (moov->iods) return GF_OK;
118 :
119 510 : if (isIOD) {
120 474 : od = gf_odf_desc_new(GF_ODF_ISOM_IOD_TAG);
121 : } else {
122 36 : od = gf_odf_desc_new(GF_ODF_ISOM_OD_TAG);
123 : }
124 510 : if (!od) return GF_OUT_OF_MEM;
125 510 : ((GF_IsomObjectDescriptor *)od)->objectDescriptorID = 1;
126 :
127 510 : iods = (GF_ObjectDescriptorBox *) gf_isom_box_new_parent(&moov->child_boxes, GF_ISOM_BOX_TYPE_IODS);
128 510 : if (!iods) return GF_OUT_OF_MEM;
129 510 : iods->descriptor = od;
130 510 : return moov_on_child_box((GF_Box*)moov, (GF_Box *)iods, GF_FALSE);
131 : }
132 :
133 : //add a track to the root OD
134 : GF_EXPORT
135 94 : GF_Err gf_isom_add_track_to_root_od(GF_ISOFile *movie, u32 trackNumber)
136 : {
137 : GF_Err e;
138 : GF_ES_ID_Inc *inc;
139 :
140 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
141 : if (e) return e;
142 94 : e = gf_isom_insert_moov(movie);
143 94 : if (e) return e;
144 :
145 94 : if (!movie->moov->iods) AddMovieIOD(movie->moov, 0);
146 :
147 94 : if (gf_isom_is_track_in_root_od(movie, trackNumber) == 1) return GF_OK;
148 :
149 94 : inc = (GF_ES_ID_Inc *) gf_odf_desc_new(GF_ODF_ESD_INC_TAG);
150 94 : inc->trackID = gf_isom_get_track_id(movie, trackNumber);
151 94 : if (!inc->trackID) {
152 0 : gf_odf_desc_del((GF_Descriptor *)inc);
153 0 : return movie->LastError;
154 : }
155 94 : if ( (movie->LastError = gf_isom_add_desc_to_root_od(movie, (GF_Descriptor *)inc) ) ) {
156 : return movie->LastError;
157 : }
158 94 : gf_odf_desc_del((GF_Descriptor *)inc);
159 94 : return GF_OK;
160 : }
161 :
162 : //remove the root OD
163 : GF_EXPORT
164 8 : GF_Err gf_isom_remove_root_od(GF_ISOFile *movie)
165 : {
166 : GF_Err e;
167 :
168 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
169 : if (e) return e;
170 8 : if (!movie->moov || !movie->moov->iods) return GF_OK;
171 3 : gf_isom_box_del_parent(&movie->moov->child_boxes, (GF_Box *)movie->moov->iods);
172 3 : movie->moov->iods = NULL;
173 3 : return GF_OK;
174 : }
175 :
176 : //remove a track to the root OD
177 : GF_EXPORT
178 72 : GF_Err gf_isom_remove_track_from_root_od(GF_ISOFile *movie, u32 trackNumber)
179 : {
180 : GF_List *esds;
181 : GF_ES_ID_Inc *inc;
182 : u32 i;
183 : GF_Err e;
184 :
185 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
186 : if (e) return e;
187 72 : if (!movie->moov) return GF_OK;
188 :
189 72 : if (!gf_isom_is_track_in_root_od(movie, trackNumber)) return GF_OK;
190 :
191 0 : if (!movie->moov->iods) {
192 0 : e = AddMovieIOD(movie->moov, 0);
193 0 : if (e) return e;
194 : }
195 0 : switch (movie->moov->iods->descriptor->tag) {
196 0 : case GF_ODF_ISOM_IOD_TAG:
197 0 : esds = ((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->ES_ID_IncDescriptors;
198 0 : break;
199 0 : case GF_ODF_ISOM_OD_TAG:
200 0 : esds = ((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->ES_ID_IncDescriptors;
201 0 : break;
202 : default:
203 : return GF_ISOM_INVALID_FILE;
204 : }
205 :
206 : //get the desc
207 0 : i=0;
208 0 : while ((inc = (GF_ES_ID_Inc*)gf_list_enum(esds, &i))) {
209 0 : if (inc->trackID == (u32) gf_isom_get_track_id(movie, trackNumber)) {
210 0 : gf_odf_desc_del((GF_Descriptor *)inc);
211 0 : gf_list_rem(esds, i-1);
212 0 : break;
213 : }
214 : }
215 : //we don't remove the iod for P&Ls and other potential info
216 : return GF_OK;
217 : }
218 :
219 : GF_EXPORT
220 1 : GF_Err gf_isom_set_creation_time(GF_ISOFile *movie, u64 ctime, u64 mtime)
221 : {
222 1 : if (!movie || !movie->moov) return GF_BAD_PARAM;
223 1 : movie->moov->mvhd->creationTime = ctime;
224 1 : movie->moov->mvhd->modificationTime = mtime;
225 1 : return GF_OK;
226 : }
227 :
228 : GF_EXPORT
229 4 : GF_Err gf_isom_set_track_creation_time(GF_ISOFile *movie,u32 trackNumber, u64 ctime, u64 mtime)
230 : {
231 : GF_TrackBox *trak;
232 4 : trak = gf_isom_get_track_from_file(movie, trackNumber);
233 4 : if (!trak) return GF_BAD_PARAM;
234 :
235 4 : trak->Header->creationTime = ctime;
236 4 : trak->Header->modificationTime = mtime;
237 4 : return GF_OK;
238 : }
239 :
240 : GF_EXPORT
241 0 : GF_Err gf_isom_set_media_creation_time(GF_ISOFile *movie,u32 trackNumber, u64 ctime, u64 mtime)
242 : {
243 : GF_TrackBox *trak;
244 0 : trak = gf_isom_get_track_from_file(movie, trackNumber);
245 0 : if (!trak) return GF_BAD_PARAM;
246 0 : if (!trak->Media || !trak->Media->mediaHeader) return GF_ISOM_INVALID_FILE;
247 :
248 0 : trak->Media->mediaHeader->creationTime = ctime;
249 0 : trak->Media->mediaHeader->modificationTime = mtime;
250 0 : return GF_OK;
251 : }
252 :
253 : //sets the enable flag of a track
254 : GF_EXPORT
255 1630 : GF_Err gf_isom_set_track_enabled(GF_ISOFile *movie, u32 trackNumber, Bool enableTrack)
256 : {
257 : GF_Err e;
258 : GF_TrackBox *trak;
259 :
260 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
261 : if (e) return e;
262 :
263 1630 : trak = gf_isom_get_track_from_file(movie, trackNumber);
264 1630 : if (!trak) return GF_BAD_PARAM;
265 :
266 1630 : if (enableTrack) {
267 1628 : trak->Header->flags |= 1;
268 : } else {
269 2 : trak->Header->flags &= ~1;
270 : }
271 : return GF_OK;
272 : }
273 :
274 : //sets the enable flag of a track
275 : GF_EXPORT
276 0 : GF_Err gf_isom_set_track_flags(GF_ISOFile *movie, u32 trackNumber, u32 flags, GF_ISOMTrackFlagOp op)
277 : {
278 : GF_Err e;
279 : GF_TrackBox *trak;
280 :
281 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
282 : if (e) return e;
283 :
284 0 : trak = gf_isom_get_track_from_file(movie, trackNumber);
285 0 : if (!trak) return GF_BAD_PARAM;
286 0 : if (op==GF_ISOM_TKFLAGS_ADD)
287 0 : trak->Header->flags |= flags;
288 0 : else if (op==GF_ISOM_TKFLAGS_REM)
289 0 : trak->Header->flags &= ~flags;
290 : else
291 0 : trak->Header->flags = flags;
292 : return GF_OK;
293 : }
294 :
295 : GF_EXPORT
296 129 : GF_Err gf_isom_set_media_language(GF_ISOFile *movie, u32 trackNumber, char *code)
297 : {
298 : GF_Err e;
299 : GF_TrackBox *trak;
300 :
301 129 : trak = gf_isom_get_track_from_file(movie, trackNumber);
302 129 : if (!trak || !code) return GF_BAD_PARAM;
303 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
304 : if (e) return e;
305 :
306 : // Old language-storage processing
307 : // if the new code is on 3 chars, we use it
308 : // otherwise, we find the associated 3 chars code and use it
309 129 : if (strlen(code) == 3) {
310 98 : memcpy(trak->Media->mediaHeader->packedLanguage, code, sizeof(char)*3);
311 : } else {
312 : s32 lang_idx;
313 : const char *code_3cc;
314 31 : lang_idx = gf_lang_find(code);
315 31 : if (lang_idx == -1) {
316 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("The given code is not a valid one: %s, using 'und' as 3-letter code\n", code));
317 : code_3cc = "und";
318 : } else {
319 31 : code_3cc = gf_lang_get_3cc(lang_idx);
320 : }
321 31 : memcpy(trak->Media->mediaHeader->packedLanguage, code_3cc, sizeof(char)*3);
322 : }
323 :
324 : // New language-storage processing
325 : // change the code in the extended language box (if any)
326 : // otherwise add an extended language box only if the given code is not 3 chars
327 : {
328 : u32 i, count;
329 : GF_ExtendedLanguageBox *elng;
330 : elng = NULL;
331 129 : count = gf_list_count(trak->Media->child_boxes);
332 516 : for (i = 0; i < count; i++) {
333 387 : GF_Box *box = (GF_Box *)gf_list_get(trak->Media->child_boxes, i);
334 387 : if (box->type == GF_ISOM_BOX_TYPE_ELNG) {
335 : elng = (GF_ExtendedLanguageBox *)box;
336 : break;
337 : }
338 : }
339 129 : if (!elng && (strlen(code) > 3)) {
340 10 : elng = (GF_ExtendedLanguageBox *)gf_isom_box_new_parent(&trak->Media->child_boxes, GF_ISOM_BOX_TYPE_ELNG);
341 10 : if (!elng) return GF_OUT_OF_MEM;
342 : }
343 129 : if (elng) {
344 10 : if (elng->extended_language) {
345 0 : gf_free(elng->extended_language);
346 : }
347 10 : elng->extended_language = gf_strdup(code);
348 : }
349 : }
350 129 : if (!movie->keep_utc)
351 129 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
352 : return GF_OK;
353 : }
354 :
355 1230 : static GF_Err gf_isom_set_root_iod(GF_ISOFile *movie)
356 : {
357 : GF_IsomInitialObjectDescriptor *iod;
358 : GF_IsomObjectDescriptor *od;
359 : GF_Err e;
360 :
361 1230 : e = gf_isom_insert_moov(movie);
362 1230 : if (e) return e;
363 1230 : if (!movie->moov->iods) {
364 470 : AddMovieIOD(movie->moov, 1);
365 470 : return GF_OK;
366 : }
367 : //if OD, switch to IOD
368 760 : if (movie->moov->iods->descriptor->tag == GF_ODF_ISOM_IOD_TAG) return GF_OK;
369 : od = (GF_IsomObjectDescriptor *) movie->moov->iods->descriptor;
370 36 : iod = (GF_IsomInitialObjectDescriptor*)gf_malloc(sizeof(GF_IsomInitialObjectDescriptor));
371 36 : if (!iod) return GF_OUT_OF_MEM;
372 :
373 : memset(iod, 0, sizeof(GF_IsomInitialObjectDescriptor));
374 :
375 36 : iod->ES_ID_IncDescriptors = od->ES_ID_IncDescriptors;
376 36 : od->ES_ID_IncDescriptors = NULL;
377 : //not used in root OD
378 36 : iod->ES_ID_RefDescriptors = NULL;
379 36 : iod->extensionDescriptors = od->extensionDescriptors;
380 36 : od->extensionDescriptors = NULL;
381 36 : iod->IPMP_Descriptors = od->IPMP_Descriptors;
382 36 : od->IPMP_Descriptors = NULL;
383 36 : iod->objectDescriptorID = od->objectDescriptorID;
384 36 : iod->OCIDescriptors = od->OCIDescriptors;
385 36 : od->OCIDescriptors = NULL;
386 36 : iod->tag = GF_ODF_ISOM_IOD_TAG;
387 36 : iod->URLString = od->URLString;
388 36 : od->URLString = NULL;
389 :
390 36 : gf_odf_desc_del((GF_Descriptor *) od);
391 36 : movie->moov->iods->descriptor = (GF_Descriptor *)iod;
392 36 : return GF_OK;
393 : }
394 :
395 : GF_EXPORT
396 100 : GF_Err gf_isom_add_desc_to_root_od(GF_ISOFile *movie, const GF_Descriptor *theDesc)
397 : {
398 : GF_Err e;
399 : GF_Descriptor *desc, *dupDesc;
400 :
401 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
402 : if (e) return e;
403 100 : e = gf_isom_insert_moov(movie);
404 100 : if (e) return e;
405 :
406 100 : if (!movie->moov->iods) {
407 0 : e = AddMovieIOD(movie->moov, 0);
408 0 : if (e) return e;
409 : }
410 100 : if (theDesc->tag==GF_ODF_IPMP_TL_TAG) gf_isom_set_root_iod(movie);
411 :
412 100 : desc = movie->moov->iods->descriptor;
413 : //the type of desc is handled at the OD/IOD level, we'll be notified
414 : //if the desc is not allowed
415 100 : switch (desc->tag) {
416 100 : case GF_ODF_ISOM_IOD_TAG:
417 : case GF_ODF_ISOM_OD_TAG:
418 : //duplicate the desc
419 100 : e = gf_odf_desc_copy((GF_Descriptor *)theDesc, &dupDesc);
420 100 : if (e) return e;
421 : //add it (MUST BE (I)OD level desc)
422 100 : movie->LastError = gf_odf_desc_add_desc(desc, dupDesc);
423 100 : if (movie->LastError) gf_odf_desc_del((GF_Descriptor *)dupDesc);
424 : break;
425 0 : default:
426 0 : movie->LastError = GF_ISOM_INVALID_FILE;
427 0 : break;
428 : }
429 100 : return movie->LastError;
430 : }
431 :
432 :
433 : GF_EXPORT
434 1494 : GF_Err gf_isom_set_timescale(GF_ISOFile *movie, u32 timeScale)
435 : {
436 : GF_TrackBox *trak;
437 : u32 i;
438 : GF_Err e;
439 1494 : if (!timeScale) return GF_BAD_PARAM;
440 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
441 : if (e) return e;
442 1494 : e = gf_isom_insert_moov(movie);
443 1494 : if (e) return e;
444 :
445 1494 : if (movie->moov->mvhd->timeScale == timeScale) return GF_OK;
446 :
447 : /*rewrite all durations and edit lists*/
448 16 : movie->moov->mvhd->duration *= timeScale;
449 16 : movie->moov->mvhd->duration /= movie->moov->mvhd->timeScale;
450 16 : if (movie->moov->mvex && movie->moov->mvex->mehd) {
451 0 : movie->moov->mvex->mehd->fragment_duration *= timeScale;
452 0 : movie->moov->mvex->mehd->fragment_duration /= movie->moov->mvhd->timeScale;
453 : }
454 :
455 16 : i=0;
456 45 : while ((trak = (GF_TrackBox*)gf_list_enum(movie->moov->trackList, &i))) {
457 13 : trak->Header->duration *= timeScale;
458 13 : trak->Header->duration /= movie->moov->mvhd->timeScale;
459 :
460 13 : if (trak->editBox && trak->editBox->editList) {
461 12 : u32 j, count = gf_list_count(trak->editBox->editList->entryList);
462 24 : for (j=0; j<count; j++) {
463 12 : GF_EdtsEntry *ent = (GF_EdtsEntry *)gf_list_get(trak->editBox->editList->entryList, j);
464 12 : ent->segmentDuration *= timeScale;
465 12 : ent->segmentDuration /= movie->moov->mvhd->timeScale;
466 : }
467 : }
468 : }
469 16 : if (movie->moov->mvex && movie->moov->mvex->mehd) {
470 0 : movie->moov->mvex->mehd->fragment_duration *= timeScale;
471 0 : movie->moov->mvex->mehd->fragment_duration /= movie->moov->mvhd->timeScale;
472 : }
473 16 : movie->moov->mvhd->timeScale = timeScale;
474 16 : movie->interleavingTime = timeScale;
475 16 : return GF_OK;
476 : }
477 :
478 :
479 : GF_EXPORT
480 1230 : GF_Err gf_isom_set_pl_indication(GF_ISOFile *movie, GF_ISOProfileLevelType PL_Code, u8 ProfileLevel)
481 : {
482 : GF_IsomInitialObjectDescriptor *iod;
483 : GF_Err e;
484 :
485 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
486 : if (e) return e;
487 :
488 1230 : e = gf_isom_set_root_iod(movie);
489 1230 : if (e) return e;
490 :
491 1230 : iod = (GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor;
492 :
493 1230 : switch (PL_Code) {
494 475 : case GF_ISOM_PL_AUDIO:
495 475 : iod->audio_profileAndLevel = ProfileLevel;
496 475 : break;
497 86 : case GF_ISOM_PL_GRAPHICS:
498 86 : iod->graphics_profileAndLevel = ProfileLevel;
499 86 : break;
500 91 : case GF_ISOM_PL_OD:
501 91 : iod->OD_profileAndLevel = ProfileLevel;
502 91 : break;
503 86 : case GF_ISOM_PL_SCENE:
504 86 : iod->scene_profileAndLevel = ProfileLevel;
505 86 : break;
506 477 : case GF_ISOM_PL_VISUAL:
507 477 : iod->visual_profileAndLevel = ProfileLevel;
508 477 : break;
509 14 : case GF_ISOM_PL_INLINE:
510 14 : iod->inlineProfileFlag = ProfileLevel ? 1 : 0;
511 14 : break;
512 : default:
513 : break;
514 : }
515 : return GF_OK;
516 : }
517 :
518 : GF_EXPORT
519 34 : GF_Err gf_isom_set_root_od_id(GF_ISOFile *movie, u32 OD_ID)
520 : {
521 : GF_Err e;
522 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
523 : if (e) return e;
524 :
525 34 : e = gf_isom_insert_moov(movie);
526 34 : if (e) return e;
527 34 : if (!movie->moov->iods) {
528 0 : e = AddMovieIOD(movie->moov, 0);
529 0 : if (e) return e;
530 : }
531 :
532 34 : switch (movie->moov->iods->descriptor->tag) {
533 0 : case GF_ODF_ISOM_OD_TAG:
534 0 : ((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->objectDescriptorID = OD_ID;
535 0 : break;
536 34 : case GF_ODF_ISOM_IOD_TAG:
537 34 : ((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->objectDescriptorID = OD_ID;
538 34 : break;
539 : default:
540 : return GF_ISOM_INVALID_FILE;
541 : }
542 : return GF_OK;
543 : }
544 :
545 : GF_EXPORT
546 0 : GF_Err gf_isom_set_root_od_url(GF_ISOFile *movie, const char *url_string)
547 : {
548 : GF_Err e;
549 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
550 : if (e) return e;
551 0 : e = gf_isom_insert_moov(movie);
552 0 : if (e) return e;
553 :
554 0 : if (!movie->moov->iods) {
555 0 : e = AddMovieIOD(movie->moov, 0);
556 0 : if (e) return e;
557 : }
558 :
559 0 : switch (movie->moov->iods->descriptor->tag) {
560 0 : case GF_ODF_ISOM_OD_TAG:
561 0 : if (((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->URLString) gf_free(((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->URLString);
562 0 : ((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->URLString = url_string ? gf_strdup(url_string) : NULL;
563 0 : break;
564 0 : case GF_ODF_ISOM_IOD_TAG:
565 0 : if (((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->URLString) gf_free(((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->URLString);
566 0 : ((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->URLString = url_string ? gf_strdup(url_string) : NULL;
567 0 : break;
568 : default:
569 : return GF_ISOM_INVALID_FILE;
570 : }
571 : return GF_OK;
572 : }
573 :
574 : GF_EXPORT
575 604 : GF_ISOTrackID gf_isom_get_last_created_track_id(GF_ISOFile *movie)
576 : {
577 604 : return movie ? movie->last_created_track_id : 0;
578 : }
579 :
580 :
581 : GF_EXPORT
582 164 : GF_Err gf_isom_load_extra_boxes(GF_ISOFile *movie, u8 *moov_boxes, u32 moov_boxes_size, Bool udta_only)
583 : {
584 : GF_BitStream *bs;
585 :
586 : GF_Err e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
587 : if (e) return e;
588 164 : e = gf_isom_insert_moov(movie);
589 164 : if (e) return e;
590 :
591 164 : bs = gf_bs_new(moov_boxes, moov_boxes_size, GF_BITSTREAM_READ);
592 :
593 : //we may have terminators in some QT files (4 bytes set to 0 ...)
594 164 : while (gf_bs_available(bs) >= 8) {
595 : GF_Box *a_box;
596 229 : e = gf_isom_box_parse_ex((GF_Box**)&a_box, bs, GF_ISOM_BOX_TYPE_MOOV, GF_FALSE);
597 229 : if (e || !a_box) goto exit;
598 :
599 229 : if (a_box->type == GF_ISOM_BOX_TYPE_UDTA) {
600 0 : if (movie->moov->udta) gf_isom_box_del_parent(&movie->moov->child_boxes, (GF_Box*)movie->moov->udta);
601 0 : movie->moov->udta = (GF_UserDataBox*) a_box;
602 :
603 0 : if (!movie->moov->child_boxes) movie->moov->child_boxes = gf_list_new();
604 0 : gf_list_add(movie->moov->child_boxes, a_box);
605 :
606 229 : } else if (!udta_only && (a_box->type!=GF_ISOM_BOX_TYPE_PSSH) ) {
607 0 : if (!movie->moov->child_boxes) movie->moov->child_boxes = gf_list_new();
608 0 : gf_list_add(movie->moov->child_boxes, a_box);
609 : } else {
610 229 : gf_isom_box_del(a_box);
611 : }
612 : }
613 164 : exit:
614 164 : gf_bs_del(bs);
615 164 : return e;
616 : }
617 :
618 : //creates a new Track. If trackID = 0, the trackID is chosen by the API
619 : //returns the track number or 0 if error
620 : GF_EXPORT
621 1639 : u32 gf_isom_new_track_from_template(GF_ISOFile *movie, GF_ISOTrackID trakID, u32 MediaType, u32 TimeScale, u8 *tk_box, u32 tk_box_size, Bool udta_only)
622 : {
623 : GF_Err e;
624 : u64 now;
625 : u8 isHint;
626 : GF_TrackBox *trak;
627 : GF_TrackHeaderBox *tkhd;
628 : GF_MediaBox *mdia;
629 : GF_UserDataBox *udta = NULL;
630 :
631 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
632 : if (e) {
633 0 : gf_isom_set_last_error(movie, e);
634 0 : return 0;
635 : }
636 1639 : e = gf_isom_insert_moov(movie);
637 1639 : if (e) return e;
638 :
639 :
640 : isHint = 0;
641 : //we're creating a hint track... it's the same, but mode HAS TO BE EDIT
642 1639 : if (MediaType == GF_ISOM_MEDIA_HINT) {
643 : // if (movie->openMode != GF_ISOM_OPEN_EDIT) return 0;
644 : isHint = 1;
645 : }
646 :
647 1639 : mdia = NULL;
648 : tkhd = NULL;
649 1639 : trak = NULL;
650 1639 : if (trakID) {
651 : //check if we are in ES_ID boundaries
652 1506 : if (!isHint && (trakID > 0xFFFF)) {
653 0 : gf_isom_set_last_error(movie, GF_BAD_PARAM);
654 0 : return 0;
655 : }
656 : //here we should look for available IDs ...
657 1506 : if (!RequestTrack(movie->moov, trakID)) return 0;
658 : } else {
659 133 : trakID = movie->moov->mvhd->nextTrackID;
660 133 : if (!trakID) trakID = 1;
661 : /*ESIDs are on 16 bits*/
662 133 : if (! isHint && (trakID > 0xFFFF)) trakID = 1;
663 :
664 : while (1) {
665 133 : if (RequestTrack(movie->moov, trakID)) break;
666 0 : trakID += 1;
667 0 : if (trakID == 0xFFFFFFFF) break;
668 : }
669 133 : if (trakID == 0xFFFFFFFF) {
670 0 : gf_isom_set_last_error(movie, GF_BAD_PARAM);
671 0 : return 0;
672 : }
673 133 : if (! isHint && (trakID > 0xFFFF)) {
674 0 : gf_isom_set_last_error(movie, GF_BAD_PARAM);
675 0 : return 0;
676 : }
677 : }
678 :
679 1626 : if (tk_box) {
680 615 : GF_BitStream *bs = gf_bs_new(tk_box, tk_box_size, GF_BITSTREAM_READ);
681 615 : gf_bs_set_cookie(bs, GF_ISOM_BS_COOKIE_NO_LOGS|GF_ISOM_BS_COOKIE_CLONE_TRACK);
682 :
683 615 : e = gf_isom_box_parse_ex((GF_Box**)&trak, bs, GF_ISOM_BOX_TYPE_MOOV, GF_FALSE);
684 615 : gf_bs_del(bs);
685 615 : if (e) trak = NULL;
686 615 : else if (udta_only) {
687 0 : udta = trak->udta;
688 0 : trak->udta = NULL;
689 0 : gf_isom_box_del((GF_Box*)trak);
690 : } else {
691 : Bool tpl_ok = GF_TRUE;
692 615 : if (!trak->Header || !trak->Media || !trak->Media->handler || !trak->Media->mediaHeader || !trak->Media->information) tpl_ok = GF_FALSE;
693 :
694 : else {
695 615 : if (!MediaType) MediaType = trak->Media->handler->handlerType;
696 615 : e = NewMedia(&trak->Media, MediaType, TimeScale);
697 615 : if (e) tpl_ok = GF_FALSE;
698 : }
699 : if (!tpl_ok) {
700 0 : udta = trak->udta;
701 0 : trak->udta = NULL;
702 0 : gf_isom_box_del((GF_Box*)trak);
703 : }
704 : }
705 : }
706 1626 : now = gf_isom_get_mp4time();
707 1626 : if (!trak) {
708 : //OK, now create a track...
709 1011 : trak = (GF_TrackBox *) gf_isom_box_new_parent(&movie->moov->child_boxes, GF_ISOM_BOX_TYPE_TRAK);
710 1011 : if (!trak) {
711 0 : gf_isom_set_last_error(movie, GF_OUT_OF_MEM);
712 0 : return 0;
713 : }
714 1011 : tkhd = (GF_TrackHeaderBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_TKHD);
715 1011 : if (!tkhd) {
716 0 : gf_isom_set_last_error(movie, GF_OUT_OF_MEM);
717 0 : return 0;
718 : }
719 :
720 : //OK, set up the media trak
721 1011 : e = NewMedia(&mdia, MediaType, TimeScale);
722 1011 : if (e) {
723 0 : gf_isom_box_del((GF_Box *)mdia);
724 0 : return 0;
725 : }
726 : assert(trak->child_boxes);
727 1011 : gf_list_add(trak->child_boxes, mdia);
728 :
729 : //OK, add this media to our track
730 1011 : mdia->mediaTrack = trak;
731 :
732 1011 : e = trak_on_child_box((GF_Box*)trak, (GF_Box *) tkhd, GF_FALSE);
733 1011 : if (e) goto err_exit;
734 1011 : e = trak_on_child_box((GF_Box*)trak, (GF_Box *) mdia, GF_FALSE);
735 1011 : if (e) goto err_exit;
736 1011 : tkhd->trackID = trakID;
737 :
738 1011 : if (gf_sys_is_test_mode() ) {
739 1010 : tkhd->creationTime = 0;
740 1010 : mdia->mediaHeader->creationTime = 0;
741 : } else {
742 1 : tkhd->creationTime = now;
743 1 : mdia->mediaHeader->creationTime = now;
744 : }
745 :
746 : } else {
747 615 : tkhd = trak->Header;
748 615 : tkhd->trackID = trakID;
749 615 : mdia = trak->Media;
750 615 : mdia->mediaTrack = trak;
751 615 : mdia->mediaHeader->timeScale = TimeScale;
752 615 : if (mdia->handler->handlerType != MediaType) {
753 0 : mdia->handler->handlerType = MediaType;
754 0 : tkhd->width = 0;
755 0 : tkhd->height = 0;
756 0 : tkhd->volume = 0;
757 : } else {
758 : MediaType = 0;
759 : }
760 615 : trak->Header->duration = 0;
761 615 : mdia->mediaHeader->duration = 0;
762 :
763 615 : if (!movie->moov->child_boxes) movie->moov->child_boxes = gf_list_new();
764 615 : gf_list_add(movie->moov->child_boxes, trak);
765 : }
766 1626 : if (MediaType) {
767 : //some default properties for Audio, Visual or private tracks
768 1011 : switch (MediaType) {
769 689 : case GF_ISOM_MEDIA_VISUAL:
770 : case GF_ISOM_MEDIA_AUXV:
771 : case GF_ISOM_MEDIA_PICT:
772 : case GF_ISOM_MEDIA_SCENE:
773 : case GF_ISOM_MEDIA_TEXT:
774 : case GF_ISOM_MEDIA_SUBT:
775 : /*320-240 pix in 16.16*/
776 689 : tkhd->width = 0x01400000;
777 689 : tkhd->height = 0x00F00000;
778 689 : break;
779 179 : case GF_ISOM_MEDIA_AUDIO:
780 179 : tkhd->volume = 0x0100;
781 179 : break;
782 : }
783 : }
784 1626 : movie->last_created_track_id = tkhd->trackID;
785 :
786 1626 : if (!movie->keep_utc && !gf_sys_is_test_mode() ) {
787 1 : tkhd->modificationTime = now;
788 1 : mdia->mediaHeader->modificationTime = now;
789 : }
790 :
791 : //OK, add our trak
792 1626 : e = moov_on_child_box((GF_Box*)movie->moov, (GF_Box *)trak, GF_FALSE);
793 1626 : if (e) goto err_exit;
794 : //set the new ID available
795 1626 : if (trakID+1> movie->moov->mvhd->nextTrackID)
796 1556 : movie->moov->mvhd->nextTrackID = trakID+1;
797 :
798 1626 : trak->udta = udta;
799 :
800 : //and return our track number
801 1626 : return gf_isom_get_track_by_id(movie, trakID);
802 :
803 0 : err_exit:
804 : //tkhd is registered with track and will be destroyed there
805 0 : if (trak) gf_isom_box_del((GF_Box *)trak);
806 0 : if (mdia) gf_isom_box_del((GF_Box *)mdia);
807 : return 0;
808 : }
809 :
810 : GF_EXPORT
811 1024 : u32 gf_isom_new_track(GF_ISOFile *movie, GF_ISOTrackID trakID, u32 MediaType, u32 TimeScale)
812 : {
813 1024 : return gf_isom_new_track_from_template(movie, trakID, MediaType, TimeScale, NULL, 0, GF_FALSE);
814 : }
815 :
816 : GF_EXPORT
817 19 : GF_Err gf_isom_remove_stream_description(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex)
818 : {
819 : GF_TrackBox *trak;
820 : GF_Err e;
821 : GF_SampleEntryBox *entry;
822 :
823 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
824 : if (e) return e;
825 :
826 19 : trak = gf_isom_get_track_from_file(movie, trackNumber);
827 19 : if (!trak || !trak->Media) return GF_BAD_PARAM;
828 :
829 19 : if (!movie->keep_utc)
830 19 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
831 :
832 19 : entry = (GF_SampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, StreamDescriptionIndex - 1);
833 19 : if (!entry) return GF_BAD_PARAM;
834 19 : gf_list_rem(trak->Media->information->sampleTable->SampleDescription->child_boxes, StreamDescriptionIndex - 1);
835 19 : gf_isom_box_del((GF_Box *)entry);
836 19 : return GF_OK;
837 : }
838 :
839 : //Create a new StreamDescription in the file. The URL and URN are used to describe external media
840 : GF_EXPORT
841 495 : GF_Err gf_isom_new_mpeg4_description(GF_ISOFile *movie,
842 : u32 trackNumber,
843 : const GF_ESD *esd,
844 : const char *URLname,
845 : const char *URNname,
846 : u32 *outDescriptionIndex)
847 : {
848 : GF_TrackBox *trak;
849 : GF_Err e;
850 : u32 dataRefIndex;
851 : GF_ESD *new_esd;
852 :
853 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
854 : if (e) return e;
855 :
856 495 : trak = gf_isom_get_track_from_file(movie, trackNumber);
857 495 : if (!trak || !trak->Media ||
858 990 : !esd || !esd->decoderConfig ||
859 495 : !esd->slConfig) return GF_BAD_PARAM;
860 :
861 : //get or create the data ref
862 495 : e = Media_FindDataRef(trak->Media->information->dataInformation->dref, (char *)URLname, (char *)URNname, &dataRefIndex);
863 495 : if (e) return e;
864 495 : if (!dataRefIndex) {
865 495 : e = Media_CreateDataRef(movie, trak->Media->information->dataInformation->dref, (char *)URLname, (char *)URNname, &dataRefIndex);
866 495 : if (e) return e;
867 : }
868 : //duplicate our desc
869 495 : e = gf_odf_desc_copy((GF_Descriptor *)esd, (GF_Descriptor **)&new_esd);
870 495 : if (e) return e;
871 495 : if (!movie->keep_utc)
872 495 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
873 495 : e = Track_SetStreamDescriptor(trak, 0, dataRefIndex, new_esd, outDescriptionIndex);
874 495 : if (e) {
875 0 : gf_odf_desc_del((GF_Descriptor *)new_esd);
876 0 : return e;
877 : }
878 : return e;
879 : }
880 :
881 43 : GF_Err gf_isom_flush_chunk(GF_TrackBox *trak, Bool is_final)
882 : {
883 : GF_Err e;
884 : u64 data_offset;
885 : u32 sample_number;
886 : u8 *chunk_data;
887 : u32 chunk_size, chunk_alloc;
888 43 : if (!trak->chunk_cache) return GF_OK;
889 :
890 43 : gf_bs_get_content_no_truncate(trak->chunk_cache, &chunk_data, &chunk_size, &chunk_alloc);
891 :
892 43 : data_offset = gf_isom_datamap_get_offset(trak->Media->information->dataHandler);
893 :
894 43 : e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, chunk_data, chunk_size);
895 43 : if (e) return e;
896 :
897 43 : sample_number = 1 + trak->Media->information->sampleTable->SampleSize->sampleCount;
898 43 : sample_number -= trak->nb_samples_in_cache;
899 :
900 43 : e = stbl_AddChunkOffset(trak->Media, sample_number, trak->chunk_stsd_idx, data_offset, trak->nb_samples_in_cache);
901 :
902 43 : if (is_final) {
903 4 : gf_free(chunk_data);
904 4 : gf_bs_del(trak->chunk_cache);
905 4 : trak->chunk_cache = NULL;
906 : } else {
907 39 : gf_bs_reassign_buffer(trak->chunk_cache, chunk_data, chunk_alloc);
908 : }
909 : return e;
910 : }
911 :
912 556199 : static GF_Err trak_add_sample(GF_ISOFile *movie, GF_TrackBox *trak, const GF_ISOSample *sample, u32 descIndex, u64 data_offset, u32 syncShadowSampleNum)
913 : {
914 : Bool skip_data = GF_FALSE;
915 : GF_Err e;
916 :
917 : //faststart mode with interleaving time, cache data until we have a full chunk
918 556199 : if ((movie->storageMode==GF_ISOM_STORE_FASTSTART) && movie->interleavingTime) {
919 : Bool flush_chunk = GF_FALSE;
920 1006 : u64 stime = sample->DTS;
921 1006 : stime *= movie->moov->mvhd->timeScale;
922 1006 : stime /= trak->Media->mediaHeader->timeScale;
923 :
924 1006 : if (stime - trak->first_dts_chunk > movie->interleavingTime)
925 : flush_chunk = GF_TRUE;
926 :
927 1006 : if (movie->next_flush_chunk_time < stime)
928 : flush_chunk = GF_TRUE;
929 :
930 1006 : if (trak->chunk_stsd_idx != descIndex)
931 : flush_chunk = GF_TRUE;
932 :
933 1006 : if (trak->Media->information->sampleTable->MaxChunkSize && trak->Media->information->sampleTable->MaxChunkSize < trak->chunk_cache_size + sample->dataLength)
934 : flush_chunk = GF_TRUE;
935 :
936 1006 : if (flush_chunk) {
937 43 : movie->next_flush_chunk_time = stime + movie->interleavingTime;
938 43 : if (trak->chunk_cache) {
939 39 : e = gf_isom_flush_chunk(trak, GF_FALSE);
940 39 : if (e) return e;
941 : }
942 43 : trak->nb_samples_in_cache = 0;
943 43 : trak->chunk_cache_size = 0;
944 43 : trak->first_dts_chunk = stime;
945 : }
946 1006 : if (!trak->chunk_cache)
947 4 : trak->chunk_cache = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
948 1006 : gf_bs_write_data(trak->chunk_cache, sample->data, sample->dataLength);
949 1006 : trak->nb_samples_in_cache += sample->nb_pack ? sample->nb_pack : 1;
950 1006 : trak->chunk_cache_size += sample->dataLength;
951 1006 : trak->chunk_stsd_idx = descIndex;
952 :
953 : skip_data = GF_TRUE;
954 : }
955 :
956 556199 : e = Media_AddSample(trak->Media, data_offset, sample, descIndex, syncShadowSampleNum);
957 556199 : if (e) return e;
958 :
959 556199 : if (!skip_data && sample->dataLength) {
960 555193 : e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, sample->data, sample->dataLength);
961 555193 : if (e) return e;
962 : }
963 :
964 : return GF_OK;
965 : }
966 :
967 : //Add samples to a track. Use streamDescriptionIndex to specify the desired stream (if several)
968 : GF_EXPORT
969 556187 : GF_Err gf_isom_add_sample(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, const GF_ISOSample *sample)
970 : {
971 : GF_Err e;
972 : GF_TrackBox *trak;
973 : GF_SampleEntryBox *entry;
974 : u32 dataRefIndex;
975 : u64 data_offset;
976 : u32 descIndex;
977 : GF_DataEntryURLBox *Dentry;
978 :
979 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
980 : if (e) return e;
981 :
982 556187 : trak = gf_isom_get_track_from_file(movie, trackNumber);
983 556187 : if (!trak) return GF_BAD_PARAM;
984 :
985 556187 : e = FlushCaptureMode(movie);
986 556187 : if (e) return e;
987 :
988 556187 : e = unpack_track(trak);
989 556187 : if (e) return e;
990 :
991 : //OK, add the sample
992 : //1- Get the streamDescriptionIndex and dataRefIndex
993 : //not specified, get the latest used...
994 : descIndex = StreamDescriptionIndex;
995 556187 : if (!StreamDescriptionIndex) {
996 0 : descIndex = trak->Media->information->sampleTable->currentEntryIndex;
997 : }
998 556187 : e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
999 556187 : if (e) return e;
1000 556187 : if (!entry || !dataRefIndex) return GF_BAD_PARAM;
1001 : //set the current to this one
1002 556187 : trak->Media->information->sampleTable->currentEntryIndex = descIndex;
1003 :
1004 :
1005 : //get this dataRef and return false if not self contained
1006 556187 : Dentry = (GF_DataEntryURLBox*)gf_list_get(trak->Media->information->dataInformation->dref->child_boxes, dataRefIndex - 1);
1007 556187 : if (!Dentry || Dentry->flags != 1) return GF_BAD_PARAM;
1008 :
1009 : //Open our data map. We are adding stuff, so use EDIT
1010 556187 : e = gf_isom_datamap_open(trak->Media, dataRefIndex, 1);
1011 556187 : if (e) return e;
1012 :
1013 : //Get the offset...
1014 556187 : data_offset = gf_isom_datamap_get_offset(trak->Media->information->dataHandler);
1015 :
1016 : /*rewrite OD frame*/
1017 556187 : if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
1018 73 : GF_ISOSample *od_sample = NULL;
1019 :
1020 73 : e = Media_ParseODFrame(trak->Media, sample, &od_sample);
1021 73 : if (e) return e;
1022 :
1023 73 : e = trak_add_sample(movie, trak, od_sample, descIndex, data_offset, 0);
1024 :
1025 73 : if (od_sample)
1026 73 : gf_isom_sample_del(&od_sample);
1027 : } else {
1028 556114 : e = trak_add_sample(movie, trak, sample, descIndex, data_offset, 0);
1029 : }
1030 556187 : if (e) return e;
1031 :
1032 :
1033 556187 : if (!movie->keep_utc)
1034 556187 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
1035 556187 : return SetTrackDuration(trak);
1036 : }
1037 :
1038 : GF_EXPORT
1039 12 : GF_Err gf_isom_add_sample_shadow(GF_ISOFile *movie, u32 trackNumber, GF_ISOSample *sample)
1040 : {
1041 : GF_Err e;
1042 : GF_TrackBox *trak;
1043 : GF_ISOSample *prev;
1044 : GF_SampleEntryBox *entry;
1045 : u32 dataRefIndex;
1046 : u64 data_offset;
1047 : u32 descIndex;
1048 : u32 sampleNum, prevSampleNum;
1049 : GF_DataEntryURLBox *Dentry;
1050 : Bool offset_times = GF_FALSE;
1051 :
1052 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
1053 : if (e) return e;
1054 :
1055 12 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1056 12 : if (!trak || !sample) return GF_BAD_PARAM;
1057 :
1058 12 : e = FlushCaptureMode(movie);
1059 12 : if (e) return e;
1060 :
1061 12 : e = unpack_track(trak);
1062 12 : if (e) return e;
1063 :
1064 12 : e = stbl_findEntryForTime(trak->Media->information->sampleTable, sample->DTS, 0, &sampleNum, &prevSampleNum);
1065 12 : if (e) return e;
1066 : /*we need the EXACT match*/
1067 12 : if (!sampleNum) return GF_BAD_PARAM;
1068 :
1069 12 : prev = gf_isom_get_sample_info(movie, trackNumber, sampleNum, &descIndex, NULL);
1070 12 : if (!prev) return gf_isom_last_error(movie);
1071 : /*for conformance*/
1072 12 : if (sample->DTS==prev->DTS) offset_times = GF_TRUE;
1073 12 : gf_isom_sample_del(&prev);
1074 :
1075 12 : e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
1076 12 : if (e) return e;
1077 12 : if (!entry || !dataRefIndex) return GF_BAD_PARAM;
1078 12 : trak->Media->information->sampleTable->currentEntryIndex = descIndex;
1079 :
1080 : //get this dataRef and return false if not self contained
1081 12 : Dentry = (GF_DataEntryURLBox*)gf_list_get(trak->Media->information->dataInformation->dref->child_boxes, dataRefIndex - 1);
1082 12 : if (!Dentry || Dentry->flags != 1) return GF_BAD_PARAM;
1083 :
1084 : //Open our data map. We are adding stuff, so use EDIT
1085 12 : e = gf_isom_datamap_open(trak->Media, dataRefIndex, 1);
1086 12 : if (e) return e;
1087 :
1088 12 : data_offset = gf_isom_datamap_get_offset(trak->Media->information->dataHandler);
1089 12 : if (offset_times) sample->DTS += 1;
1090 :
1091 : /*REWRITE ANY OD STUFF*/
1092 12 : if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
1093 3 : GF_ISOSample *od_sample = NULL;
1094 3 : e = Media_ParseODFrame(trak->Media, sample, &od_sample);
1095 3 : if (e) return e;
1096 :
1097 3 : e = trak_add_sample(movie, trak, od_sample, descIndex, data_offset, sampleNum);
1098 3 : if (od_sample)
1099 3 : gf_isom_sample_del(&od_sample);
1100 : } else {
1101 9 : e = trak_add_sample(movie, trak, sample, descIndex, data_offset, sampleNum);
1102 : }
1103 12 : if (e) return e;
1104 12 : if (offset_times) sample->DTS -= 1;
1105 :
1106 : //OK, update duration
1107 12 : e = Media_SetDuration(trak);
1108 12 : if (e) return e;
1109 12 : if (!movie->keep_utc)
1110 12 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
1111 12 : return SetTrackDuration(trak);
1112 : }
1113 :
1114 : GF_EXPORT
1115 701 : GF_Err gf_isom_append_sample_data(GF_ISOFile *movie, u32 trackNumber, u8 *data, u32 data_size)
1116 : {
1117 : GF_Err e;
1118 : GF_TrackBox *trak;
1119 : GF_SampleEntryBox *entry;
1120 : u32 dataRefIndex;
1121 : u32 descIndex;
1122 : GF_DataEntryURLBox *Dentry;
1123 :
1124 701 : if (!data_size) return GF_OK;
1125 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
1126 : if (e) return e;
1127 :
1128 701 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1129 701 : if (!trak) return GF_BAD_PARAM;
1130 :
1131 701 : if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) return GF_BAD_PARAM;
1132 :
1133 : //OK, add the sample
1134 701 : descIndex = trak->Media->information->sampleTable->currentEntryIndex;
1135 :
1136 701 : e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
1137 701 : if (e) return e;
1138 701 : if (!entry || !dataRefIndex) return GF_BAD_PARAM;
1139 :
1140 : //get this dataRef and return false if not self contained
1141 701 : Dentry = (GF_DataEntryURLBox*)gf_list_get(trak->Media->information->dataInformation->dref->child_boxes, dataRefIndex - 1);
1142 701 : if (!Dentry || Dentry->flags != 1) return GF_BAD_PARAM;
1143 :
1144 : //Open our data map. We are adding stuff, so use EDIT
1145 701 : e = gf_isom_datamap_open(trak->Media, dataRefIndex, 1);
1146 701 : if (e) return e;
1147 :
1148 : //add the media data
1149 701 : if (trak->chunk_cache) {
1150 0 : gf_bs_write_data(trak->chunk_cache, data, data_size);
1151 0 : trak->chunk_cache_size += data_size;
1152 : } else {
1153 701 : e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, data, data_size);
1154 701 : if (e) return e;
1155 : }
1156 : //update data size
1157 701 : return stbl_SampleSizeAppend(trak->Media->information->sampleTable->SampleSize, data_size);
1158 : }
1159 :
1160 :
1161 : //Add sample reference to a track. The SampleOffset is the offset of the data in the referenced file
1162 : //you must have created a StreamDescription with URL or URN specifying your referenced file
1163 : //the data offset specifies the beginning of the chunk
1164 : //Use streamDescriptionIndex to specify the desired stream (if several)
1165 : GF_EXPORT
1166 514 : GF_Err gf_isom_add_sample_reference(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_ISOSample *sample, u64 dataOffset)
1167 : {
1168 : GF_TrackBox *trak;
1169 : GF_SampleEntryBox *entry;
1170 : u32 dataRefIndex;
1171 : u32 descIndex;
1172 : GF_DataEntryURLBox *Dentry;
1173 : GF_Err e;
1174 :
1175 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
1176 : if (e) return e;
1177 :
1178 514 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1179 514 : if (!trak) return GF_BAD_PARAM;
1180 :
1181 514 : e = unpack_track(trak);
1182 514 : if (e) return e;
1183 :
1184 : //OD is not allowed as a data ref
1185 514 : if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
1186 : return GF_BAD_PARAM;
1187 : }
1188 : //OK, add the sample
1189 : //1- Get the streamDescriptionIndex and dataRefIndex
1190 : //not specified, get the latest used...
1191 : descIndex = StreamDescriptionIndex;
1192 514 : if (!StreamDescriptionIndex) {
1193 0 : descIndex = trak->Media->information->sampleTable->currentEntryIndex;
1194 : }
1195 514 : e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
1196 514 : if (e) return e;
1197 514 : if (!entry || !dataRefIndex) return GF_BAD_PARAM;
1198 : //set the current to this one
1199 514 : trak->Media->information->sampleTable->currentEntryIndex = descIndex;
1200 :
1201 :
1202 : //get this dataRef and return false if self contained
1203 514 : Dentry =(GF_DataEntryURLBox*) gf_list_get(trak->Media->information->dataInformation->dref->child_boxes, dataRefIndex - 1);
1204 514 : if (Dentry->flags == 1) return GF_BAD_PARAM;
1205 :
1206 : //add the meta data
1207 514 : e = Media_AddSample(trak->Media, dataOffset, sample, descIndex, 0);
1208 514 : if (e) return e;
1209 :
1210 514 : if (!movie->keep_utc)
1211 514 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
1212 : //OK, update duration
1213 514 : e = Media_SetDuration(trak);
1214 514 : if (e) return e;
1215 514 : return SetTrackDuration(trak);
1216 :
1217 : }
1218 :
1219 : //set the duration of the last media sample. If not set, the duration of the last sample is the
1220 : //duration of the previous one if any, or 1000 (default value).
1221 450437 : static GF_Err gf_isom_set_last_sample_duration_internal(GF_ISOFile *movie, u32 trackNumber, u64 dur_num, u32 dur_den, u32 mode)
1222 : {
1223 : GF_TrackBox *trak;
1224 : GF_SttsEntry *ent;
1225 : GF_TimeToSampleBox *stts;
1226 : u64 mdur;
1227 : u32 duration;
1228 : GF_Err e;
1229 : Bool is_patch = GF_FALSE;
1230 :
1231 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
1232 : if (e) return e;
1233 :
1234 450437 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1235 450437 : if (!trak) return GF_BAD_PARAM;
1236 :
1237 450437 : if (mode==0) {
1238 450432 : duration = (u32) dur_num;
1239 5 : } else if (mode==1) {
1240 1 : duration = (u32) dur_num;
1241 1 : if (dur_den) {
1242 1 : duration *= trak->Media->mediaHeader->timeScale;
1243 1 : duration /= dur_den;
1244 : }
1245 : } else {
1246 : is_patch = GF_TRUE;
1247 : }
1248 450437 : mdur = trak->Media->mediaHeader->duration;
1249 450437 : stts = trak->Media->information->sampleTable->TimeToSample;
1250 450437 : if (!stts->nb_entries) return GF_BAD_PARAM;
1251 :
1252 450436 : if (is_patch) {
1253 : u32 i, avg_dur, nb_samp=0;
1254 : u64 cum_dur=0;
1255 4 : for (i=0; i<stts->nb_entries; i++) {
1256 4 : ent = (GF_SttsEntry*) &stts->entries[i];
1257 4 : cum_dur += ent->sampleCount*ent->sampleDelta;
1258 4 : nb_samp += ent->sampleCount;
1259 : }
1260 4 : if (cum_dur <= dur_num || !nb_samp) return GF_OK;
1261 4 : avg_dur = (u32) (dur_num / nb_samp);
1262 :
1263 4 : stts->entries[0].sampleDelta = avg_dur;
1264 4 : for (i=1; i<stts->nb_entries; i++) {
1265 0 : stts->entries[0].sampleCount += stts->entries[i].sampleCount;
1266 : }
1267 4 : stts->nb_entries = 1;
1268 4 : stts->w_LastDTS = dur_num - avg_dur;
1269 4 : return GF_OK;
1270 : }
1271 : //get the last entry
1272 450432 : ent = (GF_SttsEntry*) &stts->entries[stts->nb_entries-1];
1273 450432 : if ((mode==1) && !duration && !dur_den) {
1274 : //same as previous, nothing to adjust
1275 0 : if (ent->sampleCount>1) return GF_OK;
1276 0 : if (stts->nb_entries==1) return GF_OK;
1277 0 : duration = stts->entries[stts->nb_entries-2].sampleDelta;
1278 : }
1279 :
1280 450432 : mdur -= ent->sampleDelta;
1281 450432 : mdur += duration;
1282 :
1283 : //we only have one sample
1284 450432 : if (ent->sampleCount == 1) {
1285 1131 : ent->sampleDelta = (u32) duration;
1286 1131 : if (mode && (stts->nb_entries>1) && (stts->entries[stts->nb_entries-2].sampleDelta==duration)) {
1287 0 : stts->entries[stts->nb_entries-2].sampleCount++;
1288 0 : stts->nb_entries--;
1289 : //and update the write cache
1290 0 : stts->w_currentSampleNum = trak->Media->information->sampleTable->SampleSize->sampleCount;
1291 : }
1292 : } else {
1293 449301 : if (ent->sampleDelta == duration) return GF_OK;
1294 16281 : ent->sampleCount -= 1;
1295 :
1296 16281 : if (stts->nb_entries==stts->alloc_size) {
1297 2730 : stts->alloc_size++;
1298 2730 : stts->entries = (GF_SttsEntry*)gf_realloc(stts->entries, sizeof(GF_SttsEntry)*stts->alloc_size);
1299 2730 : if (!stts->entries) return GF_OUT_OF_MEM;
1300 : }
1301 16281 : stts->entries[stts->nb_entries].sampleCount = 1;
1302 16281 : stts->entries[stts->nb_entries].sampleDelta = (u32) duration;
1303 16281 : stts->nb_entries++;
1304 : //and update the write cache
1305 16281 : stts->w_currentSampleNum = trak->Media->information->sampleTable->SampleSize->sampleCount;
1306 : }
1307 17412 : if (!movie->keep_utc)
1308 17412 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
1309 17412 : trak->Media->mediaHeader->duration = mdur;
1310 17412 : return SetTrackDuration(trak);
1311 : }
1312 :
1313 : GF_EXPORT
1314 450432 : GF_Err gf_isom_set_last_sample_duration(GF_ISOFile *movie, u32 trackNumber, u32 duration)
1315 : {
1316 450432 : return gf_isom_set_last_sample_duration_internal(movie, trackNumber, duration, 0, 0);
1317 : }
1318 :
1319 : GF_EXPORT
1320 4 : GF_Err gf_isom_patch_last_sample_duration(GF_ISOFile *movie, u32 trackNumber, u64 next_dts)
1321 : {
1322 4 : return gf_isom_set_last_sample_duration_internal(movie, trackNumber, next_dts, 0, 2);
1323 : }
1324 :
1325 : GF_EXPORT
1326 1 : GF_Err gf_isom_set_last_sample_duration_ex(GF_ISOFile *movie, u32 trackNumber, u32 dur_num, u32 dur_den)
1327 : {
1328 1 : return gf_isom_set_last_sample_duration_internal(movie, trackNumber, dur_num, dur_den, 1);
1329 : }
1330 :
1331 : //update a sample data in the media. Note that the sample MUST exists
1332 : GF_EXPORT
1333 4677 : GF_Err gf_isom_update_sample(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber, GF_ISOSample *sample, Bool data_only)
1334 : {
1335 : GF_Err e;
1336 : GF_TrackBox *trak;
1337 :
1338 : e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
1339 : if (e) return e;
1340 :
1341 4677 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1342 4677 : if (!trak) return GF_BAD_PARAM;
1343 :
1344 4677 : e = unpack_track(trak);
1345 4677 : if (e) return e;
1346 :
1347 : //block for hint tracks
1348 4677 : if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_HINT) return GF_BAD_PARAM;
1349 :
1350 : //REWRITE ANY OD STUFF
1351 4677 : if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
1352 0 : GF_ISOSample *od_sample = NULL;
1353 0 : e = Media_ParseODFrame(trak->Media, sample, &od_sample);
1354 0 : if (!e) e = Media_UpdateSample(trak->Media, sampleNumber, od_sample, data_only);
1355 0 : if (od_sample) gf_isom_sample_del(&od_sample);
1356 : } else {
1357 4677 : e = Media_UpdateSample(trak->Media, sampleNumber, sample, data_only);
1358 : }
1359 4677 : if (e) return e;
1360 4677 : if (!movie->keep_utc)
1361 4677 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
1362 :
1363 4677 : gf_isom_disable_inplace_rewrite(movie);
1364 4677 : return GF_OK;
1365 : }
1366 :
1367 : //update a sample data in the media. Note that the sample MUST exists,
1368 : //that sample->data MUST be NULL and sample->dataLength must be NON NULL;
1369 : GF_EXPORT
1370 0 : GF_Err gf_isom_update_sample_reference(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber, GF_ISOSample *sample, u64 data_offset)
1371 : {
1372 : GF_Err e;
1373 : GF_TrackBox *trak;
1374 :
1375 : e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
1376 : if (e) return e;
1377 :
1378 0 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1379 0 : if (!trak) return GF_BAD_PARAM;
1380 :
1381 : //block for hint tracks
1382 0 : if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_HINT) return GF_BAD_PARAM;
1383 :
1384 0 : if (!sampleNumber || !sample) return GF_BAD_PARAM;
1385 :
1386 0 : e = unpack_track(trak);
1387 0 : if (e) return e;
1388 :
1389 : //OD is not allowed as a data ref
1390 0 : if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
1391 : return GF_BAD_PARAM;
1392 : }
1393 : //OK, update it
1394 0 : e = Media_UpdateSampleReference(trak->Media, sampleNumber, sample, data_offset);
1395 0 : if (e) return e;
1396 :
1397 0 : if (!movie->keep_utc)
1398 0 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
1399 : return GF_OK;
1400 : }
1401 :
1402 :
1403 : //Remove a given sample
1404 : GF_EXPORT
1405 489 : GF_Err gf_isom_remove_sample(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber)
1406 : {
1407 : GF_Err e;
1408 : GF_TrackBox *trak;
1409 :
1410 : e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
1411 : if (e) return e;
1412 :
1413 487 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1414 487 : if (!trak || !sampleNumber || (sampleNumber > trak->Media->information->sampleTable->SampleSize->sampleCount) )
1415 : return GF_BAD_PARAM;
1416 :
1417 : //block for hint tracks
1418 487 : if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_HINT) return GF_BAD_PARAM;
1419 :
1420 487 : e = unpack_track(trak);
1421 487 : if (e) return e;
1422 : //do NOT change the order DTS, CTS, size chunk
1423 :
1424 : //remove DTS
1425 487 : e = stbl_RemoveDTS(trak->Media->information->sampleTable, sampleNumber, 1, trak->Media->mediaHeader->timeScale);
1426 487 : if (e) return e;
1427 : //remove CTS if any
1428 487 : if (trak->Media->information->sampleTable->CompositionOffset) {
1429 486 : e = stbl_RemoveCTS(trak->Media->information->sampleTable, sampleNumber, 1);
1430 486 : if (e) return e;
1431 : }
1432 : //remove size
1433 487 : e = stbl_RemoveSize(trak->Media->information->sampleTable, sampleNumber, 1);
1434 487 : if (e) return e;
1435 : //remove sampleToChunk and chunk
1436 487 : e = stbl_RemoveChunk(trak->Media->information->sampleTable, sampleNumber, 1);
1437 487 : if (e) return e;
1438 : //remove sync
1439 487 : if (trak->Media->information->sampleTable->SyncSample) {
1440 486 : e = stbl_RemoveRAP(trak->Media->information->sampleTable, sampleNumber);
1441 486 : if (e) return e;
1442 : }
1443 : //remove sample dep
1444 487 : if (trak->Media->information->sampleTable->SampleDep) {
1445 315 : e = stbl_RemoveRedundant(trak->Media->information->sampleTable, sampleNumber, 1);
1446 315 : if (e) return e;
1447 : }
1448 : //remove shadow
1449 487 : e = stbl_RemoveShadow(trak->Media->information->sampleTable, sampleNumber);
1450 487 : if (e) return e;
1451 :
1452 : //remove padding
1453 487 : e = stbl_RemovePaddingBits(trak->Media->information->sampleTable, sampleNumber);
1454 487 : if (e) return e;
1455 :
1456 487 : e = stbl_RemoveSubSample(trak->Media->information->sampleTable, sampleNumber);
1457 487 : if (e) return e;
1458 :
1459 487 : e = stbl_RemoveSampleGroup(trak->Media->information->sampleTable, sampleNumber);
1460 487 : if (e) return e;
1461 :
1462 487 : gf_isom_disable_inplace_rewrite(movie);
1463 :
1464 487 : return SetTrackDuration(trak);
1465 : }
1466 :
1467 :
1468 : GF_EXPORT
1469 222 : GF_Err gf_isom_set_final_name(GF_ISOFile *movie, char *filename)
1470 : {
1471 : GF_Err e;
1472 222 : if (!movie ) return GF_BAD_PARAM;
1473 :
1474 : //if mode is not OPEN_EDIT file was created under the right name
1475 : e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
1476 : if (e) return e;
1477 :
1478 222 : if (filename) {
1479 : //we don't allow file overwriting
1480 222 : if ( (movie->openMode == GF_ISOM_OPEN_EDIT)
1481 154 : && movie->fileName && !strcmp(filename, movie->fileName))
1482 : return GF_BAD_PARAM;
1483 222 : if (movie->finalName) gf_free(movie->finalName);
1484 222 : movie->finalName = gf_strdup(filename);
1485 222 : if (!movie->finalName) return GF_OUT_OF_MEM;
1486 222 : gf_isom_disable_inplace_rewrite(movie);
1487 : }
1488 : return GF_OK;
1489 : }
1490 :
1491 : //Add a system descriptor to the ESD of a stream(EDIT or WRITE mode only)
1492 : GF_EXPORT
1493 1 : GF_Err gf_isom_add_desc_to_description(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, const GF_Descriptor *theDesc)
1494 : {
1495 : GF_IPIPtr *ipiD;
1496 : GF_Err e;
1497 : u16 tmpRef;
1498 : GF_TrackBox *trak;
1499 : GF_Descriptor *desc;
1500 : GF_ESD *esd;
1501 : GF_TrackReferenceBox *tref;
1502 : GF_TrackReferenceTypeBox *dpnd;
1503 : GF_MPEGVisualSampleEntryBox *entry;
1504 : u32 msubtype;
1505 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
1506 : if (e) return e;
1507 :
1508 1 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1509 1 : if (!trak) return GF_BAD_PARAM;
1510 :
1511 : /*GETS NATIVE DESCRIPTOR ONLY*/
1512 1 : e = Media_GetESD(trak->Media, StreamDescriptionIndex, &esd, GF_TRUE);
1513 1 : if (e) return e;
1514 :
1515 1 : entry = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, StreamDescriptionIndex-1);
1516 1 : if (!entry) return GF_BAD_PARAM;
1517 1 : msubtype = entry->type;
1518 1 : if ((msubtype==GF_ISOM_BOX_TYPE_ENCV) || (msubtype==GF_ISOM_BOX_TYPE_ENCA))
1519 0 : gf_isom_get_original_format_type(movie, trackNumber, StreamDescriptionIndex, &msubtype);
1520 :
1521 : //duplicate the desc
1522 1 : e = gf_odf_desc_copy((GF_Descriptor *)theDesc, &desc);
1523 1 : if (e) return e;
1524 :
1525 : //and add it to the ESD EXCEPT IPI PTR (we need to translate from ES_ID to TrackID!!!
1526 1 : if (!movie->keep_utc)
1527 1 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
1528 :
1529 1 : switch (desc->tag) {
1530 : case GF_ODF_IPI_PTR_TAG:
1531 : goto insertIPI;
1532 : default:
1533 : break;
1534 : }
1535 :
1536 1 : if ((msubtype==GF_ISOM_BOX_TYPE_MP4S) || (msubtype==GF_ISOM_BOX_TYPE_MP4V) || (msubtype==GF_ISOM_BOX_TYPE_MP4A)) {
1537 0 : return gf_odf_desc_add_desc((GF_Descriptor *)esd, desc);
1538 : }
1539 :
1540 1 : if (trak->Media->handler->handlerType!=GF_ISOM_MEDIA_VISUAL) {
1541 0 : gf_odf_desc_del(desc);
1542 0 : return GF_NOT_SUPPORTED;
1543 : }
1544 1 : GF_MPEG4ExtensionDescriptorsBox *mdesc = (GF_MPEG4ExtensionDescriptorsBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_M4DS);
1545 1 : if (!mdesc) {
1546 1 : mdesc = (GF_MPEG4ExtensionDescriptorsBox *) gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_M4DS);
1547 : }
1548 1 : return gf_list_add(mdesc->descriptors, desc);
1549 :
1550 0 : insertIPI:
1551 0 : if (esd->ipiPtr) {
1552 0 : gf_odf_desc_del((GF_Descriptor *) esd->ipiPtr);
1553 0 : esd->ipiPtr = NULL;
1554 : }
1555 :
1556 0 : ipiD = (GF_IPIPtr *) desc;
1557 : //find a tref
1558 0 : if (!trak->References) {
1559 0 : tref = (GF_TrackReferenceBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_TREF);
1560 0 : if (!tref) return GF_OUT_OF_MEM;
1561 0 : e = trak_on_child_box((GF_Box*)trak, (GF_Box *)tref, GF_FALSE);
1562 0 : if (e) return e;
1563 : }
1564 0 : tref = trak->References;
1565 :
1566 0 : e = Track_FindRef(trak, GF_ISOM_REF_IPI, &dpnd);
1567 0 : if (e) return e;
1568 0 : if (!dpnd) {
1569 0 : tmpRef = 0;
1570 0 : dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new_parent(&tref->child_boxes, GF_ISOM_BOX_TYPE_REFT);
1571 0 : if (!dpnd) return GF_OUT_OF_MEM;
1572 0 : dpnd->reference_type = GF_ISOM_BOX_TYPE_IPIR;
1573 0 : e = reftype_AddRefTrack(dpnd, ipiD->IPI_ES_Id, &tmpRef);
1574 0 : if (e) return e;
1575 : //and replace the tag and value...
1576 0 : ipiD->IPI_ES_Id = tmpRef;
1577 0 : ipiD->tag = GF_ODF_ISOM_IPI_PTR_TAG;
1578 : } else {
1579 : //Watch out! ONLY ONE IPI dependency is allowed per stream
1580 0 : dpnd->trackIDCount = 1;
1581 0 : dpnd->trackIDs[0] = ipiD->IPI_ES_Id;
1582 : //and replace the tag and value...
1583 0 : ipiD->IPI_ES_Id = 1;
1584 0 : ipiD->tag = GF_ODF_ISOM_IPI_PTR_TAG;
1585 : }
1586 : //and add the desc to the esd...
1587 0 : return gf_odf_desc_add_desc((GF_Descriptor *)esd, desc);
1588 : }
1589 :
1590 :
1591 : //use carefully. Very useful when you made a lot of changes (IPMP, IPI, OCI, ...)
1592 : //THIS WILL REPLACE THE WHOLE DESCRIPTOR ...
1593 : GF_EXPORT
1594 117 : GF_Err gf_isom_change_mpeg4_description(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, const GF_ESD *newESD)
1595 : {
1596 : GF_Err e;
1597 : GF_ESD *esd;
1598 : GF_TrackBox *trak;
1599 : GF_SampleEntryBox *entry;
1600 : GF_SampleDescriptionBox *stsd;
1601 :
1602 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
1603 : if (e) return e;
1604 :
1605 117 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1606 117 : if (!trak) return GF_BAD_PARAM;
1607 :
1608 117 : stsd = trak->Media->information->sampleTable->SampleDescription;
1609 117 : if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
1610 :
1611 117 : if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
1612 0 : return movie->LastError = GF_BAD_PARAM;
1613 : }
1614 117 : entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
1615 : //no support for generic sample entries (eg, no MPEG4 descriptor)
1616 117 : if (entry == NULL) return GF_BAD_PARAM;
1617 :
1618 117 : if (!movie->keep_utc)
1619 117 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
1620 : //duplicate our desc
1621 117 : e = gf_odf_desc_copy((GF_Descriptor *)newESD, (GF_Descriptor **)&esd);
1622 117 : if (e) return e;
1623 117 : e = Track_SetStreamDescriptor(trak, StreamDescriptionIndex, entry->dataReferenceIndex, esd, NULL);
1624 117 : if (e != GF_OK) {
1625 1 : gf_odf_desc_del((GF_Descriptor *) esd);
1626 : }
1627 : return e;
1628 : }
1629 :
1630 : GF_EXPORT
1631 2539 : GF_Err gf_isom_set_visual_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 Width, u32 Height)
1632 : {
1633 : GF_Err e;
1634 : GF_TrackBox *trak;
1635 : GF_SampleEntryBox *entry;
1636 : GF_SampleDescriptionBox *stsd;
1637 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
1638 : if (e) return e;
1639 :
1640 2415 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1641 2415 : if (!trak) return GF_BAD_PARAM;
1642 :
1643 2415 : stsd = trak->Media->information->sampleTable->SampleDescription;
1644 2415 : if (!stsd) {
1645 0 : return movie->LastError = GF_ISOM_INVALID_FILE;
1646 : }
1647 2415 : if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
1648 0 : return movie->LastError = GF_BAD_PARAM;
1649 : }
1650 2415 : entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
1651 : //no support for generic sample entries (eg, no MPEG4 descriptor)
1652 2415 : if (entry == NULL) return GF_BAD_PARAM;
1653 2415 : if (!movie->keep_utc)
1654 2415 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
1655 :
1656 : //valid for MPEG visual, JPG and 3GPP H263
1657 2415 : if (entry->internal_type == GF_ISOM_SAMPLE_ENTRY_VIDEO) {
1658 2276 : ((GF_VisualSampleEntryBox*)entry)->Width = Width;
1659 2276 : ((GF_VisualSampleEntryBox*)entry)->Height = Height;
1660 2276 : trak->Header->width = Width<<16;
1661 2276 : trak->Header->height = Height<<16;
1662 2276 : return GF_OK;
1663 139 : } else if (trak->Media->handler->handlerType==GF_ISOM_MEDIA_SCENE) {
1664 45 : trak->Header->width = Width<<16;
1665 45 : trak->Header->height = Height<<16;
1666 45 : return GF_OK;
1667 : } else {
1668 : return GF_BAD_PARAM;
1669 : }
1670 : }
1671 :
1672 : GF_EXPORT
1673 1 : GF_Err gf_isom_set_visual_bit_depth(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u16 bitDepth)
1674 : {
1675 : GF_Err e;
1676 : GF_TrackBox *trak;
1677 : GF_MPEGVisualSampleEntryBox *entry;
1678 : GF_SampleDescriptionBox *stsd;
1679 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
1680 : if (e) return e;
1681 :
1682 1 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1683 1 : if (!trak) return GF_BAD_PARAM;
1684 :
1685 1 : switch (trak->Media->handler->handlerType) {
1686 : case GF_ISOM_MEDIA_VISUAL:
1687 : case GF_ISOM_MEDIA_PICT:
1688 : case GF_ISOM_MEDIA_AUXV:
1689 : break;
1690 : default:
1691 : return GF_OK;
1692 : }
1693 :
1694 1 : stsd = trak->Media->information->sampleTable->SampleDescription;
1695 1 : if (!stsd) {
1696 0 : return movie->LastError = GF_ISOM_INVALID_FILE;
1697 : }
1698 1 : if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
1699 0 : return movie->LastError = GF_BAD_PARAM;
1700 : }
1701 1 : entry = (GF_MPEGVisualSampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
1702 : //no support for generic sample entries (eg, no MPEG4 descriptor)
1703 1 : if (entry == NULL) return GF_BAD_PARAM;
1704 1 : entry->bit_depth = bitDepth;
1705 1 : return GF_OK;
1706 : }
1707 :
1708 : GF_EXPORT
1709 86 : GF_Err gf_isom_set_pixel_aspect_ratio(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, s32 hSpacing, s32 vSpacing, Bool force_par)
1710 : {
1711 : GF_Err e;
1712 : GF_TrackBox *trak;
1713 : GF_SampleEntryBox *entry;
1714 : GF_SampleDescriptionBox *stsd;
1715 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
1716 : if (e) return e;
1717 :
1718 86 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1719 86 : if (!trak) return GF_BAD_PARAM;
1720 :
1721 86 : stsd = trak->Media->information->sampleTable->SampleDescription;
1722 86 : if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
1723 86 : if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
1724 0 : return movie->LastError = GF_BAD_PARAM;
1725 : }
1726 86 : entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
1727 : //no support for generic sample entries (eg, no MPEG4 descriptor)
1728 86 : if (entry == NULL) return GF_BAD_PARAM;
1729 86 : if (!movie->keep_utc)
1730 86 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
1731 :
1732 86 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
1733 :
1734 85 : if (hSpacing<0) hSpacing = 1;
1735 85 : if (vSpacing<0) vSpacing = 1;
1736 :
1737 85 : GF_PixelAspectRatioBox *pasp = (GF_PixelAspectRatioBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_PASP);
1738 85 : if (!hSpacing || !vSpacing || ((hSpacing == vSpacing) && !force_par)) {
1739 3 : if (pasp) gf_isom_box_del_parent(&entry->child_boxes, (GF_Box *)pasp);
1740 : return GF_OK;
1741 : }
1742 82 : if (!pasp) {
1743 66 : pasp = (GF_PixelAspectRatioBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_PASP);
1744 66 : if (!pasp) return GF_OUT_OF_MEM;
1745 : }
1746 82 : pasp->hSpacing = (u32) hSpacing;
1747 82 : pasp->vSpacing = (u32) vSpacing;
1748 82 : return GF_OK;
1749 : }
1750 :
1751 : GF_EXPORT
1752 82 : GF_Err gf_isom_set_visual_color_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 colour_type, u16 colour_primaries, u16 transfer_characteristics, u16 matrix_coefficients, Bool full_range_flag, u8 *icc_data, u32 icc_size)
1753 : {
1754 : GF_Err e;
1755 : GF_TrackBox *trak;
1756 : GF_SampleEntryBox *entry;
1757 : GF_SampleDescriptionBox *stsd;
1758 : GF_ColourInformationBox *clr=NULL;
1759 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
1760 : if (e) return e;
1761 :
1762 82 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1763 82 : if (!trak) return GF_BAD_PARAM;
1764 :
1765 82 : stsd = trak->Media->information->sampleTable->SampleDescription;
1766 82 : if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
1767 82 : if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
1768 0 : return movie->LastError = GF_BAD_PARAM;
1769 : }
1770 82 : entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
1771 : //no support for generic sample entries (eg, no MPEG4 descriptor)
1772 82 : if (entry == NULL) return GF_BAD_PARAM;
1773 82 : if (!movie->keep_utc)
1774 82 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
1775 :
1776 82 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_OK;
1777 :
1778 82 : clr = (GF_ColourInformationBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_COLR);
1779 82 : if (!colour_type) {
1780 2 : if (clr) gf_isom_box_del_parent(&entry->child_boxes, (GF_Box *)clr);
1781 : return GF_OK;
1782 : }
1783 80 : if (!clr) {
1784 73 : clr = (GF_ColourInformationBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_COLR);
1785 73 : if (!clr) return GF_OUT_OF_MEM;
1786 : }
1787 80 : clr->colour_type = colour_type;
1788 80 : clr->colour_primaries = colour_primaries;
1789 80 : clr->transfer_characteristics = transfer_characteristics;
1790 80 : clr->matrix_coefficients = matrix_coefficients;
1791 80 : clr->full_range_flag = full_range_flag;
1792 80 : if (clr->opaque) gf_free(clr->opaque);
1793 80 : clr->opaque = NULL;
1794 80 : clr->opaque_size = 0;
1795 80 : if ((colour_type==GF_ISOM_SUBTYPE_RICC) || (colour_type==GF_ISOM_SUBTYPE_PROF)) {
1796 0 : clr->opaque_size = icc_data ? icc_size : 0;
1797 0 : if (clr->opaque_size) {
1798 0 : clr->opaque = gf_malloc(sizeof(char)*clr->opaque_size);
1799 0 : if (!clr->opaque) return GF_OUT_OF_MEM;
1800 0 : memcpy(clr->opaque, icc_data, sizeof(char)*clr->opaque_size);
1801 : }
1802 : }
1803 : return GF_OK;
1804 : }
1805 :
1806 : GF_EXPORT
1807 1 : GF_Err gf_isom_set_dolby_vision_profile(GF_ISOFile* movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 dv_profile)
1808 : {
1809 : GF_Err e;
1810 : GF_TrackBox* trak;
1811 : GF_SampleEntryBox* entry;
1812 : GF_SampleDescriptionBox* stsd;
1813 : GF_DOVIConfigurationBox* dovi = NULL;
1814 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
1815 : if (e) return e;
1816 :
1817 1 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1818 1 : if (!trak) return GF_BAD_PARAM;
1819 :
1820 1 : stsd = trak->Media->information->sampleTable->SampleDescription;
1821 1 : if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
1822 1 : if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
1823 0 : return movie->LastError = GF_BAD_PARAM;
1824 : }
1825 1 : entry = (GF_SampleEntryBox*)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
1826 : //no support for generic sample entries (eg, no MPEG4 descriptor)
1827 1 : if (entry == NULL) return GF_BAD_PARAM;
1828 1 : if (!movie->keep_utc)
1829 1 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
1830 :
1831 1 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_OK;
1832 :
1833 1 : dovi = ((GF_MPEGVisualSampleEntryBox*)entry)->dovi_config;
1834 1 : if (!dv_profile) {
1835 0 : if (dovi) gf_isom_box_del((GF_Box*)dovi);
1836 0 : ((GF_MPEGVisualSampleEntryBox*)entry)->dovi_config = NULL;
1837 0 : return GF_OK;
1838 : }
1839 1 : if (!dovi) {
1840 1 : dovi = (GF_DOVIConfigurationBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_DVCC);
1841 1 : if (!dovi) return GF_OUT_OF_MEM;
1842 1 : ((GF_MPEGVisualSampleEntryBox*)entry)->dovi_config = dovi;
1843 : }
1844 1 : entry->type = GF_ISOM_BOX_TYPE_DVHE;
1845 1 : dovi->DOVIConfig.dv_profile = dv_profile;
1846 1 : return GF_OK;
1847 : }
1848 :
1849 : GF_EXPORT
1850 1 : GF_Err gf_isom_set_high_dynamic_range_info(GF_ISOFile* movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_MasteringDisplayColourVolumeInfo* mdcv, GF_ContentLightLevelInfo* clli)
1851 : {
1852 : GF_Err e;
1853 : GF_TrackBox* trak;
1854 : GF_SampleEntryBox* entry;
1855 : GF_SampleDescriptionBox* stsd;
1856 :
1857 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
1858 : if (e) return e;
1859 :
1860 1 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1861 1 : if (!trak) return GF_BAD_PARAM;
1862 :
1863 1 : stsd = trak->Media->information->sampleTable->SampleDescription;
1864 1 : if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
1865 1 : if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
1866 0 : return movie->LastError = GF_BAD_PARAM;
1867 : }
1868 1 : entry = (GF_SampleEntryBox*)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
1869 : //no support for generic sample entries (eg, no MPEG4 descriptor)
1870 1 : if (entry == NULL) return GF_BAD_PARAM;
1871 1 : if (!movie->keep_utc)
1872 1 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
1873 :
1874 1 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
1875 :
1876 1 : GF_MasteringDisplayColourVolumeBox *mdcvb = (GF_MasteringDisplayColourVolumeBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_MDCV);
1877 1 : if (!mdcvb) {
1878 1 : mdcvb = (GF_MasteringDisplayColourVolumeBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_MDCV);
1879 1 : if (!mdcvb) return GF_OUT_OF_MEM;
1880 : }
1881 1 : mdcvb->mdcv = *mdcv;
1882 :
1883 : /*clli*/
1884 1 : GF_ContentLightLevelBox *cllib = (GF_ContentLightLevelBox *)gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_CLLI);
1885 1 : if (!cllib) {
1886 1 : cllib = (GF_ContentLightLevelBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_CLLI);
1887 1 : if (!cllib) return GF_OUT_OF_MEM;
1888 : }
1889 1 : cllib->clli = *clli;
1890 1 : return GF_OK;
1891 : }
1892 :
1893 : GF_EXPORT
1894 2 : GF_Err gf_isom_set_clean_aperture(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 cleanApertureWidthN, u32 cleanApertureWidthD, u32 cleanApertureHeightN, u32 cleanApertureHeightD, u32 horizOffN, u32 horizOffD, u32 vertOffN, u32 vertOffD)
1895 : {
1896 : GF_Err e;
1897 : GF_TrackBox *trak;
1898 : GF_SampleEntryBox *entry;
1899 : GF_SampleDescriptionBox *stsd;
1900 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
1901 : if (e) return e;
1902 :
1903 2 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1904 2 : if (!trak) return GF_BAD_PARAM;
1905 :
1906 2 : stsd = trak->Media->information->sampleTable->SampleDescription;
1907 2 : if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
1908 2 : if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
1909 0 : return movie->LastError = GF_BAD_PARAM;
1910 : }
1911 2 : entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
1912 : //no support for generic sample entries (eg, no MPEG4 descriptor)
1913 2 : if (entry == NULL) return GF_BAD_PARAM;
1914 2 : if (!movie->keep_utc)
1915 2 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
1916 :
1917 2 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
1918 :
1919 2 : GF_CleanApertureBox *clap = (GF_CleanApertureBox *)gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_CLAP);
1920 2 : if (!cleanApertureHeightD || !cleanApertureWidthD || !horizOffD || !vertOffD) {
1921 1 : if (clap) gf_isom_box_del_parent(&entry->child_boxes, (GF_Box*)clap);
1922 : return GF_OK;
1923 : }
1924 1 : if (!clap) {
1925 1 : clap = (GF_CleanApertureBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_CLAP);
1926 1 : if (!clap) return GF_OUT_OF_MEM;
1927 : }
1928 :
1929 1 : clap->cleanApertureWidthN = cleanApertureWidthN;
1930 1 : clap->cleanApertureWidthD = cleanApertureWidthD;
1931 1 : clap->cleanApertureHeightN = cleanApertureHeightN;
1932 1 : clap->cleanApertureHeightD = cleanApertureHeightD;
1933 1 : clap->horizOffN = horizOffN;
1934 1 : clap->horizOffD = horizOffD;
1935 1 : clap->vertOffN = vertOffN;
1936 1 : clap->vertOffD = vertOffD;
1937 1 : return GF_OK;
1938 : }
1939 :
1940 : #include <gpac/maths.h>
1941 2 : GF_Err gf_isom_update_aperture_info(GF_ISOFile *movie, u32 trackNumber, Bool remove)
1942 : {
1943 : GF_Err e;
1944 : GF_Box *box, *enof, *prof, *clef;
1945 : GF_TrackBox *trak;
1946 : GF_VisualSampleEntryBox *ventry;
1947 : GF_PixelAspectRatioBox *pasp;
1948 : GF_CleanApertureBox *clap;
1949 : u32 j, hspacing, vspacing, clap_width_num, clap_width_den, clap_height_num, clap_height_den, high, low;
1950 : Double width, height;
1951 :
1952 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
1953 : if (e) return e;
1954 :
1955 2 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1956 2 : if (!trak) return GF_BAD_PARAM;
1957 :
1958 2 : if (remove) {
1959 0 : if (trak->Aperture) {
1960 0 : gf_isom_box_del(trak->Aperture);
1961 0 : trak->Aperture = NULL;
1962 : }
1963 : return GF_OK;
1964 : }
1965 : enof = prof = clef = NULL;
1966 2 : if (!trak->Aperture) {
1967 2 : trak->Aperture = gf_isom_box_new_parent(&trak->child_boxes, GF_QT_BOX_TYPE_TAPT);
1968 2 : if (!trak->Aperture) return GF_OUT_OF_MEM;
1969 : }
1970 2 : if (!trak->Aperture->child_boxes) {
1971 2 : trak->Aperture->child_boxes = gf_list_new();
1972 2 : if (!trak->Aperture->child_boxes)
1973 : return GF_OUT_OF_MEM;
1974 : }
1975 :
1976 2 : j=0;
1977 4 : while ( (box = gf_list_enum(trak->Aperture->child_boxes, &j))) {
1978 0 : switch (box->type) {
1979 0 : case GF_QT_BOX_TYPE_CLEF: clef = box; break;
1980 0 : case GF_QT_BOX_TYPE_PROF: prof = box; break;
1981 0 : case GF_QT_BOX_TYPE_ENOF: enof = box; break;
1982 : }
1983 : }
1984 2 : if (!clef) {
1985 2 : clef = gf_isom_box_new(GF_QT_BOX_TYPE_CLEF);
1986 2 : if (!clef) return GF_OUT_OF_MEM;
1987 2 : gf_list_add(trak->Aperture->child_boxes, clef);
1988 : }
1989 2 : if (!enof) {
1990 2 : enof = gf_isom_box_new(GF_QT_BOX_TYPE_ENOF);
1991 2 : if (!enof) return GF_OUT_OF_MEM;
1992 2 : gf_list_add(trak->Aperture->child_boxes, enof);
1993 : }
1994 2 : if (!prof) {
1995 2 : prof = gf_isom_box_new(GF_QT_BOX_TYPE_PROF);
1996 2 : if (!prof) return GF_OUT_OF_MEM;
1997 2 : gf_list_add(trak->Aperture->child_boxes, prof);
1998 : }
1999 :
2000 2 : ventry = (GF_VisualSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, 0);
2001 : //no support for generic sample entries (eg, no MPEG4 descriptor)
2002 2 : if (ventry == NULL) return GF_BAD_PARAM;
2003 2 : if (!movie->keep_utc)
2004 2 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
2005 :
2006 2 : if (ventry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
2007 :
2008 2 : pasp = (GF_PixelAspectRatioBox *) gf_isom_box_find_child(ventry->child_boxes, GF_ISOM_BOX_TYPE_PASP);
2009 : hspacing = vspacing = 0;
2010 2 : if (pasp) {
2011 2 : hspacing = pasp->hSpacing;
2012 2 : vspacing = pasp->vSpacing;
2013 : }
2014 2 : clap_width_num = ventry->Width;
2015 : clap_width_den = 1;
2016 2 : clap_height_num = ventry->Height;
2017 : clap_height_den = 1;
2018 2 : clap = (GF_CleanApertureBox *) gf_isom_box_find_child(ventry->child_boxes, GF_ISOM_BOX_TYPE_CLAP);
2019 2 : if (clap) {
2020 0 : clap_width_num = clap->cleanApertureWidthN;
2021 0 : clap_width_den = clap->cleanApertureWidthD;
2022 0 : clap_height_num = clap->cleanApertureHeightN;
2023 0 : clap_height_den = clap->cleanApertureHeightD;
2024 : }
2025 : //enof: encoded pixels in 16.16
2026 2 : ((GF_ApertureBox *)enof)->width = (ventry->Width)<<16;
2027 2 : ((GF_ApertureBox *)enof)->height = (ventry->Height)<<16;
2028 :
2029 : //prof: encoded pixels + pasp in 16.16
2030 2 : width = (Float) (ventry->Width * hspacing);
2031 2 : width /= vspacing;
2032 2 : high = (u32) floor((Float)width);
2033 2 : low = (u32) ( 0xFFFF * (width - (Double)high) );
2034 2 : ((GF_ApertureBox *)prof)->width = (high)<<16 | low;
2035 2 : ((GF_ApertureBox *)prof)->height = (ventry->Height)<<16;
2036 :
2037 : //clef: encoded pixels + pasp + clap in 16.16
2038 2 : width = (Double) (clap_width_num * hspacing);
2039 2 : width /= clap_width_den * vspacing;
2040 2 : height = (Float) clap_height_num;
2041 2 : height /= clap_height_den;
2042 :
2043 2 : high = (u32) floor((Float)width);
2044 2 : low = (u32) (0xFFFF * (width - (Double)high));
2045 2 : ((GF_ApertureBox *)clef)->width = (high)<<16 | low;
2046 2 : high = (u32) floor((Float)height);
2047 2 : low = (u32) (0xFFFF * (height - (Double)high));
2048 2 : ((GF_ApertureBox *)clef)->height = (high)<<16 | low;
2049 :
2050 :
2051 2 : return GF_OK;
2052 : }
2053 :
2054 : GF_EXPORT
2055 1 : GF_Err gf_isom_set_image_sequence_coding_constraints(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, Bool remove, Bool all_ref_pics_intra, Bool intra_pred_used, u32 max_ref_per_pic)
2056 : {
2057 : GF_Err e;
2058 : GF_TrackBox *trak;
2059 : GF_SampleEntryBox *entry;
2060 : GF_SampleDescriptionBox *stsd;
2061 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
2062 : if (e) return e;
2063 :
2064 1 : trak = gf_isom_get_track_from_file(movie, trackNumber);
2065 1 : if (!trak) return GF_BAD_PARAM;
2066 :
2067 1 : stsd = trak->Media->information->sampleTable->SampleDescription;
2068 1 : if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
2069 1 : if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
2070 0 : return movie->LastError = GF_BAD_PARAM;
2071 : }
2072 1 : entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
2073 : //no support for generic sample entries (eg, no MPEG4 descriptor)
2074 1 : if (entry == NULL) return GF_BAD_PARAM;
2075 1 : if (!movie->keep_utc)
2076 1 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
2077 :
2078 1 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
2079 :
2080 1 : GF_CodingConstraintsBox*ccst = (GF_CodingConstraintsBox*) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_CCST);
2081 1 : if (remove) {
2082 0 : if (ccst) gf_isom_box_del_parent(&entry->child_boxes, (GF_Box*)ccst);
2083 : return GF_OK;
2084 : }
2085 1 : if (!ccst) {
2086 1 : ccst = (GF_CodingConstraintsBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_CCST);
2087 1 : if (!ccst) return GF_OUT_OF_MEM;
2088 : }
2089 1 : ccst->all_ref_pics_intra = all_ref_pics_intra;
2090 1 : ccst->intra_pred_used = intra_pred_used;
2091 1 : ccst->max_ref_per_pic = max_ref_per_pic;
2092 1 : return GF_OK;
2093 : }
2094 :
2095 : GF_EXPORT
2096 1 : GF_Err gf_isom_set_image_sequence_alpha(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, Bool remove)
2097 : {
2098 : GF_Err e;
2099 : GF_TrackBox *trak;
2100 : GF_SampleEntryBox *entry;
2101 : GF_SampleDescriptionBox *stsd;
2102 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
2103 : if (e) return e;
2104 :
2105 1 : trak = gf_isom_get_track_from_file(movie, trackNumber);
2106 1 : if (!trak) return GF_BAD_PARAM;
2107 :
2108 1 : stsd = trak->Media->information->sampleTable->SampleDescription;
2109 1 : if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
2110 1 : if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
2111 0 : return movie->LastError = GF_BAD_PARAM;
2112 : }
2113 1 : entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
2114 : //no support for generic sample entries (eg, no MPEG4 descriptor)
2115 1 : if (entry == NULL) return GF_BAD_PARAM;
2116 1 : if (!movie->keep_utc)
2117 1 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
2118 :
2119 1 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
2120 :
2121 1 : GF_AuxiliaryTypeInfoBox *auxi = (GF_AuxiliaryTypeInfoBox *)gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_AUXI);
2122 1 : if (remove) {
2123 0 : if (auxi) gf_isom_box_del_parent(&entry->child_boxes, (GF_Box*)auxi);
2124 : return GF_OK;
2125 : }
2126 1 : if (!auxi) {
2127 1 : auxi = (GF_AuxiliaryTypeInfoBox*)gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_AUXI);
2128 1 : if (!auxi) return GF_OUT_OF_MEM;
2129 : }
2130 1 : auxi->aux_track_type = gf_strdup("urn:mpeg:mpegB:cicp:systems:auxiliary:alpha");
2131 1 : return GF_OK;
2132 : }
2133 :
2134 : GF_EXPORT
2135 1166 : GF_Err gf_isom_set_audio_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 sampleRate, u32 nbChannels, u8 bitsPerSample, GF_AudioSampleEntryImportMode asemode)
2136 : {
2137 : GF_Err e;
2138 : u32 i, old_qtff_mode=GF_ISOM_AUDIO_QTFF_NONE;
2139 : GF_TrackBox *trak;
2140 : GF_SampleEntryBox *entry;
2141 : GF_AudioSampleEntryBox*aud_entry;
2142 : GF_SampleDescriptionBox *stsd;
2143 : GF_Box *wave_box = NULL;
2144 : GF_Box *gf_isom_audio_sample_get_audio_codec_cfg_box(GF_AudioSampleEntryBox *ptr);
2145 : GF_Box *codec_ext = NULL;
2146 : #if 0
2147 : GF_ChannelLayoutInfoBox *chan=NULL;
2148 : #endif
2149 : GF_OriginalFormatBox *frma=NULL;
2150 : GF_ChromaInfoBox *enda=NULL;
2151 : GF_ESDBox *esds=NULL;
2152 : GF_Box *terminator=NULL;
2153 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
2154 : if (e) return e;
2155 :
2156 1119 : trak = gf_isom_get_track_from_file(movie, trackNumber);
2157 1119 : if (!trak) return GF_BAD_PARAM;
2158 :
2159 1119 : stsd = trak->Media->information->sampleTable->SampleDescription;
2160 1119 : if (!stsd) {
2161 0 : return movie->LastError = GF_ISOM_INVALID_FILE;
2162 : }
2163 1119 : if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
2164 0 : return movie->LastError = GF_BAD_PARAM;
2165 : }
2166 1119 : entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
2167 : //no support for generic sample entries (eg, no MPEG4 descriptor)
2168 1119 : if (entry == NULL) return GF_BAD_PARAM;
2169 1119 : if (!movie->keep_utc)
2170 1119 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
2171 :
2172 1119 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO) return GF_BAD_PARAM;
2173 : aud_entry = (GF_AudioSampleEntryBox*) entry;
2174 :
2175 1119 : if (entry->type==GF_ISOM_BOX_TYPE_MLPA) {
2176 693 : aud_entry->samplerate_hi = sampleRate>>16;
2177 693 : aud_entry->samplerate_lo = sampleRate & 0x0000FFFF;
2178 : } else {
2179 426 : aud_entry->samplerate_hi = sampleRate;
2180 426 : aud_entry->samplerate_lo = 0;
2181 : }
2182 1119 : aud_entry->bitspersample = bitsPerSample;
2183 :
2184 1119 : switch (asemode) {
2185 1 : case GF_IMPORT_AUDIO_SAMPLE_ENTRY_v0_2:
2186 1 : stsd->version = 0;
2187 1 : aud_entry->version = 0;
2188 1 : aud_entry->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE;
2189 1 : aud_entry->channel_count = 2;
2190 1 : break;
2191 1095 : case GF_IMPORT_AUDIO_SAMPLE_ENTRY_NOT_SET:
2192 : case GF_IMPORT_AUDIO_SAMPLE_ENTRY_v0_BS:
2193 1095 : stsd->version = 0;
2194 1095 : aud_entry->version = 0;
2195 1095 : aud_entry->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE;
2196 1095 : aud_entry->channel_count = nbChannels;
2197 1095 : break;
2198 6 : case GF_IMPORT_AUDIO_SAMPLE_ENTRY_v1_MPEG:
2199 6 : stsd->version = 1;
2200 6 : aud_entry->version = 1;
2201 6 : aud_entry->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE;
2202 6 : aud_entry->channel_count = nbChannels;
2203 6 : break;
2204 17 : case GF_IMPORT_AUDIO_SAMPLE_ENTRY_v1_QTFF:
2205 17 : stsd->version = 0;
2206 17 : aud_entry->version = 1;
2207 17 : aud_entry->channel_count = nbChannels;
2208 17 : old_qtff_mode = aud_entry->qtff_mode;
2209 17 : if (aud_entry->qtff_mode != GF_ISOM_AUDIO_QTFF_ON_EXT_VALID)
2210 1 : aud_entry->qtff_mode = GF_ISOM_AUDIO_QTFF_ON_NOEXT;
2211 : break;
2212 : }
2213 :
2214 1119 : aud_entry->compression_id = 0;
2215 :
2216 : //check for wave+children and chan for QTFF or remove them for isobmff
2217 2268 : for (i=0; i<gf_list_count(aud_entry->child_boxes); i++) {
2218 1149 : GF_Box *b = gf_list_get(aud_entry->child_boxes, i);
2219 1149 : if ((b->type != GF_QT_BOX_TYPE_WAVE) && (b->type != GF_QT_BOX_TYPE_CHAN) ) continue;
2220 32 : if (asemode==GF_IMPORT_AUDIO_SAMPLE_ENTRY_v1_QTFF) {
2221 32 : if (b->type == GF_QT_BOX_TYPE_WAVE) wave_box = b;
2222 : #if 0
2223 : else chan = (GF_ChannelLayoutInfoBox *)b;
2224 : #endif
2225 :
2226 : } else {
2227 0 : gf_isom_box_del_parent(&aud_entry->child_boxes, b);
2228 0 : i--;
2229 : }
2230 : }
2231 :
2232 : //TODO: insert channelLayout for ISOBMFF
2233 1119 : if (asemode!=GF_IMPORT_AUDIO_SAMPLE_ENTRY_v1_QTFF) return GF_OK;
2234 :
2235 17 : if (aud_entry->type==GF_ISOM_BOX_TYPE_MP4A)
2236 1 : aud_entry->compression_id = -2;
2237 :
2238 17 : if (!aud_entry->child_boxes) aud_entry->child_boxes = gf_list_new();
2239 :
2240 : #if 0
2241 : if (!chan) {
2242 : chan = (GF_ChannelLayoutInfoBox *) gf_isom_box_new_parent(&aud_entry->child_boxes, GF_QT_BOX_TYPE_CHAN);
2243 : }
2244 : //TODO, proper channel mapping
2245 : chan->layout_tag = (nbChannels==2) ? 6750210 : 6553601;
2246 : #endif
2247 :
2248 17 : codec_ext = gf_isom_audio_sample_get_audio_codec_cfg_box((GF_AudioSampleEntryBox *)aud_entry);
2249 17 : if (!codec_ext) return GF_OK;
2250 :
2251 1 : if (!wave_box) {
2252 1 : wave_box = gf_isom_box_new_parent(&aud_entry->child_boxes, GF_QT_BOX_TYPE_WAVE);
2253 : }
2254 :
2255 1 : for (i=0; i<gf_list_count(wave_box->child_boxes); i++) {
2256 0 : GF_Box *b = gf_list_get(wave_box->child_boxes, i);
2257 0 : switch (b->type) {
2258 0 : case GF_QT_BOX_TYPE_ENDA:
2259 : enda = (GF_ChromaInfoBox *)b;
2260 0 : break;
2261 0 : case GF_QT_BOX_TYPE_FRMA:
2262 : frma = (GF_OriginalFormatBox *)b;
2263 0 : break;
2264 0 : case GF_ISOM_BOX_TYPE_ESDS:
2265 : esds = (GF_ESDBox *)b;
2266 0 : break;
2267 0 : case GF_ISOM_BOX_TYPE_UNKNOWN:
2268 0 : if ( ((GF_UnknownBox*)b)->original_4cc == 0)
2269 : terminator = b;
2270 : break;
2271 0 : case 0:
2272 : terminator = b;
2273 0 : break;
2274 : }
2275 : }
2276 1 : if (!wave_box->child_boxes) wave_box->child_boxes = gf_list_new();
2277 :
2278 : //do not use new_parent, we do this manually to ensure the order
2279 1 : aud_entry->qtff_mode = old_qtff_mode ? old_qtff_mode : GF_ISOM_AUDIO_QTFF_ON_NOEXT;
2280 1 : if (!frma) {
2281 1 : frma = (GF_OriginalFormatBox *)gf_isom_box_new(GF_QT_BOX_TYPE_FRMA);
2282 : } else {
2283 0 : gf_list_del_item(wave_box->child_boxes, frma);
2284 : }
2285 1 : gf_list_add(wave_box->child_boxes, frma);
2286 :
2287 1 : if (esds) gf_list_del_item(wave_box->child_boxes, esds);
2288 1 : if (!esds && (aud_entry->type==GF_ISOM_BOX_TYPE_MP4A) && ((GF_MPEGAudioSampleEntryBox*)aud_entry)->esd) {
2289 1 : gf_list_del_item(entry->child_boxes, (GF_Box *) ((GF_MPEGAudioSampleEntryBox*)aud_entry)->esd);
2290 1 : gf_list_add(wave_box->child_boxes, (GF_Box *) ((GF_MPEGAudioSampleEntryBox*)aud_entry)->esd);
2291 : }
2292 :
2293 1 : if (!enda) {
2294 1 : enda = (GF_ChromaInfoBox *)gf_isom_box_new(GF_QT_BOX_TYPE_ENDA);
2295 : } else {
2296 0 : gf_list_del_item(wave_box->child_boxes, enda);
2297 : }
2298 1 : enda->chroma=1;
2299 1 : gf_list_add(wave_box->child_boxes, enda);
2300 :
2301 1 : if (!terminator) {
2302 1 : terminator = gf_isom_box_new(0);
2303 : } else {
2304 0 : gf_list_del_item(wave_box->child_boxes, terminator);
2305 : }
2306 1 : gf_list_add(wave_box->child_boxes, terminator);
2307 :
2308 1 : if (aud_entry->type==GF_ISOM_BOX_TYPE_GNRA) {
2309 0 : frma->data_format = ((GF_GenericAudioSampleEntryBox*) aud_entry)->EntryType;
2310 : } else {
2311 1 : frma->data_format = aud_entry->type;
2312 : }
2313 :
2314 : return GF_OK;
2315 : }
2316 :
2317 : GF_EXPORT
2318 5 : GF_Err gf_isom_set_audio_layout(GF_ISOFile *movie, u32 trackNumber, u32 sampleDescriptionIndex, GF_AudioChannelLayout *layout)
2319 : {
2320 : GF_Err e;
2321 : GF_TrackBox *trak;
2322 : GF_SampleEntryBox *entry;
2323 : GF_AudioSampleEntryBox*aud_entry;
2324 : GF_SampleDescriptionBox *stsd;
2325 : GF_ChannelLayoutBox *chnl;
2326 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
2327 : if (e) return e;
2328 :
2329 5 : trak = gf_isom_get_track_from_file(movie, trackNumber);
2330 5 : if (!trak) return GF_BAD_PARAM;
2331 :
2332 5 : stsd = trak->Media->information->sampleTable->SampleDescription;
2333 5 : if (!stsd) {
2334 0 : return movie->LastError = GF_ISOM_INVALID_FILE;
2335 : }
2336 5 : if (!sampleDescriptionIndex || sampleDescriptionIndex > gf_list_count(stsd->child_boxes)) {
2337 0 : return movie->LastError = GF_BAD_PARAM;
2338 : }
2339 5 : entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, sampleDescriptionIndex - 1);
2340 : //no support for generic sample entries (eg, no MPEG4 descriptor)
2341 5 : if (entry == NULL) return GF_BAD_PARAM;
2342 5 : if (!movie->keep_utc)
2343 5 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
2344 :
2345 5 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO) return GF_BAD_PARAM;
2346 : aud_entry = (GF_AudioSampleEntryBox*) entry;
2347 5 : if (aud_entry->qtff_mode) {
2348 0 : u32 sr = aud_entry->samplerate_hi;
2349 0 : if (aud_entry->type==GF_ISOM_BOX_TYPE_MLPA) {
2350 0 : sr <<= 16;
2351 0 : sr |= aud_entry->samplerate_lo;
2352 : }
2353 0 : e = gf_isom_set_audio_info(movie, trackNumber, sampleDescriptionIndex, sr, aud_entry->channel_count, (u8) aud_entry->bitspersample, GF_IMPORT_AUDIO_SAMPLE_ENTRY_v1_MPEG);
2354 0 : if (e) return e;
2355 : }
2356 5 : chnl = (GF_ChannelLayoutBox *) gf_isom_box_find_child(aud_entry->child_boxes, GF_ISOM_BOX_TYPE_CHNL);
2357 5 : if (!chnl) {
2358 5 : chnl = (GF_ChannelLayoutBox *)gf_isom_box_new_parent(&aud_entry->child_boxes, GF_ISOM_BOX_TYPE_CHNL);
2359 5 : if (!chnl) return GF_OUT_OF_MEM;
2360 : }
2361 5 : aud_entry->channel_count = layout->channels_count;
2362 5 : memcpy(&chnl->layout, layout, sizeof(GF_AudioChannelLayout));
2363 5 : return GF_OK;
2364 : }
2365 :
2366 : //set the storage mode of a file (FLAT, STREAMABLE, INTERLEAVED)
2367 : GF_EXPORT
2368 1064 : GF_Err gf_isom_set_storage_mode(GF_ISOFile *movie, GF_ISOStorageMode storageMode)
2369 : {
2370 : GF_Err e;
2371 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
2372 : if (e) return e;
2373 :
2374 1064 : switch (storageMode) {
2375 1064 : case GF_ISOM_STORE_FLAT:
2376 : case GF_ISOM_STORE_STREAMABLE:
2377 : case GF_ISOM_STORE_INTERLEAVED:
2378 : case GF_ISOM_STORE_DRIFT_INTERLEAVED:
2379 : case GF_ISOM_STORE_TIGHT:
2380 : case GF_ISOM_STORE_FASTSTART:
2381 1064 : movie->storageMode = storageMode;
2382 : //specifying a storage mode disables inplace rewrite
2383 1064 : gf_isom_disable_inplace_rewrite(movie);
2384 1064 : return GF_OK;
2385 : default:
2386 : return GF_BAD_PARAM;
2387 : }
2388 : }
2389 :
2390 :
2391 : GF_EXPORT
2392 2 : GF_Err gf_isom_enable_compression(GF_ISOFile *file, GF_ISOCompressMode compress_mode, u32 compress_flags)
2393 : {
2394 2 : if (!file) return GF_BAD_PARAM;
2395 2 : file->compress_mode = compress_mode;
2396 2 : file->compress_flags = compress_flags;
2397 2 : return GF_OK;
2398 : }
2399 :
2400 : GF_EXPORT
2401 1 : GF_Err gf_isom_force_64bit_chunk_offset(GF_ISOFile *file, Bool set_on)
2402 : {
2403 1 : if (!file) return GF_BAD_PARAM;
2404 1 : file->force_co64 = set_on;
2405 1 : return GF_OK;
2406 : }
2407 :
2408 :
2409 : //update or insert a new edit segment in the track time line. Edits are used to modify
2410 : //the media normal timing. EditTime and EditDuration are expressed in Movie TimeScale
2411 : //If a segment with EditTime already exists, IT IS ERASED
2412 562 : static GF_Err gf_isom_set_edit_internal(GF_ISOFile *movie, u32 trackNumber, u64 EditTime, u64 EditDuration, u64 MediaTime, u32 media_rate, GF_ISOEditType EditMode)
2413 : {
2414 : GF_TrackBox *trak;
2415 : GF_EditBox *edts;
2416 : GF_EditListBox *elst;
2417 : GF_EdtsEntry *ent, *newEnt;
2418 : u32 i;
2419 : GF_Err e;
2420 : u64 startTime;
2421 :
2422 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
2423 : if (e) return e;
2424 :
2425 556 : trak = gf_isom_get_track_from_file(movie, trackNumber);
2426 556 : if (!trak) return GF_BAD_PARAM;
2427 :
2428 556 : edts = trak->editBox;
2429 556 : if (! edts) {
2430 472 : edts = (GF_EditBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_EDTS);
2431 472 : if (!edts) return GF_OUT_OF_MEM;
2432 472 : trak_on_child_box((GF_Box*)trak, (GF_Box *)edts, GF_FALSE);
2433 : }
2434 556 : elst = edts->editList;
2435 556 : if (!elst) {
2436 472 : elst = (GF_EditListBox *) gf_isom_box_new_parent(&edts->child_boxes, GF_ISOM_BOX_TYPE_ELST);
2437 472 : if (!elst) return GF_OUT_OF_MEM;
2438 472 : edts_on_child_box((GF_Box*)edts, (GF_Box *)elst, GF_FALSE);
2439 : }
2440 :
2441 : startTime = 0;
2442 : ent = NULL;
2443 : //get the prev entry to this startTime if any
2444 556 : i=0;
2445 1195 : while ((ent = (GF_EdtsEntry *)gf_list_enum(elst->entryList, &i))) {
2446 84 : if ( (startTime <= EditTime) && (startTime + ent->segmentDuration > EditTime) )
2447 : goto found;
2448 83 : startTime += ent->segmentDuration;
2449 : }
2450 :
2451 : //not found, add a new entry, insert empty one if gap
2452 : if (!ent) {
2453 : Bool empty_inserted = GF_FALSE;
2454 555 : if (startTime != EditTime) {
2455 0 : newEnt = CreateEditEntry(EditTime - startTime, 0, GF_ISOM_EDIT_EMPTY);
2456 0 : if (!newEnt) return GF_OUT_OF_MEM;
2457 : empty_inserted = GF_TRUE;
2458 0 : gf_list_add(elst->entryList, newEnt);
2459 : }
2460 555 : newEnt = CreateEditEntry(EditDuration, MediaTime, EditMode);
2461 555 : if (!newEnt) return GF_OUT_OF_MEM;
2462 555 : if (EditMode==GF_ISOM_EDIT_NORMAL+1) {
2463 2 : newEnt->mediaRate = media_rate;
2464 : }
2465 555 : gf_list_add(elst->entryList, newEnt);
2466 555 : e = SetTrackDuration(trak);
2467 555 : if (e) return e;
2468 555 : return empty_inserted ? GF_EOS : GF_OK;
2469 : }
2470 :
2471 : startTime -= ent->segmentDuration;
2472 :
2473 1 : found:
2474 :
2475 : //if same time, we erase the current one...
2476 1 : if (startTime == EditTime) {
2477 1 : ent->segmentDuration = EditDuration;
2478 1 : if (EditMode==GF_ISOM_EDIT_NORMAL+1) {
2479 0 : ent->mediaRate = media_rate;
2480 0 : ent->mediaTime = MediaTime;
2481 : } else {
2482 1 : switch (EditMode) {
2483 1 : case GF_ISOM_EDIT_EMPTY:
2484 1 : ent->mediaRate = 0x10000;
2485 1 : ent->mediaTime = -1;
2486 1 : break;
2487 0 : case GF_ISOM_EDIT_DWELL:
2488 0 : ent->mediaRate = 0;
2489 0 : ent->mediaTime = MediaTime;
2490 0 : break;
2491 0 : default:
2492 0 : ent->mediaRate = 0x10000;
2493 0 : ent->mediaTime = MediaTime;
2494 0 : break;
2495 : }
2496 : }
2497 1 : return SetTrackDuration(trak);
2498 : }
2499 :
2500 : //adjust so that the prev ent leads to EntryTime
2501 : //Note: we don't change the next one as it is unknown to us in
2502 : //a lot of case (the author's changes)
2503 0 : ent->segmentDuration = EditTime - startTime;
2504 0 : newEnt = CreateEditEntry(EditDuration, MediaTime, EditMode);
2505 0 : if (!newEnt) return GF_OUT_OF_MEM;
2506 0 : if (EditMode==GF_ISOM_EDIT_NORMAL+1) {
2507 0 : newEnt->mediaRate = media_rate;
2508 0 : newEnt->mediaTime = MediaTime;
2509 : }
2510 : //is it the last entry ???
2511 0 : if (i >= gf_list_count(elst->entryList) - 1) {
2512 : //add the new entry at the end
2513 0 : gf_list_add(elst->entryList, newEnt);
2514 0 : return SetTrackDuration(trak);
2515 : } else {
2516 : //insert after the current entry (which is i)
2517 0 : gf_list_insert(elst->entryList, newEnt, i+1);
2518 0 : return SetTrackDuration(trak);
2519 : }
2520 : }
2521 :
2522 : GF_EXPORT
2523 560 : GF_Err gf_isom_set_edit(GF_ISOFile *movie, u32 trackNumber, u64 EditTime, u64 EditDuration, u64 MediaTime, GF_ISOEditType EditMode)
2524 : {
2525 560 : return gf_isom_set_edit_internal(movie, trackNumber, EditTime, EditDuration, MediaTime, 0, EditMode);
2526 : }
2527 :
2528 : GF_EXPORT
2529 2 : GF_Err gf_isom_set_edit_with_rate(GF_ISOFile *movie, u32 trackNumber, u64 EditTime, u64 EditDuration, u64 MediaTime, u32 media_rate)
2530 : {
2531 2 : return gf_isom_set_edit_internal(movie, trackNumber, EditTime, EditDuration, MediaTime, media_rate, GF_ISOM_EDIT_NORMAL+1);
2532 :
2533 : }
2534 :
2535 : //remove the edit segments for the whole track
2536 : GF_EXPORT
2537 513 : GF_Err gf_isom_remove_edits(GF_ISOFile *movie, u32 trackNumber)
2538 : {
2539 : GF_Err e;
2540 : GF_TrackBox *trak;
2541 513 : trak = gf_isom_get_track_from_file(movie, trackNumber);
2542 513 : if (!trak) return GF_BAD_PARAM;
2543 :
2544 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
2545 : if (e) return e;
2546 :
2547 506 : if (!trak->editBox || !trak->editBox->editList) return GF_OK;
2548 :
2549 556 : while (gf_list_count(trak->editBox->editList->entryList)) {
2550 293 : GF_EdtsEntry *ent = (GF_EdtsEntry*)gf_list_get(trak->editBox->editList->entryList, 0);
2551 293 : gf_free(ent);
2552 293 : e = gf_list_rem(trak->editBox->editList->entryList, 0);
2553 293 : if (e) return e;
2554 : }
2555 : //then delete the GF_EditBox...
2556 263 : gf_isom_box_del_parent(&trak->child_boxes, (GF_Box *)trak->editBox);
2557 263 : trak->editBox = NULL;
2558 263 : return SetTrackDuration(trak);
2559 : }
2560 :
2561 :
2562 : //remove the edit segments for the whole track
2563 : GF_EXPORT
2564 0 : GF_Err gf_isom_remove_edit(GF_ISOFile *movie, u32 trackNumber, u32 seg_index)
2565 : {
2566 : GF_Err e;
2567 : GF_TrackBox *trak;
2568 : GF_EdtsEntry *ent, *next_ent;
2569 0 : trak = gf_isom_get_track_from_file(movie, trackNumber);
2570 0 : if (!trak || !seg_index) return GF_BAD_PARAM;
2571 :
2572 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
2573 : if (e) return e;
2574 :
2575 0 : if (!trak->editBox || !trak->editBox->editList) return GF_OK;
2576 0 : if (gf_list_count(trak->editBox->editList->entryList)<=1) return gf_isom_remove_edits(movie, trackNumber);
2577 :
2578 0 : ent = (GF_EdtsEntry*) gf_list_get(trak->editBox->editList->entryList, seg_index-1);
2579 0 : gf_list_rem(trak->editBox->editList->entryList, seg_index-1);
2580 0 : next_ent = (GF_EdtsEntry *)gf_list_get(trak->editBox->editList->entryList, seg_index-1);
2581 0 : if (next_ent) next_ent->segmentDuration += ent->segmentDuration;
2582 0 : gf_free(ent);
2583 0 : return SetTrackDuration(trak);
2584 : }
2585 :
2586 :
2587 : GF_EXPORT
2588 1 : GF_Err gf_isom_append_edit(GF_ISOFile *movie, u32 trackNumber, u64 EditDuration, u64 MediaTime, GF_ISOEditType EditMode)
2589 : {
2590 : GF_Err e;
2591 : GF_TrackBox *trak;
2592 : GF_EdtsEntry *ent;
2593 1 : trak = gf_isom_get_track_from_file(movie, trackNumber);
2594 1 : if (!trak) return GF_BAD_PARAM;
2595 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
2596 : if (e) return e;
2597 :
2598 1 : if (!trak->editBox) {
2599 1 : GF_EditBox *edts = (GF_EditBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_EDTS);
2600 1 : if (!edts) return GF_OUT_OF_MEM;
2601 1 : trak_on_child_box((GF_Box*)trak, (GF_Box *)edts, GF_FALSE);
2602 : assert(trak->editBox);
2603 : }
2604 1 : if (!trak->editBox->editList) {
2605 1 : GF_EditListBox *elst = (GF_EditListBox *) gf_isom_box_new_parent(&trak->editBox->child_boxes, GF_ISOM_BOX_TYPE_ELST);
2606 1 : if (!elst) return GF_OUT_OF_MEM;
2607 1 : edts_on_child_box((GF_Box*)trak->editBox, (GF_Box *)elst, GF_FALSE);
2608 : assert(trak->editBox->editList);
2609 : }
2610 1 : ent = (GF_EdtsEntry *)gf_malloc(sizeof(GF_EdtsEntry));
2611 1 : if (!ent) return GF_OUT_OF_MEM;
2612 :
2613 1 : ent->segmentDuration = EditDuration;
2614 1 : switch (EditMode) {
2615 0 : case GF_ISOM_EDIT_EMPTY:
2616 0 : ent->mediaRate = 0x10000;
2617 0 : ent->mediaTime = -1;
2618 0 : break;
2619 0 : case GF_ISOM_EDIT_DWELL:
2620 0 : ent->mediaRate = 0;
2621 0 : ent->mediaTime = MediaTime;
2622 0 : break;
2623 1 : default:
2624 1 : ent->mediaRate = 0x10000;
2625 1 : ent->mediaTime = MediaTime;
2626 1 : break;
2627 : }
2628 1 : gf_list_add(trak->editBox->editList->entryList, ent);
2629 1 : return SetTrackDuration(trak);
2630 : }
2631 :
2632 : GF_EXPORT
2633 7 : GF_Err gf_isom_modify_edit(GF_ISOFile *movie, u32 trackNumber, u32 seg_index, u64 EditDuration, u64 MediaTime, GF_ISOEditType EditMode)
2634 : {
2635 : GF_Err e;
2636 : GF_TrackBox *trak;
2637 : GF_EdtsEntry *ent;
2638 7 : trak = gf_isom_get_track_from_file(movie, trackNumber);
2639 7 : if (!trak || !seg_index) return GF_BAD_PARAM;
2640 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
2641 : if (e) return e;
2642 :
2643 7 : if (!trak->editBox || !trak->editBox->editList) return GF_OK;
2644 7 : if (gf_list_count(trak->editBox->editList->entryList)<seg_index) return GF_BAD_PARAM;
2645 7 : ent = (GF_EdtsEntry*) gf_list_get(trak->editBox->editList->entryList, seg_index-1);
2646 :
2647 7 : ent->segmentDuration = EditDuration;
2648 7 : switch (EditMode) {
2649 0 : case GF_ISOM_EDIT_EMPTY:
2650 0 : ent->mediaRate = 0x10000;
2651 0 : ent->mediaTime = -1;
2652 0 : break;
2653 0 : case GF_ISOM_EDIT_DWELL:
2654 0 : ent->mediaRate = 0;
2655 0 : ent->mediaTime = MediaTime;
2656 0 : break;
2657 7 : default:
2658 7 : ent->mediaRate = 0x10000;
2659 7 : ent->mediaTime = MediaTime;
2660 7 : break;
2661 : }
2662 7 : return SetTrackDuration(trak);
2663 : }
2664 :
2665 : //removes the desired track
2666 : GF_EXPORT
2667 133 : GF_Err gf_isom_remove_track(GF_ISOFile *movie, u32 trackNumber)
2668 : {
2669 : GF_Err e;
2670 : GF_TrackBox *the_trak, *trak;
2671 : GF_TrackReferenceTypeBox *tref;
2672 : u32 i, j, k, descIndex;
2673 : GF_ISOTrackID *newRefs;
2674 : u8 found;
2675 : GF_ISOSample *samp;
2676 133 : the_trak = gf_isom_get_track_from_file(movie, trackNumber);
2677 133 : if (!the_trak) return GF_BAD_PARAM;
2678 :
2679 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
2680 : if (e) return e;
2681 :
2682 133 : if (movie->moov->iods && movie->moov->iods->descriptor) {
2683 : GF_Descriptor *desc;
2684 : GF_ES_ID_Inc *inc;
2685 : GF_List *ESDs;
2686 : desc = movie->moov->iods->descriptor;
2687 26 : if (desc->tag == GF_ODF_ISOM_IOD_TAG) {
2688 26 : ESDs = ((GF_IsomInitialObjectDescriptor *)desc)->ES_ID_IncDescriptors;
2689 0 : } else if (desc->tag == GF_ODF_ISOM_OD_TAG) {
2690 0 : ESDs = ((GF_IsomObjectDescriptor *)desc)->ES_ID_IncDescriptors;
2691 : } else {
2692 : return GF_ISOM_INVALID_FILE;
2693 : }
2694 :
2695 : //remove the track ref from the root OD if any
2696 26 : i=0;
2697 55 : while ((inc = (GF_ES_ID_Inc *)gf_list_enum(ESDs, &i))) {
2698 3 : if (inc->trackID == the_trak->Header->trackID) {
2699 2 : gf_odf_desc_del((GF_Descriptor *)inc);
2700 2 : i--;
2701 2 : gf_list_rem(ESDs, i);
2702 : }
2703 : }
2704 : }
2705 :
2706 : //remove the track from the movie
2707 133 : gf_list_del_item(movie->moov->trackList, the_trak);
2708 :
2709 : //rewrite any OD tracks
2710 133 : i=0;
2711 378 : while ((trak = (GF_TrackBox *)gf_list_enum(movie->moov->trackList, &i))) {
2712 112 : if (trak->Media->handler->handlerType != GF_ISOM_MEDIA_OD) continue;
2713 : //this is an OD track...
2714 0 : j = gf_isom_get_sample_count(movie, i);
2715 0 : for (k=0; k < j; k++) {
2716 : //getting the sample will remove the references to the deleted track in the output OD frame
2717 0 : samp = gf_isom_get_sample(movie, i, k+1, &descIndex);
2718 0 : if (!samp) break;
2719 : //so let's update with the new OD frame ! If the sample is empty, remove it
2720 0 : if (!samp->dataLength) {
2721 0 : e = gf_isom_remove_sample(movie, i, k+1);
2722 0 : if (e) return e;
2723 : } else {
2724 0 : e = gf_isom_update_sample(movie, i, k+1, samp, GF_TRUE);
2725 0 : if (e) return e;
2726 : }
2727 : //and don't forget to delete the sample
2728 0 : gf_isom_sample_del(&samp);
2729 : }
2730 : }
2731 :
2732 : //remove the track ref from any "tref" box in all tracks, except the one to delete
2733 : //note that we don't touch scal references, as we don't want to rewrite AVC/HEVC samples ...
2734 133 : i=0;
2735 378 : while ((trak = (GF_TrackBox *)gf_list_enum(movie->moov->trackList, &i))) {
2736 112 : if (trak == the_trak) continue;
2737 112 : if (! trak->References || ! gf_list_count(trak->References->child_boxes)) continue;
2738 :
2739 48 : j=0;
2740 145 : while ((tref = (GF_TrackReferenceTypeBox *)gf_list_enum(trak->References->child_boxes, &j))) {
2741 49 : if (tref->reference_type==GF_ISOM_REF_SCAL)
2742 1 : continue;
2743 :
2744 : found = 0;
2745 84 : for (k=0; k<tref->trackIDCount; k++) {
2746 84 : if (tref->trackIDs[k] == the_trak->Header->trackID) found++;
2747 : }
2748 48 : if (!found) continue;
2749 : //no more refs, remove this ref_type
2750 9 : if (found == tref->trackIDCount) {
2751 1 : gf_isom_box_del_parent(&trak->References->child_boxes, (GF_Box *)tref);
2752 1 : j--;
2753 : } else {
2754 8 : newRefs = (GF_ISOTrackID*)gf_malloc(sizeof(GF_ISOTrackID) * (tref->trackIDCount - found));
2755 8 : if (!newRefs) return GF_OUT_OF_MEM;
2756 : found = 0;
2757 44 : for (k = 0; k < tref->trackIDCount; k++) {
2758 44 : if (tref->trackIDs[k] != the_trak->Header->trackID) {
2759 36 : newRefs[k-found] = tref->trackIDs[k];
2760 : } else {
2761 8 : found++;
2762 : }
2763 : }
2764 8 : gf_free(tref->trackIDs);
2765 8 : tref->trackIDs = newRefs;
2766 8 : tref->trackIDCount -= found;
2767 : }
2768 : }
2769 : //a little opt: remove the ref box if empty...
2770 48 : if (! gf_list_count(trak->References->child_boxes)) {
2771 1 : gf_isom_box_del_parent(&trak->child_boxes, (GF_Box *)trak->References);
2772 1 : trak->References = NULL;
2773 : }
2774 : }
2775 :
2776 133 : gf_isom_disable_inplace_rewrite(movie);
2777 :
2778 : //delete the track
2779 133 : gf_isom_box_del_parent(&movie->moov->child_boxes, (GF_Box *)the_trak);
2780 :
2781 : /*update next track ID*/
2782 133 : movie->moov->mvhd->nextTrackID = 0;
2783 133 : i=0;
2784 378 : while ((trak = (GF_TrackBox *)gf_list_enum(movie->moov->trackList, &i))) {
2785 112 : if (trak->Header->trackID>movie->moov->mvhd->nextTrackID)
2786 107 : movie->moov->mvhd->nextTrackID = trak->Header->trackID;
2787 : }
2788 :
2789 133 : if (!gf_list_count(movie->moov->trackList)) {
2790 76 : gf_list_del_item(movie->TopBoxes, movie->moov);
2791 76 : gf_isom_box_del((GF_Box *)movie->moov);
2792 76 : movie->moov = NULL;
2793 : }
2794 : return GF_OK;
2795 : }
2796 :
2797 :
2798 : GF_EXPORT
2799 1 : GF_Err gf_isom_set_copyright(GF_ISOFile *movie, const char *threeCharCode, char *notice)
2800 : {
2801 : GF_Err e;
2802 : GF_CopyrightBox *ptr;
2803 : GF_UserDataMap *map;
2804 : u32 count, i;
2805 :
2806 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
2807 : if (e) return e;
2808 :
2809 1 : if (!notice || !threeCharCode) return GF_BAD_PARAM;
2810 :
2811 1 : e = gf_isom_insert_moov(movie);
2812 1 : if (e) return e;
2813 :
2814 1 : if (!movie->moov->udta) {
2815 1 : e = moov_on_child_box((GF_Box*)movie->moov, gf_isom_box_new_parent(&movie->moov->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
2816 1 : if (e) return e;
2817 : }
2818 1 : map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_CPRT, NULL);
2819 :
2820 1 : if (map) {
2821 : //try to find one in our language...
2822 0 : count = gf_list_count(map->boxes);
2823 0 : for (i=0; i<count; i++) {
2824 0 : ptr = (GF_CopyrightBox*)gf_list_get(map->boxes, i);
2825 0 : if (!strcmp(threeCharCode, (const char *) ptr->packedLanguageCode)) {
2826 0 : gf_free(ptr->notice);
2827 0 : ptr->notice = (char*)gf_malloc(sizeof(char) * (strlen(notice) + 1));
2828 0 : if (!ptr->notice) return GF_OUT_OF_MEM;
2829 : strcpy(ptr->notice, notice);
2830 0 : return GF_OK;
2831 : }
2832 : }
2833 : }
2834 : //nope, create one
2835 1 : ptr = (GF_CopyrightBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_CPRT);
2836 1 : if (!ptr) return GF_OUT_OF_MEM;
2837 :
2838 1 : memcpy(ptr->packedLanguageCode, threeCharCode, 4);
2839 1 : ptr->notice = (char*)gf_malloc(sizeof(char) * (strlen(notice)+1));
2840 1 : if (!ptr->notice) return GF_OUT_OF_MEM;
2841 : strcpy(ptr->notice, notice);
2842 1 : return udta_on_child_box((GF_Box *)movie->moov->udta, (GF_Box *) ptr, GF_FALSE);
2843 : }
2844 :
2845 : GF_EXPORT
2846 65 : GF_Err gf_isom_add_track_kind(GF_ISOFile *movie, u32 trackNumber, const char *schemeURI, const char *value)
2847 : {
2848 : GF_Err e;
2849 : GF_KindBox *ptr;
2850 : GF_UserDataBox *udta;
2851 : GF_UserDataMap *map;
2852 : u32 i, count;
2853 :
2854 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
2855 : if (e) return e;
2856 :
2857 65 : e = gf_isom_insert_moov(movie);
2858 65 : if (e) return e;
2859 :
2860 65 : if (trackNumber) {
2861 65 : GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
2862 65 : if (!trak) return GF_BAD_PARAM;
2863 65 : if (!trak->udta) {
2864 41 : e = trak_on_child_box((GF_Box*)trak, gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
2865 41 : if (e) return e;
2866 : }
2867 65 : udta = trak->udta;
2868 : } else {
2869 : return GF_BAD_PARAM;
2870 : }
2871 :
2872 65 : map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_KIND, NULL);
2873 65 : if (map) {
2874 24 : count = gf_list_count(map->boxes);
2875 43 : for (i=0; i<count; i++) {
2876 28 : GF_Box *b = (GF_Box *)gf_list_get(map->boxes, i);
2877 28 : if (b->type == GF_ISOM_BOX_TYPE_KIND) {
2878 : GF_KindBox *kb = (GF_KindBox *)b;
2879 28 : if (!strcmp(kb->schemeURI, schemeURI) &&
2880 10 : ((value && kb->value && !strcmp(value, kb->value)) || (!value && !kb->value))) {
2881 : // Already there
2882 : return GF_OK;
2883 : }
2884 : }
2885 : }
2886 : }
2887 :
2888 56 : ptr = (GF_KindBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_KIND);
2889 56 : if (e) return e;
2890 :
2891 56 : ptr->schemeURI = gf_strdup(schemeURI);
2892 56 : if (value) ptr->value = gf_strdup(value);
2893 56 : return udta_on_child_box((GF_Box *)udta, (GF_Box *) ptr, GF_FALSE);
2894 : }
2895 :
2896 : GF_EXPORT
2897 38 : GF_Err gf_isom_remove_track_kind(GF_ISOFile *movie, u32 trackNumber, const char *schemeURI, const char *value)
2898 : {
2899 : GF_Err e;
2900 : GF_UserDataBox *udta;
2901 : GF_UserDataMap *map;
2902 : u32 i;
2903 :
2904 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
2905 : if (e) return e;
2906 38 : e = gf_isom_insert_moov(movie);
2907 38 : if (e) return e;
2908 :
2909 38 : if (trackNumber) {
2910 38 : GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
2911 38 : if (!trak) return GF_BAD_PARAM;
2912 38 : if (!trak->udta) {
2913 0 : e = trak_on_child_box((GF_Box*)trak, gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
2914 0 : if (e) return e;
2915 : }
2916 38 : udta = trak->udta;
2917 : } else {
2918 : return GF_OK;
2919 : }
2920 38 : map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_KIND, NULL);
2921 38 : if (map) {
2922 51 : for (i=0; i<gf_list_count(map->boxes); i++) {
2923 51 : GF_Box *b = (GF_Box *)gf_list_get(map->boxes, i);
2924 51 : if (b->type == GF_ISOM_BOX_TYPE_KIND) {
2925 : GF_KindBox *kb = (GF_KindBox *)b;
2926 102 : if (!schemeURI ||
2927 97 : (!strcmp(kb->schemeURI, schemeURI) &&
2928 21 : ((value && kb->value && !strcmp(value, kb->value)) || (!value && !kb->value)))) {
2929 34 : gf_isom_box_del_parent(&map->boxes, b);
2930 34 : i--;
2931 : }
2932 : }
2933 : }
2934 : }
2935 : return GF_OK;
2936 : }
2937 :
2938 : GF_EXPORT
2939 9 : GF_Err gf_isom_add_chapter(GF_ISOFile *movie, u32 trackNumber, u64 timestamp, char *name)
2940 : {
2941 : GF_Err e;
2942 : GF_ChapterListBox *ptr;
2943 : u32 i, count;
2944 : GF_ChapterEntry *ce;
2945 : GF_UserDataBox *udta;
2946 : GF_UserDataMap *map;
2947 :
2948 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
2949 : if (e) return e;
2950 :
2951 9 : e = gf_isom_insert_moov(movie);
2952 9 : if (e) return e;
2953 :
2954 9 : if (trackNumber) {
2955 0 : GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
2956 0 : if (!trak) return GF_BAD_PARAM;
2957 0 : if (!trak->udta) {
2958 0 : e = trak_on_child_box((GF_Box*)trak, gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
2959 0 : if (e) return e;
2960 : }
2961 0 : udta = trak->udta;
2962 : } else {
2963 9 : if (!movie->moov->udta) {
2964 2 : e = moov_on_child_box((GF_Box*)movie->moov, gf_isom_box_new_parent(&movie->moov->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
2965 2 : if (e) return e;
2966 : }
2967 9 : udta = movie->moov->udta;
2968 : }
2969 :
2970 : ptr = NULL;
2971 9 : map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_CHPL, NULL);
2972 9 : if (!map) {
2973 2 : ptr = (GF_ChapterListBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_CHPL);
2974 2 : e = udta_on_child_box((GF_Box *)udta, (GF_Box *) ptr, GF_FALSE);
2975 2 : if (e) return e;
2976 2 : map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_CHPL, NULL);
2977 : } else {
2978 7 : ptr = (GF_ChapterListBox*)gf_list_get(map->boxes, 0);
2979 : }
2980 9 : if (!map) return GF_OUT_OF_MEM;
2981 :
2982 : /*this may happen if original MP4 is not properly formatted*/
2983 9 : if (!ptr) {
2984 0 : ptr = (GF_ChapterListBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_CHPL);
2985 0 : if (!ptr) return GF_OUT_OF_MEM;
2986 0 : gf_list_add(map->boxes, ptr);
2987 : }
2988 :
2989 9 : GF_SAFEALLOC(ce, GF_ChapterEntry);
2990 9 : if (!ce) return GF_OUT_OF_MEM;
2991 :
2992 9 : ce->start_time = timestamp * 10000L;
2993 9 : ce->name = name ? gf_strdup(name) : NULL;
2994 :
2995 : /*insert in order*/
2996 9 : count = gf_list_count(ptr->list);
2997 25 : for (i=0; i<count; i++) {
2998 16 : GF_ChapterEntry *ace = (GF_ChapterEntry *)gf_list_get(ptr->list, i);
2999 16 : if (ace->start_time == ce->start_time) {
3000 0 : if (ace->name) gf_free(ace->name);
3001 0 : ace->name = ce->name;
3002 0 : gf_free(ce);
3003 0 : return GF_OK;
3004 : }
3005 16 : if (ace->start_time >= ce->start_time)
3006 0 : return gf_list_insert(ptr->list, ce, i);
3007 : }
3008 9 : return gf_list_add(ptr->list, ce);
3009 : }
3010 :
3011 : GF_EXPORT
3012 4 : GF_Err gf_isom_remove_chapter(GF_ISOFile *movie, u32 trackNumber, u32 index)
3013 : {
3014 : GF_Err e;
3015 : GF_ChapterListBox *ptr;
3016 : GF_ChapterEntry *ce;
3017 : GF_UserDataBox *udta;
3018 : GF_UserDataMap *map;
3019 :
3020 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
3021 : if (e) return e;
3022 4 : e = gf_isom_insert_moov(movie);
3023 4 : if (e) return e;
3024 :
3025 4 : if (trackNumber) {
3026 0 : GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
3027 0 : if (!trak) return GF_BAD_PARAM;
3028 0 : if (!trak->udta) return GF_OK;
3029 : udta = trak->udta;
3030 : } else {
3031 4 : if (!movie->moov->udta) return GF_OK;
3032 : udta = movie->moov->udta;
3033 : }
3034 :
3035 0 : map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_CHPL, NULL);
3036 0 : if (!map) return GF_OK;
3037 0 : ptr = (GF_ChapterListBox*)gf_list_get(map->boxes, 0);
3038 0 : if (!ptr) return GF_OK;
3039 :
3040 0 : if (index) {
3041 0 : ce = (GF_ChapterEntry *)gf_list_get(ptr->list, index-1);
3042 0 : if (!ce) return GF_BAD_PARAM;
3043 0 : if (ce->name) gf_free(ce->name);
3044 0 : gf_free(ce);
3045 0 : gf_list_rem(ptr->list, index-1);
3046 : } else {
3047 0 : while (gf_list_count(ptr->list)) {
3048 0 : ce = (GF_ChapterEntry *)gf_list_get(ptr->list, 0);
3049 0 : if (ce->name) gf_free(ce->name);
3050 0 : gf_free(ce);
3051 0 : gf_list_rem(ptr->list, 0);
3052 : }
3053 : }
3054 0 : if (!gf_list_count(ptr->list)) {
3055 0 : gf_list_del_item(udta->recordList, map);
3056 0 : gf_isom_box_array_del(map->boxes);
3057 0 : gf_free(map);
3058 : }
3059 : return GF_OK;
3060 : }
3061 :
3062 : #if 0 //unused
3063 : GF_Err gf_isom_remove_copyright(GF_ISOFile *movie, u32 index)
3064 : {
3065 : GF_Err e;
3066 : GF_CopyrightBox *ptr;
3067 : GF_UserDataMap *map;
3068 : u32 count;
3069 :
3070 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
3071 : if (e) return e;
3072 : e = gf_isom_insert_moov(movie);
3073 : if (e) return e;
3074 :
3075 : if (!index) return GF_BAD_PARAM;
3076 : if (!movie->moov->udta) return GF_OK;
3077 :
3078 : map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_CPRT, NULL);
3079 : if (!map) return GF_OK;
3080 :
3081 : count = gf_list_count(map->boxes);
3082 : if (index>count) return GF_BAD_PARAM;
3083 :
3084 : ptr = (GF_CopyrightBox*)gf_list_get(map->boxes, index-1);
3085 : if (ptr) {
3086 : gf_list_rem(map->boxes, index-1);
3087 : if (ptr->notice) gf_free(ptr->notice);
3088 : gf_free(ptr);
3089 : }
3090 : /*last copyright, remove*/
3091 : if (!gf_list_count(map->boxes)) {
3092 : gf_list_del_item(movie->moov->udta->recordList, map);
3093 : gf_list_del(map->boxes);
3094 : gf_free(map);
3095 : }
3096 : return GF_OK;
3097 : }
3098 :
3099 : GF_Err gf_isom_set_watermark(GF_ISOFile *movie, bin128 UUID, u8* data, u32 length)
3100 : {
3101 : GF_Err e;
3102 : GF_UnknownUUIDBox *ptr;
3103 : GF_UserDataMap *map;
3104 :
3105 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
3106 : if (e) return e;
3107 :
3108 : e = gf_isom_insert_moov(movie);
3109 : if (e) return e;
3110 : if (!movie->moov->udta) {
3111 : e = moov_on_child_box((GF_Box*)movie->moov, gf_isom_box_new_parent(&movie->moov->child_boxes, GF_ISOM_BOX_TYPE_UDTA));
3112 : if (e) return e;
3113 : }
3114 :
3115 : map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_UUID, (bin128 *) & UUID);
3116 : if (map) {
3117 : ptr = (GF_UnknownUUIDBox *)gf_list_get(map->boxes, 0);
3118 : if (ptr) {
3119 : gf_free(ptr->data);
3120 : ptr->data = (char*)gf_malloc(length);
3121 : if (!ptr->data) return GF_OUT_OF_MEM;
3122 : memcpy(ptr->data, data, length);
3123 : ptr->dataSize = length;
3124 : return GF_OK;
3125 : }
3126 : }
3127 : //nope, create one
3128 : ptr = (GF_UnknownUUIDBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_UUID);
3129 : if (!ptr) return GF_OUT_OF_MEM;
3130 :
3131 : memcpy(ptr->uuid, UUID, 16);
3132 : ptr->data = (char*)gf_malloc(length);
3133 : if (!ptr->data) return GF_OUT_OF_MEM;
3134 : memcpy(ptr->data, data, length);
3135 : ptr->dataSize = length;
3136 : return udta_on_child_box((GF_Box *)movie->moov->udta, (GF_Box *) ptr);
3137 : }
3138 : #endif
3139 :
3140 : //set the interleaving time of media data (INTERLEAVED mode only)
3141 : //InterleaveTime is in MovieTimeScale
3142 : GF_EXPORT
3143 1061 : GF_Err gf_isom_set_interleave_time(GF_ISOFile *movie, u32 InterleaveTime)
3144 : {
3145 : GF_Err e;
3146 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
3147 : if (e) return e;
3148 :
3149 1061 : if (!InterleaveTime || !movie->moov) return GF_OK;
3150 974 : movie->interleavingTime = InterleaveTime;
3151 974 : return GF_OK;
3152 : }
3153 :
3154 :
3155 :
3156 : //use a compact track version for sample size. This is not usually recommended
3157 : //except for speech codecs where the track has a lot of small samples
3158 : //compaction is done automatically while writing based on the track's sample sizes
3159 : GF_EXPORT
3160 1 : GF_Err gf_isom_use_compact_size(GF_ISOFile *movie, u32 trackNumber, Bool CompactionOn)
3161 : {
3162 : GF_TrackBox *trak;
3163 : u32 i, size;
3164 : GF_SampleSizeBox *stsz;
3165 : GF_Err e;
3166 :
3167 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
3168 : if (e) return e;
3169 :
3170 1 : trak = gf_isom_get_track_from_file(movie, trackNumber);
3171 1 : if (!trak) return GF_BAD_PARAM;
3172 :
3173 1 : if (!trak->Media || !trak->Media->information
3174 1 : || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleSize)
3175 : return GF_ISOM_INVALID_FILE;
3176 :
3177 : stsz = trak->Media->information->sampleTable->SampleSize;
3178 :
3179 : //switch to regular table
3180 1 : if (!CompactionOn) {
3181 0 : if (stsz->type == GF_ISOM_BOX_TYPE_STSZ) return GF_OK;
3182 0 : stsz->type = GF_ISOM_BOX_TYPE_STSZ;
3183 : //invalidate the sampleSize and recompute it
3184 0 : stsz->sampleSize = 0;
3185 0 : if (!stsz->sampleCount) return GF_OK;
3186 : //if the table is empty we can only assume the track is empty (no size indication)
3187 0 : if (!stsz->sizes) return GF_OK;
3188 0 : size = stsz->sizes[0];
3189 : //check whether the sizes are all the same or not
3190 0 : for (i=1; i<stsz->sampleCount; i++) {
3191 0 : if (size != stsz->sizes[i]) {
3192 : size = 0;
3193 : break;
3194 : }
3195 : }
3196 0 : if (size) {
3197 0 : gf_free(stsz->sizes);
3198 0 : stsz->sizes = NULL;
3199 0 : stsz->sampleSize = size;
3200 : }
3201 : return GF_OK;
3202 : }
3203 :
3204 : //switch to compact table
3205 1 : if (stsz->type == GF_ISOM_BOX_TYPE_STZ2) return GF_OK;
3206 : //fill the table. Although it seems weird , this is needed in case of edition
3207 : //after the function is called. NOte however than we force regular table
3208 : //at write time if all samples are of same size
3209 1 : if (stsz->sampleSize) {
3210 : //this is a weird table indeed ;)
3211 0 : if (stsz->sizes) gf_free(stsz->sizes);
3212 0 : stsz->sizes = (u32*) gf_malloc(sizeof(u32)*stsz->sampleCount);
3213 0 : if (!stsz->sizes) return GF_OUT_OF_MEM;
3214 0 : memset(stsz->sizes, stsz->sampleSize, sizeof(u32));
3215 : }
3216 : //set the SampleSize to 0 while the file is open
3217 1 : stsz->sampleSize = 0;
3218 1 : stsz->type = GF_ISOM_BOX_TYPE_STZ2;
3219 1 : return GF_OK;
3220 : }
3221 :
3222 :
3223 : GF_EXPORT
3224 2824 : GF_Err gf_isom_set_brand_info(GF_ISOFile *movie, u32 MajorBrand, u32 MinorVersion)
3225 : {
3226 : u32 i, *p;
3227 :
3228 2824 : if (!MajorBrand) return GF_BAD_PARAM;
3229 :
3230 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3231 2824 : if (! (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY)) {
3232 : GF_Err e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
3233 : if (e) return e;
3234 :
3235 2485 : e = CheckNoData(movie);
3236 : if (e) return e;
3237 : }
3238 : #endif
3239 :
3240 2824 : if (!movie->brand) {
3241 1297 : movie->brand = (GF_FileTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_FTYP);
3242 1297 : if (!movie->brand) return GF_OUT_OF_MEM;
3243 1297 : gf_list_add(movie->TopBoxes, movie->brand);
3244 : }
3245 :
3246 2824 : movie->brand->majorBrand = MajorBrand;
3247 2824 : movie->brand->minorVersion = MinorVersion;
3248 :
3249 2824 : if (!movie->brand->altBrand) {
3250 1297 : movie->brand->altBrand = (u32*)gf_malloc(sizeof(u32));
3251 1297 : if (!movie->brand->altBrand) return GF_OUT_OF_MEM;
3252 1297 : movie->brand->altBrand[0] = MajorBrand;
3253 1297 : movie->brand->altCount = 1;
3254 1297 : return GF_OK;
3255 : }
3256 :
3257 : //if brand already present don't change anything
3258 1802 : for (i=0; i<movie->brand->altCount; i++) {
3259 2198 : if (movie->brand->altBrand[i] == MajorBrand) return GF_OK;
3260 : }
3261 1131 : p = (u32*)gf_malloc(sizeof(u32)*(movie->brand->altCount + 1));
3262 1131 : if (!p) return GF_OUT_OF_MEM;
3263 1131 : memcpy(p, movie->brand->altBrand, sizeof(u32)*movie->brand->altCount);
3264 1131 : p[movie->brand->altCount] = MajorBrand;
3265 1131 : movie->brand->altCount += 1;
3266 1131 : gf_free(movie->brand->altBrand);
3267 1131 : movie->brand->altBrand = p;
3268 1131 : return GF_OK;
3269 : }
3270 :
3271 :
3272 : GF_EXPORT
3273 9767 : GF_Err gf_isom_modify_alternate_brand(GF_ISOFile *movie, u32 Brand, Bool AddIt)
3274 : {
3275 : u32 i, k, *p;
3276 :
3277 9767 : if (!Brand) return GF_BAD_PARAM;
3278 :
3279 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3280 9767 : if (! (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY)) {
3281 : GF_Err e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
3282 : if (e) return e;
3283 :
3284 7032 : e = CheckNoData(movie);
3285 : if (e) return e;
3286 : }
3287 : #endif
3288 :
3289 9763 : if (!movie->brand && AddIt) {
3290 0 : movie->brand = (GF_FileTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_FTYP);
3291 0 : if (!movie->brand) return GF_OUT_OF_MEM;
3292 0 : gf_list_add(movie->TopBoxes, movie->brand);
3293 : }
3294 9763 : if (!AddIt && !movie->brand) return GF_OK;
3295 :
3296 : //do not mofify major one
3297 9763 : if (!AddIt && movie->brand->majorBrand == Brand) return GF_OK;
3298 :
3299 9030 : if (!AddIt && movie->brand->altCount == 1) {
3300 : //fixes it in case
3301 1049 : movie->brand->altBrand[0] = movie->brand->majorBrand;
3302 1049 : return GF_OK;
3303 : }
3304 : //check for the brand
3305 9108 : for (i=0; i<movie->brand->altCount; i++) {
3306 12998 : if (movie->brand->altBrand[i] == Brand) goto found;
3307 : }
3308 : //Not found
3309 4091 : if (!AddIt) return GF_OK;
3310 : //add it
3311 2145 : p = (u32*)gf_malloc(sizeof(u32)*(movie->brand->altCount + 1));
3312 2145 : if (!p) return GF_OUT_OF_MEM;
3313 2145 : if (movie->brand->altBrand) {
3314 1613 : memcpy(p, movie->brand->altBrand, sizeof(u32)*movie->brand->altCount);
3315 1613 : gf_free(movie->brand->altBrand);
3316 : }
3317 2145 : p[movie->brand->altCount] = Brand;
3318 2145 : movie->brand->altCount += 1;
3319 2145 : movie->brand->altBrand = p;
3320 2145 : return GF_OK;
3321 :
3322 3890 : found:
3323 :
3324 : //found
3325 3890 : if (AddIt) return GF_OK;
3326 : assert(movie->brand->altCount>1);
3327 :
3328 : //remove it
3329 561 : p = (u32*)gf_malloc(sizeof(u32)*(movie->brand->altCount - 1));
3330 561 : if (!p) return GF_OUT_OF_MEM;
3331 : k = 0;
3332 1326 : for (i=0; i<movie->brand->altCount; i++) {
3333 1326 : if (movie->brand->altBrand[i] == Brand) continue;
3334 : else {
3335 765 : p[k] = movie->brand->altBrand[i];
3336 765 : k++;
3337 : }
3338 : }
3339 561 : movie->brand->altCount -= 1;
3340 561 : gf_free(movie->brand->altBrand);
3341 561 : movie->brand->altBrand = p;
3342 561 : return GF_OK;
3343 : }
3344 :
3345 :
3346 1048 : GF_Err gf_isom_reset_alt_brands_ex(GF_ISOFile *movie, Bool leave_empty)
3347 : {
3348 : u32 *p;
3349 :
3350 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3351 1048 : if (! (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY)) {
3352 : GF_Err e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
3353 : if (e) return e;
3354 :
3355 709 : e = CheckNoData(movie);
3356 : if (e) return e;
3357 : }
3358 : #endif
3359 :
3360 1048 : if (!movie->brand) {
3361 0 : movie->brand = (GF_FileTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_FTYP);
3362 0 : if (!movie->brand) return GF_OUT_OF_MEM;
3363 0 : gf_list_add(movie->TopBoxes, movie->brand);
3364 : }
3365 1048 : gf_free(movie->brand->altBrand);
3366 1048 : if (leave_empty) {
3367 532 : movie->brand->altCount = 0;
3368 532 : movie->brand->altBrand = NULL;
3369 : } else {
3370 516 : p = (u32*)gf_malloc(sizeof(u32));
3371 516 : if (!p) return GF_OUT_OF_MEM;
3372 516 : p[0] = movie->brand->majorBrand;
3373 516 : movie->brand->altCount = 1;
3374 516 : movie->brand->altBrand = p;
3375 : }
3376 : return GF_OK;
3377 : }
3378 : GF_EXPORT
3379 516 : GF_Err gf_isom_reset_alt_brands(GF_ISOFile *movie)
3380 : {
3381 516 : return gf_isom_reset_alt_brands_ex(movie, GF_FALSE);
3382 : }
3383 :
3384 : #if 0 //unused
3385 : GF_Err gf_isom_set_sample_padding_bits(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber, u8 NbBits)
3386 : {
3387 : GF_TrackBox *trak;
3388 : GF_Err e;
3389 :
3390 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
3391 : if (e) return e;
3392 :
3393 : trak = gf_isom_get_track_from_file(movie, trackNumber);
3394 : if (!trak || NbBits > 7) return GF_BAD_PARAM;
3395 :
3396 : //set Padding info
3397 : return stbl_SetPaddingBits(trak->Media->information->sampleTable, sampleNumber, NbBits);
3398 : }
3399 : #endif
3400 :
3401 : GF_EXPORT
3402 0 : GF_Err gf_isom_remove_user_data_item(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID, u32 UserDataIndex)
3403 : {
3404 : GF_UserDataMap *map;
3405 : GF_Box *a;
3406 : u32 i;
3407 : bin128 t;
3408 : GF_Err e;
3409 : GF_TrackBox *trak;
3410 : GF_UserDataBox *udta;
3411 :
3412 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
3413 : if (e) return e;
3414 :
3415 0 : if (UserDataType == GF_ISOM_BOX_TYPE_UUID) UserDataType = 0;
3416 : memset(t, 1, 16);
3417 :
3418 0 : if (trackNumber) {
3419 0 : trak = gf_isom_get_track_from_file(movie, trackNumber);
3420 0 : if (!trak) return GF_BAD_PARAM;
3421 0 : udta = trak->udta;
3422 : } else {
3423 0 : udta = movie->moov->udta;
3424 : }
3425 0 : if (!udta) return GF_BAD_PARAM;
3426 0 : if (!UserDataIndex) return GF_BAD_PARAM;
3427 :
3428 0 : i=0;
3429 0 : while ((map = (GF_UserDataMap*)gf_list_enum(udta->recordList, &i))) {
3430 0 : if ((map->boxType == GF_ISOM_BOX_TYPE_UUID) && !memcmp(map->uuid, UUID, 16)) goto found;
3431 0 : else if (map->boxType == UserDataType) goto found;
3432 : }
3433 : //not found
3434 : return GF_OK;
3435 :
3436 0 : found:
3437 :
3438 0 : if (UserDataIndex > gf_list_count(map->boxes) ) return GF_BAD_PARAM;
3439 : //delete the box
3440 0 : a = (GF_Box*)gf_list_get(map->boxes, UserDataIndex-1);
3441 0 : gf_isom_box_del_parent(&map->boxes, a);
3442 :
3443 : //remove the map if empty
3444 0 : if (!gf_list_count(map->boxes)) {
3445 0 : gf_list_rem(udta->recordList, i-1);
3446 0 : gf_isom_box_array_del(map->boxes);
3447 0 : gf_free(map);
3448 : }
3449 : //but we keep the UDTA no matter what
3450 : return GF_OK;
3451 : }
3452 :
3453 : GF_EXPORT
3454 1 : GF_Err gf_isom_remove_user_data(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID)
3455 : {
3456 : GF_UserDataMap *map;
3457 : u32 i;
3458 : GF_Err e;
3459 : bin128 t;
3460 : GF_TrackBox *trak;
3461 : GF_UserDataBox *udta;
3462 :
3463 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
3464 : if (e) return e;
3465 :
3466 1 : if (UserDataType == GF_ISOM_BOX_TYPE_UUID) UserDataType = 0;
3467 : memset(t, 1, 16);
3468 :
3469 1 : if (trackNumber) {
3470 0 : trak = gf_isom_get_track_from_file(movie, trackNumber);
3471 0 : if (!trak) return GF_EOS;
3472 0 : udta = trak->udta;
3473 : } else {
3474 1 : udta = movie->moov->udta;
3475 : }
3476 : //do not return any error if no udta
3477 1 : if (!udta) return GF_EOS;
3478 :
3479 1 : i=0;
3480 2 : while ((map = (GF_UserDataMap*)gf_list_enum(udta->recordList, &i))) {
3481 1 : if ((map->boxType == GF_ISOM_BOX_TYPE_UUID) && !memcmp(map->uuid, UUID, 16)) goto found;
3482 1 : else if (map->boxType == UserDataType) goto found;
3483 : }
3484 : //not found
3485 : return GF_OK;
3486 :
3487 1 : found:
3488 :
3489 1 : gf_list_rem(udta->recordList, i-1);
3490 1 : gf_isom_box_array_del(map->boxes);
3491 1 : gf_free(map);
3492 :
3493 : //but we keep the UDTA no matter what
3494 1 : return GF_OK;
3495 : }
3496 :
3497 : GF_EXPORT
3498 5 : GF_Err gf_isom_add_user_data(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID, u8 *data, u32 DataLength)
3499 : {
3500 : GF_Err e;
3501 : GF_TrackBox *trak;
3502 : GF_UserDataBox *udta;
3503 :
3504 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
3505 : if (e) return e;
3506 :
3507 5 : if (UserDataType == GF_ISOM_BOX_TYPE_UUID) UserDataType = 0;
3508 :
3509 5 : if (trackNumber) {
3510 4 : trak = gf_isom_get_track_from_file(movie, trackNumber);
3511 4 : if (!trak) return GF_BAD_PARAM;
3512 4 : if (!trak->udta) trak_on_child_box((GF_Box*)trak, gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
3513 4 : udta = trak->udta;
3514 : } else {
3515 1 : if (!movie->moov->udta) moov_on_child_box((GF_Box*)movie->moov, gf_isom_box_new_parent(&movie->moov->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
3516 1 : udta = movie->moov->udta;
3517 : }
3518 5 : if (!udta) return GF_OUT_OF_MEM;
3519 :
3520 : //create a default box
3521 5 : if (UserDataType) {
3522 5 : GF_UnknownBox *a = (GF_UnknownBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_UNKNOWN);
3523 5 : if (!a) return GF_OUT_OF_MEM;
3524 5 : a->original_4cc = UserDataType;
3525 5 : if (DataLength) {
3526 3 : a->data = (char*)gf_malloc(sizeof(char)*DataLength);
3527 3 : if (!a->data) return GF_OUT_OF_MEM;
3528 : memcpy(a->data, data, DataLength);
3529 3 : a->dataSize = DataLength;
3530 : }
3531 5 : return udta_on_child_box((GF_Box *)udta, (GF_Box *) a, GF_FALSE);
3532 : } else {
3533 0 : GF_UnknownUUIDBox *a = (GF_UnknownUUIDBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_UUID);
3534 0 : if (!a) return GF_OUT_OF_MEM;
3535 0 : memcpy(a->uuid, UUID, 16);
3536 0 : if (DataLength) {
3537 0 : a->data = (char*)gf_malloc(sizeof(char)*DataLength);
3538 0 : if (!a->data) return GF_OUT_OF_MEM;
3539 : memcpy(a->data, data, DataLength);
3540 0 : a->dataSize = DataLength;
3541 : }
3542 0 : return udta_on_child_box((GF_Box *)udta, (GF_Box *) a, GF_FALSE);
3543 : }
3544 : return GF_OK;
3545 : }
3546 :
3547 : GF_EXPORT
3548 1 : GF_Err gf_isom_add_user_data_boxes(GF_ISOFile *movie, u32 trackNumber, u8 *data, u32 DataLength)
3549 : {
3550 : GF_Err e;
3551 : GF_TrackBox *trak;
3552 : GF_UserDataBox *udta;
3553 : GF_BitStream *bs;
3554 :
3555 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
3556 : if (e) return e;
3557 :
3558 1 : if (trackNumber) {
3559 1 : trak = gf_isom_get_track_from_file(movie, trackNumber);
3560 1 : if (!trak) return GF_BAD_PARAM;
3561 1 : if (!trak->udta) trak_on_child_box((GF_Box*)trak, gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
3562 1 : udta = trak->udta;
3563 : } else {
3564 0 : if (!movie->moov) return GF_BAD_PARAM;
3565 0 : if (!movie->moov->udta) moov_on_child_box((GF_Box*)movie->moov, gf_isom_box_new_parent(&movie->moov->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
3566 0 : udta = movie->moov->udta;
3567 : }
3568 1 : if (!udta) return GF_OUT_OF_MEM;
3569 :
3570 1 : bs = gf_bs_new(data, DataLength, GF_BITSTREAM_READ);
3571 1 : while (gf_bs_available(bs)) {
3572 : GF_Box *a;
3573 4 : e = gf_isom_box_parse(&a, bs);
3574 4 : if (e) break;
3575 4 : e = udta_on_child_box((GF_Box *)udta, a, GF_FALSE);
3576 4 : if (e) break;
3577 : }
3578 1 : gf_bs_del(bs);
3579 1 : return e;
3580 : }
3581 :
3582 : GF_EXPORT
3583 7 : GF_Err gf_isom_clone_pl_indications(GF_ISOFile *orig, GF_ISOFile *dest)
3584 : {
3585 : GF_IsomInitialObjectDescriptor *iod_d;
3586 7 : if (!orig || !dest) return GF_BAD_PARAM;
3587 7 : if (!orig->moov->iods || !orig->moov->iods->descriptor) return GF_OK;
3588 5 : if (orig->moov->iods->descriptor->tag != GF_ODF_ISOM_IOD_TAG) return GF_OK;
3589 :
3590 5 : AddMovieIOD(dest->moov, 1);
3591 5 : gf_odf_desc_del((GF_Descriptor *)dest->moov->iods->descriptor);
3592 5 : gf_odf_desc_copy((GF_Descriptor *)orig->moov->iods->descriptor, (GF_Descriptor **)&dest->moov->iods->descriptor);
3593 5 : iod_d = (GF_IsomInitialObjectDescriptor *) dest->moov->iods->descriptor;
3594 10 : while (gf_list_count(iod_d->ES_ID_IncDescriptors)) {
3595 0 : GF_Descriptor *d = (GF_Descriptor *)gf_list_get(iod_d->ES_ID_IncDescriptors, 0);
3596 0 : gf_list_rem(iod_d->ES_ID_IncDescriptors, 0);
3597 0 : gf_odf_desc_del(d);
3598 : }
3599 5 : while (gf_list_count(iod_d->ES_ID_RefDescriptors)) {
3600 0 : GF_Descriptor *d = (GF_Descriptor *)gf_list_get(iod_d->ES_ID_RefDescriptors, 0);
3601 0 : gf_list_rem(iod_d->ES_ID_RefDescriptors, 0);
3602 0 : gf_odf_desc_del(d);
3603 : }
3604 : return GF_OK;
3605 : }
3606 :
3607 : GF_EXPORT
3608 584 : GF_Err gf_isom_clone_box(GF_Box *src, GF_Box **dst)
3609 : {
3610 : GF_Err e;
3611 : u8 *data;
3612 : u32 data_size;
3613 : GF_BitStream *bs;
3614 :
3615 584 : if (*dst) {
3616 0 : gf_isom_box_del(*dst);
3617 0 : *dst=NULL;
3618 : }
3619 584 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
3620 584 : if (!bs) return GF_OUT_OF_MEM;
3621 584 : e = gf_isom_box_size( (GF_Box *) src);
3622 584 : if (!e) e = gf_isom_box_write((GF_Box *) src, bs);
3623 584 : gf_bs_get_content(bs, &data, &data_size);
3624 584 : gf_bs_del(bs);
3625 584 : if (e) {
3626 4 : if (data) gf_free(data);
3627 : return e;
3628 : }
3629 580 : bs = gf_bs_new(data, data_size, GF_BITSTREAM_READ);
3630 580 : if (!bs) {
3631 0 : if (data) gf_free(data);
3632 : return GF_OUT_OF_MEM;
3633 : }
3634 580 : e = gf_isom_box_parse(dst, bs);
3635 580 : gf_bs_del(bs);
3636 580 : gf_free(data);
3637 580 : return e;
3638 : }
3639 :
3640 : #if 0 //unused
3641 : /*clones the entire movie file to destination. Tracks can be cloned if clone_tracks is set, in which case hint tracks can be
3642 : kept if keep_hint_tracks is set
3643 : if keep_pssh, all pssh boxes will be kept
3644 : fragment information (mvex) is not kept*/
3645 : GF_Err gf_isom_clone_movie(GF_ISOFile *orig_file, GF_ISOFile *dest_file, Bool clone_tracks, Bool keep_hint_tracks, Bool keep_pssh)
3646 : {
3647 : GF_Err e;
3648 : u32 i;
3649 : GF_Box *box;
3650 :
3651 : e = CanAccessMovie(dest_file, GF_ISOM_OPEN_WRITE);
3652 : if (e) return e;
3653 :
3654 : if (orig_file->brand) {
3655 : gf_list_del_item(dest_file->TopBoxes, dest_file->brand);
3656 : gf_isom_box_del((GF_Box *)dest_file->brand);
3657 : dest_file->brand = NULL;
3658 : gf_isom_clone_box((GF_Box *)orig_file->brand, (GF_Box **)&dest_file->brand);
3659 : if (dest_file->brand) gf_list_add(dest_file->TopBoxes, dest_file->brand);
3660 : }
3661 :
3662 : if (orig_file->meta) {
3663 : gf_list_del_item(dest_file->TopBoxes, dest_file->meta);
3664 : gf_isom_box_del((GF_Box *)dest_file->meta);
3665 : dest_file->meta = NULL;
3666 : /*fixme - check imports*/
3667 : gf_isom_clone_box((GF_Box *)orig_file->meta, (GF_Box **)&dest_file->meta);
3668 : if (dest_file->meta) gf_list_add(dest_file->TopBoxes, dest_file->meta);
3669 : }
3670 : if (orig_file->moov) {
3671 : u32 i, dstTrack;
3672 : GF_Box *iods;
3673 : GF_List *tracks = gf_list_new();
3674 : GF_List *old_tracks = orig_file->moov->trackList;
3675 : orig_file->moov->trackList = tracks;
3676 : iods = (GF_Box*)orig_file->moov->iods;
3677 : orig_file->moov->iods = NULL;
3678 : e = gf_isom_clone_box((GF_Box *)orig_file->moov, (GF_Box **)&dest_file->moov);
3679 : if (e) {
3680 : gf_list_del(tracks);
3681 : orig_file->moov->trackList = old_tracks;
3682 : return e;
3683 : }
3684 : orig_file->moov->trackList = old_tracks;
3685 : gf_list_del(tracks);
3686 : orig_file->moov->iods = (GF_ObjectDescriptorBox*)iods;
3687 : gf_list_add(dest_file->TopBoxes, dest_file->moov);
3688 :
3689 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3690 : if (dest_file->moov->mvex) {
3691 : gf_isom_box_del_parent(&dest_file->moov->child_boxes, (GF_Box *)dest_file->moov->mvex);
3692 : dest_file->moov->mvex = NULL;
3693 : }
3694 : #endif
3695 :
3696 : if (clone_tracks) {
3697 : for (i=0; i<gf_list_count(orig_file->moov->trackList); i++) {
3698 : GF_TrackBox *trak = (GF_TrackBox*)gf_list_get( orig_file->moov->trackList, i);
3699 : if (!trak) continue;
3700 : if (keep_hint_tracks || (trak->Media->handler->handlerType != GF_ISOM_MEDIA_HINT)) {
3701 : e = gf_isom_clone_track(orig_file, i+1, dest_file, 0, &dstTrack);
3702 : if (e) return e;
3703 : }
3704 : }
3705 : if (iods)
3706 : gf_isom_clone_box((GF_Box *)orig_file->moov->iods, (GF_Box **)dest_file->moov->iods);
3707 : } else {
3708 : dest_file->moov->mvhd->nextTrackID = 1;
3709 : gf_isom_clone_pl_indications(orig_file, dest_file);
3710 : }
3711 : dest_file->moov->mov = dest_file;
3712 : }
3713 :
3714 : if (!keep_pssh) {
3715 : i=0;
3716 : while ((box = (GF_Box*)gf_list_get(dest_file->moov->child_boxes, i++))) {
3717 : if (box->type == GF_ISOM_BOX_TYPE_PSSH) {
3718 : i--;
3719 : gf_isom_box_del_parent(&dest_file->moov->child_boxes, box);
3720 : }
3721 : }
3722 : }
3723 :
3724 : //duplicate other boxes
3725 : i=0;
3726 : while ((box = (GF_Box*)gf_list_get(orig_file->TopBoxes, i++))) {
3727 : switch(box->type) {
3728 : case GF_ISOM_BOX_TYPE_MOOV:
3729 : case GF_ISOM_BOX_TYPE_META:
3730 : case GF_ISOM_BOX_TYPE_MDAT:
3731 : case GF_ISOM_BOX_TYPE_FTYP:
3732 : case GF_ISOM_BOX_TYPE_PDIN:
3733 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3734 : case GF_ISOM_BOX_TYPE_STYP:
3735 : case GF_ISOM_BOX_TYPE_SIDX:
3736 : case GF_ISOM_BOX_TYPE_SSIX:
3737 : case GF_ISOM_BOX_TYPE_MOOF:
3738 : #endif
3739 : case GF_ISOM_BOX_TYPE_JP:
3740 : break;
3741 :
3742 : case GF_ISOM_BOX_TYPE_PSSH:
3743 : if (!keep_pssh)
3744 : break;
3745 :
3746 : default:
3747 : {
3748 : GF_Box *box2 = NULL;
3749 : gf_isom_clone_box(box, &box2);
3750 : gf_list_add(dest_file->TopBoxes, box2);
3751 : }
3752 : break;
3753 : }
3754 : }
3755 :
3756 : return GF_OK;
3757 : }
3758 : #endif
3759 :
3760 :
3761 : GF_EXPORT
3762 1138 : GF_Err gf_isom_get_raw_user_data(GF_ISOFile *file, u8 **output, u32 *output_size)
3763 : {
3764 : GF_BitStream *bs;
3765 : GF_Err e;
3766 : GF_Box *b;
3767 : u32 i;
3768 :
3769 1138 : *output = NULL;
3770 1138 : *output_size = 0;
3771 1138 : if (!file || !file->moov || (!file->moov->udta && !file->moov->child_boxes)) return GF_OK;
3772 1138 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
3773 :
3774 1138 : if (file->moov->udta) {
3775 6 : e = gf_isom_box_size( (GF_Box *) file->moov->udta);
3776 6 : if (e) goto exit;
3777 6 : e = gf_isom_box_write((GF_Box *) file->moov->udta, bs);
3778 6 : if (e) goto exit;
3779 : }
3780 : e = GF_OK;
3781 1138 : i=0;
3782 7260 : while ((b = gf_list_enum(file->moov->child_boxes, &i))) {
3783 4984 : switch (b->type) {
3784 4725 : case GF_ISOM_BOX_TYPE_TRAK:
3785 : case GF_ISOM_BOX_TYPE_MVHD:
3786 : case GF_ISOM_BOX_TYPE_MVEX:
3787 : case GF_ISOM_BOX_TYPE_IODS:
3788 : case GF_ISOM_BOX_TYPE_META:
3789 4725 : continue;
3790 : }
3791 259 : e = gf_isom_box_size( (GF_Box *) b);
3792 259 : if (e) goto exit;
3793 259 : e = gf_isom_box_write((GF_Box *) b, bs);
3794 259 : if (e) goto exit;
3795 : }
3796 :
3797 1138 : gf_bs_get_content(bs, output, output_size);
3798 :
3799 1138 : exit:
3800 1138 : gf_bs_del(bs);
3801 1138 : return e;
3802 : }
3803 :
3804 : GF_EXPORT
3805 1138 : GF_Err gf_isom_get_track_template(GF_ISOFile *file, u32 track, u8 **output, u32 *output_size)
3806 : {
3807 : GF_TrackBox *trak;
3808 : GF_BitStream *bs;
3809 : GF_DataReferenceBox *dref;
3810 : GF_SampleTableBox *stbl, *stbl_temp;
3811 : GF_SampleEncryptionBox *senc;
3812 : u32 i, count;
3813 :
3814 1138 : *output = NULL;
3815 1138 : *output_size = 0;
3816 : /*get orig sample desc and clone it*/
3817 1138 : trak = gf_isom_get_track_from_file(file, track);
3818 1138 : if (!trak || !trak->Media) return GF_BAD_PARAM;
3819 :
3820 : //don't serialize dref
3821 : dref = NULL;
3822 1138 : if (trak->Media->information->dataInformation) {
3823 1133 : dref = trak->Media->information->dataInformation->dref;
3824 1133 : trak->Media->information->dataInformation->dref = NULL;
3825 1133 : gf_list_del_item(trak->Media->information->dataInformation->child_boxes, dref);
3826 : }
3827 :
3828 : //don't serialize stbl but create a temp one
3829 1138 : stbl_temp = (GF_SampleTableBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STBL);
3830 1138 : if (!stbl_temp->child_boxes) stbl_temp->child_boxes = gf_list_new();
3831 1138 : stbl = trak->Media->information->sampleTable;
3832 1138 : gf_list_del_item(trak->Media->information->child_boxes, stbl);
3833 :
3834 1138 : trak->Media->information->sampleTable = stbl_temp;
3835 1138 : gf_list_add(trak->Media->information->child_boxes, stbl_temp);
3836 :
3837 : /*do not clone sampleDescription table but create an empty one*/
3838 1138 : stbl_temp->SampleDescription = (GF_SampleDescriptionBox *) gf_isom_box_new_parent(&stbl_temp->child_boxes, GF_ISOM_BOX_TYPE_STSD);
3839 :
3840 : /*clone sampleGroups description tables if any*/
3841 1138 : stbl_temp->sampleGroupsDescription = stbl->sampleGroupsDescription;
3842 1138 : count = gf_list_count(stbl->sampleGroupsDescription);
3843 1293 : for (i=0;i<count; i++) {
3844 155 : GF_Box *b = gf_list_get(stbl->sampleGroupsDescription, i);
3845 155 : gf_list_add(stbl_temp->child_boxes, b);
3846 : }
3847 : /*clone CompositionToDecode table, we may remove it later*/
3848 1138 : stbl_temp->CompositionToDecode = stbl->CompositionToDecode;
3849 1138 : gf_list_add(stbl_temp->child_boxes, stbl->CompositionToDecode);
3850 :
3851 :
3852 : //don't serialize senc
3853 1138 : senc = trak->sample_encryption;
3854 1138 : if (senc) {
3855 : assert(trak->child_boxes);
3856 163 : gf_list_del_item(trak->child_boxes, senc);
3857 163 : trak->sample_encryption = NULL;
3858 : }
3859 :
3860 1138 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
3861 :
3862 1138 : gf_isom_box_size( (GF_Box *) trak);
3863 1138 : gf_isom_box_write((GF_Box *) trak, bs);
3864 1138 : gf_bs_get_content(bs, output, output_size);
3865 1138 : gf_bs_del(bs);
3866 :
3867 : //restore our pointers
3868 1138 : if (dref) {
3869 1133 : trak->Media->information->dataInformation->dref = dref;
3870 1133 : gf_list_add(trak->Media->information->dataInformation->child_boxes, dref);
3871 : }
3872 1138 : trak->Media->information->sampleTable = stbl;
3873 1138 : gf_list_add(trak->Media->information->child_boxes, stbl);
3874 1138 : gf_list_del_item(trak->Media->information->child_boxes, stbl_temp);
3875 1138 : if (senc) {
3876 163 : trak->sample_encryption = senc;
3877 163 : gf_list_add(trak->child_boxes, senc);
3878 : }
3879 :
3880 1138 : stbl_temp->sampleGroupsDescription = NULL;
3881 1138 : count = gf_list_count(stbl->sampleGroupsDescription);
3882 1293 : for (i=0;i<count; i++) {
3883 155 : GF_Box *b = gf_list_get(stbl->sampleGroupsDescription, i);
3884 155 : gf_list_del_item(stbl_temp->child_boxes, b);
3885 : }
3886 :
3887 1138 : stbl_temp->CompositionToDecode = NULL;
3888 1138 : gf_list_del_item(stbl_temp->child_boxes, stbl->CompositionToDecode);
3889 1138 : gf_isom_box_del((GF_Box *)stbl_temp);
3890 1138 : return GF_OK;
3891 :
3892 : }
3893 :
3894 : GF_EXPORT
3895 1138 : GF_Err gf_isom_get_trex_template(GF_ISOFile *file, u32 track, u8 **output, u32 *output_size)
3896 : {
3897 : GF_TrackBox *trak;
3898 : GF_BitStream *bs;
3899 : u32 i;
3900 : GF_TrackExtendsBox *trex = NULL;
3901 : GF_TrackExtensionPropertiesBox *trexprop = NULL;
3902 :
3903 1138 : *output = NULL;
3904 1138 : *output_size = 0;
3905 : /*get orig sample desc and clone it*/
3906 1138 : trak = gf_isom_get_track_from_file(file, track);
3907 1138 : if (!trak || !trak->Media) return GF_BAD_PARAM;
3908 1138 : if (!file->moov->mvex) return GF_NOT_FOUND;
3909 322 : for (i=0; i<gf_list_count(file->moov->mvex->TrackExList); i++) {
3910 586 : trex = gf_list_get(file->moov->mvex->TrackExList, i);
3911 586 : if (trex->trackID == trak->Header->trackID) break;
3912 : trex = NULL;
3913 : }
3914 264 : if (!trex) return GF_NOT_FOUND;
3915 :
3916 0 : for (i=0; i<gf_list_count(file->moov->mvex->TrackExPropList); i++) {
3917 0 : trexprop = gf_list_get(file->moov->mvex->TrackExPropList, i);
3918 0 : if (trexprop->trackID== trak->Header->trackID) break;
3919 : trexprop = NULL;
3920 : }
3921 264 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
3922 264 : gf_isom_box_size( (GF_Box *) trex);
3923 264 : gf_isom_box_write((GF_Box *) trex, bs);
3924 :
3925 264 : if (trexprop) {
3926 0 : gf_isom_box_size( (GF_Box *) trexprop);
3927 0 : gf_isom_box_write((GF_Box *) trexprop, bs);
3928 : }
3929 264 : gf_bs_get_content(bs, output, output_size);
3930 264 : gf_bs_del(bs);
3931 :
3932 264 : return GF_OK;
3933 :
3934 : }
3935 :
3936 : GF_EXPORT
3937 1195 : GF_Err gf_isom_get_stsd_template(GF_ISOFile *file, u32 track, u32 stsd_idx, u8 **output, u32 *output_size)
3938 : {
3939 : GF_TrackBox *trak;
3940 : GF_BitStream *bs;
3941 : GF_Box *ent;
3942 :
3943 1195 : *output = NULL;
3944 1195 : *output_size = 0;
3945 : /*get orig sample desc and clone it*/
3946 1195 : trak = gf_isom_get_track_from_file(file, track);
3947 1195 : if (!trak || !stsd_idx || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleDescription) return GF_BAD_PARAM;
3948 :
3949 1195 : ent = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, stsd_idx-1);
3950 1195 : if (!ent) return GF_BAD_PARAM;
3951 :
3952 1195 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
3953 :
3954 1195 : gf_isom_box_size( (GF_Box *) ent);
3955 1195 : gf_isom_box_write((GF_Box *) ent, bs);
3956 1195 : gf_bs_get_content(bs, output, output_size);
3957 1195 : gf_bs_del(bs);
3958 1195 : return GF_OK;
3959 :
3960 : }
3961 :
3962 :
3963 : GF_EXPORT
3964 105 : GF_Err gf_isom_clone_track(GF_ISOFile *orig_file, u32 orig_track, GF_ISOFile *dest_file, GF_ISOTrackCloneFlags flags, u32 *dest_track)
3965 : {
3966 : GF_TrackBox *trak, *new_tk;
3967 : GF_BitStream *bs;
3968 : u8 *data;
3969 : const u8 *buffer;
3970 : u32 data_size;
3971 : u32 i, count;
3972 : GF_Err e;
3973 : GF_SampleTableBox *stbl, *stbl_temp;
3974 : GF_SampleEncryptionBox *senc;
3975 :
3976 : e = CanAccessMovie(dest_file, GF_ISOM_OPEN_WRITE);
3977 : if (e) return e;
3978 105 : e = gf_isom_insert_moov(dest_file);
3979 105 : if (e) return e;
3980 :
3981 : /*get orig sample desc and clone it*/
3982 105 : trak = gf_isom_get_track_from_file(orig_file, orig_track);
3983 105 : if (!trak || !trak->Media) return GF_BAD_PARAM;
3984 :
3985 105 : stbl = trak->Media->information->sampleTable;
3986 105 : stbl_temp = (GF_SampleTableBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STBL);
3987 105 : if (!stbl_temp->child_boxes) stbl_temp->child_boxes = gf_list_new();
3988 :
3989 105 : trak->Media->information->sampleTable = stbl_temp;
3990 105 : gf_list_add(trak->Media->information->child_boxes, stbl_temp);
3991 105 : gf_list_del_item(trak->Media->information->child_boxes, stbl);
3992 :
3993 105 : if (!stbl_temp->child_boxes) stbl_temp->child_boxes = gf_list_new();
3994 :
3995 : /*clone sampleDescription table*/
3996 105 : stbl_temp->SampleDescription = stbl->SampleDescription;
3997 105 : gf_list_add(stbl_temp->child_boxes, stbl->SampleDescription);
3998 : /*also clone sampleGroups description tables if any*/
3999 105 : stbl_temp->sampleGroupsDescription = stbl->sampleGroupsDescription;
4000 105 : count = gf_list_count(stbl->sampleGroupsDescription);
4001 112 : for (i=0; i<count; i++) {
4002 7 : GF_Box *b = gf_list_get(stbl->sampleGroupsDescription, i);
4003 7 : gf_list_add(stbl_temp->child_boxes, b);
4004 : }
4005 : /*clone CompositionToDecode table, we may remove it later*/
4006 105 : stbl_temp->CompositionToDecode = stbl->CompositionToDecode;
4007 105 : gf_list_add(stbl_temp->child_boxes, stbl->CompositionToDecode);
4008 :
4009 105 : senc = trak->sample_encryption;
4010 105 : if (senc) {
4011 : assert(trak->child_boxes);
4012 2 : gf_list_del_item(trak->child_boxes, senc);
4013 2 : trak->sample_encryption = NULL;
4014 : }
4015 :
4016 105 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
4017 :
4018 105 : gf_isom_box_size( (GF_Box *) trak);
4019 105 : gf_isom_box_write((GF_Box *) trak, bs);
4020 105 : gf_bs_get_content(bs, &data, &data_size);
4021 105 : gf_bs_del(bs);
4022 105 : bs = gf_bs_new(data, data_size, GF_BITSTREAM_READ);
4023 105 : if (flags & GF_ISOM_CLONE_TRACK_NO_QT)
4024 39 : gf_bs_set_cookie(bs, GF_ISOM_BS_COOKIE_QT_CONV | GF_ISOM_BS_COOKIE_CLONE_TRACK);
4025 : else
4026 66 : gf_bs_set_cookie(bs, GF_ISOM_BS_COOKIE_CLONE_TRACK);
4027 :
4028 105 : e = gf_isom_box_parse((GF_Box **) &new_tk, bs);
4029 105 : gf_bs_del(bs);
4030 105 : gf_free(data);
4031 :
4032 105 : trak->Media->information->sampleTable = stbl;
4033 105 : gf_list_del_item(trak->Media->information->child_boxes, stbl_temp);
4034 105 : gf_list_add(trak->Media->information->child_boxes, stbl);
4035 :
4036 105 : if (senc) {
4037 2 : trak->sample_encryption = senc;
4038 2 : gf_list_add(trak->child_boxes, senc);
4039 : }
4040 105 : gf_list_del_item(stbl_temp->child_boxes, stbl_temp->SampleDescription);
4041 105 : stbl_temp->SampleDescription = NULL;
4042 :
4043 105 : count = gf_list_count(stbl->sampleGroupsDescription);
4044 112 : for (i=0; i<count; i++) {
4045 7 : GF_Box *b = gf_list_get(stbl->sampleGroupsDescription, i);
4046 7 : gf_list_del_item(stbl_temp->child_boxes, b);
4047 : }
4048 105 : stbl_temp->sampleGroupsDescription = NULL;
4049 :
4050 105 : gf_list_del_item(stbl_temp->child_boxes, stbl_temp->CompositionToDecode);
4051 105 : stbl_temp->CompositionToDecode = NULL;
4052 105 : gf_isom_box_del((GF_Box *)stbl_temp);
4053 :
4054 105 : if (e) {
4055 0 : if (new_tk) gf_isom_box_del((GF_Box *)new_tk);
4056 : return e;
4057 : }
4058 :
4059 105 : gf_isom_disable_inplace_rewrite(dest_file);
4060 :
4061 : /*create default boxes*/
4062 105 : stbl = new_tk->Media->information->sampleTable;
4063 105 : stbl->ChunkOffset = gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STCO);
4064 105 : if (!stbl->ChunkOffset) return GF_OUT_OF_MEM;
4065 105 : stbl->SampleSize = (GF_SampleSizeBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSZ);
4066 105 : if (!stbl->SampleSize) return GF_OUT_OF_MEM;
4067 105 : stbl->SampleToChunk = (GF_SampleToChunkBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSC);
4068 105 : if (!stbl->SampleToChunk) return GF_OUT_OF_MEM;
4069 105 : stbl->TimeToSample = (GF_TimeToSampleBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STTS);
4070 105 : if (!stbl->TimeToSample) return GF_OUT_OF_MEM;
4071 :
4072 : /*check trackID validity before adding track*/
4073 105 : if (gf_isom_get_track_by_id(dest_file, new_tk->Header->trackID)) {
4074 : u32 ID = 1;
4075 : while (1) {
4076 218 : if (RequestTrack(dest_file->moov, ID)) break;
4077 181 : ID += 1;
4078 181 : if (ID == 0xFFFFFFFF) break;
4079 : }
4080 37 : new_tk->Header->trackID = ID;
4081 : }
4082 105 : if (!dest_file->moov->child_boxes) dest_file->moov->child_boxes = gf_list_new();
4083 105 : gf_list_add(dest_file->moov->child_boxes, new_tk);
4084 105 : moov_on_child_box((GF_Box*)dest_file->moov, (GF_Box *)new_tk, GF_FALSE);
4085 :
4086 : /*set originalID*/
4087 105 : new_tk->originalID = trak->Header->trackID;
4088 : /*set originalFile*/
4089 105 : buffer = gf_isom_get_filename(orig_file);
4090 105 : new_tk->originalFile = gf_crc_32(buffer, (u32) strlen(buffer));
4091 :
4092 : /*rewrite edit list segmentDuration to new movie timescale*/
4093 105 : if (dest_file->moov->mvhd->timeScale != orig_file->moov->mvhd->timeScale) {
4094 2 : Double ts_scale = dest_file->moov->mvhd->timeScale;
4095 2 : ts_scale /= orig_file->moov->mvhd->timeScale;
4096 2 : new_tk->Header->duration = (u64) (new_tk->Header->duration * ts_scale);
4097 2 : if (new_tk->editBox && new_tk->editBox->editList) {
4098 1 : count = gf_list_count(new_tk->editBox->editList->entryList);
4099 2 : for (i=0; i<count; i++) {
4100 1 : GF_EdtsEntry *ent = (GF_EdtsEntry *)gf_list_get(new_tk->editBox->editList->entryList, i);
4101 1 : ent->segmentDuration = (u64) (ent->segmentDuration * ts_scale);
4102 : }
4103 : }
4104 : }
4105 :
4106 105 : if (!new_tk->Media->information->dataInformation->dref) return GF_BAD_PARAM;
4107 :
4108 : /*reset data ref*/
4109 105 : if (! (flags & GF_ISOM_CLONE_TRACK_KEEP_DREF) ) {
4110 : GF_SampleEntryBox *entry;
4111 : Bool use_alis = GF_FALSE;
4112 102 : if (! (flags & GF_ISOM_CLONE_TRACK_NO_QT)) {
4113 66 : GF_Box *b = gf_list_get(new_tk->Media->information->dataInformation->dref->child_boxes, 0);
4114 66 : if (b && b->type==GF_QT_BOX_TYPE_ALIS)
4115 : use_alis = GF_TRUE;
4116 : }
4117 102 : gf_isom_box_array_del(new_tk->Media->information->dataInformation->dref->child_boxes);
4118 102 : new_tk->Media->information->dataInformation->dref->child_boxes = gf_list_new();
4119 : /*update data ref*/
4120 102 : entry = (GF_SampleEntryBox*)gf_list_get(new_tk->Media->information->sampleTable->SampleDescription->child_boxes, 0);
4121 102 : if (entry) {
4122 : u32 dref;
4123 102 : Media_CreateDataRef(dest_file, new_tk->Media->information->dataInformation->dref, use_alis ? "alis" : NULL, NULL, &dref);
4124 102 : entry->dataReferenceIndex = dref;
4125 : }
4126 : } else {
4127 3 : for (i=0; i<gf_list_count(new_tk->Media->information->dataInformation->dref->child_boxes); i++) {
4128 3 : GF_DataEntryBox *dref_entry = (GF_DataEntryBox *)gf_list_get(new_tk->Media->information->dataInformation->dref->child_boxes, i);
4129 3 : if (dref_entry->flags & 1) {
4130 3 : dref_entry->flags &= ~1;
4131 3 : e = Media_SetDrefURL((GF_DataEntryURLBox *)dref_entry, orig_file->fileName, dest_file->finalName);
4132 3 : if (e) return e;
4133 : }
4134 : }
4135 : }
4136 :
4137 105 : *dest_track = gf_list_count(dest_file->moov->trackList);
4138 :
4139 105 : if (dest_file->moov->mvhd->nextTrackID<= new_tk->Header->trackID)
4140 105 : dest_file->moov->mvhd->nextTrackID = new_tk->Header->trackID+1;
4141 :
4142 : return GF_OK;
4143 : }
4144 :
4145 : #if 0
4146 : /*clones all sampleDescription entries in new track, after an optional reset of existing entries*/
4147 : GF_Err gf_isom_clone_sample_descriptions(GF_ISOFile *the_file, u32 trackNumber, GF_ISOFile *orig_file, u32 orig_track, Bool reset_existing)
4148 : {
4149 : u32 i;
4150 : GF_TrackBox *dst_trak, *src_trak;
4151 : GF_Err e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
4152 : if (e) return e;
4153 :
4154 : dst_trak = gf_isom_get_track_from_file(the_file, trackNumber);
4155 : if (!dst_trak || !dst_trak->Media) return GF_BAD_PARAM;
4156 : src_trak = gf_isom_get_track_from_file(orig_file, orig_track);
4157 : if (!src_trak || !src_trak->Media) return GF_BAD_PARAM;
4158 :
4159 : if (reset_existing) {
4160 : gf_isom_box_array_del(dst_trak->Media->information->sampleTable->SampleDescription->child_boxes);
4161 : dst_trak->Media->information->sampleTable->SampleDescription->child_boxes = gf_list_new();
4162 : }
4163 :
4164 : for (i=0; i<gf_list_count(src_trak->Media->information->sampleTable->SampleDescription->child_boxes); i++) {
4165 : u32 outDesc;
4166 : e = gf_isom_clone_sample_description(the_file, trackNumber, orig_file, orig_track, i+1, NULL, NULL, &outDesc);
4167 : if (e) break;
4168 : }
4169 : return e;
4170 : }
4171 : #endif
4172 :
4173 :
4174 : GF_EXPORT
4175 7 : GF_Err gf_isom_clone_sample_description(GF_ISOFile *the_file, u32 trackNumber, GF_ISOFile *orig_file, u32 orig_track, u32 orig_desc_index, const char *URLname, const char *URNname, u32 *outDescriptionIndex)
4176 : {
4177 : GF_TrackBox *trak;
4178 : GF_BitStream *bs;
4179 : u8 *data;
4180 : u32 data_size;
4181 : GF_Box *entry;
4182 : GF_Err e;
4183 : u32 dataRefIndex;
4184 : u32 mtype;
4185 :
4186 : e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
4187 : if (e) return e;
4188 :
4189 : /*get orig sample desc and clone it*/
4190 7 : trak = gf_isom_get_track_from_file(orig_file, orig_track);
4191 7 : if (!trak || !trak->Media) return GF_BAD_PARAM;
4192 :
4193 7 : entry = (GF_Box*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, orig_desc_index-1);
4194 7 : if (!entry) return GF_BAD_PARAM;
4195 :
4196 7 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
4197 :
4198 7 : gf_isom_box_size(entry);
4199 7 : gf_isom_box_write(entry, bs);
4200 7 : gf_bs_get_content(bs, &data, &data_size);
4201 7 : gf_bs_del(bs);
4202 7 : bs = gf_bs_new(data, data_size, GF_BITSTREAM_READ);
4203 7 : e = gf_isom_box_parse(&entry, bs);
4204 7 : gf_bs_del(bs);
4205 7 : gf_free(data);
4206 7 : if (e) return e;
4207 :
4208 : /*get new track and insert clone*/
4209 7 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
4210 7 : if (!trak || !trak->Media) goto exit;
4211 :
4212 : /*get or create the data ref*/
4213 7 : e = Media_FindDataRef(trak->Media->information->dataInformation->dref, (char *)URLname, (char *)URNname, &dataRefIndex);
4214 7 : if (e) goto exit;
4215 7 : if (!dataRefIndex) {
4216 1 : e = Media_CreateDataRef(the_file, trak->Media->information->dataInformation->dref, (char *)URLname, (char *)URNname, &dataRefIndex);
4217 1 : if (e) goto exit;
4218 : }
4219 7 : if (!the_file->keep_utc)
4220 7 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
4221 : /*overwrite dref*/
4222 7 : ((GF_SampleEntryBox *)entry)->dataReferenceIndex = dataRefIndex;
4223 7 : e = gf_list_add(trak->Media->information->sampleTable->SampleDescription->child_boxes, entry);
4224 7 : *outDescriptionIndex = gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes);
4225 :
4226 : /*also clone track w/h info*/
4227 7 : mtype = gf_isom_get_media_type(the_file, trackNumber);
4228 7 : if (gf_isom_is_video_handler_type(mtype) ) {
4229 7 : gf_isom_set_visual_info(the_file, trackNumber, (*outDescriptionIndex), ((GF_VisualSampleEntryBox*)entry)->Width, ((GF_VisualSampleEntryBox*)entry)->Height);
4230 : }
4231 : return e;
4232 :
4233 0 : exit:
4234 0 : gf_isom_box_del(entry);
4235 0 : return e;
4236 : }
4237 :
4238 : GF_EXPORT
4239 88 : GF_Err gf_isom_new_generic_sample_description(GF_ISOFile *movie, u32 trackNumber, const char *URLname, const char *URNname, GF_GenericSampleDescription *udesc, u32 *outDescriptionIndex)
4240 : {
4241 : GF_TrackBox *trak;
4242 : GF_Err e;
4243 : u32 dataRefIndex;
4244 :
4245 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
4246 : if (e) return e;
4247 :
4248 88 : trak = gf_isom_get_track_from_file(movie, trackNumber);
4249 88 : if (!trak || !trak->Media || !udesc) return GF_BAD_PARAM;
4250 :
4251 : //get or create the data ref
4252 88 : e = Media_FindDataRef(trak->Media->information->dataInformation->dref, (char *)URLname, (char *)URNname, &dataRefIndex);
4253 88 : if (e) return e;
4254 88 : if (!dataRefIndex) {
4255 88 : e = Media_CreateDataRef(movie, trak->Media->information->dataInformation->dref, (char *)URLname, (char *)URNname, &dataRefIndex);
4256 88 : if (e) return e;
4257 : }
4258 88 : if (!movie->keep_utc)
4259 88 : trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
4260 :
4261 88 : if (gf_isom_is_video_handler_type(trak->Media->handler->handlerType)) {
4262 : GF_GenericVisualSampleEntryBox *entry;
4263 : //create a new entry
4264 20 : entry = (GF_GenericVisualSampleEntryBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_GNRV);
4265 20 : if (!entry) return GF_OUT_OF_MEM;
4266 :
4267 20 : if (!udesc->codec_tag) {
4268 0 : entry->EntryType = GF_ISOM_BOX_TYPE_UUID;
4269 0 : memcpy(entry->uuid, udesc->UUID, sizeof(bin128));
4270 : } else {
4271 20 : entry->EntryType = udesc->codec_tag;
4272 : }
4273 20 : if (entry->EntryType == 0) {
4274 0 : gf_isom_box_del((GF_Box *)entry);
4275 0 : return GF_NOT_SUPPORTED;
4276 : }
4277 :
4278 20 : entry->dataReferenceIndex = dataRefIndex;
4279 20 : entry->vendor = udesc->vendor_code;
4280 20 : entry->version = udesc->version;
4281 20 : entry->revision = udesc->revision;
4282 20 : entry->temporal_quality = udesc->temporal_quality;
4283 20 : entry->spatial_quality = udesc->spatial_quality;
4284 20 : entry->Width = udesc->width;
4285 20 : entry->Height = udesc->height;
4286 20 : strcpy(entry->compressor_name, udesc->compressor_name);
4287 20 : entry->color_table_index = -1;
4288 20 : entry->frames_per_sample = 1;
4289 20 : entry->horiz_res = udesc->h_res ? udesc->h_res : 0x00480000;
4290 20 : entry->vert_res = udesc->v_res ? udesc->v_res : 0x00480000;
4291 20 : entry->bit_depth = udesc->depth ? udesc->depth : 0x18;
4292 20 : if (udesc->extension_buf && udesc->extension_buf_size) {
4293 0 : entry->data = (char*)gf_malloc(sizeof(char) * udesc->extension_buf_size);
4294 0 : if (!entry->data) {
4295 0 : gf_isom_box_del((GF_Box *) entry);
4296 0 : return GF_OUT_OF_MEM;
4297 : }
4298 0 : memcpy(entry->data, udesc->extension_buf, udesc->extension_buf_size);
4299 0 : entry->data_size = udesc->extension_buf_size;
4300 : }
4301 20 : e = gf_list_add(trak->Media->information->sampleTable->SampleDescription->child_boxes, entry);
4302 : }
4303 68 : else if (trak->Media->handler->handlerType==GF_ISOM_MEDIA_AUDIO) {
4304 : GF_GenericAudioSampleEntryBox *gena;
4305 : //create a new entry
4306 68 : gena = (GF_GenericAudioSampleEntryBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_GNRA);
4307 68 : if (!gena) return GF_OUT_OF_MEM;
4308 :
4309 68 : if (!udesc->codec_tag) {
4310 0 : gena->EntryType = GF_ISOM_BOX_TYPE_UUID;
4311 0 : memcpy(gena->uuid, udesc->UUID, sizeof(bin128));
4312 : } else {
4313 68 : gena->EntryType = udesc->codec_tag;
4314 : }
4315 68 : if (gena->EntryType == 0) {
4316 0 : gf_isom_box_del((GF_Box *)gena);
4317 0 : return GF_NOT_SUPPORTED;
4318 : }
4319 :
4320 68 : gena->dataReferenceIndex = dataRefIndex;
4321 68 : gena->vendor = udesc->vendor_code;
4322 68 : gena->version = udesc->version;
4323 68 : gena->revision = udesc->revision;
4324 68 : gena->bitspersample = udesc->bits_per_sample ? udesc->bits_per_sample : 16;
4325 68 : gena->channel_count = udesc->nb_channels ? udesc->nb_channels : 2;
4326 68 : gena->samplerate_hi = udesc->samplerate;
4327 68 : gena->samplerate_lo = 0;
4328 68 : gena->qtff_mode = udesc->is_qtff ? GF_ISOM_AUDIO_QTFF_ON_NOEXT : GF_ISOM_AUDIO_QTFF_NONE;
4329 :
4330 68 : if (udesc->extension_buf && udesc->extension_buf_size) {
4331 5 : gena->data = (char*)gf_malloc(sizeof(char) * udesc->extension_buf_size);
4332 5 : if (!gena->data) {
4333 0 : gf_isom_box_del((GF_Box *) gena);
4334 0 : return GF_OUT_OF_MEM;
4335 : }
4336 5 : memcpy(gena->data, udesc->extension_buf, udesc->extension_buf_size);
4337 5 : gena->data_size = udesc->extension_buf_size;
4338 : }
4339 68 : e = gf_list_add(trak->Media->information->sampleTable->SampleDescription->child_boxes, gena);
4340 : }
4341 : else {
4342 : GF_GenericSampleEntryBox *genm;
4343 : //create a new entry
4344 0 : genm = (GF_GenericSampleEntryBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_GNRM);
4345 0 : if (!genm) return GF_OUT_OF_MEM;
4346 :
4347 0 : if (!udesc->codec_tag) {
4348 0 : genm->EntryType = GF_ISOM_BOX_TYPE_UUID;
4349 0 : memcpy(genm->uuid, udesc->UUID, sizeof(bin128));
4350 : } else {
4351 0 : genm->EntryType = udesc->codec_tag;
4352 : }
4353 0 : if (genm->EntryType == 0) {
4354 0 : gf_isom_box_del((GF_Box *)genm);
4355 0 : return GF_NOT_SUPPORTED;
4356 : }
4357 :
4358 0 : genm->dataReferenceIndex = dataRefIndex;
4359 0 : if (udesc->extension_buf && udesc->extension_buf_size) {
4360 0 : genm->data = (char*)gf_malloc(sizeof(char) * udesc->extension_buf_size);
4361 0 : if (!genm->data) {
4362 0 : gf_isom_box_del((GF_Box *) genm);
4363 0 : return GF_OUT_OF_MEM;
4364 : }
4365 0 : memcpy(genm->data, udesc->extension_buf, udesc->extension_buf_size);
4366 0 : genm->data_size = udesc->extension_buf_size;
4367 : }
4368 0 : e = gf_list_add(trak->Media->information->sampleTable->SampleDescription->child_boxes, genm);
4369 : }
4370 88 : *outDescriptionIndex = gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes);
4371 88 : return e;
4372 : }
4373 :
4374 : //use carefully. Very useful when you made a lot of changes (IPMP, IPI, OCI, ...)
4375 : //THIS WILL REPLACE THE WHOLE DESCRIPTOR ...
4376 : #if 0 //unused
4377 : /*change the data field of an unknown sample description*/
4378 : GF_Err gf_isom_change_generic_sample_description(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_GenericSampleDescription *udesc)
4379 : {
4380 : GF_TrackBox *trak;
4381 : GF_Err e;
4382 : GF_GenericVisualSampleEntryBox *entry;
4383 :
4384 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
4385 : if (e) return e;
4386 :
4387 : trak = gf_isom_get_track_from_file(movie, trackNumber);
4388 : if (!trak || !trak->Media || !StreamDescriptionIndex) return GF_BAD_PARAM;
4389 :
4390 : entry = (GF_GenericVisualSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, StreamDescriptionIndex-1);
4391 : if (!entry) return GF_BAD_PARAM;
4392 : if (entry->type == GF_ISOM_BOX_TYPE_GNRV) {
4393 : entry->vendor = udesc->vendor_code;
4394 : entry->version = udesc->version;
4395 : entry->revision = udesc->revision;
4396 : entry->temporal_quality = udesc->temporal_quality;
4397 : entry->spatial_quality = udesc->spatial_quality;
4398 : entry->Width = udesc->width;
4399 : entry->Height = udesc->height;
4400 : strcpy(entry->compressor_name, udesc->compressor_name);
4401 : entry->color_table_index = -1;
4402 : entry->frames_per_sample = 1;
4403 : entry->horiz_res = udesc->h_res ? udesc->h_res : 0x00480000;
4404 : entry->vert_res = udesc->v_res ? udesc->v_res : 0x00480000;
4405 : entry->bit_depth = udesc->depth ? udesc->depth : 0x18;
4406 : if (entry->data) gf_free(entry->data);
4407 : entry->data = NULL;
4408 : entry->data_size = 0;
4409 : if (udesc->extension_buf && udesc->extension_buf_size) {
4410 : entry->data = (char*)gf_malloc(sizeof(char) * udesc->extension_buf_size);
4411 : if (!entry->data) {
4412 : gf_isom_box_del((GF_Box *) entry);
4413 : return GF_OUT_OF_MEM;
4414 : }
4415 : memcpy(entry->data, udesc->extension_buf, udesc->extension_buf_size);
4416 : entry->data_size = udesc->extension_buf_size;
4417 : }
4418 : return GF_OK;
4419 : } else if (entry->type == GF_ISOM_BOX_TYPE_GNRA) {
4420 : GF_GenericAudioSampleEntryBox *gena = (GF_GenericAudioSampleEntryBox *)entry;
4421 : gena->vendor = udesc->vendor_code;
4422 : gena->version = udesc->version;
4423 : gena->revision = udesc->revision;
4424 : gena->bitspersample = udesc->bits_per_sample ? udesc->bits_per_sample : 16;
4425 : gena->channel_count = udesc->nb_channels ? udesc->nb_channels : 2;
4426 : gena->samplerate_hi = udesc->samplerate;
4427 : gena->samplerate_lo = 0;
4428 : if (gena->data) gf_free(gena->data);
4429 : gena->data = NULL;
4430 : gena->data_size = 0;
4431 :
4432 : if (udesc->extension_buf && udesc->extension_buf_size) {
4433 : gena->data = (char*)gf_malloc(sizeof(char) * udesc->extension_buf_size);
4434 : if (!gena->data) {
4435 : gf_isom_box_del((GF_Box *) gena);
4436 : return GF_OUT_OF_MEM;
4437 : }
4438 : memcpy(gena->data, udesc->extension_buf, udesc->extension_buf_size);
4439 : gena->data_size = udesc->extension_buf_size;
4440 : }
4441 : return GF_OK;
4442 : } else if (entry->type == GF_ISOM_BOX_TYPE_GNRM) {
4443 : GF_GenericSampleEntryBox *genm = (GF_GenericSampleEntryBox *)entry;
4444 : if (genm->data) gf_free(genm->data);
4445 : genm->data = NULL;
4446 : genm->data_size = 0;
4447 :
4448 : if (udesc->extension_buf && udesc->extension_buf_size) {
4449 : genm->data = (char*)gf_malloc(sizeof(char) * udesc->extension_buf_size);
4450 : if (!genm->data) {
4451 : gf_isom_box_del((GF_Box *) genm);
4452 : return GF_OUT_OF_MEM;
4453 : }
4454 : memcpy(genm->data, udesc->extension_buf, udesc->extension_buf_size);
4455 : genm->data_size = udesc->extension_buf_size;
4456 : }
4457 : return GF_OK;
4458 : }
4459 : return GF_BAD_PARAM;
4460 : }
4461 : #endif
4462 :
4463 : #if 0
4464 : /*removes given stream description*/
4465 : GF_Err gf_isom_remove_sample_description(GF_ISOFile *movie, u32 trackNumber, u32 streamDescIndex)
4466 : {
4467 : GF_TrackBox *trak;
4468 : GF_Err e;
4469 : GF_Box *entry;
4470 :
4471 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
4472 : if (e) return e;
4473 : trak = gf_isom_get_track_from_file(movie, trackNumber);
4474 : if (!trak || !trak->Media || !streamDescIndex) return GF_BAD_PARAM;
4475 : entry = (GF_Box*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, streamDescIndex-1);
4476 : if (!entry) return GF_BAD_PARAM;
4477 : gf_list_rem(trak->Media->information->sampleTable->SampleDescription->child_boxes, streamDescIndex-1);
4478 : gf_isom_box_del(entry);
4479 : return GF_OK;
4480 : }
4481 : #endif
4482 :
4483 : //sets a track reference
4484 : GF_EXPORT
4485 334 : GF_Err gf_isom_set_track_reference(GF_ISOFile *the_file, u32 trackNumber, u32 referenceType, GF_ISOTrackID ReferencedTrackID)
4486 : {
4487 : GF_Err e;
4488 : GF_TrackBox *trak;
4489 : GF_TrackReferenceBox *tref;
4490 : GF_TrackReferenceTypeBox *dpnd;
4491 :
4492 334 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
4493 334 : if (!trak) return GF_BAD_PARAM;
4494 :
4495 : //no tref, create one
4496 334 : tref = trak->References;
4497 334 : if (!tref) {
4498 90 : tref = (GF_TrackReferenceBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_TREF);
4499 90 : if (!tref) return GF_OUT_OF_MEM;
4500 90 : e = trak_on_child_box((GF_Box*)trak, (GF_Box *) tref, GF_FALSE);
4501 90 : if (e) return e;
4502 : }
4503 : //find a ref of the given type
4504 334 : e = Track_FindRef(trak, referenceType, &dpnd);
4505 334 : if (e) return e;
4506 :
4507 334 : if (!dpnd) {
4508 144 : dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new_parent(&tref->child_boxes, GF_ISOM_BOX_TYPE_REFT);
4509 144 : if (!dpnd) return GF_OUT_OF_MEM;
4510 144 : dpnd->reference_type = referenceType;
4511 : }
4512 : //add the ref
4513 334 : return reftype_AddRefTrack(dpnd, ReferencedTrackID, NULL);
4514 : }
4515 :
4516 : GF_EXPORT
4517 1127 : GF_Err gf_isom_purge_track_reference(GF_ISOFile *the_file, u32 trackNumber)
4518 : {
4519 : GF_TrackBox *trak;
4520 : GF_TrackReferenceTypeBox *ref;
4521 1127 : u32 i=0;
4522 1127 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
4523 1127 : if (!trak) return GF_BAD_PARAM;
4524 :
4525 : //no tref, nothing to remove
4526 1095 : if (!trak->References) return GF_OK;
4527 :
4528 65 : while ((ref = gf_list_enum(trak->References->child_boxes, &i))) {
4529 : u32 k;
4530 33 : if (!ref->reference_type) continue;
4531 :
4532 47 : for (k=0; k<ref->trackIDCount; k++) {
4533 47 : u32 tk = gf_isom_get_track_by_id(the_file, ref->trackIDs[k]);
4534 47 : if (!tk) {
4535 1 : memmove(&ref->trackIDs[k], &ref->trackIDs[k+1], ref->trackIDCount-k-1);
4536 1 : k--;
4537 1 : ref->trackIDCount--;
4538 : }
4539 : }
4540 33 : if (!ref->trackIDCount) {
4541 1 : i--;
4542 1 : gf_isom_box_del_parent(&trak->References->child_boxes, (GF_Box *) ref);
4543 : }
4544 : }
4545 32 : if (!trak->References->child_boxes || !gf_list_count(trak->References->child_boxes)) {
4546 1 : gf_isom_box_del_parent(&trak->child_boxes, (GF_Box *) trak->References);
4547 1 : trak->References = NULL;
4548 : }
4549 : return GF_OK;
4550 : }
4551 :
4552 : //sets a track reference
4553 : GF_EXPORT
4554 11 : GF_Err gf_isom_remove_track_references(GF_ISOFile *the_file, u32 trackNumber)
4555 : {
4556 : GF_TrackBox *trak;
4557 :
4558 11 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
4559 11 : if (!trak) return GF_BAD_PARAM;
4560 :
4561 11 : if (trak->References) {
4562 0 : gf_isom_box_del_parent(&trak->child_boxes, (GF_Box *)trak->References);
4563 0 : trak->References = NULL;
4564 : }
4565 : return GF_OK;
4566 : }
4567 :
4568 3075 : GF_Err gf_isom_remove_track_reference(GF_ISOFile *isom_file, u32 trackNumber, u32 ref_type)
4569 : {
4570 : GF_TrackBox *trak;
4571 3075 : u32 i=0;
4572 : GF_TrackReferenceTypeBox *ref;
4573 3075 : trak = gf_isom_get_track_from_file(isom_file, trackNumber);
4574 3075 : if (!trak) return GF_BAD_PARAM;
4575 :
4576 3075 : if (!trak->References) return GF_OK;
4577 492 : while ((ref = gf_list_enum(trak->References->child_boxes, &i))) {
4578 231 : if (ref->reference_type == ref_type) {
4579 54 : gf_isom_box_del_parent(&trak->References->child_boxes, (GF_Box *)ref);
4580 54 : break;
4581 : }
4582 : }
4583 : return GF_OK;
4584 :
4585 : }
4586 :
4587 : //changes track ID
4588 : GF_EXPORT
4589 12 : GF_Err gf_isom_set_track_id(GF_ISOFile *movie, u32 trackNumber, GF_ISOTrackID trackID)
4590 : {
4591 : GF_TrackReferenceTypeBox *ref;
4592 : GF_TrackBox *trak, *a_trak;
4593 : u32 i, j, k;
4594 :
4595 12 : if (!movie) return GF_BAD_PARAM;
4596 12 : trak = gf_isom_get_track_from_file(movie, trackNumber);
4597 12 : if (trak && (trak->Header->trackID==trackID)) return GF_OK;
4598 12 : a_trak = gf_isom_get_track_from_id(movie->moov, trackID);
4599 12 : if (!trak || a_trak) return GF_BAD_PARAM;
4600 :
4601 12 : if (movie->moov->mvhd->nextTrackID<=trackID)
4602 6 : movie->moov->mvhd->nextTrackID = trackID;
4603 :
4604 : /*rewrite all dependencies*/
4605 12 : i=0;
4606 46 : while ((a_trak = (GF_TrackBox*)gf_list_enum(movie->moov->trackList, &i))) {
4607 22 : if (!a_trak->References) continue;
4608 0 : j=0;
4609 0 : while ((ref = (GF_TrackReferenceTypeBox *)gf_list_enum(a_trak->References->child_boxes, &j))) {
4610 0 : for (k=0; k<ref->trackIDCount; k++) {
4611 0 : if (ref->trackIDs[k]==trak->Header->trackID) {
4612 0 : ref->trackIDs[k] = trackID;
4613 0 : break;
4614 : }
4615 : }
4616 : }
4617 : }
4618 :
4619 : /*and update IOD if any*/
4620 12 : if (movie->moov->iods && movie->moov->iods->descriptor) {
4621 : GF_ES_ID_Inc *inc;
4622 : GF_IsomObjectDescriptor *od = (GF_IsomObjectDescriptor *)movie->moov->iods->descriptor;
4623 :
4624 12 : i=0;
4625 24 : while ((inc = (GF_ES_ID_Inc*)gf_list_enum(od->ES_ID_IncDescriptors, &i))) {
4626 0 : if (inc->trackID==trak->Header->trackID) inc->trackID = trackID;
4627 : }
4628 : }
4629 12 : trak->Header->trackID = trackID;
4630 12 : return GF_OK;
4631 : }
4632 :
4633 : /*force to rewrite all dependencies when the trackID of referenced track changes*/
4634 : GF_EXPORT
4635 667 : GF_Err gf_isom_rewrite_track_dependencies(GF_ISOFile *movie, u32 trackNumber)
4636 : {
4637 : GF_TrackReferenceTypeBox *ref;
4638 : GF_TrackBox *trak, *a_trak;
4639 : u32 i, k;
4640 :
4641 667 : trak = gf_isom_get_track_from_file(movie, trackNumber);
4642 667 : if (!trak)
4643 : return GF_BAD_PARAM;
4644 667 : if (!trak->References)
4645 : return GF_OK;
4646 :
4647 6 : i=0;
4648 22 : while ((ref = (GF_TrackReferenceTypeBox *)gf_list_enum(trak->References->child_boxes, &i))) {
4649 11 : for (k=0; k < ref->trackIDCount; k++) {
4650 11 : a_trak = gf_isom_get_track_from_original_id(movie->moov, ref->trackIDs[k], trak->originalFile);
4651 11 : if (a_trak) {
4652 10 : ref->trackIDs[k] = a_trak->Header->trackID;
4653 : } else {
4654 1 : a_trak = gf_isom_get_track_from_id(movie->moov, ref->trackIDs[k]);
4655 : /*we should have a track with no original ID (not imported) - should we rewrite the dependency ?*/
4656 1 : if (! a_trak || a_trak->originalID) return GF_BAD_PARAM;
4657 : }
4658 : }
4659 : }
4660 :
4661 : return GF_OK;
4662 : }
4663 :
4664 : #if 0 //unused
4665 :
4666 : /*! changes the sample description index of a sample
4667 : \param isom_file the destination ISO file
4668 : \param trackNumber the destination track
4669 : \param sampleNum the target sample number
4670 : \param fnewSampleDescIndex the new sample description index to assign to the sample
4671 : \return error if any
4672 : */
4673 : GF_EXPORT
4674 : GF_Err gf_isom_change_sample_desc_index(GF_ISOFile *the_file, u32 trackNumber, u32 sample_number, u32 newSampleDescIndex)
4675 : {
4676 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
4677 : if (!trak || !sample_number || !newSampleDescIndex) return GF_BAD_PARAM;
4678 : if (!trak->is_unpacked) {
4679 : unpack_track(trak);
4680 : }
4681 : if (!trak->Media->information->sampleTable->SampleToChunk) return GF_BAD_PARAM;
4682 : if (trak->Media->information->sampleTable->SampleToChunk->nb_entries < sample_number) return GF_BAD_PARAM;
4683 : trak->Media->information->sampleTable->SampleToChunk->entries[sample_number-1].sampleDescriptionIndex = newSampleDescIndex;
4684 : return GF_OK;
4685 : }
4686 :
4687 : /*modify CTS offset of a given sample (used for B-frames) - MUST be called in unpack mode only*/
4688 : GF_EXPORT
4689 : GF_Err gf_isom_modify_cts_offset(GF_ISOFile *the_file, u32 trackNumber, u32 sample_number, u32 offset)
4690 : {
4691 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
4692 : if (!trak) return GF_BAD_PARAM;
4693 : if (!trak->Media->information->sampleTable->CompositionOffset) return GF_BAD_PARAM;
4694 : if (!trak->Media->information->sampleTable->CompositionOffset->unpack_mode) return GF_BAD_PARAM;
4695 : /*we're in unpack mode: one entry per sample*/
4696 : trak->Media->information->sampleTable->CompositionOffset->entries[sample_number - 1].decodingOffset = offset;
4697 : return GF_OK;
4698 : }
4699 : #endif
4700 :
4701 : GF_EXPORT
4702 177 : GF_Err gf_isom_shift_cts_offset(GF_ISOFile *the_file, u32 trackNumber, s32 offset_shift)
4703 : {
4704 : u32 i;
4705 177 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
4706 177 : if (!trak) return GF_BAD_PARAM;
4707 177 : if (!trak->Media->information->sampleTable->CompositionOffset) return GF_BAD_PARAM;
4708 177 : if (!trak->Media->information->sampleTable->CompositionOffset->unpack_mode) return GF_BAD_PARAM;
4709 :
4710 132181 : for (i=0; i<trak->Media->information->sampleTable->CompositionOffset->nb_entries; i++) {
4711 : /*we're in unpack mode: one entry per sample*/
4712 132181 : trak->Media->information->sampleTable->CompositionOffset->entries[i].decodingOffset -= offset_shift;
4713 : }
4714 : return GF_OK;
4715 : }
4716 :
4717 : #if 0 //unused
4718 : GF_Err gf_isom_remove_cts_info(GF_ISOFile *the_file, u32 trackNumber)
4719 : {
4720 : GF_SampleTableBox *stbl;
4721 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
4722 : if (!trak) return GF_BAD_PARAM;
4723 :
4724 : stbl = trak->Media->information->sampleTable;
4725 : if (!stbl->CompositionOffset) return GF_OK;
4726 :
4727 : gf_isom_box_del_parent(&stbl->child_boxes, (GF_Box *)stbl->CompositionOffset);
4728 : stbl->CompositionOffset = NULL;
4729 : return GF_OK;
4730 : }
4731 : #endif
4732 :
4733 : GF_EXPORT
4734 364 : GF_Err gf_isom_set_cts_packing(GF_ISOFile *the_file, u32 trackNumber, Bool unpack)
4735 : {
4736 : GF_Err e;
4737 : GF_Err stbl_repackCTS(GF_CompositionOffsetBox *ctts);
4738 : GF_Err stbl_unpackCTS(GF_SampleTableBox *stbl);
4739 : GF_SampleTableBox *stbl;
4740 :
4741 364 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
4742 364 : if (!trak) return GF_BAD_PARAM;
4743 :
4744 364 : stbl = trak->Media->information->sampleTable;
4745 364 : if (unpack) {
4746 182 : if (!stbl->CompositionOffset) {
4747 2 : stbl->CompositionOffset = (GF_CompositionOffsetBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_CTTS);
4748 2 : if (!stbl->CompositionOffset) return GF_OUT_OF_MEM;
4749 : }
4750 182 : e = stbl_unpackCTS(stbl);
4751 : } else {
4752 182 : if (!stbl->CompositionOffset) return GF_OK;
4753 182 : e = stbl_repackCTS(stbl->CompositionOffset);
4754 : }
4755 364 : if (e) return e;
4756 364 : return SetTrackDuration(trak);
4757 : }
4758 :
4759 : GF_EXPORT
4760 0 : GF_Err gf_isom_set_track_matrix(GF_ISOFile *the_file, u32 trackNumber, s32 matrix[9])
4761 : {
4762 0 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
4763 0 : if (!trak || !trak->Header) return GF_BAD_PARAM;
4764 0 : memcpy(trak->Header->matrix, matrix, sizeof(trak->Header->matrix));
4765 0 : return GF_OK;
4766 : }
4767 :
4768 : GF_EXPORT
4769 2426 : GF_Err gf_isom_set_track_layout_info(GF_ISOFile *the_file, u32 trackNumber, u32 width, u32 height, s32 translation_x, s32 translation_y, s16 layer)
4770 : {
4771 2426 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
4772 2426 : if (!trak || !trak->Header) return GF_BAD_PARAM;
4773 2426 : trak->Header->width = width;
4774 2426 : trak->Header->height = height;
4775 2426 : trak->Header->matrix[6] = translation_x;
4776 2426 : trak->Header->matrix[7] = translation_y;
4777 2426 : trak->Header->layer = layer;
4778 2426 : return GF_OK;
4779 : }
4780 :
4781 : GF_EXPORT
4782 12 : GF_Err gf_isom_set_media_timescale(GF_ISOFile *the_file, u32 trackNumber, u32 newTS, u32 new_tsinc, u32 force_rescale_type)
4783 : {
4784 : Double scale;
4785 : u32 old_ts_inc=0;
4786 : u32 old_timescale;
4787 : GF_TrackBox *trak;
4788 : GF_SampleTableBox *stbl;
4789 :
4790 12 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
4791 12 : if (!trak || !trak->Media || !trak->Media->mediaHeader) return GF_BAD_PARAM;
4792 12 : if ((trak->Media->mediaHeader->timeScale==newTS) && !new_tsinc)
4793 : return GF_EOS;
4794 :
4795 5 : if (!newTS) newTS = trak->Media->mediaHeader->timeScale;
4796 5 : scale = newTS;
4797 5 : scale /= trak->Media->mediaHeader->timeScale;
4798 : old_timescale = trak->Media->mediaHeader->timeScale;
4799 5 : trak->Media->mediaHeader->timeScale = newTS;
4800 :
4801 5 : stbl = trak->Media->information->sampleTable;
4802 5 : if (new_tsinc) {
4803 : u32 i;
4804 4 : if (!stbl->TimeToSample || !stbl->TimeToSample->nb_entries)
4805 : return GF_BAD_PARAM;
4806 :
4807 8 : for (i=0; i<stbl->TimeToSample->nb_entries; i++) {
4808 4 : if (!old_ts_inc)
4809 4 : old_ts_inc = stbl->TimeToSample->entries[i].sampleDelta;
4810 0 : else if (old_ts_inc<stbl->TimeToSample->entries[i].sampleDelta)
4811 : old_ts_inc = stbl->TimeToSample->entries[i].sampleDelta;
4812 : }
4813 :
4814 4 : if ((old_timescale==newTS) && (old_ts_inc==new_tsinc) && (force_rescale_type!=2) )
4815 : return GF_EOS;
4816 :
4817 4 : if (!force_rescale_type)
4818 : force_rescale_type = 1;
4819 4 : else if (force_rescale_type==2) {
4820 0 : gf_free(stbl->TimeToSample->entries);
4821 0 : stbl->TimeToSample->alloc_size = 1;
4822 0 : stbl->TimeToSample->nb_entries = 1;
4823 0 : stbl->TimeToSample->entries = gf_malloc(sizeof(GF_SttsEntry));
4824 0 : stbl->TimeToSample->entries[0].sampleDelta = new_tsinc;
4825 0 : stbl->TimeToSample->entries[0].sampleCount = stbl->SampleSize->sampleCount;
4826 : }
4827 :
4828 :
4829 8 : for (i=0; i<stbl->TimeToSample->nb_entries; i++) {
4830 4 : stbl->TimeToSample->entries[i].sampleDelta = new_tsinc;
4831 : }
4832 :
4833 4 : if (stbl->CompositionOffset) {
4834 372 : for (i=0; i<stbl->CompositionOffset->nb_entries; i++) {
4835 368 : u32 old_offset = stbl->CompositionOffset->entries[i].decodingOffset;
4836 368 : if (force_rescale_type==2) {
4837 : u32 val = old_offset ;
4838 : //get number of TS delta
4839 0 : old_offset /= old_ts_inc;
4840 0 : if (old_offset * old_ts_inc < val)
4841 0 : old_offset++;
4842 0 : old_offset *= new_tsinc;
4843 : } else {
4844 368 : old_offset *= new_tsinc;
4845 368 : old_offset /= old_ts_inc;
4846 : }
4847 368 : stbl->CompositionOffset->entries[i].decodingOffset = old_offset;
4848 : }
4849 : }
4850 :
4851 : #define RESCALE_TSVAL(_tsval) {\
4852 : s64 val = ((s64) _tsval) * new_tsinc;\
4853 : val /= old_ts_inc;\
4854 : _tsval = (s32) val;\
4855 : }
4856 :
4857 4 : if (stbl->CompositionToDecode) {
4858 0 : RESCALE_TSVAL(stbl->CompositionToDecode->compositionEndTime)
4859 0 : RESCALE_TSVAL(stbl->CompositionToDecode->compositionStartTime)
4860 0 : RESCALE_TSVAL(stbl->CompositionToDecode->compositionToDTSShift)
4861 0 : RESCALE_TSVAL(stbl->CompositionToDecode->greatestDecodeToDisplayDelta)
4862 0 : RESCALE_TSVAL(stbl->CompositionToDecode->leastDecodeToDisplayDelta)
4863 : }
4864 4 : if (trak->editBox) {
4865 : GF_EdtsEntry *ent;
4866 4 : i=0;
4867 12 : while ((ent = (GF_EdtsEntry*)gf_list_enum(trak->editBox->editList->entryList, &i))) {
4868 4 : RESCALE_TSVAL(ent->mediaTime)
4869 : }
4870 : }
4871 : #undef RESCALE_TSVAL
4872 :
4873 4 : return SetTrackDuration(trak);
4874 : }
4875 :
4876 : //rescale timings
4877 : u32 i, k, idx, last_delta;
4878 : u64 cur_dts;
4879 : u64*DTSs = NULL;
4880 : s64*CTSs = NULL;
4881 :
4882 1 : if (trak->editBox) {
4883 : GF_EdtsEntry *ent;
4884 1 : i=0;
4885 3 : while ((ent = (GF_EdtsEntry*)gf_list_enum(trak->editBox->editList->entryList, &i))) {
4886 1 : ent->mediaTime = (u32) (scale*ent->mediaTime);
4887 : }
4888 : }
4889 1 : if (! stbl || !stbl->TimeToSample || !stbl->TimeToSample->nb_entries) {
4890 0 : return SetTrackDuration(trak);
4891 : }
4892 :
4893 : idx = 0;
4894 : cur_dts = 0;
4895 : //unpack the DTSs
4896 1 : DTSs = (u64*)gf_malloc(sizeof(u64) * (stbl->SampleSize->sampleCount) );
4897 1 : if (!DTSs) return GF_OUT_OF_MEM;
4898 :
4899 : CTSs = NULL;
4900 1 : if (stbl->CompositionOffset) {
4901 0 : CTSs = (s64*)gf_malloc(sizeof(u64) * (stbl->SampleSize->sampleCount) );
4902 0 : if (!CTSs) return GF_OUT_OF_MEM;
4903 : }
4904 :
4905 2 : for (i=0; i<stbl->TimeToSample->nb_entries; i++) {
4906 31 : for (k=0; k<stbl->TimeToSample->entries[i].sampleCount; k++) {
4907 31 : cur_dts += stbl->TimeToSample->entries[i].sampleDelta;
4908 31 : DTSs[idx] = (u64) (cur_dts * scale);
4909 :
4910 31 : if (stbl->CompositionOffset) {
4911 : s32 cts_o;
4912 0 : stbl_GetSampleCTS(stbl->CompositionOffset, idx+1, &cts_o);
4913 0 : CTSs[idx] = (s64) ( ((s64) cur_dts + cts_o) * scale);
4914 : }
4915 31 : idx++;
4916 : }
4917 : }
4918 1 : last_delta = (u32) (stbl->TimeToSample->entries[stbl->TimeToSample->nb_entries-1].sampleDelta * scale);
4919 :
4920 : //repack DTS
4921 1 : if (stbl->SampleSize->sampleCount) {
4922 1 : stbl->TimeToSample->entries = gf_realloc(stbl->TimeToSample->entries, sizeof(GF_SttsEntry)*stbl->SampleSize->sampleCount);
4923 1 : memset(stbl->TimeToSample->entries, 0, sizeof(GF_SttsEntry)*stbl->SampleSize->sampleCount);
4924 1 : stbl->TimeToSample->entries[0].sampleDelta = (u32) DTSs[0];
4925 1 : stbl->TimeToSample->entries[0].sampleCount = 1;
4926 : idx=0;
4927 30 : for (i=1; i< stbl->SampleSize->sampleCount - 1; i++) {
4928 29 : if (DTSs[i+1] - DTSs[i] == stbl->TimeToSample->entries[idx].sampleDelta) {
4929 29 : stbl->TimeToSample->entries[idx].sampleCount++;
4930 : } else {
4931 0 : idx++;
4932 0 : stbl->TimeToSample->entries[idx].sampleDelta = (u32) ( DTSs[i+1] - DTSs[i] );
4933 0 : stbl->TimeToSample->entries[idx].sampleCount=1;
4934 : }
4935 : }
4936 1 : if (stbl->SampleSize->sampleCount > 1) {
4937 : //add the sample delta for the last sample
4938 1 : if (stbl->TimeToSample->entries[idx].sampleDelta == last_delta) {
4939 1 : stbl->TimeToSample->entries[idx].sampleCount++;
4940 : } else {
4941 0 : idx++;
4942 0 : stbl->TimeToSample->entries[idx].sampleDelta = last_delta;
4943 0 : stbl->TimeToSample->entries[idx].sampleCount=1;
4944 : }
4945 :
4946 1 : stbl->TimeToSample->nb_entries = idx+1;
4947 1 : stbl->TimeToSample->entries = gf_realloc(stbl->TimeToSample->entries, sizeof(GF_SttsEntry)*stbl->TimeToSample->nb_entries);
4948 : }
4949 : }
4950 :
4951 1 : if (CTSs && stbl->SampleSize->sampleCount>0) {
4952 : //repack CTS
4953 0 : stbl->CompositionOffset->entries = gf_realloc(stbl->CompositionOffset->entries, sizeof(GF_DttsEntry)*stbl->SampleSize->sampleCount);
4954 0 : memset(stbl->CompositionOffset->entries, 0, sizeof(GF_DttsEntry)*stbl->SampleSize->sampleCount);
4955 0 : stbl->CompositionOffset->entries[0].decodingOffset = (s32) (CTSs[0] - DTSs[0]);
4956 0 : stbl->CompositionOffset->entries[0].sampleCount = 1;
4957 : idx=0;
4958 0 : for (i=1; i< stbl->SampleSize->sampleCount; i++) {
4959 0 : s32 cts_o = (s32) (CTSs[i] - DTSs[i]);
4960 0 : if (cts_o == stbl->CompositionOffset->entries[idx].decodingOffset) {
4961 0 : stbl->CompositionOffset->entries[idx].sampleCount++;
4962 : } else {
4963 0 : idx++;
4964 0 : stbl->CompositionOffset->entries[idx].decodingOffset = cts_o;
4965 0 : stbl->CompositionOffset->entries[idx].sampleCount=1;
4966 : }
4967 : }
4968 0 : stbl->CompositionOffset->nb_entries = idx+1;
4969 0 : stbl->CompositionOffset->entries = gf_realloc(stbl->CompositionOffset->entries, sizeof(GF_DttsEntry)*stbl->CompositionOffset->nb_entries);
4970 :
4971 0 : gf_free(CTSs);
4972 : }
4973 1 : gf_free(DTSs);
4974 :
4975 1 : if (stbl->CompositionToDecode) {
4976 0 : stbl->CompositionToDecode->compositionEndTime = (s32) (stbl->CompositionToDecode->compositionEndTime * scale);
4977 0 : stbl->CompositionToDecode->compositionStartTime = (s32)(stbl->CompositionToDecode->compositionStartTime * scale);
4978 0 : stbl->CompositionToDecode->compositionToDTSShift = (s32)(stbl->CompositionToDecode->compositionToDTSShift * scale);
4979 0 : stbl->CompositionToDecode->greatestDecodeToDisplayDelta = (s32)(stbl->CompositionToDecode->greatestDecodeToDisplayDelta * scale);
4980 0 : stbl->CompositionToDecode->leastDecodeToDisplayDelta = (s32)(stbl->CompositionToDecode->leastDecodeToDisplayDelta * scale);
4981 : }
4982 :
4983 1 : return SetTrackDuration(trak);
4984 : }
4985 :
4986 : GF_EXPORT
4987 380 : Bool gf_isom_box_equal(GF_Box *a, GF_Box *b)
4988 : {
4989 : Bool ret;
4990 : u8 *data1, *data2;
4991 : u32 data1_size, data2_size;
4992 : GF_BitStream *bs;
4993 :
4994 380 : if (a == b) return GF_TRUE;
4995 379 : if (!a || !b) return GF_FALSE;
4996 :
4997 141 : data1 = data2 = NULL;
4998 :
4999 141 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
5000 141 : gf_isom_box_size(a);
5001 141 : gf_isom_box_write(a, bs);
5002 141 : gf_bs_get_content(bs, &data1, &data1_size);
5003 141 : gf_bs_del(bs);
5004 :
5005 141 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
5006 141 : gf_isom_box_size(b);
5007 141 : gf_isom_box_write(b, bs);
5008 141 : gf_bs_get_content(bs, &data2, &data2_size);
5009 141 : gf_bs_del(bs);
5010 :
5011 : ret = GF_FALSE;
5012 141 : if (data1_size == data2_size) {
5013 132 : ret = (memcmp(data1, data2, sizeof(char)*data1_size) == 0) ? GF_TRUE : GF_FALSE;
5014 : }
5015 141 : gf_free(data1);
5016 141 : gf_free(data2);
5017 141 : return ret;
5018 : }
5019 :
5020 : GF_EXPORT
5021 28 : Bool gf_isom_is_same_sample_description(GF_ISOFile *f1, u32 tk1, u32 sdesc_index1, GF_ISOFile *f2, u32 tk2, u32 sdesc_index2)
5022 : {
5023 : u32 i, count;
5024 : GF_TrackBox *trak1, *trak2;
5025 : GF_ESD *esd1, *esd2;
5026 : Bool need_memcmp, ret;
5027 : GF_Box *a, *b;
5028 :
5029 : /*get orig sample desc and clone it*/
5030 28 : trak1 = gf_isom_get_track_from_file(f1, tk1);
5031 28 : if (!trak1 || !trak1->Media) return GF_FALSE;
5032 28 : trak2 = gf_isom_get_track_from_file(f2, tk2);
5033 28 : if (!trak2 || !trak2->Media) return GF_FALSE;
5034 :
5035 25 : if (trak1->Media->handler->handlerType != trak2->Media->handler->handlerType) return GF_FALSE;
5036 25 : count = gf_list_count(trak1->Media->information->sampleTable->SampleDescription->child_boxes);
5037 25 : if (count != gf_list_count(trak2->Media->information->sampleTable->SampleDescription->child_boxes)) {
5038 0 : if (!sdesc_index1 && !sdesc_index2) return GF_FALSE;
5039 : }
5040 :
5041 : need_memcmp = GF_TRUE;
5042 2 : for (i=0; i<count; i++) {
5043 25 : GF_Box *ent1 = (GF_Box *)gf_list_get(trak1->Media->information->sampleTable->SampleDescription->child_boxes, i);
5044 25 : GF_Box *ent2 = (GF_Box *)gf_list_get(trak2->Media->information->sampleTable->SampleDescription->child_boxes, i);
5045 :
5046 25 : if (sdesc_index1) ent1 = (GF_Box *)gf_list_get(trak1->Media->information->sampleTable->SampleDescription->child_boxes, sdesc_index1 - 1);
5047 25 : if (sdesc_index2) ent2 = (GF_Box *)gf_list_get(trak2->Media->information->sampleTable->SampleDescription->child_boxes, sdesc_index2 - 1);
5048 :
5049 25 : if (!ent1 || !ent2) return GF_FALSE;
5050 25 : if (ent1->type != ent2->type) return GF_FALSE;
5051 :
5052 24 : switch (ent1->type) {
5053 : /*for MPEG-4 streams, only compare decSpecInfo (bitrate may not be the same but that's not an issue)*/
5054 1 : case GF_ISOM_BOX_TYPE_MP4S:
5055 : case GF_ISOM_BOX_TYPE_MP4A:
5056 : case GF_ISOM_BOX_TYPE_MP4V:
5057 : case GF_ISOM_BOX_TYPE_ENCA:
5058 : case GF_ISOM_BOX_TYPE_ENCV:
5059 : case GF_ISOM_BOX_TYPE_RESV:
5060 : case GF_ISOM_BOX_TYPE_ENCS:
5061 1 : Media_GetESD(trak1->Media, sdesc_index1 ? sdesc_index1 : i+1, &esd1, GF_TRUE);
5062 1 : Media_GetESD(trak2->Media, sdesc_index2 ? sdesc_index2 : i+1, &esd2, GF_TRUE);
5063 1 : if (!esd1 || !esd2) continue;
5064 : need_memcmp = GF_FALSE;
5065 1 : if (esd1->decoderConfig->streamType != esd2->decoderConfig->streamType) return GF_FALSE;
5066 1 : if (esd1->decoderConfig->objectTypeIndication != esd2->decoderConfig->objectTypeIndication) return GF_FALSE;
5067 1 : if (!esd1->decoderConfig->decoderSpecificInfo && esd2->decoderConfig->decoderSpecificInfo) return GF_FALSE;
5068 1 : if (esd1->decoderConfig->decoderSpecificInfo && !esd2->decoderConfig->decoderSpecificInfo) return GF_FALSE;
5069 1 : if (!esd1->decoderConfig->decoderSpecificInfo || !esd2->decoderConfig->decoderSpecificInfo) continue;
5070 1 : if (memcmp(esd1->decoderConfig->decoderSpecificInfo->data, esd2->decoderConfig->decoderSpecificInfo->data, sizeof(char)*esd1->decoderConfig->decoderSpecificInfo->dataLength)!=0) return GF_FALSE;
5071 : break;
5072 : case GF_ISOM_BOX_TYPE_HVT1:
5073 : return GF_TRUE;
5074 21 : case GF_ISOM_BOX_TYPE_AVC1:
5075 : case GF_ISOM_BOX_TYPE_AVC2:
5076 : case GF_ISOM_BOX_TYPE_AVC3:
5077 : case GF_ISOM_BOX_TYPE_AVC4:
5078 : case GF_ISOM_BOX_TYPE_SVC1:
5079 : case GF_ISOM_BOX_TYPE_MVC1:
5080 : case GF_ISOM_BOX_TYPE_HVC1:
5081 : case GF_ISOM_BOX_TYPE_HEV1:
5082 : case GF_ISOM_BOX_TYPE_HVC2:
5083 : case GF_ISOM_BOX_TYPE_HEV2:
5084 : case GF_ISOM_BOX_TYPE_LHE1:
5085 : case GF_ISOM_BOX_TYPE_LHV1:
5086 : case GF_ISOM_BOX_TYPE_AV01:
5087 : case GF_ISOM_BOX_TYPE_VVC1:
5088 : case GF_ISOM_BOX_TYPE_VVI1:
5089 : {
5090 : GF_MPEGVisualSampleEntryBox *avc1 = (GF_MPEGVisualSampleEntryBox *)ent1;
5091 : GF_MPEGVisualSampleEntryBox *avc2 = (GF_MPEGVisualSampleEntryBox *)ent2;
5092 :
5093 21 : if (avc1->hevc_config)
5094 : a = (GF_Box *) avc1->hevc_config;
5095 14 : else if (avc1->lhvc_config)
5096 : a = (GF_Box *) avc1->lhvc_config;
5097 14 : else if (avc1->svc_config)
5098 : a = (GF_Box *) avc1->svc_config;
5099 14 : else if (avc1->mvc_config)
5100 : a = (GF_Box *) avc1->mvc_config;
5101 14 : else if (avc1->av1_config)
5102 : a = (GF_Box *)avc1->av1_config;
5103 : else
5104 14 : a = (GF_Box *) avc1->avc_config;
5105 :
5106 21 : if (avc2->hevc_config)
5107 : b = (GF_Box *) avc2->hevc_config;
5108 14 : else if (avc2->lhvc_config)
5109 : b = (GF_Box *) avc2->lhvc_config;
5110 14 : else if (avc2->svc_config)
5111 : b = (GF_Box *) avc2->svc_config;
5112 14 : else if (avc2->mvc_config)
5113 : b = (GF_Box *) avc2->mvc_config;
5114 14 : else if (avc2->av1_config)
5115 : b = (GF_Box *)avc2->av1_config;
5116 : else
5117 14 : b = (GF_Box *) avc2->avc_config;
5118 :
5119 21 : return gf_isom_box_equal(a,b);
5120 : }
5121 : break;
5122 0 : case GF_ISOM_BOX_TYPE_LSR1:
5123 : {
5124 : GF_LASeRSampleEntryBox *lsr1 = (GF_LASeRSampleEntryBox *)ent1;
5125 : GF_LASeRSampleEntryBox *lsr2 = (GF_LASeRSampleEntryBox *)ent2;
5126 0 : if (lsr1->lsr_config && lsr2->lsr_config
5127 0 : && lsr1->lsr_config->hdr && lsr2->lsr_config->hdr
5128 0 : && (lsr1->lsr_config->hdr_size==lsr2->lsr_config->hdr_size)
5129 0 : && !memcmp(lsr1->lsr_config->hdr, lsr2->lsr_config->hdr, lsr2->lsr_config->hdr_size)
5130 : ) {
5131 : return GF_TRUE;
5132 : }
5133 0 : return GF_FALSE;
5134 : }
5135 : break;
5136 : #ifndef GPAC_DISABLE_VTT
5137 0 : case GF_ISOM_BOX_TYPE_WVTT:
5138 : {
5139 : GF_WebVTTSampleEntryBox *wvtt1 = (GF_WebVTTSampleEntryBox *)ent1;
5140 : GF_WebVTTSampleEntryBox *wvtt2 = (GF_WebVTTSampleEntryBox *)ent2;
5141 0 : if (wvtt1->config && wvtt2->config &&
5142 0 : (wvtt1->config->string && wvtt2->config->string && !strcmp(wvtt1->config->string, wvtt2->config->string))) {
5143 : return GF_TRUE;
5144 : }
5145 0 : return GF_FALSE;
5146 : }
5147 : break;
5148 : #endif
5149 0 : case GF_ISOM_BOX_TYPE_STPP:
5150 : {
5151 : GF_MetaDataSampleEntryBox *stpp1 = (GF_MetaDataSampleEntryBox *)ent1;
5152 : GF_MetaDataSampleEntryBox *stpp2 = (GF_MetaDataSampleEntryBox *)ent2;
5153 0 : if (stpp1->xml_namespace && stpp2->xml_namespace && !strcmp(stpp1->xml_namespace, stpp2->xml_namespace)) {
5154 : return GF_TRUE;
5155 : }
5156 0 : return GF_FALSE;
5157 : }
5158 : break;
5159 0 : case GF_ISOM_BOX_TYPE_SBTT:
5160 : {
5161 0 : return GF_FALSE;
5162 : }
5163 : break;
5164 0 : case GF_ISOM_BOX_TYPE_STXT:
5165 : {
5166 : GF_MetaDataSampleEntryBox *stxt1 = (GF_MetaDataSampleEntryBox *)ent1;
5167 : GF_MetaDataSampleEntryBox *stxt2 = (GF_MetaDataSampleEntryBox *)ent2;
5168 0 : if (stxt1->mime_type && stxt2->mime_type &&
5169 0 : ( (!stxt1->config && !stxt2->config) ||
5170 0 : (stxt1->config && stxt2->config && stxt1->config->config && stxt2->config->config &&
5171 0 : !strcmp(stxt1->config->config, stxt2->config->config)))) {
5172 : return GF_TRUE;
5173 : }
5174 0 : return GF_FALSE;
5175 : }
5176 : case GF_ISOM_BOX_TYPE_MP3:
5177 : case GF_QT_SUBTYPE_RAW_AUD:
5178 : case GF_QT_SUBTYPE_TWOS:
5179 : case GF_QT_SUBTYPE_SOWT:
5180 : case GF_QT_SUBTYPE_FL32:
5181 : case GF_QT_SUBTYPE_FL64:
5182 : case GF_QT_SUBTYPE_IN24:
5183 : case GF_QT_SUBTYPE_IN32:
5184 : case GF_QT_SUBTYPE_ULAW:
5185 : case GF_QT_SUBTYPE_ALAW:
5186 : case GF_QT_SUBTYPE_ADPCM:
5187 : case GF_QT_SUBTYPE_IMA_ADPCM:
5188 : case GF_QT_SUBTYPE_DVCA:
5189 : case GF_QT_SUBTYPE_QDMC:
5190 : case GF_QT_SUBTYPE_QDMC2:
5191 : case GF_QT_SUBTYPE_QCELP:
5192 : case GF_QT_SUBTYPE_kMP3:
5193 : return GF_TRUE;
5194 : case GF_QT_SUBTYPE_APCH:
5195 : case GF_QT_SUBTYPE_APCO:
5196 : case GF_QT_SUBTYPE_APCN:
5197 : case GF_QT_SUBTYPE_APCS:
5198 : case GF_QT_SUBTYPE_AP4X:
5199 : case GF_QT_SUBTYPE_AP4H:
5200 : case GF_QT_SUBTYPE_RAW_VID:
5201 : case GF_QT_SUBTYPE_YUYV:
5202 : case GF_QT_SUBTYPE_UYVY:
5203 : case GF_QT_SUBTYPE_YUV444:
5204 : case GF_QT_SUBTYPE_YUVA444:
5205 : case GF_QT_SUBTYPE_YUV422_10:
5206 : case GF_QT_SUBTYPE_YUV444_10:
5207 : case GF_QT_SUBTYPE_YUV422_16:
5208 : case GF_QT_SUBTYPE_YUV420:
5209 : case GF_QT_SUBTYPE_I420:
5210 : case GF_QT_SUBTYPE_IYUV:
5211 : case GF_QT_SUBTYPE_YV12:
5212 : case GF_QT_SUBTYPE_YVYU:
5213 : case GF_QT_SUBTYPE_RGBA:
5214 : case GF_QT_SUBTYPE_ABGR:
5215 : return GF_TRUE;
5216 : }
5217 :
5218 3 : if (sdesc_index1 && sdesc_index2) break;
5219 : }
5220 3 : if (!need_memcmp) return GF_TRUE;
5221 2 : a = (GF_Box *)trak1->Media->information->sampleTable->SampleDescription;
5222 2 : b = (GF_Box *)trak2->Media->information->sampleTable->SampleDescription;
5223 : //we ignore all bitrate boxes when comparing the box, disable their writing
5224 2 : gf_isom_registry_disable(GF_ISOM_BOX_TYPE_BTRT, GF_TRUE);
5225 2 : ret = gf_isom_box_equal(a,b);
5226 : //re-enable btrt writing
5227 2 : gf_isom_registry_disable(GF_ISOM_BOX_TYPE_BTRT, GF_FALSE);
5228 :
5229 2 : return ret;
5230 : }
5231 :
5232 : GF_EXPORT
5233 1 : u64 gf_isom_estimate_size(GF_ISOFile *movie)
5234 : {
5235 : GF_Err e;
5236 : GF_Box *a;
5237 : u32 i, count;
5238 : u64 mdat_size;
5239 1 : if (!movie || !movie->moov) return 0;
5240 :
5241 : mdat_size = 0;
5242 1 : count = gf_list_count(movie->moov->trackList);
5243 3 : for (i=0; i<count; i++) {
5244 2 : mdat_size += gf_isom_get_media_data_size(movie, i+1);
5245 : }
5246 1 : if (mdat_size) {
5247 1 : mdat_size += 8;
5248 1 : if (mdat_size > 0xFFFFFFFF) mdat_size += 8;
5249 : }
5250 :
5251 1 : i=0;
5252 5 : while ((a = (GF_Box*)gf_list_enum(movie->TopBoxes, &i))) {
5253 3 : e = gf_isom_box_size(a);
5254 3 : if (e == GF_OK)
5255 3 : mdat_size += a->size;
5256 : }
5257 : return mdat_size;
5258 : }
5259 :
5260 :
5261 : //set shadowing on/off
5262 : #if 0 //unused
5263 : GF_Err gf_isom_remove_sync_shadows(GF_ISOFile *movie, u32 trackNumber)
5264 : {
5265 : GF_TrackBox *trak;
5266 : GF_SampleTableBox *stbl;
5267 :
5268 : if (movie->openMode == GF_ISOM_OPEN_READ) return GF_ISOM_INVALID_MODE;
5269 : trak = gf_isom_get_track_from_file(movie, trackNumber);
5270 : if (!trak) return GF_BAD_PARAM;
5271 :
5272 : stbl = trak->Media->information->sampleTable;
5273 : if (stbl->ShadowSync) {
5274 : gf_isom_box_del_parent(&stbl->child_boxes, (GF_Box *) stbl->ShadowSync);
5275 : stbl->ShadowSync = NULL;
5276 : }
5277 : return GF_OK;
5278 : }
5279 :
5280 : /*Use this function to do the shadowing if you use shadowing.
5281 : the sample to be shadowed MUST be a non-sync sample (ignored if not)
5282 : the sample shadowing must be a Sync sample (error if not)*/
5283 : GF_Err gf_isom_set_sync_shadow(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber, u32 syncSample)
5284 : {
5285 : GF_TrackBox *trak;
5286 : GF_SampleTableBox *stbl;
5287 : GF_ISOSAPType isRAP;
5288 : GF_Err e;
5289 :
5290 : if (movie->openMode == GF_ISOM_OPEN_READ) return GF_ISOM_INVALID_MODE;
5291 : trak = gf_isom_get_track_from_file(movie, trackNumber);
5292 : if (!trak || !sampleNumber || !syncSample) return GF_BAD_PARAM;
5293 :
5294 : stbl = trak->Media->information->sampleTable;
5295 : if (!stbl->ShadowSync) {
5296 : stbl->ShadowSync = (GF_ShadowSyncBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSH);
5297 : if (!stbl->ShadowSync) return GF_OUT_OF_MEM;
5298 : }
5299 :
5300 : //if no sync, skip
5301 : if (!stbl->SyncSample) return GF_OK;
5302 : //else set the sync shadow.
5303 : //if the sample is sync, ignore
5304 : e = stbl_GetSampleRAP(stbl->SyncSample, sampleNumber, &isRAP, NULL, NULL);
5305 : if (e) return e;
5306 : if (isRAP) return GF_OK;
5307 : //if the shadowing sample is not sync, error
5308 : e = stbl_GetSampleRAP(stbl->SyncSample, syncSample, &isRAP, NULL, NULL);
5309 : if (e) return e;
5310 : if (!isRAP) return GF_BAD_PARAM;
5311 :
5312 : return stbl_SetSyncShadow(stbl->ShadowSync, sampleNumber, syncSample);
5313 : }
5314 : #endif
5315 :
5316 : //set the GroupID of a track (only used for interleaving)
5317 : GF_EXPORT
5318 156 : GF_Err gf_isom_set_track_interleaving_group(GF_ISOFile *movie, u32 trackNumber, u32 GroupID)
5319 : {
5320 : GF_TrackBox *trak;
5321 :
5322 156 : if (movie->openMode != GF_ISOM_OPEN_EDIT) return GF_ISOM_INVALID_MODE;
5323 140 : trak = gf_isom_get_track_from_file(movie, trackNumber);
5324 140 : if (!trak || !GroupID) return GF_BAD_PARAM;
5325 :
5326 126 : trak->Media->information->sampleTable->groupID = GroupID;
5327 126 : return GF_OK;
5328 : }
5329 :
5330 :
5331 : //set the Priority of a track within a Group (only used for tight interleaving)
5332 : //Priority ranges from 1 to 9
5333 : GF_EXPORT
5334 146 : GF_Err gf_isom_set_track_priority_in_group(GF_ISOFile *movie, u32 trackNumber, u32 Priority)
5335 : {
5336 : GF_TrackBox *trak;
5337 :
5338 146 : if (movie->openMode != GF_ISOM_OPEN_EDIT) return GF_ISOM_INVALID_MODE;
5339 140 : trak = gf_isom_get_track_from_file(movie, trackNumber);
5340 140 : if (!trak || !Priority) return GF_BAD_PARAM;
5341 :
5342 133 : trak->Media->information->sampleTable->trackPriority = Priority > 255 ? 255 : Priority;
5343 133 : return GF_OK;
5344 : }
5345 :
5346 : //set the max SamplesPerChunk (for file optimization)
5347 : GF_EXPORT
5348 6 : GF_Err gf_isom_hint_max_chunk_size(GF_ISOFile *movie, u32 trackNumber, u32 maxChunkSize)
5349 : {
5350 : GF_TrackBox *trak;
5351 :
5352 6 : if (movie->openMode == GF_ISOM_OPEN_READ) return GF_ISOM_INVALID_MODE;
5353 6 : trak = gf_isom_get_track_from_file(movie, trackNumber);
5354 6 : if (!trak || !maxChunkSize) return GF_BAD_PARAM;
5355 :
5356 6 : trak->Media->information->sampleTable->MaxChunkSize = maxChunkSize;
5357 6 : return GF_OK;
5358 : }
5359 :
5360 :
5361 : //set the max SamplesPerChunk (for file optimization)
5362 : GF_EXPORT
5363 8 : GF_Err gf_isom_hint_max_chunk_duration(GF_ISOFile *movie, u32 trackNumber, u32 maxChunkDur)
5364 : {
5365 : GF_TrackBox *trak;
5366 :
5367 8 : if (movie->openMode == GF_ISOM_OPEN_READ) return GF_ISOM_INVALID_MODE;
5368 8 : trak = gf_isom_get_track_from_file(movie, trackNumber);
5369 8 : if (!trak) return GF_BAD_PARAM;
5370 :
5371 8 : trak->Media->information->sampleTable->MaxChunkDur = maxChunkDur;
5372 8 : return GF_OK;
5373 : }
5374 :
5375 :
5376 : GF_EXPORT
5377 43 : GF_Err gf_isom_set_extraction_slc(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex, const GF_SLConfig *slConfig)
5378 : {
5379 : GF_TrackBox *trak;
5380 : GF_SampleEntryBox *entry;
5381 : GF_Err e;
5382 : GF_SLConfig **slc;
5383 : GF_ESDBox *esds;
5384 :
5385 43 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
5386 43 : if (!trak) return GF_BAD_PARAM;
5387 :
5388 43 : e = Media_GetSampleDesc(trak->Media, StreamDescriptionIndex, &entry, NULL);
5389 43 : if (e) return e;
5390 :
5391 : //we must be sure we are not using a remote ESD
5392 43 : switch (entry->type) {
5393 10 : case GF_ISOM_BOX_TYPE_MP4S:
5394 10 : esds = ((GF_MPEGSampleEntryBox *)entry)->esd;
5395 10 : if (!esds || !esds->desc || !esds->desc->slConfig || (esds->desc->slConfig->predefined != SLPredef_MP4))
5396 : return GF_ISOM_INVALID_FILE;
5397 10 : slc = & ((GF_MPEGSampleEntryBox *)entry)->slc;
5398 10 : break;
5399 15 : case GF_ISOM_BOX_TYPE_MP4A:
5400 15 : esds = ((GF_MPEGAudioSampleEntryBox *)entry)->esd;
5401 15 : if (!esds || !esds->desc || !esds->desc->slConfig || (esds->desc->slConfig->predefined != SLPredef_MP4))
5402 : return GF_ISOM_INVALID_FILE;
5403 15 : slc = & ((GF_MPEGAudioSampleEntryBox *)entry)->slc;
5404 15 : break;
5405 13 : case GF_ISOM_BOX_TYPE_MP4V:
5406 13 : esds = ((GF_MPEGVisualSampleEntryBox *)entry)->esd;
5407 13 : if (!esds || !esds->desc || !esds->desc->slConfig || (esds->desc->slConfig->predefined != SLPredef_MP4))
5408 : return GF_ISOM_INVALID_FILE;
5409 13 : slc = & ((GF_MPEGVisualSampleEntryBox *)entry)->slc;
5410 13 : break;
5411 : default:
5412 : return GF_OK;
5413 : }
5414 :
5415 38 : if (*slc) {
5416 0 : gf_odf_desc_del((GF_Descriptor *)*slc);
5417 0 : *slc = NULL;
5418 : }
5419 38 : if (!slConfig) return GF_OK;
5420 : //finally duplicate the SL
5421 38 : return gf_odf_desc_copy((GF_Descriptor *) slConfig, (GF_Descriptor **) slc);
5422 : }
5423 :
5424 : #if 0 //unused
5425 : GF_Err gf_isom_get_extraction_slc(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex, GF_SLConfig **slConfig)
5426 : {
5427 : GF_TrackBox *trak;
5428 : GF_SampleEntryBox *entry;
5429 : GF_Err e;
5430 : GF_SLConfig *slc;
5431 :
5432 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
5433 : if (!trak) return GF_BAD_PARAM;
5434 :
5435 : e = Media_GetSampleDesc(trak->Media, StreamDescriptionIndex, &entry, NULL);
5436 : if (e) return e;
5437 :
5438 : //we must be sure we are not using a remote ESD
5439 : slc = NULL;
5440 : *slConfig = NULL;
5441 : switch (entry->type) {
5442 : case GF_ISOM_BOX_TYPE_MP4S:
5443 : if (((GF_MPEGSampleEntryBox *)entry)->esd->desc->slConfig->predefined != SLPredef_MP4) return GF_BAD_PARAM;
5444 : slc = ((GF_MPEGSampleEntryBox *)entry)->slc;
5445 : break;
5446 : case GF_ISOM_BOX_TYPE_MP4A:
5447 : if (((GF_MPEGAudioSampleEntryBox *)entry)->esd->desc->slConfig->predefined != SLPredef_MP4) return GF_BAD_PARAM;
5448 : slc = ((GF_MPEGAudioSampleEntryBox *)entry)->slc;
5449 : break;
5450 : case GF_ISOM_BOX_TYPE_MP4V:
5451 : if (((GF_MPEGVisualSampleEntryBox *)entry)->esd->desc->slConfig->predefined != SLPredef_MP4) return GF_BAD_PARAM;
5452 : slc = ((GF_MPEGVisualSampleEntryBox *)entry)->slc;
5453 : break;
5454 : default:
5455 : return GF_BAD_PARAM;
5456 : }
5457 :
5458 : if (!slc) return GF_OK;
5459 : //finally duplicate the SL
5460 : return gf_odf_desc_copy((GF_Descriptor *) slc, (GF_Descriptor **) slConfig);
5461 : }
5462 :
5463 : u32 gf_isom_get_track_group(GF_ISOFile *the_file, u32 trackNumber)
5464 : {
5465 : GF_TrackBox *trak;
5466 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
5467 : if (!trak) return 0;
5468 : return trak->Media->information->sampleTable->groupID;
5469 : }
5470 :
5471 : u32 gf_isom_get_track_priority_in_group(GF_ISOFile *the_file, u32 trackNumber)
5472 : {
5473 : GF_TrackBox *trak;
5474 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
5475 : if (!trak) return 0;
5476 : return trak->Media->information->sampleTable->trackPriority;
5477 : }
5478 : #endif
5479 :
5480 :
5481 : GF_EXPORT
5482 1059 : GF_Err gf_isom_make_interleave_ex(GF_ISOFile *file, GF_Fraction *fTimeInSec)
5483 : {
5484 : GF_Err e;
5485 : u64 itime;
5486 1059 : if (!file || !fTimeInSec->den || (fTimeInSec->num<=0)) return GF_BAD_PARAM;
5487 :
5488 1059 : itime = (u64) fTimeInSec->num;
5489 1059 : itime *= gf_isom_get_timescale(file);
5490 1059 : itime /= fTimeInSec->den;
5491 1059 : if (file->storageMode==GF_ISOM_STORE_FASTSTART) {
5492 4 : return gf_isom_set_interleave_time(file, (u32) itime);
5493 : }
5494 1055 : if (gf_isom_get_mode(file) < GF_ISOM_OPEN_EDIT) return GF_BAD_PARAM;
5495 1055 : e = gf_isom_set_storage_mode(file, GF_ISOM_STORE_DRIFT_INTERLEAVED);
5496 1055 : if (e) return e;
5497 1055 : return gf_isom_set_interleave_time(file, (u32) itime);
5498 : }
5499 :
5500 : GF_EXPORT
5501 674 : GF_Err gf_isom_make_interleave(GF_ISOFile *file, Double TimeInSec)
5502 : {
5503 : GF_Fraction f;
5504 674 : f.num = (s32) (TimeInSec * 1000);
5505 674 : f.den = 1000;
5506 674 : return gf_isom_make_interleave_ex(file, &f);
5507 :
5508 : }
5509 : GF_EXPORT
5510 559 : GF_Err gf_isom_set_handler_name(GF_ISOFile *the_file, u32 trackNumber, const char *nameUTF8)
5511 : {
5512 : GF_TrackBox *trak;
5513 559 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
5514 559 : if (!trak) return GF_BAD_PARAM;
5515 559 : if (trak->Media->handler->nameUTF8) gf_free(trak->Media->handler->nameUTF8);
5516 559 : trak->Media->handler->nameUTF8 = NULL;
5517 :
5518 559 : if (!nameUTF8) return GF_OK;
5519 :
5520 559 : if (!strnicmp(nameUTF8, "file://", 7)) {
5521 : u8 BOM[4];
5522 0 : FILE *f = gf_fopen(nameUTF8+7, "rb");
5523 : u64 size;
5524 0 : if (!f) return GF_URL_ERROR;
5525 0 : size = gf_fsize(f);
5526 0 : if (3!=gf_fread(BOM, 3, f)) {
5527 0 : gf_fclose(f);
5528 0 : return GF_CORRUPTED_DATA;
5529 : }
5530 : /*skip BOM if any*/
5531 0 : if ((BOM[0]==0xEF) && (BOM[1]==0xBB) && (BOM[2]==0xBF)) size -= 3;
5532 0 : else if ((BOM[0]==0xEF) || (BOM[0]==0xFF)) {
5533 0 : gf_fclose(f);
5534 0 : return GF_BAD_PARAM;
5535 : }
5536 0 : else gf_fseek(f, 0, SEEK_SET);
5537 0 : trak->Media->handler->nameUTF8 = (char*)gf_malloc(sizeof(char)*(size_t)(size+1));
5538 0 : if (!trak->Media->handler->nameUTF8) {
5539 0 : gf_fclose(f);
5540 0 : return GF_OUT_OF_MEM;
5541 : }
5542 0 : size = gf_fread(trak->Media->handler->nameUTF8, (size_t)size, f);
5543 0 : trak->Media->handler->nameUTF8[size] = 0;
5544 0 : gf_fclose(f);
5545 : } else {
5546 : u32 i, j, len;
5547 : char szOrig[1024], szLine[1024];
5548 : strcpy(szOrig, nameUTF8);
5549 : j=0;
5550 559 : len = (u32) strlen(szOrig);
5551 20624 : for (i=0; i<len; i++) {
5552 20065 : if (szOrig[i] & 0x80) {
5553 : /*non UTF8 (likely some win-CP)*/
5554 0 : if ( (szOrig[i+1] & 0xc0) != 0x80) {
5555 0 : szLine[j] = 0xc0 | ( (szOrig[i] >> 6) & 0x3 );
5556 0 : j++;
5557 0 : szOrig[i] &= 0xbf;
5558 : }
5559 : /*UTF8 2 bytes char */
5560 0 : else if ( (szOrig[i] & 0xe0) == 0xc0) {
5561 0 : szLine[j] = szOrig[i];
5562 : i++;
5563 0 : j++;
5564 : }
5565 : /*UTF8 3 bytes char */
5566 0 : else if ( (szOrig[i] & 0xf0) == 0xe0) {
5567 0 : szLine[j] = szOrig[i];
5568 : i++;
5569 0 : j++;
5570 0 : szLine[j] = szOrig[i];
5571 0 : i++;
5572 0 : j++;
5573 : }
5574 : /*UTF8 4 bytes char */
5575 0 : else if ( (szOrig[i] & 0xf8) == 0xf0) {
5576 0 : szLine[j] = szOrig[i];
5577 : i++;
5578 0 : j++;
5579 0 : szLine[j] = szOrig[i];
5580 0 : i++;
5581 0 : j++;
5582 0 : szLine[j] = szOrig[i];
5583 0 : i++;
5584 0 : j++;
5585 : }
5586 : }
5587 20065 : szLine[j] = szOrig[i];
5588 20065 : j++;
5589 : }
5590 559 : szLine[j] = 0;
5591 559 : trak->Media->handler->nameUTF8 = gf_strdup(szLine);
5592 : }
5593 : return GF_OK;
5594 : }
5595 :
5596 : #if 0 //unused
5597 : /*clones root OD from input to output file, without copying root OD track references*/
5598 : GF_Err gf_isom_clone_root_od(GF_ISOFile *input, GF_ISOFile *output)
5599 : {
5600 : GF_List *esds;
5601 : GF_Err e;
5602 : u32 i;
5603 : GF_Descriptor *desc;
5604 :
5605 : e = gf_isom_remove_root_od(output);
5606 : if (e) return e;
5607 : if (!input->moov || !input->moov->iods || !input->moov->iods->descriptor) return GF_OK;
5608 : e = gf_isom_insert_moov(output);
5609 : if (e) return e;
5610 : e = AddMovieIOD(output->moov, 0);
5611 : if (e) return e;
5612 : if (output->moov->iods->descriptor) gf_odf_desc_del(output->moov->iods->descriptor);
5613 : output->moov->iods->descriptor = NULL;
5614 : gf_odf_desc_copy(input->moov->iods->descriptor, &output->moov->iods->descriptor);
5615 :
5616 : switch (output->moov->iods->descriptor->tag) {
5617 : case GF_ODF_ISOM_IOD_TAG:
5618 : esds = ((GF_IsomInitialObjectDescriptor *)output->moov->iods->descriptor)->ES_ID_IncDescriptors;
5619 : break;
5620 : case GF_ODF_ISOM_OD_TAG:
5621 : esds = ((GF_IsomObjectDescriptor *)output->moov->iods->descriptor)->ES_ID_IncDescriptors;
5622 : break;
5623 : default:
5624 : return GF_ISOM_INVALID_FILE;
5625 : }
5626 :
5627 : //get the desc
5628 : i=0;
5629 : while ((desc = (GF_Descriptor*)gf_list_enum(esds, &i))) {
5630 : gf_odf_desc_del(desc);
5631 : gf_list_rem(esds, i-1);
5632 : }
5633 : return GF_OK;
5634 : }
5635 : #endif
5636 :
5637 : GF_EXPORT
5638 620 : GF_Err gf_isom_set_media_type(GF_ISOFile *movie, u32 trackNumber, u32 new_type)
5639 : {
5640 620 : GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
5641 620 : if (!trak || !new_type) return GF_BAD_PARAM;
5642 620 : trak->Media->handler->handlerType = new_type;
5643 620 : return GF_OK;
5644 : }
5645 :
5646 : GF_EXPORT
5647 1 : GF_Err gf_isom_set_media_subtype(GF_ISOFile *movie, u32 trackNumber, u32 sampleDescriptionIndex, u32 new_type)
5648 : {
5649 : GF_SampleEntryBox*entry;
5650 1 : GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
5651 1 : if (!trak || !sampleDescriptionIndex || !new_type) return GF_BAD_PARAM;
5652 :
5653 1 : entry = (GF_SampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDescriptionIndex - 1);
5654 1 : if (!entry) return GF_BAD_PARAM;
5655 1 : entry->type = new_type;
5656 1 : return GF_OK;
5657 : }
5658 :
5659 :
5660 : #if 0 //unused
5661 : GF_Err gf_isom_set_JPEG2000(GF_ISOFile *mov, Bool set_on)
5662 : {
5663 : if (!mov) return GF_BAD_PARAM;
5664 : mov->is_jp2 = set_on;
5665 : return GF_OK;
5666 : }
5667 : #endif
5668 :
5669 2 : GF_Err gf_isom_remove_uuid(GF_ISOFile *movie, u32 trackNumber, bin128 UUID)
5670 : {
5671 : u32 i, count;
5672 : GF_List *list;
5673 :
5674 2 : if (trackNumber==(u32) -1) {
5675 0 : if (!movie) return GF_BAD_PARAM;
5676 0 : list = movie->TopBoxes;
5677 2 : } else if (trackNumber) {
5678 2 : GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
5679 2 : if (!trak) return GF_BAD_PARAM;
5680 2 : list = trak->child_boxes;
5681 : } else {
5682 0 : if (!movie) return GF_BAD_PARAM;
5683 0 : list = movie->moov->child_boxes;
5684 : }
5685 :
5686 2 : count = list ? gf_list_count(list) : 0;
5687 6 : for (i=0; i<count; i++) {
5688 6 : GF_UnknownUUIDBox *uuid = (GF_UnknownUUIDBox *)gf_list_get(list, i);
5689 6 : if (uuid->type != GF_ISOM_BOX_TYPE_UUID) continue;
5690 0 : if (memcmp(UUID, uuid->uuid, sizeof(bin128))) continue;
5691 0 : gf_list_rem(list, i);
5692 0 : i--;
5693 0 : count--;
5694 0 : gf_isom_box_del((GF_Box*)uuid);
5695 : }
5696 : return GF_OK;
5697 : }
5698 :
5699 : GF_EXPORT
5700 2 : GF_Err gf_isom_add_uuid(GF_ISOFile *movie, u32 trackNumber, bin128 UUID, const u8 *data, u32 data_size)
5701 : {
5702 : GF_List *list;
5703 : u32 btype;
5704 : GF_Box *box;
5705 : GF_UnknownUUIDBox *uuidb;
5706 :
5707 2 : if (data_size && !data) return GF_BAD_PARAM;
5708 2 : if (trackNumber==(u32) -1) {
5709 0 : if (!movie) return GF_BAD_PARAM;
5710 0 : list = movie->TopBoxes;
5711 2 : } else if (trackNumber) {
5712 2 : GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
5713 2 : if (!trak) return GF_BAD_PARAM;
5714 2 : if (!trak->child_boxes) trak->child_boxes = gf_list_new();
5715 2 : list = trak->child_boxes;
5716 : } else {
5717 0 : if (!movie) return GF_BAD_PARAM;
5718 0 : if (!movie->moov->child_boxes) movie->moov->child_boxes = gf_list_new();
5719 0 : list = movie->moov->child_boxes;
5720 : }
5721 2 : btype = gf_isom_solve_uuid_box((char *) UUID);
5722 2 : if (!btype) btype = GF_ISOM_BOX_TYPE_UUID;
5723 2 : box = gf_isom_box_new(btype);
5724 2 : if (!box) return GF_OUT_OF_MEM;
5725 : uuidb = (GF_UnknownUUIDBox*)box;
5726 2 : uuidb->internal_4cc = gf_isom_solve_uuid_box((char *) UUID);
5727 2 : memcpy(uuidb->uuid, UUID, sizeof(bin128));
5728 2 : uuidb->dataSize = data_size;
5729 2 : if (data_size) {
5730 2 : uuidb->data = (char*)gf_malloc(sizeof(char)*data_size);
5731 2 : if (!uuidb->data) return GF_OUT_OF_MEM;
5732 : memcpy(uuidb->data, data, sizeof(char)*data_size);
5733 : }
5734 2 : gf_list_add(list, uuidb);
5735 2 : return GF_OK;
5736 : }
5737 :
5738 :
5739 : GF_EXPORT
5740 2 : GF_Err gf_isom_apple_set_tag(GF_ISOFile *mov, GF_ISOiTunesTag tag, const u8 *data, u32 data_len, u64 int_val, u32 int_val2)
5741 : {
5742 : GF_Err e;
5743 : GF_ItemListBox *ilst;
5744 : GF_MetaBox *meta;
5745 : GF_ListItemBox *info;
5746 : u32 btype, i, itype;
5747 : s32 tag_idx;
5748 2 : u32 n=0, d=0;
5749 : u8 loc_data[10];
5750 : u32 int_flags = 0x15;
5751 : GF_DataBox *dbox;
5752 :
5753 : e = CanAccessMovie(mov, GF_ISOM_OPEN_WRITE);
5754 : if (e) return e;
5755 :
5756 2 : tag_idx = gf_itags_find_by_itag(tag);
5757 2 : if (tag_idx<0) {
5758 : itype = GF_ITAG_STR;
5759 : } else {
5760 2 : itype = gf_itags_get_type(tag_idx);
5761 : }
5762 2 : meta = (GF_MetaBox *) gf_isom_create_meta_extensions(mov, GF_FALSE);
5763 2 : if (!meta) return GF_BAD_PARAM;
5764 :
5765 2 : ilst = gf_ismo_locate_box(meta->child_boxes, GF_ISOM_BOX_TYPE_ILST, NULL);
5766 2 : if (!ilst) {
5767 0 : ilst = (GF_ItemListBox *) gf_isom_box_new_parent(&meta->child_boxes, GF_ISOM_BOX_TYPE_ILST);
5768 : }
5769 :
5770 2 : if (tag==GF_ISOM_ITUNE_RESET) {
5771 0 : gf_isom_box_del_parent(&meta->child_boxes, (GF_Box *) ilst);
5772 : //if last, delete udta - we may still have a handler box remaining
5773 0 : if ((gf_list_count(meta->child_boxes) <= 1) && (gf_list_count(mov->moov->udta->recordList)==1)) {
5774 0 : gf_isom_box_del_parent(&mov->moov->child_boxes, (GF_Box *) mov->moov->udta);
5775 0 : mov->moov->udta = NULL;
5776 : }
5777 : return GF_OK;
5778 : }
5779 :
5780 2 : if (tag==GF_ISOM_ITUNE_GENRE) {
5781 1 : if (!int_val && data) {
5782 1 : int_val = gf_id3_get_genre_tag(data);
5783 1 : if (int_val) {
5784 : data = NULL;
5785 : data_len = 0;
5786 : itype = GF_ITAG_INT16;
5787 : int_flags = 0;
5788 : }
5789 : }
5790 1 : btype = data ? GF_ISOM_ITUNE_GENRE_USER : GF_ISOM_ITUNE_GENRE;
5791 : } else {
5792 : btype = tag;
5793 : }
5794 : /*remove tag*/
5795 2 : i = 0;
5796 5 : while ((info = (GF_ListItemBox*)gf_list_enum(ilst->child_boxes, &i))) {
5797 1 : if (info->type==btype) {
5798 0 : gf_isom_box_del_parent(&ilst->child_boxes, (GF_Box *) info);
5799 : info = NULL;
5800 0 : break;
5801 : }
5802 1 : if (info->type==GF_ISOM_BOX_TYPE_UNKNOWN) {
5803 : GF_UnknownBox *u = (GF_UnknownBox *) info;
5804 0 : if (u->original_4cc==btype) {
5805 0 : gf_isom_box_del_parent(&ilst->child_boxes, (GF_Box *) info);
5806 : info = NULL;
5807 0 : break;
5808 : }
5809 : }
5810 : }
5811 :
5812 2 : if (!data && data_len) {
5813 0 : if (!gf_list_count(ilst->child_boxes) )
5814 0 : gf_isom_box_del_parent(&meta->child_boxes, (GF_Box *) ilst);
5815 : return GF_OK;
5816 : }
5817 :
5818 2 : info = (GF_ListItemBox *)gf_isom_box_new(btype);
5819 2 : if (info == NULL) return GF_OUT_OF_MEM;
5820 :
5821 2 : dbox = (GF_DataBox *)gf_isom_box_new_parent(&info->child_boxes, GF_ISOM_BOX_TYPE_DATA);
5822 2 : if (!dbox) {
5823 0 : gf_isom_box_del((GF_Box *)info);
5824 0 : return GF_OUT_OF_MEM;
5825 : }
5826 2 : if (info->type!=GF_ISOM_BOX_TYPE_UNKNOWN) {
5827 2 : info->data = dbox;
5828 : }
5829 :
5830 2 : switch (itype) {
5831 0 : case GF_ITAG_FRAC6:
5832 : case GF_ITAG_FRAC8:
5833 0 : if (data && data_len) {
5834 0 : if (sscanf(data, "%u/%u", &n, &d) != 2) {
5835 0 : n = d = 0;
5836 0 : if (sscanf(data, "%u", &n) != 1)
5837 0 : n = 0;
5838 : }
5839 : } else {
5840 0 : n = (u32) int_val;
5841 0 : d = int_val2;
5842 : }
5843 0 : if (n) {
5844 : memset(loc_data, 0, sizeof(char) * 8);
5845 0 : data_len = (itype == GF_ITAG_FRAC6) ? 6 : 8;
5846 0 : loc_data[3] = n;
5847 0 : loc_data[2] = n >> 8;
5848 0 : loc_data[5] = d;
5849 0 : loc_data[4] = d >> 8;
5850 : data = loc_data;
5851 : } else {
5852 : data = NULL;
5853 : }
5854 0 : dbox->flags = 0x15;
5855 0 : break;
5856 0 : case GF_ITAG_BOOL:
5857 0 : loc_data[0] = 0;
5858 0 : if (data && data_len) {
5859 0 : if ( !strcmp(data, "yes") || !strcmp(data, "1") || !strcmp(data, "true"))
5860 0 : loc_data[0] = 1;
5861 : } else {
5862 0 : loc_data[0] = int_val ? 1 : 0;
5863 : }
5864 : data = loc_data;
5865 : data_len = 0;
5866 0 : dbox->flags = int_flags;
5867 0 : break;
5868 1 : case GF_ITAG_INT16:
5869 1 : loc_data[0] = 0;
5870 1 : if (data && data_len) int_val = atoi(data);
5871 1 : loc_data[1] = (u8) int_val;
5872 1 : loc_data[0] = (u8) (int_val>>8);
5873 : data = loc_data;
5874 : data_len = 2;
5875 1 : dbox->flags = int_flags;
5876 1 : break;
5877 0 : case GF_ITAG_INT32:
5878 0 : loc_data[0] = 0;
5879 0 : if (data && data_len) int_val = atoi(data);
5880 0 : loc_data[3] = (u8) int_val;
5881 0 : loc_data[2] = (u8) (int_val>>8);
5882 0 : loc_data[1] = (u8) (int_val>>16);
5883 0 : loc_data[0] = (u8) (int_val>>24);
5884 : data = loc_data;
5885 : data_len = 4;
5886 0 : dbox->flags = int_flags;
5887 0 : break;
5888 0 : case GF_ITAG_INT64:
5889 0 : loc_data[0] = 0;
5890 0 : if (data && data_len) sscanf(data, LLU, &int_val);
5891 0 : loc_data[7] = (u8) int_val;
5892 0 : loc_data[6] = (u8) (int_val>>8);
5893 0 : loc_data[5] = (u8) (int_val>>16);
5894 0 : loc_data[4] = (u8) (int_val>>24);
5895 0 : loc_data[3] = (u8) (int_val>>32);
5896 0 : loc_data[2] = (u8) (int_val>>40);
5897 0 : loc_data[1] = (u8) (int_val>>48);
5898 0 : loc_data[0] = (u8) (int_val>>56);
5899 : data = loc_data;
5900 : data_len = 4;
5901 0 : dbox->flags = int_flags;
5902 0 : break;
5903 1 : default:
5904 1 : dbox->flags = 1;
5905 1 : break;
5906 : }
5907 :
5908 2 : if (!data) return GF_BAD_PARAM;
5909 :
5910 :
5911 2 : if (tag==GF_ISOM_ITUNE_COVER_ART) {
5912 1 : info->data->flags = 0;
5913 : /*check for PNG sig*/
5914 1 : if ((data_len>4) && (data[0] == 0x89) && (data[1] == 0x50) && (data[2] == 0x4E) && (data[3] == 0x47) ) {
5915 1 : info->data->flags = 14;
5916 : }
5917 0 : else if ((data_len>4) && (data[0] == 0xFF) && (data[1] == 0xD8) && (data[2] == 0xFF) && (data[3] == 0xE0) ) {
5918 0 : info->data->flags = 13;
5919 : }
5920 0 : else if ((data_len>3) && (data[0] == 'G') && (data[1] == 'I') && (data[2] == 'F') ) {
5921 0 : info->data->flags = 12;
5922 : }
5923 : }
5924 :
5925 2 : dbox->dataSize = data_len;
5926 2 : dbox->data = (char*)gf_malloc(sizeof(char)*data_len);
5927 2 : if (!dbox->data) return GF_OUT_OF_MEM;
5928 : memcpy(dbox->data, data, sizeof(char)*data_len);
5929 :
5930 : if (!info && !gf_list_count(ilst->child_boxes) ) {
5931 : gf_isom_box_del_parent(&meta->child_boxes, (GF_Box *) ilst);
5932 : return GF_OK;
5933 : }
5934 2 : if (!ilst->child_boxes) ilst->child_boxes = gf_list_new();
5935 :
5936 2 : return gf_list_add(ilst->child_boxes, info);
5937 : }
5938 :
5939 : #include <gpac/utf.h>
5940 :
5941 : GF_EXPORT
5942 0 : GF_Err gf_isom_wma_set_tag(GF_ISOFile *mov, char *name, char *value)
5943 : {
5944 : GF_Err e;
5945 : GF_XtraTag *tag=NULL;
5946 : u32 count, i;
5947 : GF_XtraBox *xtra;
5948 :
5949 : e = CanAccessMovie(mov, GF_ISOM_OPEN_WRITE);
5950 : if (e) return e;
5951 :
5952 0 : gf_isom_create_meta_extensions(mov, GF_FALSE);
5953 :
5954 0 : xtra = (GF_XtraBox *) gf_isom_create_meta_extensions(mov, GF_TRUE);
5955 0 : if (!xtra) return GF_BAD_PARAM;
5956 :
5957 0 : count = gf_list_count(xtra->tags);
5958 0 : for (i=0; i<count; i++) {
5959 0 : tag = gf_list_get(xtra->tags, i);
5960 0 : if (name && tag->name && !strcmp(tag->name, name)) {
5961 :
5962 : } else {
5963 : tag = NULL;
5964 0 : continue;
5965 : }
5966 :
5967 0 : if (!value) {
5968 0 : gf_list_rem(xtra->tags, i);
5969 0 : gf_free(tag->name);
5970 0 : if (tag->prop_value) gf_free(tag->prop_value);
5971 0 : gf_free(tag);
5972 0 : return GF_OK;
5973 : }
5974 0 : gf_free(tag->prop_value);
5975 0 : tag->prop_value = 0;
5976 : }
5977 0 : if (!tag) {
5978 0 : if (!name) return GF_OK;
5979 :
5980 0 : GF_SAFEALLOC(tag, GF_XtraTag);
5981 0 : tag->name = gf_strdup(name);
5982 0 : tag->prop_type = 0;
5983 0 : tag->flags = 1;
5984 0 : gf_list_add(xtra->tags, tag);
5985 : }
5986 :
5987 0 : u32 len = (u32) strlen(value);
5988 0 : tag->prop_value = gf_malloc(sizeof(u16) * (len+1) );
5989 : memset(tag->prop_value, 0, sizeof(u16) * (len+1) );
5990 0 : if (len) {
5991 0 : u32 _len = (u32) gf_utf8_mbstowcs((u16 *) tag->prop_value, len, (const char **) &value);
5992 0 : if (_len != (u32) -1) {
5993 0 : tag->prop_value[2 * _len] = 0;
5994 0 : tag->prop_value[2 * _len + 1] = 0;
5995 : }
5996 0 : tag->prop_size = 2 * _len + 2;
5997 : } else {
5998 0 : tag->prop_size = 2;
5999 : }
6000 : return GF_OK;
6001 : }
6002 :
6003 :
6004 : GF_EXPORT
6005 1 : GF_Err gf_isom_set_alternate_group_id(GF_ISOFile *movie, u32 trackNumber, u32 groupId)
6006 : {
6007 1 : GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
6008 1 : if (!trak) return GF_BAD_PARAM;
6009 1 : trak->Header->alternate_group = groupId;
6010 1 : return GF_OK;
6011 : }
6012 :
6013 :
6014 : GF_EXPORT
6015 4 : GF_Err gf_isom_set_track_switch_parameter(GF_ISOFile *movie, u32 trackNumber, u32 trackRefGroup, Bool is_switch_group, u32 *switchGroupID, u32 *criteriaList, u32 criteriaListCount)
6016 : {
6017 : GF_TrackSelectionBox *tsel;
6018 : GF_TrackBox *trak;
6019 : GF_UserDataMap *map;
6020 : GF_Err e;
6021 : u32 alternateGroupID = 0;
6022 : u32 next_switch_group_id = 0;
6023 :
6024 4 : trak = gf_isom_get_track_from_file(movie, trackNumber);
6025 4 : if (!trak || !switchGroupID) return GF_BAD_PARAM;
6026 :
6027 :
6028 4 : if (trackRefGroup) {
6029 2 : GF_TrackBox *trak_ref = gf_isom_get_track_from_file(movie, trackRefGroup);
6030 2 : if (trak_ref != trak) {
6031 2 : if (!trak_ref || !trak_ref->Header->alternate_group) {
6032 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("Track %d has not an alternate group - skipping\n", trak_ref ? trak_ref->Header->trackID : 0));
6033 : return GF_BAD_PARAM;
6034 : }
6035 2 : alternateGroupID = trak_ref->Header->alternate_group;
6036 : } else {
6037 0 : alternateGroupID = trak->Header->alternate_group;
6038 : }
6039 : }
6040 2 : if (!alternateGroupID) {
6041 : /*there is a function for this ....*/
6042 2 : if (trak->Header->alternate_group) {
6043 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("Track %d has already an alternate group - skipping\n", trak->Header->trackID));
6044 : return GF_BAD_PARAM;
6045 : }
6046 2 : alternateGroupID = gf_isom_get_next_alternate_group_id(movie);
6047 : }
6048 :
6049 4 : if (is_switch_group) {
6050 : u32 i=0;
6051 20 : while (i< gf_isom_get_track_count(movie) ) {
6052 : //locate first available ID
6053 16 : GF_TrackBox *a_trak = gf_isom_get_track_from_file(movie, i+1);
6054 :
6055 16 : if (a_trak->udta) {
6056 : u32 j, count;
6057 6 : map = udta_getEntry(a_trak->udta, GF_ISOM_BOX_TYPE_TSEL, NULL);
6058 6 : if (map) {
6059 6 : count = gf_list_count(map->boxes);
6060 12 : for (j=0; j<count; j++) {
6061 6 : tsel = (GF_TrackSelectionBox*)gf_list_get(map->boxes, j);
6062 :
6063 6 : if (*switchGroupID) {
6064 6 : if (tsel->switchGroup==next_switch_group_id) {
6065 0 : if (a_trak->Header->alternate_group != alternateGroupID) return GF_BAD_PARAM;
6066 : }
6067 : } else {
6068 0 : if (tsel->switchGroup && (tsel->switchGroup>=next_switch_group_id) )
6069 : next_switch_group_id = tsel->switchGroup;
6070 : }
6071 : }
6072 : }
6073 :
6074 : }
6075 : i++;
6076 : }
6077 4 : if (! *switchGroupID) *switchGroupID = next_switch_group_id+1;
6078 : }
6079 :
6080 :
6081 4 : trak->Header->alternate_group = alternateGroupID;
6082 :
6083 : tsel = NULL;
6084 4 : if (*switchGroupID) {
6085 4 : if (!trak->udta) {
6086 4 : e = trak_on_child_box((GF_Box*)trak, gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
6087 4 : if (e) return e;
6088 : }
6089 :
6090 4 : map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_TSEL, NULL);
6091 :
6092 : /*locate tsel box with no switch group*/
6093 4 : if (map) {
6094 0 : u32 j, count = gf_list_count(map->boxes);
6095 0 : for (j=0; j<count; j++) {
6096 0 : tsel = (GF_TrackSelectionBox*)gf_list_get(map->boxes, j);
6097 0 : if (tsel->switchGroup == *switchGroupID) break;
6098 : tsel = NULL;
6099 : }
6100 : }
6101 0 : if (!tsel) {
6102 4 : tsel = (GF_TrackSelectionBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_TSEL);
6103 4 : if (!tsel) return GF_OUT_OF_MEM;
6104 4 : e = udta_on_child_box((GF_Box *)trak->udta, (GF_Box *) tsel, GF_FALSE);
6105 4 : if (e) return e;
6106 : }
6107 :
6108 4 : tsel->switchGroup = *switchGroupID;
6109 4 : tsel->attributeListCount = criteriaListCount;
6110 4 : if (tsel->attributeList) gf_free(tsel->attributeList);
6111 4 : tsel->attributeList = (u32*)gf_malloc(sizeof(u32)*criteriaListCount);
6112 4 : if (!tsel->attributeList) return GF_OUT_OF_MEM;
6113 : memcpy(tsel->attributeList, criteriaList, sizeof(u32)*criteriaListCount);
6114 : }
6115 : return GF_OK;
6116 : }
6117 :
6118 7 : void reset_tsel_box(GF_TrackBox *trak)
6119 : {
6120 : GF_UserDataMap *map;
6121 7 : trak->Header->alternate_group = 0;
6122 7 : map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_TSEL, NULL);
6123 7 : if (map) {
6124 4 : gf_list_del_item(trak->udta->recordList, map);
6125 4 : gf_isom_box_array_del(map->boxes);
6126 4 : gf_free(map);
6127 : }
6128 :
6129 7 : }
6130 :
6131 : GF_EXPORT
6132 2 : GF_Err gf_isom_reset_track_switch_parameter(GF_ISOFile *movie, u32 trackNumber, Bool reset_all_group)
6133 : {
6134 : GF_TrackBox *trak;
6135 : u32 alternateGroupID = 0;
6136 :
6137 2 : trak = gf_isom_get_track_from_file(movie, trackNumber);
6138 2 : if (!trak) return GF_BAD_PARAM;
6139 2 : if (!trak->Header->alternate_group) return GF_OK;
6140 :
6141 : alternateGroupID = trak->Header->alternate_group;
6142 2 : if (reset_all_group) {
6143 : u32 i=0;
6144 5 : while (i< gf_isom_get_track_count(movie) ) {
6145 : //locate first available ID
6146 4 : GF_TrackBox *a_trak = gf_isom_get_track_from_file(movie, i+1);
6147 4 : if (a_trak->Header->alternate_group == alternateGroupID) reset_tsel_box(a_trak);
6148 : i++;
6149 : }
6150 : } else {
6151 1 : reset_tsel_box(trak);
6152 : }
6153 : return GF_OK;
6154 : }
6155 :
6156 :
6157 : GF_EXPORT
6158 1 : GF_Err gf_isom_reset_switch_parameters(GF_ISOFile *movie)
6159 : {
6160 : u32 i=0;
6161 6 : while (i< gf_isom_get_track_count(movie) ) {
6162 : //locate first available ID
6163 4 : GF_TrackBox *a_trak = gf_isom_get_track_from_file(movie, i+1);
6164 4 : reset_tsel_box(a_trak);
6165 : i++;
6166 : }
6167 1 : return GF_OK;
6168 : }
6169 :
6170 :
6171 1543 : GF_Err gf_isom_add_subsample(GF_ISOFile *movie, u32 track, u32 sampleNumber, u32 flags, u32 subSampleSize, u8 priority, u32 reserved, Bool discardable)
6172 : {
6173 : u32 i, count;
6174 : GF_SubSampleInformationBox *sub_samples;
6175 : GF_TrackBox *trak;
6176 : GF_Err e;
6177 :
6178 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
6179 : if (e) return e;
6180 :
6181 1543 : trak = gf_isom_get_track_from_file(movie, track);
6182 1543 : if (!trak || !trak->Media || !trak->Media->information->sampleTable)
6183 : return GF_BAD_PARAM;
6184 :
6185 1543 : if (!trak->Media->information->sampleTable->sub_samples) {
6186 4 : trak->Media->information->sampleTable->sub_samples=gf_list_new();
6187 : }
6188 :
6189 : sub_samples = NULL;
6190 1543 : count = gf_list_count(trak->Media->information->sampleTable->sub_samples);
6191 1543 : for (i=0; i<count; i++) {
6192 1539 : sub_samples = gf_list_get(trak->Media->information->sampleTable->sub_samples, i);
6193 1539 : if (sub_samples->flags==flags) break;
6194 : sub_samples = NULL;
6195 : }
6196 1543 : if (!sub_samples) {
6197 4 : sub_samples = (GF_SubSampleInformationBox *) gf_isom_box_new_parent(&trak->Media->information->sampleTable->child_boxes, GF_ISOM_BOX_TYPE_SUBS);
6198 4 : if (!sub_samples) return GF_OUT_OF_MEM;
6199 4 : gf_list_add(trak->Media->information->sampleTable->sub_samples, sub_samples);
6200 4 : sub_samples->version = (subSampleSize>0xFFFF) ? 1 : 0;
6201 4 : sub_samples->flags = flags;
6202 : }
6203 1543 : return gf_isom_add_subsample_info(sub_samples, sampleNumber, subSampleSize, priority, reserved, discardable);
6204 : }
6205 :
6206 :
6207 : GF_EXPORT
6208 1 : GF_Err gf_isom_set_rvc_config(GF_ISOFile *movie, u32 track, u32 sampleDescriptionIndex, u16 rvc_predefined, char *mime, u8 *data, u32 size)
6209 : {
6210 : GF_MPEGVisualSampleEntryBox *entry;
6211 : GF_Err e;
6212 : GF_TrackBox *trak;
6213 :
6214 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
6215 : if (e) return e;
6216 :
6217 1 : trak = gf_isom_get_track_from_file(movie, track);
6218 1 : if (!trak) return GF_BAD_PARAM;
6219 :
6220 :
6221 1 : entry = (GF_MPEGVisualSampleEntryBox *) gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDescriptionIndex-1);
6222 1 : if (!entry ) return GF_BAD_PARAM;
6223 1 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
6224 :
6225 1 : GF_RVCConfigurationBox *rvcc = (GF_RVCConfigurationBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_RVCC);
6226 1 : if (rvcc && rvcc->rvc_meta_idx) {
6227 0 : gf_isom_remove_meta_item(movie, GF_FALSE, track, rvcc->rvc_meta_idx);
6228 0 : rvcc->rvc_meta_idx = 0;
6229 : }
6230 :
6231 1 : if (!rvcc) {
6232 1 : rvcc = (GF_RVCConfigurationBox *) gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_RVCC);
6233 1 : if (!rvcc) return GF_OUT_OF_MEM;
6234 : }
6235 1 : rvcc->predefined_rvc_config = rvc_predefined;
6236 1 : if (!rvc_predefined) {
6237 1 : u32 it_id=0;
6238 1 : e = gf_isom_set_meta_type(movie, GF_FALSE, track, GF_META_TYPE_RVCI);
6239 1 : if (e) return e;
6240 1 : gf_isom_modify_alternate_brand(movie, GF_ISOM_BRAND_ISO2, GF_TRUE);
6241 1 : e = gf_isom_add_meta_item_memory(movie, GF_FALSE, track, "rvcconfig.xml", &it_id, GF_META_ITEM_TYPE_MIME, mime, NULL, NULL, data, size, NULL);
6242 1 : if (e) return e;
6243 1 : rvcc->rvc_meta_idx = gf_isom_get_meta_item_count(movie, GF_FALSE, track);
6244 : }
6245 : return GF_OK;
6246 : }
6247 :
6248 : /*for now not exported*/
6249 : /*expands sampleGroup table for the given grouping type and sample_number. If sample_number is 0, just appends an entry at the end of the table*/
6250 21049 : static GF_Err gf_isom_add_sample_group_entry(GF_List *sampleGroups, u32 sample_number, u32 grouping_type, u32 grouping_type_parameter, u32 sampleGroupDescriptionIndex, GF_List *parent, GF_SampleTableBox *stbl)
6251 : {
6252 : GF_SampleGroupBox *sgroup = NULL;
6253 : u32 i, count, last_sample_in_entry;
6254 : Bool all_samples = GF_FALSE;
6255 : assert(sampleGroups);
6256 21049 : count = gf_list_count(sampleGroups);
6257 21049 : for (i=0; i<count; i++) {
6258 20777 : sgroup = (GF_SampleGroupBox*)gf_list_get(sampleGroups, i);
6259 20777 : if (sgroup->grouping_type==grouping_type) break;
6260 : sgroup = NULL;
6261 : }
6262 21049 : if (!sgroup) {
6263 272 : sgroup = (GF_SampleGroupBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_SBGP);
6264 272 : if (!sgroup) return GF_OUT_OF_MEM;
6265 272 : sgroup->grouping_type = grouping_type;
6266 272 : sgroup->grouping_type_parameter = grouping_type_parameter;
6267 : // gf_list_add(sampleGroups, sgroup);
6268 : //crude patch to align old arch and filters
6269 272 : gf_list_insert(sampleGroups, sgroup, 0);
6270 : assert(parent);
6271 272 : gf_list_add(parent, sgroup);
6272 : }
6273 : /*used in fragments, means we are adding the last sample*/
6274 21049 : if (!sample_number) {
6275 : sample_number = 1;
6276 0 : if (sgroup->entry_count) {
6277 0 : for (i=0; i<sgroup->entry_count; i++) {
6278 0 : sample_number += sgroup->sample_entries[i].sample_count;
6279 : }
6280 : }
6281 21049 : } else if (sample_number==(u32) -1) {
6282 : all_samples = GF_TRUE;
6283 : sample_number = 1;
6284 : }
6285 :
6286 21049 : if (!sgroup->entry_count) {
6287 : u32 idx = 0;
6288 272 : sgroup->entry_count = (sample_number>1) ? 2 : 1;
6289 272 : sgroup->sample_entries = (GF_SampleGroupEntry*)gf_malloc(sizeof(GF_SampleGroupEntry) * sgroup->entry_count );
6290 272 : if (!sgroup->sample_entries) return GF_OUT_OF_MEM;
6291 272 : if (sample_number>1) {
6292 70 : sgroup->sample_entries[0].sample_count = sample_number-1;
6293 70 : sgroup->sample_entries[0].group_description_index = sampleGroupDescriptionIndex ? 0 : 1;
6294 : idx = 1;
6295 : }
6296 272 : sgroup->sample_entries[idx].sample_count = 1;
6297 272 : sgroup->sample_entries[idx].group_description_index = sampleGroupDescriptionIndex;
6298 272 : if (all_samples && stbl) {
6299 0 : sgroup->sample_entries[idx].sample_count = stbl->SampleSize->sampleCount;
6300 : }
6301 : return GF_OK;
6302 : }
6303 20777 : if (all_samples && stbl) {
6304 0 : sgroup->entry_count = 1;
6305 0 : sgroup->sample_entries[0].group_description_index = sampleGroupDescriptionIndex;
6306 0 : sgroup->sample_entries[0].sample_count = stbl->SampleSize->sampleCount;
6307 0 : return GF_OK;
6308 : }
6309 : last_sample_in_entry = 0;
6310 214145 : for (i=0; i<sgroup->entry_count; i++) {
6311 : /*TODO*/
6312 214145 : if (last_sample_in_entry + sgroup->sample_entries[i].sample_count > sample_number) return GF_NOT_SUPPORTED;
6313 : last_sample_in_entry += sgroup->sample_entries[i].sample_count;
6314 : }
6315 :
6316 20777 : if (last_sample_in_entry == sample_number) {
6317 9 : if (sgroup->sample_entries[sgroup->entry_count-1].group_description_index==sampleGroupDescriptionIndex)
6318 : return GF_OK;
6319 : else
6320 0 : return GF_NOT_SUPPORTED;
6321 : }
6322 :
6323 20768 : if ((sgroup->sample_entries[sgroup->entry_count-1].group_description_index==sampleGroupDescriptionIndex) && (last_sample_in_entry+1==sample_number)) {
6324 18874 : sgroup->sample_entries[sgroup->entry_count-1].sample_count++;
6325 18874 : return GF_OK;
6326 : }
6327 : /*last entry was an empty desc (no group associated), just add the number of samples missing until new one, then add new one*/
6328 1894 : if (! sgroup->sample_entries[sgroup->entry_count-1].group_description_index) {
6329 599 : sgroup->sample_entries[sgroup->entry_count-1].sample_count += sample_number - 1 - last_sample_in_entry;
6330 599 : sgroup->sample_entries = (GF_SampleGroupEntry*)gf_realloc(sgroup->sample_entries, sizeof(GF_SampleGroupEntry) * (sgroup->entry_count + 1) );
6331 599 : sgroup->sample_entries[sgroup->entry_count].sample_count = 1;
6332 599 : sgroup->sample_entries[sgroup->entry_count].group_description_index = sampleGroupDescriptionIndex;
6333 599 : sgroup->entry_count++;
6334 599 : return GF_OK;
6335 : }
6336 : /*we are adding a sample with no desc, add entry at the end*/
6337 1295 : if (!sampleGroupDescriptionIndex || (sample_number - 1 - last_sample_in_entry==0) ) {
6338 825 : sgroup->sample_entries = (GF_SampleGroupEntry*)gf_realloc(sgroup->sample_entries, sizeof(GF_SampleGroupEntry) * (sgroup->entry_count + 1) );
6339 825 : sgroup->sample_entries[sgroup->entry_count].sample_count = 1;
6340 825 : sgroup->sample_entries[sgroup->entry_count].group_description_index = sampleGroupDescriptionIndex;
6341 825 : sgroup->entry_count++;
6342 825 : return GF_OK;
6343 : }
6344 : /*need to insert two entries ...*/
6345 470 : sgroup->sample_entries = (GF_SampleGroupEntry*)gf_realloc(sgroup->sample_entries, sizeof(GF_SampleGroupEntry) * (sgroup->entry_count + 2) );
6346 :
6347 470 : sgroup->sample_entries[sgroup->entry_count].sample_count = sample_number - 1 - last_sample_in_entry;
6348 470 : sgroup->sample_entries[sgroup->entry_count].group_description_index = 0;
6349 :
6350 470 : sgroup->sample_entries[sgroup->entry_count+1].sample_count = 1;
6351 470 : sgroup->sample_entries[sgroup->entry_count+1].group_description_index = sampleGroupDescriptionIndex;
6352 470 : sgroup->entry_count+=2;
6353 470 : return GF_OK;
6354 : }
6355 :
6356 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
6357 20132 : static GF_SampleGroupDescriptionBox *get_sgdp(GF_SampleTableBox *stbl, GF_TrackFragmentBox *traf, u32 grouping_type, Bool *is_traf_sgdp)
6358 : #else
6359 : static GF_SampleGroupDescriptionBox *get_sgdp(GF_SampleTableBox *stbl, void *traf, u32 grouping_type, Bool *is_traf_sgdp)
6360 : #endif /* GPAC_DISABLE_ISOM_FRAGMENTS */
6361 : {
6362 : GF_List *groupList=NULL;
6363 : GF_List **parent=NULL;
6364 : GF_SampleGroupDescriptionBox *sgdesc=NULL;
6365 : u32 count, i;
6366 :
6367 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
6368 20132 : if (!stbl && traf && traf->trex->track->Media->information->sampleTable)
6369 : stbl = traf->trex->track->Media->information->sampleTable;
6370 : #endif
6371 20132 : if (stbl) {
6372 20132 : if (!stbl->sampleGroupsDescription && !traf)
6373 79 : stbl->sampleGroupsDescription = gf_list_new();
6374 :
6375 20132 : groupList = stbl->sampleGroupsDescription;
6376 20132 : if (is_traf_sgdp) *is_traf_sgdp = GF_FALSE;
6377 20132 : parent = &stbl->child_boxes;
6378 :
6379 20132 : count = gf_list_count(groupList);
6380 20156 : for (i=0; i<count; i++) {
6381 18228 : sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(groupList, i);
6382 18228 : if (sgdesc->grouping_type==grouping_type) break;
6383 : sgdesc = NULL;
6384 : }
6385 : }
6386 :
6387 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
6388 : /*look in stbl or traf for sample sampleGroupsDescription*/
6389 20132 : if (!sgdesc && traf) {
6390 1837 : if (!traf->sampleGroupsDescription)
6391 62 : traf->sampleGroupsDescription = gf_list_new();
6392 1837 : groupList = traf->sampleGroupsDescription;
6393 1837 : parent = &traf->child_boxes;
6394 1837 : if (is_traf_sgdp) *is_traf_sgdp = GF_TRUE;
6395 :
6396 1837 : count = gf_list_count(groupList);
6397 1837 : for (i=0; i<count; i++) {
6398 1775 : sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(groupList, i);
6399 1775 : if (sgdesc->grouping_type==grouping_type) break;
6400 : sgdesc = NULL;
6401 : }
6402 : }
6403 : #endif
6404 :
6405 20132 : if (!sgdesc) {
6406 153 : sgdesc = (GF_SampleGroupDescriptionBox *) gf_isom_box_new_parent(parent, GF_ISOM_BOX_TYPE_SGPD);
6407 153 : if (!sgdesc) return NULL;
6408 153 : sgdesc->grouping_type = grouping_type;
6409 : assert(groupList);
6410 153 : gf_list_add(groupList, sgdesc);
6411 : }
6412 : return sgdesc;
6413 : }
6414 :
6415 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
6416 19323 : static GF_Err gf_isom_set_sample_group_info_ex(GF_SampleTableBox *stbl, GF_TrackFragmentBox *traf, u32 sample_number, u32 grouping_type, u32 grouping_type_parameter, void *udta, void *(*sg_create_entry)(void *udta), Bool (*sg_compare_entry)(void *udta, void *entry))
6417 : #else
6418 : static GF_Err gf_isom_set_sample_group_info_ex(GF_SampleTableBox *stbl, void *traf, u32 sample_number, u32 grouping_type, u32 grouping_type_parameter, void *udta, void *(*sg_create_entry)(void *udta), Bool (*sg_compare_entry)(void *udta, void *entry))
6419 : #endif /* GPAC_DISABLE_ISOM_FRAGMENTS */
6420 : {
6421 : GF_List *groupList, *parent;
6422 : void *entry;
6423 : Bool is_traf_sgpd;
6424 : GF_SampleGroupDescriptionBox *sgdesc = NULL;
6425 : u32 i, entry_idx;
6426 :
6427 19323 : if (!stbl && !traf) return GF_BAD_PARAM;
6428 :
6429 19323 : sgdesc = get_sgdp(stbl, traf, grouping_type, &is_traf_sgpd);
6430 19323 : if (!sgdesc) return GF_OUT_OF_MEM;
6431 :
6432 : entry = NULL;
6433 19323 : if (sg_compare_entry) {
6434 1740 : for (i=0; i<gf_list_count(sgdesc->group_descriptions); i++) {
6435 11168 : entry = gf_list_get(sgdesc->group_descriptions, i);
6436 11168 : if (sg_compare_entry(udta, entry)) break;
6437 : entry = NULL;
6438 : }
6439 : }
6440 19323 : if (!entry && sg_create_entry) {
6441 81 : entry = sg_create_entry(udta);
6442 81 : if (!entry) return GF_IO_ERR;
6443 81 : if (traf && !is_traf_sgpd) {
6444 0 : sgdesc = get_sgdp(NULL, traf, grouping_type, &is_traf_sgpd);
6445 : }
6446 81 : gf_list_add(sgdesc->group_descriptions, entry);
6447 : }
6448 19323 : if (!entry)
6449 : entry_idx = 0;
6450 : else
6451 9509 : entry_idx = 1 + gf_list_find(sgdesc->group_descriptions, entry);
6452 :
6453 : /*look in stbl or traf for sample sampleGroups*/
6454 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
6455 19323 : if (traf) {
6456 12319 : if (!traf->sampleGroups)
6457 229 : traf->sampleGroups = gf_list_new();
6458 12319 : groupList = traf->sampleGroups;
6459 12319 : parent = traf->child_boxes;
6460 12319 : if (entry_idx && is_traf_sgpd)
6461 206 : entry_idx |= 0x10000;
6462 : } else
6463 : #endif
6464 : {
6465 7004 : if (!stbl->sampleGroups)
6466 40 : stbl->sampleGroups = gf_list_new();
6467 7004 : groupList = stbl->sampleGroups;
6468 7004 : parent = stbl->child_boxes;
6469 : }
6470 :
6471 19323 : return gf_isom_add_sample_group_entry(groupList, sample_number, grouping_type, grouping_type_parameter, entry_idx, parent, stbl);
6472 : }
6473 :
6474 : /*for now not exported*/
6475 19323 : static GF_Err gf_isom_set_sample_group_info(GF_ISOFile *movie, u32 track, u32 trafID, u32 sample_number, u32 grouping_type, u32 grouping_type_parameter, void *udta, void *(*sg_create_entry)(void *udta), Bool (*sg_compare_entry)(void *udta, void *entry))
6476 : {
6477 : GF_Err e;
6478 : GF_TrackBox *trak=NULL;
6479 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
6480 : GF_TrackFragmentBox *traf=NULL;
6481 : #endif
6482 19323 : if (!trafID && (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY)) {
6483 3466 : trak = gf_isom_get_track_from_file(movie, track);
6484 3466 : if (!trak) return GF_BAD_PARAM;
6485 3466 : trafID = trak->Header->trackID;
6486 : }
6487 :
6488 19323 : if (trafID) {
6489 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
6490 12319 : if (!movie->moof || !(movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY) )
6491 : return GF_BAD_PARAM;
6492 :
6493 12319 : traf = gf_isom_get_traf(movie, trafID);
6494 : #else
6495 : return GF_NOT_SUPPORTED;
6496 : #endif
6497 :
6498 7004 : } else if (track) {
6499 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
6500 : if (e) return e;
6501 :
6502 7004 : trak = gf_isom_get_track_from_file(movie, track);
6503 7004 : if (!trak) return GF_BAD_PARAM;
6504 : }
6505 :
6506 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
6507 19323 : return gf_isom_set_sample_group_info_ex(trak ? trak->Media->information->sampleTable : NULL, traf, sample_number, grouping_type, grouping_type_parameter, udta, sg_create_entry, sg_compare_entry);
6508 : #else
6509 : return gf_isom_set_sample_group_info_ex(trak->Media->information->sampleTable, sample_number, grouping_type, grouping_type_parameter, udta, sg_create_entry, sg_compare_entry);
6510 : #endif
6511 :
6512 : }
6513 :
6514 :
6515 : GF_EXPORT
6516 809 : GF_Err gf_isom_add_sample_group_info(GF_ISOFile *movie, u32 track, u32 grouping_type, void *data, u32 data_size, Bool is_default, u32 *sampleGroupDescriptionIndex)
6517 : {
6518 : GF_Err e;
6519 : GF_TrackBox *trak;
6520 : GF_DefaultSampleGroupDescriptionEntry *entry=NULL;
6521 : GF_SampleGroupDescriptionBox *sgdesc = NULL;
6522 :
6523 809 : if (sampleGroupDescriptionIndex) *sampleGroupDescriptionIndex = 0;
6524 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
6525 : if (e) return e;
6526 :
6527 809 : trak = gf_isom_get_track_from_file(movie, track);
6528 809 : if (!trak) return GF_BAD_PARAM;
6529 :
6530 :
6531 809 : sgdesc = get_sgdp(trak->Media->information->sampleTable, NULL, grouping_type, NULL);
6532 809 : if (!sgdesc) return GF_OUT_OF_MEM;
6533 :
6534 809 : if (grouping_type==GF_ISOM_SAMPLE_GROUP_OINF) {
6535 6 : GF_OperatingPointsInformation *ptr = gf_isom_oinf_new_entry();
6536 6 : GF_BitStream *bs=gf_bs_new(data, data_size, GF_BITSTREAM_READ);
6537 6 : e = gf_isom_oinf_read_entry(ptr, bs);
6538 6 : gf_bs_del(bs);
6539 6 : if (e) {
6540 0 : gf_isom_oinf_del_entry(ptr);
6541 0 : return e;
6542 : }
6543 6 : e = gf_list_add(sgdesc->group_descriptions, ptr);
6544 6 : if (e) return e;
6545 : entry = (GF_DefaultSampleGroupDescriptionEntry *) ptr;
6546 803 : } else if (grouping_type==GF_ISOM_SAMPLE_GROUP_LINF) {
6547 8 : GF_LHVCLayerInformation *ptr = gf_isom_linf_new_entry();
6548 8 : GF_BitStream *bs=gf_bs_new(data, data_size, GF_BITSTREAM_READ);
6549 8 : e = gf_isom_linf_read_entry(ptr, bs);
6550 8 : gf_bs_del(bs);
6551 8 : if (e) {
6552 0 : gf_isom_linf_del_entry(ptr);
6553 0 : return e;
6554 : }
6555 8 : e = gf_list_add(sgdesc->group_descriptions, ptr);
6556 8 : if (e) return e;
6557 : entry = (GF_DefaultSampleGroupDescriptionEntry *) ptr;
6558 : } else {
6559 795 : u32 i, count=gf_list_count(sgdesc->group_descriptions);
6560 1580 : for (i=0; i<count; i++) {
6561 1533 : GF_DefaultSampleGroupDescriptionEntry *ent = gf_list_get(sgdesc->group_descriptions, i);
6562 1533 : if ((ent->length == data_size) && !memcmp(ent->data, data, data_size)) {
6563 : entry = ent;
6564 : break;
6565 : }
6566 : entry=NULL;
6567 : }
6568 795 : if (!entry) {
6569 47 : GF_SAFEALLOC(entry, GF_DefaultSampleGroupDescriptionEntry);
6570 47 : if (!entry) return GF_OUT_OF_MEM;
6571 47 : entry->data = (u8*)gf_malloc(sizeof(char) * data_size);
6572 47 : if (!entry->data) {
6573 0 : gf_free(entry);
6574 0 : return GF_OUT_OF_MEM;
6575 : }
6576 47 : entry->length = data_size;
6577 : memcpy(entry->data, data, sizeof(char) * data_size);
6578 47 : e = gf_list_add(sgdesc->group_descriptions, entry);
6579 47 : if (e) {
6580 0 : gf_free(entry->data);
6581 0 : gf_free(entry);
6582 0 : return e;
6583 : }
6584 : }
6585 : }
6586 :
6587 :
6588 809 : if (is_default) {
6589 50 : sgdesc->default_description_index = 1 + gf_list_find(sgdesc->group_descriptions, entry);
6590 50 : sgdesc->version = 2;
6591 : }
6592 809 : if (sampleGroupDescriptionIndex) *sampleGroupDescriptionIndex = 1 + gf_list_find(sgdesc->group_descriptions, entry);
6593 :
6594 : return GF_OK;
6595 : }
6596 :
6597 : GF_EXPORT
6598 3 : GF_Err gf_isom_remove_sample_group(GF_ISOFile *movie, u32 track, u32 grouping_type)
6599 : {
6600 : GF_Err e;
6601 : GF_TrackBox *trak;
6602 : u32 count, i;
6603 :
6604 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
6605 : if (e) return e;
6606 :
6607 3 : trak = gf_isom_get_track_from_file(movie, track);
6608 3 : if (!trak) return GF_BAD_PARAM;
6609 :
6610 3 : if (trak->Media->information->sampleTable->sampleGroupsDescription) {
6611 3 : count = gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription);
6612 9 : for (i=0; i<count; i++) {
6613 6 : GF_SampleGroupDescriptionBox *sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, i);
6614 6 : if (sgdesc->grouping_type==grouping_type) {
6615 2 : gf_isom_box_del_parent(&trak->Media->information->sampleTable->child_boxes, (GF_Box*)sgdesc);
6616 2 : gf_list_rem(trak->Media->information->sampleTable->sampleGroupsDescription, i);
6617 2 : i--;
6618 2 : count--;
6619 : }
6620 : }
6621 : }
6622 3 : if (trak->Media->information->sampleTable->sampleGroups) {
6623 1 : count = gf_list_count(trak->Media->information->sampleTable->sampleGroups);
6624 2 : for (i=0; i<count; i++) {
6625 1 : GF_SampleGroupBox *sgroup = gf_list_get(trak->Media->information->sampleTable->sampleGroups, i);
6626 1 : if (sgroup->grouping_type==grouping_type) {
6627 0 : gf_isom_box_del_parent(&trak->Media->information->sampleTable->child_boxes, (GF_Box*)sgroup);
6628 0 : gf_list_rem(trak->Media->information->sampleTable->sampleGroups, i);
6629 0 : i--;
6630 0 : count--;
6631 : }
6632 : }
6633 : }
6634 : return GF_OK;
6635 : }
6636 :
6637 : GF_EXPORT
6638 750 : GF_Err gf_isom_add_sample_info(GF_ISOFile *movie, u32 track, u32 sample_number, u32 grouping_type, u32 sampleGroupDescriptionIndex, u32 grouping_type_parameter)
6639 : {
6640 : GF_Err e;
6641 : GF_TrackBox *trak;
6642 : GF_List *groupList;
6643 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
6644 : if (e) return e;
6645 :
6646 750 : trak = gf_isom_get_track_from_file(movie, track);
6647 750 : if (!trak) return GF_BAD_PARAM;
6648 :
6649 750 : if (!trak->Media->information->sampleTable->sampleGroups)
6650 1 : trak->Media->information->sampleTable->sampleGroups = gf_list_new();
6651 :
6652 750 : groupList = trak->Media->information->sampleTable->sampleGroups;
6653 750 : return gf_isom_add_sample_group_entry(groupList, sample_number, grouping_type, grouping_type_parameter, sampleGroupDescriptionIndex, trak->Media->information->sampleTable->child_boxes, trak->Media->information->sampleTable);
6654 : }
6655 :
6656 32 : void *sg_rap_create_entry(void *udta)
6657 : {
6658 : GF_VisualRandomAccessEntry *entry;
6659 : u32 *num_leading_samples = (u32 *) udta;
6660 : assert(udta);
6661 32 : GF_SAFEALLOC(entry, GF_VisualRandomAccessEntry);
6662 32 : if (!entry) return NULL;
6663 32 : entry->num_leading_samples = *num_leading_samples;
6664 32 : entry->num_leading_samples_known = entry->num_leading_samples ? 1 : 0;
6665 32 : return entry;
6666 : }
6667 :
6668 752 : Bool sg_rap_compare_entry(void *udta, void *entry)
6669 : {
6670 : u32 *num_leading_samples = (u32 *) udta;
6671 752 : if (*num_leading_samples == ((GF_VisualRandomAccessEntry *)entry)->num_leading_samples) return GF_TRUE;
6672 0 : return GF_FALSE;
6673 : }
6674 :
6675 : GF_EXPORT
6676 499 : GF_Err gf_isom_set_sample_rap_group(GF_ISOFile *movie, u32 track, u32 sample_number, Bool is_rap, u32 num_leading_samples)
6677 : {
6678 499 : return gf_isom_set_sample_group_info(movie, track, 0, sample_number, GF_ISOM_SAMPLE_GROUP_RAP, 0, &num_leading_samples, is_rap ? sg_rap_create_entry : NULL, is_rap ? sg_rap_compare_entry : NULL);
6679 : }
6680 :
6681 8111 : GF_Err gf_isom_fragment_set_sample_rap_group(GF_ISOFile *movie, GF_ISOTrackID trackID, u32 sample_number_in_frag, Bool is_rap, u32 num_leading_samples)
6682 : {
6683 8111 : return gf_isom_set_sample_group_info(movie, 0, trackID, sample_number_in_frag, GF_ISOM_SAMPLE_GROUP_RAP, 0, &num_leading_samples, is_rap ? sg_rap_create_entry : NULL, is_rap ? sg_rap_compare_entry : NULL);
6684 : }
6685 :
6686 :
6687 :
6688 16 : void *sg_roll_create_entry(void *udta)
6689 : {
6690 : GF_RollRecoveryEntry *entry;
6691 : s16 *roll_distance = (s16 *) udta;
6692 16 : GF_SAFEALLOC(entry, GF_RollRecoveryEntry);
6693 16 : if (!entry) return NULL;
6694 16 : entry->roll_distance = *roll_distance;
6695 16 : return entry;
6696 : }
6697 :
6698 170 : Bool sg_roll_compare_entry(void *udta, void *entry)
6699 : {
6700 : s16 *roll_distance = (s16 *) udta;
6701 170 : if (*roll_distance == ((GF_RollRecoveryEntry *)entry)->roll_distance) return GF_TRUE;
6702 0 : return GF_FALSE;
6703 : }
6704 :
6705 : GF_EXPORT
6706 742 : GF_Err gf_isom_set_sample_roll_group(GF_ISOFile *movie, u32 track, u32 sample_number, GF_ISOSampleRollType roll_type, s16 roll_distance)
6707 : {
6708 742 : u32 grp_type = (roll_type>=GF_ISOM_SAMPLE_PREROLL) ? GF_ISOM_SAMPLE_GROUP_PROL : GF_ISOM_SAMPLE_GROUP_ROLL;
6709 742 : if (roll_type==GF_ISOM_SAMPLE_PREROLL_NONE)
6710 : roll_type = 0;
6711 :
6712 742 : return gf_isom_set_sample_group_info(movie, track, 0, sample_number, grp_type, 0, &roll_distance, roll_type ? sg_roll_create_entry : NULL, roll_type ? sg_roll_compare_entry : NULL);
6713 : }
6714 :
6715 : GF_EXPORT
6716 742 : GF_Err gf_isom_fragment_set_sample_roll_group(GF_ISOFile *movie, GF_ISOTrackID trackID, u32 sample_number_in_frag, GF_ISOSampleRollType roll_type, s16 roll_distance)
6717 : {
6718 742 : u32 grp_type = (roll_type>=GF_ISOM_SAMPLE_PREROLL) ? GF_ISOM_SAMPLE_GROUP_PROL : GF_ISOM_SAMPLE_GROUP_ROLL;
6719 742 : if (roll_type==GF_ISOM_SAMPLE_PREROLL_NONE)
6720 : roll_type = 0;
6721 :
6722 742 : return gf_isom_set_sample_group_info(movie, 0, trackID, sample_number_in_frag, grp_type, 0, &roll_distance, roll_type ? sg_roll_create_entry : NULL, roll_type ? sg_roll_compare_entry : NULL);
6723 : }
6724 :
6725 :
6726 33 : void *sg_encryption_create_entry(void *udta)
6727 : {
6728 : GF_CENCSampleEncryptionGroupEntry *entry, *from_entry;
6729 33 : GF_SAFEALLOC(entry, GF_CENCSampleEncryptionGroupEntry);
6730 33 : if (!entry) return NULL;
6731 : from_entry = (GF_CENCSampleEncryptionGroupEntry *)udta;
6732 : memcpy(entry, from_entry, sizeof(GF_CENCSampleEncryptionGroupEntry) );
6733 33 : entry->key_info = gf_malloc(sizeof(u8) * entry->key_info_size);
6734 33 : if (!entry->key_info) {
6735 0 : gf_free(entry);
6736 0 : return NULL;
6737 : }
6738 33 : memcpy(entry->key_info, from_entry->key_info, entry->key_info_size);
6739 33 : return entry;
6740 : }
6741 :
6742 10246 : Bool sg_encryption_compare_entry(void *udta, void *_entry)
6743 : {
6744 : GF_CENCSampleEncryptionGroupEntry *entry = (GF_CENCSampleEncryptionGroupEntry *)_entry;
6745 : GF_CENCSampleEncryptionGroupEntry *with_entry = (GF_CENCSampleEncryptionGroupEntry *)udta;
6746 :
6747 10246 : if (entry->IsProtected != with_entry->IsProtected) return GF_FALSE;
6748 10246 : if (entry->skip_byte_block != with_entry->skip_byte_block) return GF_FALSE;
6749 10246 : if (entry->crypt_byte_block != with_entry->crypt_byte_block) return GF_FALSE;
6750 10246 : if (entry->key_info_size != with_entry->key_info_size) return GF_FALSE;
6751 :
6752 10246 : if (!memcmp(entry->key_info, with_entry->key_info, with_entry->key_info_size))
6753 : return GF_TRUE;
6754 1740 : return GF_FALSE;
6755 : }
6756 :
6757 :
6758 : /*sample encryption information group can be in stbl or traf*/
6759 : GF_EXPORT
6760 8539 : GF_Err gf_isom_set_sample_cenc_group(GF_ISOFile *movie, u32 track, u32 sample_number, u8 isEncrypted, u8 crypt_byte_block, u8 skip_byte_block, u8 *key_info, u32 key_info_size)
6761 : {
6762 : GF_CENCSampleEncryptionGroupEntry entry;
6763 8539 : if (!key_info || (key_info_size<19))
6764 : return GF_BAD_PARAM;
6765 :
6766 : memset(&entry, 0, sizeof(GF_CENCSampleEncryptionGroupEntry));
6767 8539 : entry.crypt_byte_block = crypt_byte_block;
6768 8539 : entry.skip_byte_block = skip_byte_block;
6769 8539 : entry.IsProtected = isEncrypted;
6770 8539 : entry.key_info = key_info;
6771 8539 : entry.key_info_size = key_info_size;
6772 :
6773 8539 : return gf_isom_set_sample_group_info(movie, track, 0, sample_number, GF_ISOM_SAMPLE_GROUP_SEIG, 0, &entry, sg_encryption_create_entry, sg_encryption_compare_entry);
6774 : }
6775 :
6776 :
6777 :
6778 : GF_EXPORT
6779 690 : GF_Err gf_isom_set_sample_cenc_default_group(GF_ISOFile *movie, u32 track, u32 sample_number)
6780 : {
6781 690 : return gf_isom_set_sample_group_info(movie, track, 0, sample_number, GF_ISOM_SAMPLE_GROUP_SEIG, 0, NULL, NULL, NULL);
6782 : }
6783 :
6784 85 : GF_Err gf_isom_force_ctts(GF_ISOFile *file, u32 track)
6785 : {
6786 : GF_TrackBox *trak;
6787 : GF_Err e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
6788 : if (e) return e;
6789 82 : trak = gf_isom_get_track_from_file(file, track);
6790 82 : if (!trak) return GF_BAD_PARAM;
6791 82 : if (trak->Media->information->sampleTable->CompositionOffset) return GF_OK;
6792 :
6793 1 : trak->Media->information->sampleTable->CompositionOffset = (GF_CompositionOffsetBox *) gf_isom_box_new_parent(&trak->Media->information->sampleTable->child_boxes, GF_ISOM_BOX_TYPE_CTTS);
6794 1 : if (!trak->Media->information->sampleTable->CompositionOffset) return GF_OUT_OF_MEM;
6795 1 : trak->Media->information->sampleTable->CompositionOffset->nb_entries = 1;
6796 1 : trak->Media->information->sampleTable->CompositionOffset->entries = gf_malloc(sizeof(GF_DttsEntry));
6797 1 : trak->Media->information->sampleTable->CompositionOffset->entries[0].decodingOffset = 0;
6798 1 : trak->Media->information->sampleTable->CompositionOffset->entries[0].sampleCount = trak->Media->information->sampleTable->SampleSize->sampleCount;
6799 1 : return GF_OK;
6800 : }
6801 :
6802 2 : GF_Err gf_isom_set_ctts_v1(GF_ISOFile *file, u32 track, u32 ctts_shift)
6803 : {
6804 : u32 i, shift;
6805 : u64 duration;
6806 : GF_CompositionOffsetBox *ctts;
6807 : GF_CompositionToDecodeBox *cslg;
6808 : s32 leastCTTS, greatestCTTS;
6809 : GF_TrackBox *trak;
6810 : GF_Err e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
6811 : if (e) return e;
6812 :
6813 2 : trak = gf_isom_get_track_from_file(file, track);
6814 2 : if (!trak) return GF_BAD_PARAM;
6815 :
6816 2 : ctts = trak->Media->information->sampleTable->CompositionOffset;
6817 2 : shift = ctts->version ? ctts_shift : ctts->entries[0].decodingOffset;
6818 : leastCTTS = GF_INT_MAX;
6819 : greatestCTTS = 0;
6820 1514 : for (i=0; i<ctts->nb_entries; i++) {
6821 1512 : if (!ctts->version)
6822 1512 : ctts->entries[i].decodingOffset -= shift;
6823 :
6824 1512 : if ((s32)ctts->entries[i].decodingOffset < leastCTTS)
6825 : leastCTTS = ctts->entries[i].decodingOffset;
6826 1512 : if ((s32)ctts->entries[i].decodingOffset > greatestCTTS)
6827 : greatestCTTS = ctts->entries[i].decodingOffset;
6828 : }
6829 2 : if (!ctts->version) {
6830 2 : ctts->version = 1;
6831 : //if we had edit lists, shift all media times by the given amount
6832 2 : if (trak->editBox && trak->editBox->editList) {
6833 0 : for (i=0; i<gf_list_count(trak->editBox->editList->entryList); i++) {
6834 2 : GF_EdtsEntry *ent = (GF_EdtsEntry*)gf_list_get(trak->editBox->editList->entryList, i);
6835 : //empty edit
6836 2 : if (ent->mediaTime<0) continue;
6837 2 : if (ent->mediaTime>=shift) ent->mediaTime -= shift;
6838 0 : else ent->mediaTime = 0;
6839 : //no offset and last entry, trash edit
6840 2 : if (!ent->mediaTime && (gf_list_count(trak->editBox->editList->entryList)==1)) {
6841 2 : gf_isom_box_del_parent(&trak->child_boxes, (GF_Box *)trak->editBox);
6842 2 : trak->editBox = NULL;
6843 2 : break;
6844 : }
6845 : }
6846 2 : SetTrackDuration(trak);
6847 : }
6848 : }
6849 :
6850 2 : if (!trak->Media->information->sampleTable->CompositionToDecode) {
6851 2 : trak->Media->information->sampleTable->CompositionToDecode = (GF_CompositionToDecodeBox *) gf_isom_box_new_parent(&trak->Media->information->sampleTable->child_boxes, GF_ISOM_BOX_TYPE_CSLG);
6852 2 : if (!trak->Media->information->sampleTable->CompositionToDecode)
6853 : return GF_OUT_OF_MEM;
6854 : }
6855 :
6856 2 : cslg = trak->Media->information->sampleTable->CompositionToDecode;
6857 2 : if (cslg) {
6858 2 : cslg->compositionToDTSShift = shift;
6859 2 : cslg->leastDecodeToDisplayDelta = leastCTTS;
6860 2 : cslg->greatestDecodeToDisplayDelta = greatestCTTS;
6861 2 : cslg->compositionStartTime = 0;
6862 : /*for our use case (first CTS set to 0), the composition end time is the media duration if it fits on 32 bits*/
6863 2 : duration = gf_isom_get_media_duration(file, track);
6864 2 : cslg->compositionEndTime = (duration<0x7FFFFFFF) ? (s32) duration : 0;
6865 : }
6866 :
6867 2 : gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_ISO4, GF_TRUE);
6868 2 : return GF_OK;
6869 : }
6870 :
6871 173 : static GF_Err gf_isom_set_ctts_v0(GF_ISOFile *file, GF_TrackBox *trak)
6872 : {
6873 : u32 i;
6874 : s32 shift;
6875 : GF_CompositionOffsetBox *ctts;
6876 : GF_CompositionToDecodeBox *cslg;
6877 :
6878 173 : ctts = trak->Media->information->sampleTable->CompositionOffset;
6879 :
6880 173 : if (!trak->Media->information->sampleTable->CompositionToDecode)
6881 : {
6882 : shift = 0;
6883 114852 : for (i=0; i<ctts->nb_entries; i++) {
6884 114852 : if (-ctts->entries[i].decodingOffset > shift)
6885 : shift = -ctts->entries[i].decodingOffset;
6886 : }
6887 173 : if (shift > 0)
6888 : {
6889 0 : for (i=0; i<ctts->nb_entries; i++) {
6890 0 : ctts->entries[i].decodingOffset += shift;
6891 : }
6892 : }
6893 : }
6894 : else
6895 : {
6896 : cslg = trak->Media->information->sampleTable->CompositionToDecode;
6897 0 : shift = cslg->compositionToDTSShift;
6898 0 : for (i=0; i<ctts->nb_entries; i++) {
6899 0 : ctts->entries[i].decodingOffset += shift;
6900 : }
6901 0 : gf_isom_box_del_parent(&trak->Media->information->sampleTable->child_boxes, (GF_Box *)cslg);
6902 0 : trak->Media->information->sampleTable->CompositionToDecode = NULL;
6903 : }
6904 173 : if (shift>0) {
6905 : //no edits, insert one
6906 0 : if (! trak->editBox) {
6907 0 : u64 dur = trak->Media->mediaHeader->duration;
6908 0 : dur *= file->moov->mvhd->timeScale;
6909 0 : dur /= trak->Media->mediaHeader->timeScale;
6910 0 : gf_isom_set_edit(file, gf_list_find(file->moov->trackList, trak)+1, 0, dur, shift, GF_ISOM_EDIT_NORMAL);
6911 : } else {
6912 : //otherwise shift media times in all entries
6913 0 : for (i=0; i<gf_list_count(trak->editBox->editList->entryList); i++) {
6914 0 : GF_EdtsEntry *ent = (GF_EdtsEntry*)gf_list_get(trak->editBox->editList->entryList, i);
6915 : //empty edit
6916 0 : if (ent->mediaTime<0) continue;
6917 0 : ent->mediaTime += shift;
6918 : }
6919 0 : SetTrackDuration(trak);
6920 : }
6921 : }
6922 173 : ctts->version = 0;
6923 173 : gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_ISO4, GF_FALSE);
6924 173 : return GF_OK;
6925 : }
6926 :
6927 : GF_EXPORT
6928 3093 : GF_Err gf_isom_set_composition_offset_mode(GF_ISOFile *file, u32 track, Bool use_negative_offsets)
6929 : {
6930 : GF_Err e;
6931 : GF_TrackBox *trak;
6932 : GF_CompositionOffsetBox *ctts;
6933 :
6934 : e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
6935 : if (e) return e;
6936 :
6937 3092 : trak = gf_isom_get_track_from_file(file, track);
6938 3092 : if (!trak) return GF_BAD_PARAM;
6939 :
6940 3092 : ctts = trak->Media->information->sampleTable->CompositionOffset;
6941 3092 : if (!ctts) {
6942 2914 : if (!use_negative_offsets && trak->Media->information->sampleTable->CompositionToDecode) {
6943 5 : gf_isom_box_del_parent(&trak->Media->information->sampleTable->child_boxes, (GF_Box *)trak->Media->information->sampleTable->CompositionToDecode);
6944 5 : trak->Media->information->sampleTable->CompositionToDecode = NULL;
6945 : }
6946 : return GF_OK;
6947 : }
6948 :
6949 178 : if (use_negative_offsets) {
6950 2 : return gf_isom_set_ctts_v1(file, track, 0);
6951 : } else {
6952 176 : if (ctts->version==0) return GF_OK;
6953 173 : return gf_isom_set_ctts_v0(file, trak);
6954 : }
6955 : }
6956 :
6957 : #if 0 //unused
6958 : GF_Err gf_isom_set_sync_table(GF_ISOFile *file, u32 track)
6959 : {
6960 : GF_Err e;
6961 : GF_TrackBox *trak;
6962 :
6963 : e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
6964 : if (e) return e;
6965 :
6966 : trak = gf_isom_get_track_from_file(file, track);
6967 : if (!trak) return GF_BAD_PARAM;
6968 :
6969 : if (!trak->Media->information->sampleTable->SyncSample) {
6970 : trak->Media->information->sampleTable->SyncSample = (GF_SyncSampleBox *) gf_isom_box_new_parent(&trak->Media->information->sampleTable->child_boxes, GF_ISOM_BOX_TYPE_STSS);
6971 :
6972 : if (!trak->Media->information->sampleTable->SyncSample)
6973 : return GF_OUT_OF_MEM;
6974 : }
6975 : return GF_OK;
6976 : }
6977 : #endif
6978 :
6979 3346 : GF_Err gf_isom_set_sample_flags(GF_ISOFile *file, u32 track, u32 sampleNumber, u32 isLeading, u32 dependsOn, u32 dependedOn, u32 redundant)
6980 : {
6981 : GF_Err e;
6982 : GF_TrackBox *trak;
6983 :
6984 : e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
6985 : if (e) return e;
6986 :
6987 3346 : trak = gf_isom_get_track_from_file(file, track);
6988 3346 : if (!trak) return GF_BAD_PARAM;
6989 3346 : return stbl_SetDependencyType(trak->Media->information->sampleTable, sampleNumber, isLeading, dependsOn, dependedOn, redundant);
6990 : }
6991 :
6992 : #if 0 //unused
6993 : GF_Err gf_isom_sample_set_dep_info(GF_ISOFile *file, u32 track, u32 sampleNumber, u32 isLeading, u32 dependsOn, u32 dependedOn, u32 redundant)
6994 : {
6995 : GF_TrackBox *trak;
6996 :
6997 : trak = gf_isom_get_track_from_file(file, track);
6998 : if (!trak) return GF_BAD_PARAM;
6999 :
7000 : return stbl_AddDependencyType(trak->Media->information->sampleTable, sampleNumber, isLeading, dependsOn, dependedOn, redundant);
7001 : }
7002 : #endif
7003 :
7004 : GF_EXPORT
7005 44114 : GF_Err gf_isom_copy_sample_info(GF_ISOFile *dst, u32 dst_track, GF_ISOFile *src, u32 src_track, u32 sampleNumber)
7006 : {
7007 : u32 i, count, idx, dst_sample_num, subs_flags;
7008 : GF_SubSampleInfoEntry *sub_sample;
7009 : GF_Err e;
7010 : GF_TrackBox *src_trak, *dst_trak;
7011 :
7012 44114 : src_trak = gf_isom_get_track_from_file(src, src_track);
7013 44114 : if (!src_trak) return GF_BAD_PARAM;
7014 :
7015 44114 : dst_trak = gf_isom_get_track_from_file(dst, dst_track);
7016 44114 : if (!dst_trak) return GF_BAD_PARAM;
7017 :
7018 44114 : dst_sample_num = dst_trak->Media->information->sampleTable->SampleSize->sampleCount;
7019 :
7020 : /*modify depends flags*/
7021 44114 : if (src_trak->Media->information->sampleTable->SampleDep) {
7022 : u32 isLeading, dependsOn, dependedOn, redundant;
7023 :
7024 505 : isLeading = dependsOn = dependedOn = redundant = 0;
7025 :
7026 505 : e = stbl_GetSampleDepType(src_trak->Media->information->sampleTable->SampleDep, sampleNumber, &isLeading, &dependsOn, &dependedOn, &redundant);
7027 505 : if (e) return e;
7028 :
7029 505 : e = stbl_AppendDependencyType(dst_trak->Media->information->sampleTable, isLeading, dependsOn, dependedOn, redundant);
7030 505 : if (e) return e;
7031 : }
7032 :
7033 : /*copy subsample info if any*/
7034 : idx=1;
7035 44114 : while (gf_isom_get_subsample_types(src, src_track, idx, &subs_flags)) {
7036 : GF_SubSampleInformationBox *dst_subs=NULL;
7037 0 : idx++;
7038 :
7039 0 : if ( ! gf_isom_sample_get_subsample_entry(src, src_track, sampleNumber, subs_flags, &sub_sample))
7040 0 : continue;
7041 :
7042 : /*create subsample if needed*/
7043 0 : if (!dst_trak->Media->information->sampleTable->sub_samples) {
7044 0 : dst_trak->Media->information->sampleTable->sub_samples = gf_list_new();
7045 : }
7046 0 : count = gf_list_count(dst_trak->Media->information->sampleTable->sub_samples);
7047 0 : for (i=0; i<count; i++) {
7048 0 : dst_subs = gf_list_get(dst_trak->Media->information->sampleTable->sub_samples, i);
7049 0 : if (dst_subs->flags==subs_flags) break;
7050 : dst_subs=NULL;
7051 : }
7052 0 : if (!dst_subs) {
7053 0 : dst_subs = (GF_SubSampleInformationBox *) gf_isom_box_new_parent(&dst_trak->Media->information->sampleTable->child_boxes, GF_ISOM_BOX_TYPE_SUBS);
7054 0 : if (!dst_subs) return GF_OUT_OF_MEM;
7055 0 : dst_subs->version=0;
7056 0 : dst_subs->flags = subs_flags;
7057 0 : gf_list_add(dst_trak->Media->information->sampleTable->sub_samples, dst_subs);
7058 : }
7059 :
7060 0 : count = gf_list_count(sub_sample->SubSamples);
7061 0 : for (i=0; i<count; i++) {
7062 0 : GF_SubSampleEntry *entry = (GF_SubSampleEntry*)gf_list_get(sub_sample->SubSamples, i);
7063 0 : e = gf_isom_add_subsample_info(dst_subs, dst_sample_num, entry->subsample_size, entry->subsample_priority, entry->reserved, entry->discardable);
7064 0 : if (e) return e;
7065 : }
7066 : }
7067 :
7068 : /*copy sampleToGroup info if any*/
7069 : count = 0;
7070 44114 : if (src_trak->Media->information->sampleTable->sampleGroups)
7071 1004 : count = gf_list_count(src_trak->Media->information->sampleTable->sampleGroups);
7072 :
7073 45118 : for (i=0; i<count; i++) {
7074 : GF_SampleGroupBox *sg;
7075 : u32 j, k, default_index;
7076 : u32 first_sample_in_entry, last_sample_in_entry, group_desc_index_src, group_desc_index_dst;
7077 : first_sample_in_entry = 1;
7078 :
7079 1004 : sg = (GF_SampleGroupBox*)gf_list_get(src_trak->Media->information->sampleTable->sampleGroups, i);
7080 10785 : for (j=0; j<sg->entry_count; j++) {
7081 10757 : last_sample_in_entry = first_sample_in_entry + sg->sample_entries[j].sample_count - 1;
7082 10757 : if ((sampleNumber<first_sample_in_entry) || (sampleNumber>last_sample_in_entry)) {
7083 : first_sample_in_entry = last_sample_in_entry+1;
7084 9781 : continue;
7085 : }
7086 :
7087 976 : if (!dst_trak->Media->information->sampleTable->sampleGroups)
7088 2 : dst_trak->Media->information->sampleTable->sampleGroups = gf_list_new();
7089 :
7090 976 : group_desc_index_src = group_desc_index_dst = sg->sample_entries[j].group_description_index;
7091 :
7092 976 : if (group_desc_index_src) {
7093 : GF_SampleGroupDescriptionBox *sgd_src, *sgd_dst;
7094 : GF_DefaultSampleGroupDescriptionEntry *sgde_src, *sgde_dst;
7095 :
7096 : group_desc_index_dst = 0;
7097 : //check that the sample group description exists !!
7098 21 : sgde_src = gf_isom_get_sample_group_info_entry(src, src_trak, sg->grouping_type, sg->sample_entries[j].group_description_index, &default_index, &sgd_src);
7099 :
7100 21 : if (!sgde_src) break;
7101 :
7102 21 : if (!dst_trak->Media->information->sampleTable->sampleGroupsDescription)
7103 0 : dst_trak->Media->information->sampleTable->sampleGroupsDescription = gf_list_new();
7104 :
7105 21 : sgd_dst = NULL;
7106 21 : for (k=0; k< gf_list_count(dst_trak->Media->information->sampleTable->sampleGroupsDescription); k++) {
7107 21 : sgd_dst = gf_list_get(dst_trak->Media->information->sampleTable->sampleGroupsDescription, k);
7108 21 : if (sgd_dst->grouping_type==sgd_src->grouping_type) break;
7109 0 : sgd_dst = NULL;
7110 : }
7111 21 : if (!sgd_dst) {
7112 0 : gf_isom_clone_box( (GF_Box *) sgd_src, (GF_Box **) &sgd_dst);
7113 0 : if (!sgd_dst) return GF_OUT_OF_MEM;
7114 0 : gf_list_add(dst_trak->Media->information->sampleTable->sampleGroupsDescription, sgd_dst);
7115 : }
7116 :
7117 : //find the same entry
7118 0 : for (k=0; k<gf_list_count(sgd_dst->group_descriptions); k++) {
7119 21 : sgde_dst = gf_list_get(sgd_dst->group_descriptions, i);
7120 21 : if (gf_isom_is_identical_sgpd(sgde_src, sgde_dst, sgd_src->grouping_type)) {
7121 21 : group_desc_index_dst = k+1;
7122 21 : break;
7123 : }
7124 : }
7125 21 : if (!group_desc_index_dst) {
7126 0 : GF_SampleGroupDescriptionBox *cloned=NULL;
7127 0 : gf_isom_clone_box( (GF_Box *) sgd_src, (GF_Box **) &cloned);
7128 0 : if (!cloned) return GF_OUT_OF_MEM;
7129 0 : sgde_dst = gf_list_get(cloned->group_descriptions, group_desc_index_dst);
7130 0 : gf_list_rem(cloned->group_descriptions, group_desc_index_dst);
7131 0 : gf_isom_box_del( (GF_Box *) cloned);
7132 0 : gf_list_add(sgd_dst->group_descriptions, sgde_dst);
7133 0 : group_desc_index_dst = gf_list_count(sgd_dst->group_descriptions);
7134 : }
7135 : }
7136 :
7137 :
7138 : /*found our sample, add it to trak->sampleGroups*/
7139 976 : e = gf_isom_add_sample_group_entry(dst_trak->Media->information->sampleTable->sampleGroups, dst_sample_num, sg->grouping_type, sg->grouping_type_parameter, group_desc_index_dst, dst_trak->Media->information->sampleTable->child_boxes, NULL);
7140 976 : if (e) return e;
7141 : break;
7142 : }
7143 : }
7144 :
7145 : return GF_OK;
7146 : }
7147 :
7148 : GF_EXPORT
7149 1 : GF_Err gf_isom_text_set_display_flags(GF_ISOFile *file, u32 track, u32 desc_index, u32 flags, GF_TextFlagsMode op_type)
7150 : {
7151 : u32 i;
7152 : GF_Err e;
7153 : GF_TrackBox *trak;
7154 :
7155 : e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
7156 : if (e) return e;
7157 :
7158 1 : trak = gf_isom_get_track_from_file(file, track);
7159 1 : if (!trak) return GF_BAD_PARAM;
7160 :
7161 1 : for (i=0; i < gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes); i++) {
7162 : GF_Tx3gSampleEntryBox *txt;
7163 1 : if (desc_index && (i+1 != desc_index)) continue;
7164 :
7165 1 : txt = (GF_Tx3gSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, i);
7166 1 : if (txt->type != GF_ISOM_BOX_TYPE_TX3G) continue;
7167 :
7168 0 : switch (op_type) {
7169 0 : case GF_ISOM_TEXT_FLAGS_TOGGLE:
7170 0 : txt->displayFlags |= flags;
7171 0 : break;
7172 0 : case GF_ISOM_TEXT_FLAGS_UNTOGGLE:
7173 0 : txt->displayFlags &= ~flags;
7174 0 : break;
7175 0 : default:
7176 0 : txt->displayFlags = flags;
7177 0 : break;
7178 : }
7179 : }
7180 : return GF_OK;
7181 :
7182 : }
7183 :
7184 :
7185 : GF_EXPORT
7186 2690 : GF_Err gf_isom_update_duration(GF_ISOFile *movie)
7187 : {
7188 : u32 i;
7189 : u64 maxDur;
7190 : GF_TrackBox *trak;
7191 :
7192 2690 : if (!movie || !movie->moov) return GF_BAD_PARAM;
7193 :
7194 : //if file was open in Write or Edit mode, recompute the duration
7195 : //the duration of a movie is the MaxDuration of all the tracks...
7196 :
7197 : maxDur = 0;
7198 2690 : i=0;
7199 10964 : while ((trak = (GF_TrackBox *)gf_list_enum(movie->moov->trackList, &i))) {
7200 5584 : if( (movie->LastError = SetTrackDuration(trak)) ) return movie->LastError;
7201 5584 : if (trak->Header && (trak->Header->duration > maxDur))
7202 : maxDur = trak->Header->duration;
7203 : }
7204 2690 : movie->moov->mvhd->duration = maxDur;
7205 :
7206 2690 : return GF_OK;
7207 : }
7208 :
7209 : GF_EXPORT
7210 23 : GF_Err gf_isom_update_edit_list_duration(GF_ISOFile *file, u32 track)
7211 : {
7212 : u32 i;
7213 : u64 trackDuration;
7214 : GF_EdtsEntry *ent;
7215 : GF_Err e;
7216 : GF_TrackBox *trak;
7217 :
7218 : e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
7219 : if (e) return e;
7220 :
7221 23 : trak = gf_isom_get_track_from_file(file, track);
7222 23 : if (!trak) return GF_BAD_PARAM;
7223 :
7224 :
7225 : //the total duration is the media duration: adjust it in case...
7226 23 : e = Media_SetDuration(trak);
7227 23 : if (e) return e;
7228 :
7229 : //assert the timeScales are non-NULL
7230 23 : if (!trak->moov->mvhd->timeScale || !trak->Media->mediaHeader->timeScale) return GF_ISOM_INVALID_FILE;
7231 23 : trackDuration = (trak->Media->mediaHeader->duration * trak->moov->mvhd->timeScale) / trak->Media->mediaHeader->timeScale;
7232 :
7233 : //if we have an edit list, the duration is the sum of all the editList
7234 : //entries' duration (always expressed in MovieTimeScale)
7235 23 : if (trak->editBox && trak->editBox->editList) {
7236 : u64 editListDuration = 0;
7237 : GF_EditListBox *elst = trak->editBox->editList;
7238 20 : i=0;
7239 79 : while ((ent = (GF_EdtsEntry*)gf_list_enum(elst->entryList, &i))) {
7240 39 : if (ent->segmentDuration > trackDuration)
7241 8 : ent->segmentDuration = trackDuration;
7242 39 : if (!ent->segmentDuration) {
7243 : u64 diff;
7244 22 : ent->segmentDuration = trackDuration;
7245 22 : if (ent->mediaTime>0) {
7246 1 : diff = ent->mediaTime;
7247 1 : diff *= trak->moov->mvhd->timeScale;
7248 1 : diff /= trak->Media->mediaHeader->timeScale;
7249 1 : if (diff < ent->segmentDuration)
7250 1 : ent->segmentDuration -= diff;
7251 : /*
7252 : else
7253 : diff = 0;
7254 : */
7255 : }
7256 : }
7257 39 : if ((ent->mediaTime>=0) && ((u64) ent->mediaTime>=trak->Media->mediaHeader->duration)) {
7258 2 : ent->mediaTime = trak->Media->mediaHeader->duration;
7259 : }
7260 39 : editListDuration += ent->segmentDuration;
7261 : }
7262 : trackDuration = editListDuration;
7263 : }
7264 23 : if (!trackDuration) {
7265 2 : trackDuration = (trak->Media->mediaHeader->duration * trak->moov->mvhd->timeScale) / trak->Media->mediaHeader->timeScale;
7266 : }
7267 23 : trak->Header->duration = trackDuration;
7268 :
7269 23 : return GF_OK;
7270 :
7271 : }
7272 :
7273 :
7274 : GF_EXPORT
7275 2 : GF_Err gf_isom_clone_pssh(GF_ISOFile *output, GF_ISOFile *input, Bool in_moof) {
7276 : GF_Box *a;
7277 : u32 i;
7278 2 : i = 0;
7279 :
7280 15 : while ((a = (GF_Box *)gf_list_enum(input->moov->child_boxes, &i))) {
7281 11 : if (a->type == GF_ISOM_BOX_TYPE_PSSH) {
7282 4 : GF_List **child_boxes = &output->moov->child_boxes;
7283 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
7284 4 : if (in_moof)
7285 0 : child_boxes = &output->moof->child_boxes;
7286 : #endif
7287 :
7288 4 : GF_ProtectionSystemHeaderBox *pssh = (GF_ProtectionSystemHeaderBox *)gf_isom_box_new_parent(child_boxes, GF_ISOM_BOX_TYPE_PSSH);
7289 4 : if (!pssh) return GF_OUT_OF_MEM;
7290 4 : memmove(pssh->SystemID, ((GF_ProtectionSystemHeaderBox *)a)->SystemID, 16);
7291 4 : if (((GF_ProtectionSystemHeaderBox *)a)->KIDs && ((GF_ProtectionSystemHeaderBox *)a)->KID_count > 0) {
7292 2 : pssh->KID_count = ((GF_ProtectionSystemHeaderBox *)a)->KID_count;
7293 2 : pssh->KIDs = (bin128 *)gf_malloc(pssh->KID_count*sizeof(bin128));
7294 2 : if (!pssh->KIDs) return GF_OUT_OF_MEM;
7295 2 : memmove(pssh->KIDs, ((GF_ProtectionSystemHeaderBox *)a)->KIDs, pssh->KID_count*sizeof(bin128));
7296 : }
7297 4 : pssh->private_data_size = ((GF_ProtectionSystemHeaderBox *)a)->private_data_size;
7298 4 : pssh->private_data = (u8 *)gf_malloc(pssh->private_data_size*sizeof(char));
7299 4 : if (!pssh->private_data) return GF_OUT_OF_MEM;
7300 4 : memmove(pssh->private_data, ((GF_ProtectionSystemHeaderBox *)a)->private_data, pssh->private_data_size);
7301 : }
7302 : }
7303 : return GF_OK;
7304 : }
7305 :
7306 : GF_EXPORT
7307 6 : GF_Err gf_isom_set_track_group(GF_ISOFile *file, u32 track_number, u32 track_group_id, u32 group_type, Bool do_add)
7308 : {
7309 : u32 i, j;
7310 : GF_TrackGroupTypeBox *trgt;
7311 : GF_Err e;
7312 : GF_TrackBox *trak;
7313 :
7314 : e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
7315 : if (e) return e;
7316 :
7317 6 : trak = gf_isom_get_track_from_file(file, track_number);
7318 6 : if (!trak) return GF_BAD_PARAM;
7319 6 : if (!trak->groups) trak->groups = (GF_TrackGroupBox*) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_TRGR);
7320 6 : if (!trak->groups) return GF_OUT_OF_MEM;
7321 :
7322 6 : for (j=0; j<gf_list_count(file->moov->trackList); j++) {
7323 6 : GF_TrackBox *a_trak = gf_list_get(file->moov->trackList, j);
7324 6 : if (!a_trak->groups) continue;
7325 :
7326 0 : for (i=0; i<gf_list_count(a_trak->groups->groups); i++) {
7327 0 : trgt = gf_list_get(a_trak->groups->groups, i);
7328 :
7329 0 : if (trgt->track_group_id==track_group_id) {
7330 0 : if (trgt->group_type != group_type) {
7331 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("A track with same group ID is already defined for different group type %s\n", gf_4cc_to_str(trgt->group_type) ));
7332 : return GF_BAD_PARAM;
7333 : }
7334 0 : if (a_trak==trak) {
7335 0 : if (!do_add) {
7336 0 : gf_list_rem(trak->groups->groups, i);
7337 0 : gf_isom_box_del_parent(&trak->groups->child_boxes, (GF_Box *)trgt);
7338 : }
7339 : return GF_OK;
7340 : }
7341 : }
7342 : }
7343 : }
7344 : //not found, add new group
7345 6 : trgt = (GF_TrackGroupTypeBox*) gf_isom_box_new_parent(&trak->groups->child_boxes, GF_ISOM_BOX_TYPE_TRGT);
7346 6 : if (!trgt) return GF_OUT_OF_MEM;
7347 6 : trgt->track_group_id = track_group_id;
7348 6 : trgt->group_type = group_type;
7349 6 : return gf_list_add(trak->groups->groups, trgt);
7350 : }
7351 :
7352 : GF_EXPORT
7353 1 : GF_Err gf_isom_set_nalu_length_field(GF_ISOFile *file, u32 track, u32 StreamDescriptionIndex, u32 nalu_size_length)
7354 : {
7355 : GF_Err e;
7356 : GF_TrackBox *trak;
7357 : GF_SampleEntryBox *entry;
7358 : GF_MPEGVisualSampleEntryBox *ve;
7359 : GF_SampleDescriptionBox *stsd;
7360 :
7361 : e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
7362 : if (e) return e;
7363 :
7364 1 : trak = gf_isom_get_track_from_file(file, track);
7365 1 : if (!trak) return GF_BAD_PARAM;
7366 :
7367 1 : stsd = trak->Media->information->sampleTable->SampleDescription;
7368 1 : if (!stsd || !StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
7369 : return GF_BAD_PARAM;
7370 : }
7371 :
7372 1 : entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
7373 : //no support for generic sample entries (eg, no MPEG4 descriptor)
7374 1 : if (!entry || ! gf_isom_is_nalu_based_entry(trak->Media, entry)) {
7375 : return GF_BAD_PARAM;
7376 : }
7377 :
7378 : ve = (GF_MPEGVisualSampleEntryBox*)entry;
7379 1 : if (ve->avc_config) ve->avc_config->config->nal_unit_size = nalu_size_length;
7380 1 : if (ve->svc_config) ve->svc_config->config->nal_unit_size = nalu_size_length;
7381 1 : if (ve->hevc_config) ve->hevc_config->config->nal_unit_size = nalu_size_length;
7382 1 : if (ve->lhvc_config) ve->lhvc_config->config->nal_unit_size = nalu_size_length;
7383 : return GF_OK;
7384 : }
7385 :
7386 1 : GF_Err gf_isom_set_sample_group_in_traf(GF_ISOFile *file)
7387 : {
7388 : GF_Err e;
7389 : e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
7390 : if (e) return e;
7391 :
7392 1 : file->sample_groups_in_traf = GF_TRUE;
7393 1 : return GF_OK;
7394 : }
7395 :
7396 : GF_EXPORT
7397 724 : void gf_isom_set_progress_callback(GF_ISOFile *file, void (*progress_cbk)(void *udta, u64 nb_done, u64 nb_total), void *progress_cbk_udta)
7398 : {
7399 724 : if (file) {
7400 724 : file->progress_cbk = progress_cbk;
7401 724 : file->progress_cbk_udta = progress_cbk_udta;
7402 :
7403 : }
7404 724 : }
7405 :
7406 2 : GF_Err gf_isom_update_video_sample_entry_fields(GF_ISOFile *file, u32 track, u32 stsd_idx, u16 revision, u32 vendor, u32 temporalQ, u32 spatialQ, u32 horiz_res, u32 vert_res, u16 frames_per_sample, const char *compressor_name, s16 color_table_index)
7407 : {
7408 :
7409 : GF_TrackBox *trak;
7410 : GF_MPEGVisualSampleEntryBox *vid_ent;
7411 :
7412 : /*get orig sample desc and clone it*/
7413 2 : trak = gf_isom_get_track_from_file(file, track);
7414 2 : if (!trak || !stsd_idx) return GF_BAD_PARAM;
7415 :
7416 2 : if (!trak->Media || !trak->Media->handler || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleDescription)
7417 : return GF_ISOM_INVALID_FILE;
7418 :
7419 2 : switch (trak->Media->handler->handlerType) {
7420 : case GF_ISOM_MEDIA_VISUAL:
7421 : case GF_ISOM_MEDIA_AUXV:
7422 : case GF_ISOM_MEDIA_PICT:
7423 : break;
7424 : default:
7425 : return GF_BAD_PARAM;
7426 : }
7427 2 : vid_ent = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, stsd_idx-1);
7428 2 : if (!vid_ent)
7429 : return GF_BAD_PARAM;
7430 :
7431 2 : vid_ent->revision = revision;
7432 2 : vid_ent->vendor = vendor;
7433 2 : vid_ent->temporal_quality = temporalQ;
7434 2 : vid_ent->spatial_quality = spatialQ;
7435 2 : vid_ent->horiz_res = horiz_res;
7436 2 : vid_ent->vert_res = vert_res;
7437 2 : vid_ent->frames_per_sample = frames_per_sample;
7438 2 : if (compressor_name)
7439 2 : strncpy(vid_ent->compressor_name, compressor_name, 32);
7440 :
7441 2 : vid_ent->color_table_index = color_table_index;
7442 2 : return GF_OK;
7443 : }
7444 :
7445 :
7446 1109 : GF_Err gf_isom_update_sample_description_from_template(GF_ISOFile *file, u32 track, u32 sampleDescriptionIndex, u8 *data, u32 size)
7447 : {
7448 : GF_BitStream *bs;
7449 : GF_TrackBox *trak;
7450 : GF_Box *ent, *tpl_ent;
7451 : GF_Err e;
7452 : /*get orig sample desc and clone it*/
7453 1109 : trak = gf_isom_get_track_from_file(file, track);
7454 1109 : if (!trak || !sampleDescriptionIndex) return GF_BAD_PARAM;
7455 :
7456 1109 : if (!trak->Media || !trak->Media->handler || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleDescription)
7457 : return GF_ISOM_INVALID_FILE;
7458 :
7459 1109 : ent = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDescriptionIndex-1);
7460 1109 : if (!ent) return GF_BAD_PARAM;
7461 :
7462 1109 : bs = gf_bs_new(data, size, GF_BITSTREAM_READ);
7463 : // e = gf_isom_box_parse(&tpl_ent, bs);
7464 1109 : e = gf_isom_box_parse_ex (&tpl_ent, bs, GF_ISOM_BOX_TYPE_STSD, GF_FALSE);
7465 1109 : gf_bs_del(bs);
7466 1109 : if (e) return e;
7467 :
7468 3623 : while (gf_list_count(tpl_ent->child_boxes)) {
7469 : u32 j=0;
7470 : Bool found = GF_FALSE;
7471 2514 : GF_Box *abox = gf_list_pop_front(tpl_ent->child_boxes);
7472 :
7473 2514 : switch (abox->type) {
7474 : case GF_ISOM_BOX_TYPE_SINF:
7475 : case GF_ISOM_BOX_TYPE_RINF:
7476 : case GF_ISOM_BOX_TYPE_BTRT:
7477 : found = GF_TRUE;
7478 : break;
7479 : }
7480 :
7481 : if (found) {
7482 1295 : gf_isom_box_del(abox);
7483 1295 : continue;
7484 : }
7485 :
7486 1219 : if (!ent->child_boxes) ent->child_boxes = gf_list_new();
7487 349 : for (j=0; j<gf_list_count(ent->child_boxes); j++) {
7488 1467 : GF_Box *b = gf_list_get(ent->child_boxes, j);
7489 1467 : if (b->type == abox->type) {
7490 : found = GF_TRUE;
7491 : break;
7492 : }
7493 : }
7494 1219 : if (!found) {
7495 101 : gf_list_add(ent->child_boxes, abox);
7496 : } else {
7497 1118 : gf_isom_box_del(abox);
7498 : }
7499 : }
7500 1109 : gf_isom_box_del(tpl_ent);
7501 :
7502 : //patch for old export
7503 1109 : GF_Box *abox = gf_isom_box_find_child(ent->child_boxes, GF_ISOM_BOX_TYPE_SINF);
7504 1109 : if (abox) {
7505 352 : gf_list_del_item(ent->child_boxes, abox);
7506 352 : gf_list_add(ent->child_boxes, abox);
7507 : }
7508 : return GF_OK;
7509 : }
7510 :
7511 : #include <gpac/xml.h>
7512 : GF_EXPORT
7513 16 : GF_Err gf_isom_apply_box_patch(GF_ISOFile *file, GF_ISOTrackID globalTrackID, const char *box_patch_filename, Bool for_fragments)
7514 : {
7515 : GF_Err e;
7516 : GF_DOMParser *dom;
7517 : u32 i;
7518 : GF_XMLNode *root;
7519 16 : u8 *box_data=NULL;
7520 : u32 box_data_size;
7521 16 : if (!file || !box_patch_filename) return GF_BAD_PARAM;
7522 16 : dom = gf_xml_dom_new();
7523 16 : if (strstr(box_patch_filename, "<?xml")) {
7524 2 : e = gf_xml_dom_parse_string(dom, (char *) box_patch_filename);
7525 : } else {
7526 14 : e = gf_xml_dom_parse(dom, box_patch_filename, NULL, NULL);
7527 : }
7528 16 : if (e) goto err_exit;
7529 :
7530 16 : root = gf_xml_dom_get_root(dom);
7531 16 : if (!root || strcmp(root->name, "GPACBOXES")) {
7532 : e = GF_NON_COMPLIANT_BITSTREAM;
7533 : goto err_exit;
7534 : }
7535 :
7536 : //compute size of each child boxes to freeze the order
7537 16 : if (for_fragments) {
7538 2 : u32 count = file->moof ? gf_list_count(file->moof->child_boxes) : 0;
7539 6 : for (i=0; i<count; i++) {
7540 4 : GF_Box *box = gf_list_get(file->moof->child_boxes, i);
7541 4 : if (!(box->internal_flags & GF_ISOM_ORDER_FREEZE)) {
7542 4 : gf_isom_box_size(box);
7543 4 : gf_isom_box_freeze_order(box);
7544 : }
7545 : }
7546 : } else {
7547 48 : for (i=0; i<gf_list_count(file->TopBoxes); i++) {
7548 48 : GF_Box *box = gf_list_get(file->TopBoxes, i);
7549 48 : if (!(box->internal_flags & GF_ISOM_ORDER_FREEZE)) {
7550 48 : gf_isom_box_size(box);
7551 48 : gf_isom_box_freeze_order(box);
7552 : }
7553 : }
7554 : }
7555 :
7556 52 : for (i=0; i<gf_list_count(root->content); i++) {
7557 : u32 j;
7558 : u32 path_len;
7559 : Bool essential_prop=GF_FALSE;
7560 : u32 trackID=globalTrackID;
7561 : u32 item_id=trackID;
7562 : Bool is_frag_box;
7563 : char *box_path=NULL;
7564 : GF_Box *parent_box = NULL;
7565 52 : GF_XMLNode *box_edit = gf_list_get(root->content, i);
7566 52 : if (!box_edit->name || strcmp(box_edit->name, "Box")) continue;
7567 :
7568 22 : for (j=0; j<gf_list_count(box_edit->attributes);j++) {
7569 22 : GF_XMLAttribute *att = gf_list_get(box_edit->attributes, j);
7570 22 : if (!strcmp(att->name, "path")) box_path = att->value;
7571 3 : else if (!strcmp(att->name, "essential")) {
7572 2 : if (!strcmp(att->value, "yes") || !strcmp(att->value, "true") || !strcmp(att->value, "1")) {
7573 : essential_prop=GF_TRUE;
7574 : }
7575 : }
7576 1 : else if (!strcmp(att->name, "itemID"))
7577 2 : item_id = atoi(att->value);
7578 0 : else if (!globalTrackID && !strcmp(att->name, "trackID"))
7579 0 : trackID = atoi(att->value);
7580 : }
7581 :
7582 19 : if (!box_path) continue;
7583 19 : path_len = (u32) strlen(box_path);
7584 :
7585 19 : is_frag_box = !strncmp(box_path, "traf", 4) ? GF_TRUE : GF_FALSE;
7586 :
7587 19 : if (for_fragments && !is_frag_box) continue;
7588 17 : else if (!for_fragments && is_frag_box) continue;
7589 :
7590 16 : gf_xml_parse_bit_sequence(box_edit, box_patch_filename, &box_data, &box_data_size);
7591 16 : if (box_data_size && (box_data_size<4) ) {
7592 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISOBMFF] Wrong BS specification for box, shall either be empty or at least 4 bytes for box type\n"));
7593 : e = GF_NON_COMPLIANT_BITSTREAM;
7594 : goto err_exit;
7595 : }
7596 :
7597 45 : while (box_path && (path_len>=4)) {
7598 : u32 parent_list_box_type;
7599 : GF_List **parent_list;
7600 29 : u32 box_type = GF_4CC(box_path[0],box_path[1],box_path[2],box_path[3]);
7601 : GF_Box *box=NULL;
7602 : GF_BitStream *bs;
7603 : s32 insert_pos = -1;
7604 29 : box_path+=4;
7605 29 : path_len-=4;
7606 :
7607 29 : if (!parent_box) {
7608 16 : box=gf_isom_box_find_child(file->TopBoxes, box_type);
7609 16 : if (!box) {
7610 8 : if (box_type==GF_ISOM_BOX_TYPE_TRAK) {
7611 6 : if (trackID) {
7612 3 : box = (GF_Box *) gf_isom_get_track_from_file(file, gf_isom_get_track_by_id(file, trackID) );
7613 : }
7614 6 : if (!box && gf_list_count(file->moov->trackList)==1) {
7615 3 : box = gf_list_get(file->moov->trackList, 0);
7616 : }
7617 : }
7618 2 : else if (box_type==GF_ISOM_BOX_TYPE_TRAF) {
7619 2 : if (trackID) {
7620 0 : box = (GF_Box *) gf_isom_get_traf(file, trackID);
7621 : }
7622 2 : if (!box && file->moof && gf_list_count(file->moof->TrackList)==1) {
7623 2 : box = gf_list_get(file->moof->TrackList, 0);
7624 : }
7625 : }
7626 : }
7627 16 : if (!box) {
7628 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISOBMFF] Cannot locate box type %s at root or as track\n", gf_4cc_to_str(box_type) ));
7629 : e = GF_BAD_PARAM;
7630 : goto err_exit;
7631 : }
7632 : } else {
7633 13 : box = gf_isom_box_find_child(parent_box->child_boxes, box_type);
7634 13 : if (!box) {
7635 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISOBMFF] Cannot locate box type %s at child of %s\n", gf_4cc_to_str(box_type), gf_4cc_to_str(parent_box->type)));
7636 : e = GF_BAD_PARAM;
7637 : goto err_exit;
7638 : }
7639 : }
7640 : // '.' is child access
7641 29 : if (path_len && (box_path[0]=='.')) {
7642 13 : box_path += 1;
7643 13 : path_len-=1;
7644 : parent_box = box;
7645 13 : continue;
7646 : }
7647 :
7648 16 : if (parent_box && !parent_box->child_boxes) parent_box->child_boxes = gf_list_new();
7649 16 : parent_list = parent_box ? &parent_box->child_boxes : &file->TopBoxes;
7650 16 : parent_list_box_type = parent_box ? parent_box->type : 0;
7651 :
7652 : // '+' is append after, '-' is insert before
7653 16 : if (path_len && ((box_path[0]=='-') || (box_path[0]=='+')) ) {
7654 12 : s32 idx = gf_list_find(*parent_list, box);
7655 : assert(idx>=0);
7656 12 : if (box_path[0]=='+') insert_pos = idx+1;
7657 : else insert_pos = idx;
7658 : }
7659 4 : else if (path_len) {
7660 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISOBMFF] Invalid path %s, expecting either '-', '+' or '.' as separators\n", box_path));
7661 : e = GF_NON_COMPLIANT_BITSTREAM;
7662 : goto err_exit;
7663 : }
7664 :
7665 16 : if (!box_data) {
7666 2 : if (insert_pos>=0) {
7667 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[ISOBMFF] Invalid path %s for box removal, ignoring position\n", box_path));
7668 : }
7669 2 : switch (box->type) {
7670 0 : case GF_ISOM_BOX_TYPE_MOOV:
7671 0 : file->moov = NULL;
7672 0 : break;
7673 0 : case GF_ISOM_BOX_TYPE_MDAT:
7674 0 : file->mdat = NULL;
7675 0 : break;
7676 0 : case GF_ISOM_BOX_TYPE_PDIN:
7677 0 : file->pdin = NULL;
7678 0 : break;
7679 0 : case GF_ISOM_BOX_TYPE_FTYP:
7680 0 : file->brand = NULL;
7681 0 : break;
7682 0 : case GF_ISOM_BOX_TYPE_META:
7683 0 : if ((GF_Box *) file->meta == box) file->meta = NULL;
7684 : break;
7685 : }
7686 2 : if (parent_box) {
7687 1 : gf_isom_box_remove_from_parent(parent_box, box);
7688 : }
7689 2 : gf_isom_box_del_parent(parent_list, box);
7690 : } else {
7691 : u32 size;
7692 :
7693 14 : bs = gf_bs_new(box_data, box_data_size, GF_BITSTREAM_READ);
7694 14 : size = gf_bs_read_u32(bs);
7695 14 : if (size != box_data_size) {
7696 14 : GF_UnknownBox *new_box = (GF_UnknownBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_UNKNOWN);
7697 14 : new_box->original_4cc = size;
7698 14 : new_box->dataSize = (u32) gf_bs_available(bs);
7699 14 : new_box->data = gf_malloc(sizeof(u8)*new_box->dataSize);
7700 14 : gf_bs_read_data(bs, new_box->data, new_box->dataSize);
7701 14 : if (insert_pos<0) {
7702 2 : gf_list_add(box->child_boxes, new_box);
7703 2 : insert_pos = gf_list_find(box->child_boxes, new_box);
7704 : } else {
7705 12 : gf_list_insert(*parent_list, new_box, insert_pos);
7706 : }
7707 :
7708 14 : if (parent_box && (parent_box->type==GF_ISOM_BOX_TYPE_IPRP)) {
7709 2 : GF_ItemPropertyAssociationBox *ipma = (GF_ItemPropertyAssociationBox *) gf_isom_box_find_child(parent_box->child_boxes, GF_ISOM_BOX_TYPE_IPMA);
7710 2 : if (!item_id) {
7711 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[ISOBMFF] Inserting box in ipco without itemID, no association added\n"));
7712 2 : } else if (ipma) {
7713 : u32 nb_asso, k;
7714 : GF_ItemPropertyAssociationEntry *entry = NULL;
7715 2 : nb_asso = gf_list_count(ipma->entries);
7716 2 : for (k=0; k<nb_asso;k++) {
7717 2 : entry = gf_list_get(ipma->entries, k);
7718 2 : if (entry->item_id==item_id) break;
7719 : entry = NULL;
7720 : }
7721 2 : if (!entry) {
7722 0 : GF_SAFEALLOC(entry, GF_ItemPropertyAssociationEntry);
7723 0 : if (!entry) return GF_OUT_OF_MEM;
7724 0 : gf_list_add(ipma->entries, entry);
7725 0 : entry->item_id = item_id;
7726 : }
7727 2 : entry->associations = gf_realloc(entry->associations, sizeof(GF_ItemPropertyAssociationSlot) * (entry->nb_associations+1));
7728 2 : entry->associations[entry->nb_associations].essential = essential_prop;
7729 2 : entry->associations[entry->nb_associations].index = 1+insert_pos;
7730 2 : entry->nb_associations++;
7731 : }
7732 : }
7733 : } else {
7734 : u32 box_idx = 0;
7735 :
7736 0 : gf_bs_seek(bs, 0);
7737 0 : while (gf_bs_available(bs)) {
7738 : GF_Box *new_box;
7739 0 : e = gf_isom_box_parse_ex(&new_box, bs, (insert_pos<0) ? box->type : parent_list_box_type, parent_box ? GF_FALSE : GF_TRUE);
7740 0 : if (e) {
7741 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISOBMFF] failed to parse box\n", box_path));
7742 0 : gf_bs_del(bs);
7743 0 : goto err_exit;
7744 : }
7745 0 : if (insert_pos<0) {
7746 0 : gf_list_add(box->child_boxes, new_box);
7747 : } else {
7748 0 : gf_list_insert(*parent_list, new_box, insert_pos+box_idx);
7749 0 : box_idx++;
7750 : }
7751 : }
7752 : }
7753 14 : gf_bs_del(bs);
7754 :
7755 : }
7756 16 : gf_free(box_data);
7757 16 : box_data = NULL;
7758 : box_path = NULL;
7759 : }
7760 : }
7761 :
7762 16 : err_exit:
7763 :
7764 16 : gf_xml_dom_del(dom);
7765 16 : if (box_data) gf_free(box_data);
7766 : return e;
7767 : }
7768 :
7769 : GF_EXPORT
7770 623 : GF_Err gf_isom_set_track_magic(GF_ISOFile *movie, u32 trackNumber, u64 magic)
7771 : {
7772 623 : GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
7773 623 : if (!trak) return GF_BAD_PARAM;
7774 623 : trak->magic = magic;
7775 623 : return GF_OK;
7776 : }
7777 :
7778 : GF_EXPORT
7779 461 : GF_Err gf_isom_set_track_index(GF_ISOFile *movie, u32 trackNumber, u32 index, void (*track_num_changed)(void *udta, u32 old_track_num, u32 new_track_num), void *udta)
7780 : {
7781 : u32 i, count;
7782 : GF_List *tracks;
7783 : u32 prev_index=0, prev_pos=0;
7784 461 : GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
7785 461 : if (!trak || !index) return GF_BAD_PARAM;
7786 461 : trak->index = index;
7787 461 : tracks = gf_list_new();
7788 461 : count = gf_list_count(movie->moov->trackList);
7789 : //sort tracks in new list
7790 974 : for (i=0; i<count; i++) {
7791 513 : GF_TrackBox *a_tk = gf_list_get(movie->moov->trackList, i);
7792 513 : if (!a_tk->index) {
7793 0 : gf_list_insert(tracks, a_tk, 0);
7794 513 : } else if (a_tk->index < prev_index) {
7795 0 : gf_list_insert(tracks, a_tk, prev_pos);
7796 : } else {
7797 513 : gf_list_add(tracks, a_tk);
7798 : }
7799 513 : prev_pos = gf_list_count(tracks) - 1;
7800 513 : prev_index = a_tk->index;
7801 : }
7802 461 : if (gf_list_count(tracks) != count) {
7803 0 : gf_list_del(tracks);
7804 0 : return GF_OUT_OF_MEM;
7805 : }
7806 461 : if (track_num_changed) {
7807 513 : for (i=0; i<count; i++) {
7808 513 : GF_TrackBox *a_tk = gf_list_get(tracks, i);
7809 513 : s32 old_pos = gf_list_find(movie->moov->trackList, a_tk);
7810 : assert(old_pos>=0);
7811 513 : if (old_pos != i)
7812 0 : track_num_changed(udta, old_pos+1, i+1);
7813 : }
7814 : }
7815 461 : gf_list_del(movie->moov->trackList);
7816 461 : movie->moov->trackList = tracks;
7817 461 : return GF_OK;
7818 : }
7819 :
7820 : GF_EXPORT
7821 1 : GF_Err gf_isom_set_ipod_compatible(GF_ISOFile *the_file, u32 trackNumber)
7822 : {
7823 : GF_TrackBox *trak;
7824 : GF_Err e;
7825 : GF_MPEGVisualSampleEntryBox *entry;
7826 :
7827 : e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
7828 : if (e) return e;
7829 1 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
7830 1 : if (!trak || !trak->Media) return GF_BAD_PARAM;
7831 1 : entry = (GF_MPEGVisualSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, 0);
7832 1 : if (!entry) return GF_OK;
7833 1 : switch (entry->type) {
7834 : case GF_ISOM_BOX_TYPE_AVC1:
7835 : case GF_ISOM_BOX_TYPE_AVC2:
7836 : case GF_ISOM_BOX_TYPE_AVC3:
7837 : case GF_ISOM_BOX_TYPE_AVC4:
7838 : case GF_ISOM_BOX_TYPE_SVC1:
7839 : case GF_ISOM_BOX_TYPE_MVC1:
7840 : case GF_ISOM_BOX_TYPE_HVC1:
7841 : case GF_ISOM_BOX_TYPE_HEV1:
7842 : case GF_ISOM_BOX_TYPE_HVT1:
7843 : break;
7844 : default:
7845 : return GF_OK;
7846 : }
7847 :
7848 1 : if (!entry->ipod_ext) {
7849 1 : entry->ipod_ext = (GF_UnknownUUIDBox *) gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_UUID);
7850 1 : if (!entry->ipod_ext) return GF_OUT_OF_MEM;
7851 : }
7852 1 : memcpy(entry->ipod_ext->uuid, GF_ISOM_IPOD_EXT, sizeof(u8)*16);
7853 1 : entry->ipod_ext->dataSize = 4;
7854 1 : entry->ipod_ext->data = gf_malloc(sizeof(u8)*4);
7855 1 : if (!entry->ipod_ext->data) return GF_OUT_OF_MEM;
7856 : memset(entry->ipod_ext->data, 0, sizeof(u8)*4);
7857 1 : return GF_OK;
7858 : }
7859 :
7860 : GF_EXPORT
7861 1588 : Bool gf_isom_is_inplace_rewrite(GF_ISOFile *movie)
7862 : {
7863 1588 : if (!movie) return GF_FALSE;
7864 1588 : if (!movie->no_inplace_rewrite) {
7865 : //things where added to the file, no inplace rewrite
7866 592 : if (movie->editFileMap && gf_bs_get_size(movie->editFileMap->bs))
7867 404 : movie->no_inplace_rewrite = GF_TRUE;
7868 : //block redirect (used by mp4mx), no inplace rewrite
7869 188 : else if (movie->on_block_out || !strcmp(movie->finalName, "_gpac_isobmff_redirect"))
7870 0 : movie->no_inplace_rewrite = GF_TRUE;
7871 : //stdout redirect, no inplace rewrite
7872 188 : else if (!strcmp(movie->finalName, "std"))
7873 0 : movie->no_inplace_rewrite = GF_TRUE;
7874 : //new file, no inplace rewrite
7875 188 : else if (!movie->fileName)
7876 6 : movie->no_inplace_rewrite = GF_TRUE;
7877 : }
7878 1588 : if (movie->no_inplace_rewrite) return GF_FALSE;
7879 :
7880 182 : return GF_TRUE;
7881 : }
7882 :
7883 : GF_EXPORT
7884 10653 : void gf_isom_disable_inplace_rewrite(GF_ISOFile *movie)
7885 : {
7886 10653 : if (movie)
7887 10653 : movie->no_inplace_rewrite = GF_TRUE;
7888 10653 : }
7889 :
7890 :
7891 0 : GF_Err gf_isom_set_y3d_info(GF_ISOFile *movie, u32 trackNumber, u32 sampleDescriptionIndex, GF_ISOM_Y3D_Info *info)
7892 : {
7893 : GF_Err e;
7894 : u32 proj_type;
7895 : GF_SampleEntryBox *ent;
7896 : GF_TrackBox *trak;
7897 :
7898 : e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
7899 : if (e) return e;
7900 :
7901 0 : trak = gf_isom_get_track_from_file(movie, trackNumber);
7902 0 : if (!trak || !trak->Media || !info) return GF_BAD_PARAM;
7903 :
7904 0 : ent = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDescriptionIndex-1);
7905 0 : if (!ent) return GF_BAD_PARAM;
7906 :
7907 0 : if (info->projection_type > GF_PROJ360_EQR) return GF_NOT_SUPPORTED;
7908 :
7909 0 : GF_Stereo3DBox *st3d = (GF_Stereo3DBox *) gf_isom_box_find_child(ent->child_boxes, GF_ISOM_BOX_TYPE_ST3D);
7910 0 : if (st3d) {
7911 0 : if (info->stereo_type) {
7912 0 : st3d->stereo_type = info->stereo_type;
7913 : } else {
7914 0 : gf_isom_box_del_parent(&ent->child_boxes, (GF_Box *) st3d);
7915 : }
7916 0 : } else if (info->stereo_type) {
7917 0 : st3d = (GF_Stereo3DBox *) gf_isom_box_new_parent(&ent->child_boxes, GF_ISOM_BOX_TYPE_ST3D);
7918 0 : if (!st3d) return GF_OUT_OF_MEM;
7919 0 : st3d->stereo_type = info->stereo_type;
7920 : }
7921 :
7922 :
7923 0 : GF_Box *sv3d = gf_isom_box_find_child(ent->child_boxes, GF_ISOM_BOX_TYPE_SV3D);
7924 0 : if (sv3d && !info->projection_type) {
7925 0 : gf_isom_box_del_parent(&ent->child_boxes, sv3d);
7926 0 : return GF_OK;
7927 : }
7928 :
7929 0 : if (!sv3d && !info->projection_type) {
7930 : return GF_OK;
7931 : }
7932 0 : if (!sv3d) {
7933 0 : sv3d = gf_isom_box_new_parent(&ent->child_boxes, GF_ISOM_BOX_TYPE_SV3D);
7934 0 : if (!sv3d) return GF_OUT_OF_MEM;
7935 : }
7936 :
7937 : //svhd mandatory
7938 0 : GF_SphericalVideoInfoBox *svhd = (GF_SphericalVideoInfoBox *) gf_isom_box_find_child(sv3d->child_boxes, GF_ISOM_BOX_TYPE_SVHD);
7939 0 : if (svhd) {
7940 0 : if (svhd->string) gf_free(svhd->string);
7941 : } else {
7942 0 : svhd = (GF_SphericalVideoInfoBox *) gf_isom_box_new_parent(&sv3d->child_boxes, GF_ISOM_BOX_TYPE_SVHD);
7943 0 : if (!svhd) return GF_OUT_OF_MEM;
7944 : }
7945 0 : svhd->string = gf_strdup(info->meta_data ? info->meta_data : "");
7946 :
7947 : //proj mandatory
7948 0 : GF_Box *proj = gf_isom_box_find_child(sv3d->child_boxes, GF_ISOM_BOX_TYPE_PROJ);
7949 0 : if (!proj) {
7950 0 : proj = (GF_Box *) gf_isom_box_new_parent(&sv3d->child_boxes, GF_ISOM_BOX_TYPE_PROJ);
7951 0 : if (!proj) return GF_OUT_OF_MEM;
7952 : }
7953 :
7954 0 : GF_ProjectionHeaderBox *projh = (GF_ProjectionHeaderBox *) gf_isom_box_find_child(proj->child_boxes, GF_ISOM_BOX_TYPE_PRHD);
7955 : //prj header mandatory
7956 0 : if (!projh) {
7957 0 : projh = (GF_ProjectionHeaderBox *) gf_isom_box_new_parent(&proj->child_boxes, GF_ISOM_BOX_TYPE_PRHD);
7958 0 : if (!projh) return GF_OUT_OF_MEM;
7959 : }
7960 0 : projh->yaw = info->yaw;
7961 0 : projh->pitch = info->pitch;
7962 0 : projh->roll = info->roll;
7963 :
7964 0 : proj_type = (info->projection_type==GF_PROJ360_CUBE_MAP) ? GF_ISOM_BOX_TYPE_CBMP : GF_ISOM_BOX_TYPE_EQUI;
7965 :
7966 0 : GF_ProjectionTypeBox *projt = (GF_ProjectionTypeBox *) gf_isom_box_find_child(proj->child_boxes, proj_type);
7967 0 : if (!projt) {
7968 0 : projt = (GF_ProjectionTypeBox *) gf_isom_box_new_parent(&proj->child_boxes, proj_type);
7969 0 : if (!projt) return GF_OUT_OF_MEM;
7970 : }
7971 0 : if (info->projection_type==GF_PROJ360_CUBE_MAP) {
7972 0 : projt->layout = info->layout;
7973 0 : projt->padding = info->padding;
7974 : } else {
7975 0 : projt->bounds_top = info->top;
7976 0 : projt->bounds_bottom = info->bottom;
7977 0 : projt->bounds_left = info->left;
7978 0 : projt->bounds_right = info->right;
7979 : }
7980 :
7981 : //remove other ones
7982 0 : GF_Box *b = gf_isom_box_new_parent(&proj->child_boxes, GF_ISOM_BOX_TYPE_MSHP);
7983 0 : if (b) gf_isom_box_del_parent(&proj->child_boxes, b);
7984 0 : if (info->projection_type==GF_PROJ360_CUBE_MAP) {
7985 0 : b = gf_isom_box_new_parent(&proj->child_boxes, GF_ISOM_BOX_TYPE_EQUI);
7986 0 : if (b) gf_isom_box_del_parent(&proj->child_boxes, b);
7987 : } else {
7988 0 : b = gf_isom_box_new_parent(&proj->child_boxes, GF_ISOM_BOX_TYPE_EQUI);
7989 0 : if (b) gf_isom_box_del_parent(&proj->child_boxes, b);
7990 :
7991 : }
7992 : return GF_OK;
7993 : }
7994 :
7995 :
7996 : #endif /*!defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_WRITE)*/
|