1 /*
2 * GPAC - Multimedia Framework C SDK
3 *
4 * Authors: Jean Le Feuvre
5 * Copyright (c) Telecom ParisTech 2000-2012
6 * All rights reserved
7 *
8 * This file is part of GPAC / ISO Media File Format sub-project
9 *
10 * GPAC is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * GPAC is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; see the file COPYING. If not, write to
22 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25
26
27 #include <gpac/internal/isomedia_dev.h>
28 #include <gpac/constants.h>
29
30 #ifndef GPAC_DISABLE_ISOM
31
32 //the only static var. Used to store any error happening while opening a movie
33 static GF_Err MP4_API_IO_Err;
34
gf_isom_set_last_error(GF_ISOFile * movie,GF_Err error)35 void gf_isom_set_last_error(GF_ISOFile *movie, GF_Err error)
36 {
37 if (!movie) {
38 MP4_API_IO_Err = error;
39 }
40 else {
41 movie->LastError = error;
42 }
43 }
44
45
46 GF_EXPORT
gf_isom_last_error(GF_ISOFile * the_file)47 GF_Err gf_isom_last_error(GF_ISOFile *the_file)
48 {
49 if (!the_file) return MP4_API_IO_Err;
50 return the_file->LastError;
51 }
52
53 GF_EXPORT
gf_isom_get_mode(GF_ISOFile * the_file)54 u8 gf_isom_get_mode(GF_ISOFile *the_file)
55 {
56 if (!the_file) return 0;
57 return the_file->openMode;
58 }
59
60 GF_EXPORT
gf_isom_get_file_size(GF_ISOFile * the_file)61 u64 gf_isom_get_file_size(GF_ISOFile *the_file)
62 {
63 if (!the_file) return 0;
64 if (the_file->movieFileMap) return gf_bs_get_size(the_file->movieFileMap->bs);
65 #ifndef GPAC_DISABLE_ISOM_WRITE
66 if (the_file->editFileMap) return gf_bs_get_size(the_file->editFileMap->bs);
67 #endif
68 return 0;
69 }
70
71 /**************************************************************
72 Sample Manip
73 **************************************************************/
74
75 //creates a new empty sample
76 GF_EXPORT
gf_isom_sample_new()77 GF_ISOSample *gf_isom_sample_new()
78 {
79 GF_ISOSample *tmp;
80 GF_SAFEALLOC(tmp, GF_ISOSample);
81 return tmp;
82 }
83
84 //delete a sample
85 GF_EXPORT
gf_isom_sample_del(GF_ISOSample ** samp)86 void gf_isom_sample_del(GF_ISOSample **samp)
87 {
88 if (!*samp) return;
89 if ((*samp)->data && (*samp)->dataLength) gf_free((*samp)->data);
90 gf_free(*samp);
91 *samp = NULL;
92 }
93
94 GF_EXPORT
gf_isom_probe_file(const char * fileName)95 u32 gf_isom_probe_file(const char *fileName)
96 {
97 u32 type = 0;
98
99 if (!strncmp(fileName, "gmem://", 7)) {
100 u32 size;
101 u8 *mem_address;
102 if (sscanf(fileName, "gmem://%d@%p", &size, &mem_address) != 2) {
103 return 0;
104 }
105 if (size>8)
106 type = GF_4CC(mem_address[4], mem_address[5], mem_address[6], mem_address[7]);
107 }
108 else {
109 unsigned char data[4];
110 FILE *f = gf_fopen(fileName, "rb");
111 if (!f) return 0;
112 type = 0;
113 if (fread(data, 1, 4, f) == 4) {
114 if (fread(data, 1, 4, f) == 4) {
115 type = GF_4CC(data[0], data[1], data[2], data[3]);
116 }
117 }
118 gf_fclose(f);
119 }
120 switch (type) {
121 case GF_ISOM_BOX_TYPE_FTYP:
122 case GF_ISOM_BOX_TYPE_MOOV:
123 return 2;
124 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
125 case GF_ISOM_BOX_TYPE_MOOF:
126 case GF_ISOM_BOX_TYPE_STYP:
127 return 3;
128 #ifndef GPAC_DISABLE_ISOM_ADOBE
129 /*Adobe specific*/
130 case GF_ISOM_BOX_TYPE_AFRA:
131 case GF_ISOM_BOX_TYPE_ABST:
132 #endif
133 #endif
134 case GF_ISOM_BOX_TYPE_MDAT:
135 case GF_ISOM_BOX_TYPE_FREE:
136 case GF_ISOM_BOX_TYPE_SKIP:
137 case GF_ISOM_BOX_TYPE_UDTA:
138 case GF_ISOM_BOX_TYPE_META:
139 case GF_ISOM_BOX_TYPE_VOID:
140 case GF_4CC('j', 'P', ' ', ' '):
141 case GF_4CC('w', 'i', 'd', 'e'):
142 return 1;
143 default:
144 return 0;
145 }
146 }
147
148 /**************************************************************
149 File Opening in streaming mode
150 the file map is regular (through FILE handles)
151 **************************************************************/
152 GF_EXPORT
gf_isom_open_progressive(const char * fileName,u64 start_range,u64 end_range,GF_ISOFile ** the_file,u64 * BytesMissing)153 GF_Err gf_isom_open_progressive(const char *fileName, u64 start_range, u64 end_range, GF_ISOFile **the_file, u64 *BytesMissing)
154 {
155 GF_Err e;
156 GF_ISOFile *movie;
157
158 if (!BytesMissing || !the_file)
159 return GF_BAD_PARAM;
160 *BytesMissing = 0;
161 *the_file = NULL;
162
163 movie = gf_isom_new_movie();
164 if (!movie) return GF_OUT_OF_MEM;
165
166 movie->fileName = gf_strdup(fileName);
167 movie->openMode = GF_ISOM_OPEN_READ;
168 //do NOT use FileMapping on incomplete files
169 e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_READ, &movie->movieFileMap);
170 if (e) {
171 gf_isom_delete_movie(movie);
172 return e;
173 }
174
175 #ifndef GPAC_DISABLE_ISOM_WRITE
176 movie->editFileMap = NULL;
177 movie->finalName = NULL;
178 #endif /*GPAC_DISABLE_ISOM_WRITE*/
179
180 if (end_range>start_range) {
181 gf_bs_seek(movie->movieFileMap->bs, end_range + 1);
182 gf_bs_truncate(movie->movieFileMap->bs);
183 gf_bs_seek(movie->movieFileMap->bs, start_range);
184 }
185 e = gf_isom_parse_movie_boxes(movie, BytesMissing, GF_TRUE);
186 if (e == GF_ISOM_INCOMPLETE_FILE) {
187 //if we have a moov, we're fine
188 if (movie->moov) {
189 *the_file = (GF_ISOFile *)movie;
190 return GF_OK;
191 }
192 //if not, delete the movie
193 gf_isom_delete_movie(movie);
194 return e;
195 }
196 else if (e) {
197 //if not, delete the movie
198 gf_isom_delete_movie(movie);
199 return e;
200 }
201 //OK, let's return
202 *the_file = (GF_ISOFile *)movie;
203 return GF_OK;
204 }
205
206 /**************************************************************
207 File Reading
208 **************************************************************/
209
210 GF_EXPORT
gf_isom_open(const char * fileName,u32 OpenMode,const char * tmp_dir)211 GF_ISOFile *gf_isom_open(const char *fileName, u32 OpenMode, const char *tmp_dir)
212 {
213 GF_ISOFile *movie;
214 MP4_API_IO_Err = GF_OK;
215
216 switch (OpenMode & 0xFF) {
217 case GF_ISOM_OPEN_READ_DUMP:
218 case GF_ISOM_OPEN_READ:
219 movie = gf_isom_open_file(fileName, OpenMode, NULL);
220 break;
221
222 #ifndef GPAC_DISABLE_ISOM_WRITE
223
224 case GF_ISOM_OPEN_WRITE:
225 movie = gf_isom_create_movie(fileName, OpenMode, tmp_dir);
226 break;
227 case GF_ISOM_OPEN_EDIT:
228 case GF_ISOM_OPEN_CAT_FRAGMENTS:
229 movie = gf_isom_open_file(fileName, OpenMode, tmp_dir);
230 break;
231 case GF_ISOM_WRITE_EDIT:
232 movie = gf_isom_create_movie(fileName, OpenMode, tmp_dir);
233 break;
234
235 #endif /*GPAC_DISABLE_ISOM_WRITE*/
236
237 default:
238 return NULL;
239 }
240 return (GF_ISOFile *)movie;
241 }
242
243 GF_EXPORT
gf_isom_close(GF_ISOFile * movie)244 GF_Err gf_isom_close(GF_ISOFile *movie)
245 {
246 GF_Err e;
247 if (movie == NULL) return GF_ISOM_INVALID_FILE;
248 e = GF_OK;
249
250 #ifndef GPAC_DISABLE_ISOM_WRITE
251 //write our movie to the file
252 if (movie->openMode != GF_ISOM_OPEN_READ) {
253 gf_isom_get_duration(movie);
254 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
255 //movie fragment mode, just store the fragment
256 if ((movie->openMode == GF_ISOM_OPEN_WRITE) && (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY)) {
257 e = gf_isom_close_fragments(movie);
258 if (e) return e;
259 }
260 else
261 #endif
262 e = WriteToFile(movie);
263 }
264 #endif /*GPAC_DISABLE_ISOM_WRITE*/
265
266 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
267 if (movie->moov) {
268 u32 i;
269
270 for (i = 0; i<gf_list_count(movie->moov->trackList); i++) {
271 GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
272 /*delete any pending dataHandler of scalable enhancements*/
273 if (trak->Media && trak->Media->information && trak->Media->information->scalableDataHandler && (trak->Media->information->scalableDataHandler != movie->movieFileMap))
274 gf_isom_datamap_del(trak->Media->information->scalableDataHandler);
275 }
276 }
277 #endif
278
279 //free and return;
280 gf_isom_delete_movie(movie);
281 return e;
282 }
283
284
285 GF_EXPORT
gf_isom_has_root_od(GF_ISOFile * movie)286 Bool gf_isom_has_root_od(GF_ISOFile *movie)
287 {
288 if (!movie || !movie->moov || !movie->moov->iods || !movie->moov->iods->descriptor) return GF_FALSE;
289 return GF_TRUE;
290 }
291
292 //this funct is used for exchange files, where the iods contains an OD
293 GF_EXPORT
gf_isom_get_root_od(GF_ISOFile * movie)294 GF_Descriptor *gf_isom_get_root_od(GF_ISOFile *movie)
295 {
296 GF_Descriptor *desc;
297 GF_ObjectDescriptor *od;
298 GF_InitialObjectDescriptor *iod;
299 GF_IsomObjectDescriptor *isom_od;
300 GF_IsomInitialObjectDescriptor *isom_iod;
301 GF_ESD *esd;
302 GF_ES_ID_Inc *inc;
303 u32 i;
304 u8 useIOD;
305
306 if (!movie || !movie->moov) return NULL;
307 if (!movie->moov->iods) return NULL;
308
309 od = NULL;
310 iod = NULL;
311
312 switch (movie->moov->iods->descriptor->tag) {
313 case GF_ODF_ISOM_OD_TAG:
314 od = (GF_ObjectDescriptor*)gf_malloc(sizeof(GF_ObjectDescriptor));
315 memset(od, 0, sizeof(GF_ObjectDescriptor));
316 od->ESDescriptors = gf_list_new();
317 useIOD = 0;
318 break;
319 case GF_ODF_ISOM_IOD_TAG:
320 iod = (GF_InitialObjectDescriptor*)gf_malloc(sizeof(GF_InitialObjectDescriptor));
321 memset(iod, 0, sizeof(GF_InitialObjectDescriptor));
322 iod->ESDescriptors = gf_list_new();
323 useIOD = 1;
324 break;
325 default:
326 return NULL;
327 }
328
329 //duplicate our descriptor
330 movie->LastError = gf_odf_desc_copy((GF_Descriptor *)movie->moov->iods->descriptor, &desc);
331 if (movie->LastError) return NULL;
332
333 if (!useIOD) {
334 isom_od = (GF_IsomObjectDescriptor *)desc;
335 od->objectDescriptorID = isom_od->objectDescriptorID;
336 od->extensionDescriptors = isom_od->extensionDescriptors;
337 isom_od->extensionDescriptors = NULL;
338 od->IPMP_Descriptors = isom_od->IPMP_Descriptors;
339 isom_od->IPMP_Descriptors = NULL;
340 od->OCIDescriptors = isom_od->OCIDescriptors;
341 isom_od->OCIDescriptors = NULL;
342 od->URLString = isom_od->URLString;
343 isom_od->URLString = NULL;
344 od->tag = GF_ODF_OD_TAG;
345 //then recreate the desc in Inc
346 i = 0;
347 while ((inc = (GF_ES_ID_Inc*)gf_list_enum(isom_od->ES_ID_IncDescriptors, &i))) {
348 movie->LastError = GetESDForTime(movie->moov, inc->trackID, 0, &esd);
349 if (!movie->LastError) movie->LastError = gf_list_add(od->ESDescriptors, esd);
350 if (movie->LastError) {
351 gf_odf_desc_del(desc);
352 gf_odf_desc_del((GF_Descriptor *)od);
353 return NULL;
354 }
355 }
356 gf_odf_desc_del(desc);
357 return (GF_Descriptor *)od;
358 }
359 else {
360 isom_iod = (GF_IsomInitialObjectDescriptor *)desc;
361 iod->objectDescriptorID = isom_iod->objectDescriptorID;
362 iod->extensionDescriptors = isom_iod->extensionDescriptors;
363 isom_iod->extensionDescriptors = NULL;
364 iod->IPMP_Descriptors = isom_iod->IPMP_Descriptors;
365 isom_iod->IPMP_Descriptors = NULL;
366 iod->OCIDescriptors = isom_iod->OCIDescriptors;
367 isom_iod->OCIDescriptors = NULL;
368 iod->URLString = isom_iod->URLString;
369 isom_iod->URLString = NULL;
370 iod->tag = GF_ODF_IOD_TAG;
371
372 iod->audio_profileAndLevel = isom_iod->audio_profileAndLevel;
373 iod->graphics_profileAndLevel = isom_iod->graphics_profileAndLevel;
374 iod->inlineProfileFlag = isom_iod->inlineProfileFlag;
375 iod->OD_profileAndLevel = isom_iod->OD_profileAndLevel;
376 iod->scene_profileAndLevel = isom_iod->scene_profileAndLevel;
377 iod->visual_profileAndLevel = isom_iod->visual_profileAndLevel;
378 iod->IPMPToolList = isom_iod->IPMPToolList;
379 isom_iod->IPMPToolList = NULL;
380
381 //then recreate the desc in Inc
382 i = 0;
383 while ((inc = (GF_ES_ID_Inc*)gf_list_enum(isom_iod->ES_ID_IncDescriptors, &i))) {
384 movie->LastError = GetESDForTime(movie->moov, inc->trackID, 0, &esd);
385 if (!movie->LastError) movie->LastError = gf_list_add(iod->ESDescriptors, esd);
386 if (movie->LastError) {
387 gf_odf_desc_del(desc);
388 gf_odf_desc_del((GF_Descriptor *)iod);
389 return NULL;
390 }
391 }
392 gf_odf_desc_del(desc);
393 return (GF_Descriptor *)iod;
394 }
395 }
396
397
398 GF_EXPORT
gf_isom_get_track_count(GF_ISOFile * movie)399 u32 gf_isom_get_track_count(GF_ISOFile *movie)
400 {
401 if (!movie || !movie->moov) return 0;
402
403 if (!movie->moov->trackList) {
404 movie->LastError = GF_ISOM_INVALID_FILE;
405 return 0;
406 }
407 return gf_list_count(movie->moov->trackList);
408 }
409
410
411 GF_EXPORT
gf_isom_get_track_id(GF_ISOFile * movie,u32 trackNumber)412 u32 gf_isom_get_track_id(GF_ISOFile *movie, u32 trackNumber)
413 {
414 GF_TrackBox *trak;
415 if (!movie) return 0;
416 trak = gf_isom_get_track_from_file(movie, trackNumber);
417 if (!trak) return 0;
418 return trak->Header->trackID;
419 }
420
421
422 GF_EXPORT
gf_isom_get_track_by_id(GF_ISOFile * the_file,u32 trackID)423 u32 gf_isom_get_track_by_id(GF_ISOFile *the_file, u32 trackID)
424 {
425 GF_TrackBox *trak;
426 u32 count;
427 u32 i;
428 if (the_file == NULL) return 0;
429
430 count = gf_isom_get_track_count(the_file);
431 if (!count) return 0;
432 for (i = 0; i < count; i++) {
433 trak = gf_isom_get_track_from_file(the_file, i + 1);
434 if (!trak) return 0;
435 if (trak->Header->trackID == trackID) return i + 1;
436 }
437 return 0;
438 }
439
440 GF_EXPORT
gf_isom_get_track_original_id(GF_ISOFile * movie,u32 trackNumber)441 u32 gf_isom_get_track_original_id(GF_ISOFile *movie, u32 trackNumber)
442 {
443 GF_TrackBox *trak;
444 if (!movie) return 0;
445 trak = gf_isom_get_track_from_file(movie, trackNumber);
446 if (!trak) return 0;
447 return trak->originalID;
448 }
449
450 //return the timescale of the movie, 0 if error
451 GF_EXPORT
gf_isom_has_movie(GF_ISOFile * file)452 Bool gf_isom_has_movie(GF_ISOFile *file)
453 {
454 if (file && file->moov) return GF_TRUE;
455 return GF_FALSE;
456 }
457
458 #ifndef GPAC_DISABLE_ISOM
459 GF_EXPORT
gf_isom_has_segment(GF_ISOFile * file,u32 * brand,u32 * version)460 Bool gf_isom_has_segment(GF_ISOFile *file, u32 *brand, u32 *version)
461 {
462 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
463 u32 i;
464 GF_Box *a;
465 i = 0;
466 while (NULL != (a = (GF_Box*)gf_list_enum(file->TopBoxes, &i))) {
467 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
468 if (a->type == GF_ISOM_BOX_TYPE_STYP) {
469 GF_SegmentTypeBox *styp = (GF_SegmentTypeBox *)a;
470 *brand = styp->majorBrand;
471 *version = styp->minorVersion;
472 return GF_TRUE;
473 }
474 #endif
475 }
476 #endif
477 return GF_FALSE;
478 }
479
480 GF_EXPORT
gf_isom_segment_get_fragment_count(GF_ISOFile * file)481 u32 gf_isom_segment_get_fragment_count(GF_ISOFile *file)
482 {
483 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
484 if (file) {
485 u32 i, count = 0;
486 for (i = 0; i<gf_list_count(file->TopBoxes); i++) {
487 GF_Box *a = (GF_Box*)gf_list_get(file->TopBoxes, i);
488 if (a->type == GF_ISOM_BOX_TYPE_MOOF) count++;
489 }
490 return count;
491 }
492 #endif
493 return 0;
494 }
495
496 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
gf_isom_get_moof(GF_ISOFile * file,u32 moof_index)497 static GF_MovieFragmentBox *gf_isom_get_moof(GF_ISOFile *file, u32 moof_index)
498 {
499 u32 i;
500 for (i = 0; i<gf_list_count(file->TopBoxes); i++) {
501 GF_Box *a = (GF_Box*)gf_list_get(file->TopBoxes, i);
502 if (a->type == GF_ISOM_BOX_TYPE_MOOF) {
503 moof_index--;
504 if (!moof_index) return (GF_MovieFragmentBox *)a;
505 }
506 }
507 return NULL;
508 }
509 #endif /* GPAC_DISABLE_ISOM_FRAGMENTS */
510
511 GF_EXPORT
gf_isom_segment_get_track_fragment_count(GF_ISOFile * file,u32 moof_index)512 u32 gf_isom_segment_get_track_fragment_count(GF_ISOFile *file, u32 moof_index)
513 {
514 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
515 GF_MovieFragmentBox *moof;
516 if (!file) return 0;
517 gf_list_count(file->TopBoxes);
518 moof = gf_isom_get_moof(file, moof_index);
519 return moof ? gf_list_count(moof->TrackList) : 0;
520 #endif
521 return 0;
522 }
523
524 GF_EXPORT
gf_isom_segment_get_track_fragment_decode_time(GF_ISOFile * file,u32 moof_index,u32 traf_index,u64 * decode_time)525 u32 gf_isom_segment_get_track_fragment_decode_time(GF_ISOFile *file, u32 moof_index, u32 traf_index, u64 *decode_time)
526 {
527 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
528 GF_MovieFragmentBox *moof;
529 GF_TrackFragmentBox *traf;
530 if (!file) return 0;
531 gf_list_count(file->TopBoxes);
532 moof = gf_isom_get_moof(file, moof_index);
533 traf = moof ? (GF_TrackFragmentBox*)gf_list_get(moof->TrackList, traf_index - 1) : NULL;
534 if (!traf) return 0;
535 if (decode_time) {
536 *decode_time = traf->tfdt ? traf->tfdt->baseMediaDecodeTime : 0;
537 }
538 return traf->tfhd->trackID;
539 #endif
540 return 0;
541 }
542 #endif
543
544 //return the timescale of the movie, 0 if error
545 GF_EXPORT
gf_isom_get_timescale(GF_ISOFile * movie)546 u32 gf_isom_get_timescale(GF_ISOFile *movie)
547 {
548 if (!movie || !movie->moov) return 0;
549 return movie->moov->mvhd->timeScale;
550 }
551
552
553 //return the duration of the movie, 0 if error
554 GF_EXPORT
gf_isom_get_duration(GF_ISOFile * movie)555 u64 gf_isom_get_duration(GF_ISOFile *movie)
556 {
557 if (!movie || !movie->moov) return 0;
558
559 //if file was open in Write or Edit mode, recompute the duration
560 //the duration of a movie is the MaxDuration of all the tracks...
561
562 #ifndef GPAC_DISABLE_ISOM_WRITE
563 gf_isom_update_duration(movie);
564 #endif /*GPAC_DISABLE_ISOM_WRITE*/
565
566 return movie->moov->mvhd->duration;
567 }
568 //return the duration of the movie, 0 if error
569 GF_EXPORT
gf_isom_get_original_duration(GF_ISOFile * movie)570 u64 gf_isom_get_original_duration(GF_ISOFile *movie)
571 {
572 if (!movie || !movie->moov) return 0;
573 return movie->moov->mvhd->original_duration;
574 }
575
576 //return the creation info of the movie
577 GF_EXPORT
gf_isom_get_creation_time(GF_ISOFile * movie,u64 * creationTime,u64 * modificationTime)578 GF_Err gf_isom_get_creation_time(GF_ISOFile *movie, u64 *creationTime, u64 *modificationTime)
579 {
580 if (!movie || !movie->moov) return GF_BAD_PARAM;
581
582 if (creationTime) *creationTime = movie->moov->mvhd->creationTime;
583 if (creationTime) *modificationTime = movie->moov->mvhd->modificationTime;
584 return GF_OK;
585 }
586
587
588 //check the presence of a track in IOD. 0: NO, 1: YES, 2: ERROR
589 GF_EXPORT
gf_isom_is_track_in_root_od(GF_ISOFile * movie,u32 trackNumber)590 u8 gf_isom_is_track_in_root_od(GF_ISOFile *movie, u32 trackNumber)
591 {
592 u32 i;
593 u32 trackID;
594 GF_Descriptor *desc;
595 GF_ES_ID_Inc *inc;
596 GF_List *inc_list;
597 if (!movie) return 2;
598 if (!movie->moov || !movie->moov->iods) return 0;
599
600 desc = movie->moov->iods->descriptor;
601 switch (desc->tag) {
602 case GF_ODF_ISOM_IOD_TAG:
603 inc_list = ((GF_IsomInitialObjectDescriptor *)desc)->ES_ID_IncDescriptors;
604 break;
605 case GF_ODF_ISOM_OD_TAG:
606 inc_list = ((GF_IsomObjectDescriptor *)desc)->ES_ID_IncDescriptors;
607 break;
608 //files without IOD are possible !
609 default:
610 return 0;
611 }
612 trackID = gf_isom_get_track_id(movie, trackNumber);
613 if (!trackID) return 2;
614 i = 0;
615 while ((inc = (GF_ES_ID_Inc*)gf_list_enum(inc_list, &i))) {
616 if (inc->trackID == trackID) return 1;
617 }
618 return 0;
619 }
620
621
622
623 //gets the enable flag of a track
624 //0: NO, 1: yes, 2: error
625 GF_EXPORT
gf_isom_is_track_enabled(GF_ISOFile * the_file,u32 trackNumber)626 u8 gf_isom_is_track_enabled(GF_ISOFile *the_file, u32 trackNumber)
627 {
628 GF_TrackBox *trak;
629 trak = gf_isom_get_track_from_file(the_file, trackNumber);
630
631 if (!trak) return 2;
632 return (trak->Header->flags & 1) ? 1 : 0;
633 }
634
635
636 //get the track duration
637 //return 0 if bad param
638 GF_EXPORT
gf_isom_get_track_duration(GF_ISOFile * movie,u32 trackNumber)639 u64 gf_isom_get_track_duration(GF_ISOFile *movie, u32 trackNumber)
640 {
641 GF_TrackBox *trak;
642 trak = gf_isom_get_track_from_file(movie, trackNumber);
643 if (!trak) return 0;
644
645 #ifndef GPAC_DISABLE_ISOM_WRITE
646 /*in all modes except dump recompute duration in case headers are wrong*/
647 if (movie->openMode != GF_ISOM_OPEN_READ_DUMP) {
648 SetTrackDuration(trak);
649 }
650 #endif
651 return trak->Header->duration;
652 }
653
654 GF_EXPORT
gf_isom_get_media_language(GF_ISOFile * the_file,u32 trackNumber,char ** lang)655 GF_Err gf_isom_get_media_language(GF_ISOFile *the_file, u32 trackNumber, char **lang)
656 {
657 u32 count;
658 Bool elng_found = GF_FALSE;
659 GF_TrackBox *trak;
660 if (!lang) {
661 return GF_BAD_PARAM;
662 }
663 *lang = NULL;
664 trak = gf_isom_get_track_from_file(the_file, trackNumber);
665 if (!trak) return GF_BAD_PARAM;
666 count = gf_list_count(trak->Media->other_boxes);
667 if (count>0) {
668 u32 i;
669 for (i = 0; i < count; i++) {
670 GF_Box *box = (GF_Box *)gf_list_get(trak->Media->other_boxes, i);
671 if (box->type == GF_ISOM_BOX_TYPE_ELNG) {
672 *lang = gf_strdup(((GF_ExtendedLanguageBox *)box)->extended_language);
673 return GF_OK;
674 }
675 }
676 }
677 if (!elng_found) {
678 *lang = gf_strdup(trak->Media->mediaHeader->packedLanguage);
679 }
680 return GF_OK;
681 }
682
683 GF_EXPORT
gf_isom_get_track_kind_count(GF_ISOFile * the_file,u32 trackNumber)684 u32 gf_isom_get_track_kind_count(GF_ISOFile *the_file, u32 trackNumber)
685 {
686 GF_UserDataBox *udta;
687 GF_UserDataMap *map;
688 if (trackNumber) {
689 GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
690 if (!trak) return 0;
691 if (!trak->udta) {
692 return 0;
693 }
694 udta = trak->udta;
695 }
696 else {
697 return 0;
698 }
699 map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_KIND, NULL);
700 if (!map) return 0;
701
702 return gf_list_count(map->other_boxes);
703 }
704
705 GF_EXPORT
gf_isom_get_track_kind(GF_ISOFile * the_file,u32 trackNumber,u32 index,char ** scheme,char ** value)706 GF_Err gf_isom_get_track_kind(GF_ISOFile *the_file, u32 trackNumber, u32 index, char **scheme, char **value)
707 {
708 GF_Err e;
709 GF_UserDataBox *udta;
710 GF_UserDataMap *map;
711 GF_KindBox *kindBox;
712 if (!scheme || !value) {
713 return GF_BAD_PARAM;
714 }
715 *scheme = NULL;
716 *value = NULL;
717
718 if (trackNumber) {
719 GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
720 if (!trak) return GF_BAD_PARAM;
721 if (!trak->udta) {
722 e = trak_AddBox((GF_Box*)trak, gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA));
723 if (e) return e;
724 }
725 udta = trak->udta;
726 }
727 else {
728 return GF_BAD_PARAM;
729 }
730 map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_KIND, NULL);
731 if (!map) return GF_BAD_PARAM;
732
733 kindBox = (GF_KindBox *)gf_list_get(map->other_boxes, index);
734 if (!kindBox) return GF_BAD_PARAM;
735
736 *scheme = gf_strdup(kindBox->schemeURI);
737 if (kindBox->value) {
738 *value = gf_strdup(kindBox->value);
739 }
740 return GF_OK;
741 }
742
743
744 //Return the number of track references of a track for a given ReferenceType
745 //return 0 if error
746 GF_EXPORT
gf_isom_get_reference_count(GF_ISOFile * movie,u32 trackNumber,u32 referenceType)747 s32 gf_isom_get_reference_count(GF_ISOFile *movie, u32 trackNumber, u32 referenceType)
748 {
749 GF_TrackBox *trak;
750 GF_TrackReferenceTypeBox *dpnd;
751 trak = gf_isom_get_track_from_file(movie, trackNumber);
752 if (!trak) return -1;
753 if (!trak->References) return 0;
754 if (movie->openMode == GF_ISOM_OPEN_WRITE) {
755 movie->LastError = GF_ISOM_INVALID_MODE;
756 return -1;
757 }
758
759 dpnd = NULL;
760 if ((movie->LastError = Track_FindRef(trak, referenceType, &dpnd))) return -1;
761 if (!dpnd) return 0;
762 return dpnd->trackIDCount;
763 }
764
765
766 //Return the referenced track number for a track and a given ReferenceType and Index
767 //return -1 if error, 0 if the reference is a NULL one, or the trackNumber
768 GF_EXPORT
gf_isom_get_reference(GF_ISOFile * movie,u32 trackNumber,u32 referenceType,u32 referenceIndex,u32 * refTrack)769 GF_Err gf_isom_get_reference(GF_ISOFile *movie, u32 trackNumber, u32 referenceType, u32 referenceIndex, u32 *refTrack)
770 {
771 GF_Err e;
772 GF_TrackBox *trak;
773 GF_TrackReferenceTypeBox *dpnd;
774 u32 refTrackNum;
775 trak = gf_isom_get_track_from_file(movie, trackNumber);
776
777 *refTrack = 0;
778 if (!trak || !trak->References) return GF_BAD_PARAM;
779
780 dpnd = NULL;
781 e = Track_FindRef(trak, referenceType, &dpnd);
782 if (e) return e;
783 if (!dpnd) return GF_BAD_PARAM;
784
785 if (referenceIndex > dpnd->trackIDCount) return GF_BAD_PARAM;
786
787 //the spec allows a NULL reference
788 //(ex, to force desync of a track, set a sync ref with ID = 0)
789 if (dpnd->trackIDs[referenceIndex - 1] == 0) return GF_OK;
790
791 refTrackNum = gf_isom_get_tracknum_from_id(movie->moov, dpnd->trackIDs[referenceIndex - 1]);
792
793 //if the track was not found, this means the file is broken !!!
794 if (!refTrackNum) return GF_ISOM_INVALID_FILE;
795 *refTrack = refTrackNum;
796 return GF_OK;
797 }
798
799 //Return the referenced track ID for a track and a given ReferenceType and Index
800 //return -1 if error, 0 if the reference is a NULL one, or the trackNumber
801 GF_EXPORT
gf_isom_get_reference_ID(GF_ISOFile * movie,u32 trackNumber,u32 referenceType,u32 referenceIndex,u32 * refTrackID)802 GF_Err gf_isom_get_reference_ID(GF_ISOFile *movie, u32 trackNumber, u32 referenceType, u32 referenceIndex, u32 *refTrackID)
803 {
804 GF_Err e;
805 GF_TrackBox *trak;
806 GF_TrackReferenceTypeBox *dpnd;
807 trak = gf_isom_get_track_from_file(movie, trackNumber);
808
809 *refTrackID = 0;
810 if (!trak || !trak->References) return GF_BAD_PARAM;
811
812 dpnd = NULL;
813 e = Track_FindRef(trak, referenceType, &dpnd);
814 if (e) return e;
815 if (!dpnd) return GF_BAD_PARAM;
816
817 if (referenceIndex > dpnd->trackIDCount) return GF_BAD_PARAM;
818
819 *refTrackID = dpnd->trackIDs[referenceIndex - 1];
820
821 return GF_OK;
822 }
823
824 //Return referenceIndex if the given track has a reference to the given TreckID of a given ReferenceType
825 //return 0 if error
826 GF_EXPORT
gf_isom_has_track_reference(GF_ISOFile * movie,u32 trackNumber,u32 referenceType,u32 refTrackID)827 u32 gf_isom_has_track_reference(GF_ISOFile *movie, u32 trackNumber, u32 referenceType, u32 refTrackID)
828 {
829 u32 i;
830 GF_TrackBox *trak;
831 GF_TrackReferenceTypeBox *dpnd;
832 trak = gf_isom_get_track_from_file(movie, trackNumber);
833 if (!trak) return 0;
834 if (!trak->References) return 0;
835
836 dpnd = NULL;
837 if ((movie->LastError = Track_FindRef(trak, referenceType, &dpnd))) return 0;
838 if (!dpnd) return 0;
839 for (i = 0; i<dpnd->trackIDCount; i++) {
840 if (dpnd->trackIDs[i] == refTrackID) return i + 1;
841 }
842 return 0;
843 }
844
845
846
847 //Return the media time given the absolute time in the Movie
848 GF_EXPORT
gf_isom_get_media_time(GF_ISOFile * the_file,u32 trackNumber,u32 movieTime,u64 * MediaTime)849 GF_Err gf_isom_get_media_time(GF_ISOFile *the_file, u32 trackNumber, u32 movieTime, u64 *MediaTime)
850 {
851 GF_TrackBox *trak;
852 u8 useEdit;
853 s64 SegmentStartTime, mediaOffset;
854 trak = gf_isom_get_track_from_file(the_file, trackNumber);
855 if (!trak || !MediaTime) return GF_BAD_PARAM;;
856
857 SegmentStartTime = 0;
858 return GetMediaTime(trak, GF_FALSE, movieTime, MediaTime, &SegmentStartTime, &mediaOffset, &useEdit, NULL);
859 }
860
861
862 //Get the stream description index (eg, the ESD) for a given time IN MEDIA TIMESCALE
863 //return 0 if error or if empty
864 GF_EXPORT
gf_isom_get_sample_description_index(GF_ISOFile * movie,u32 trackNumber,u64 for_time)865 u32 gf_isom_get_sample_description_index(GF_ISOFile *movie, u32 trackNumber, u64 for_time)
866 {
867 u32 streamDescIndex;
868 GF_TrackBox *trak;
869 trak = gf_isom_get_track_from_file(movie, trackNumber);
870 if (!trak) return 0;
871
872 if ((movie->LastError = Media_GetSampleDescIndex(trak->Media, for_time, &streamDescIndex))) {
873 return 0;
874 }
875 return streamDescIndex;
876 }
877
878 //Get the number of "streams" stored in the media - a media can have several stream descriptions...
879 GF_EXPORT
gf_isom_get_sample_description_count(GF_ISOFile * the_file,u32 trackNumber)880 u32 gf_isom_get_sample_description_count(GF_ISOFile *the_file, u32 trackNumber)
881 {
882 GF_TrackBox *trak;
883 trak = gf_isom_get_track_from_file(the_file, trackNumber);
884 if (!trak) return 0;
885
886 return gf_list_count(trak->Media->information->sampleTable->SampleDescription->other_boxes);
887 }
888
889
890 //Get the GF_ESD given the StreamDescriptionIndex
891 //THE DESCRIPTOR IS DUPLICATED, SO HAS TO BE DELETED BY THE APP
892 GF_EXPORT
gf_isom_get_esd(GF_ISOFile * movie,u32 trackNumber,u32 StreamDescriptionIndex)893 GF_ESD *gf_isom_get_esd(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex)
894 {
895 GF_ESD *esd;
896 GF_Err e;
897 e = GetESD(movie->moov, gf_isom_get_track_id(movie, trackNumber), StreamDescriptionIndex, &esd);
898 if (e && (e != GF_ISOM_INVALID_MEDIA)) {
899 movie->LastError = e;
900 return NULL;
901 }
902
903 return esd;
904 }
905
906 //Get the decoderConfigDescriptor given the SampleDescriptionIndex
907 //THE DESCRIPTOR IS DUPLICATED, SO HAS TO BE DELETED BY THE APP
908 GF_EXPORT
gf_isom_get_decoder_config(GF_ISOFile * the_file,u32 trackNumber,u32 StreamDescriptionIndex)909 GF_DecoderConfig *gf_isom_get_decoder_config(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex)
910 {
911 GF_TrackBox *trak;
912 GF_ESD *esd;
913 GF_Descriptor *decInfo;
914 trak = gf_isom_get_track_from_file(the_file, trackNumber);
915 if (!trak) return NULL;
916 //get the ESD (possibly emulated)
917 Media_GetESD(trak->Media, StreamDescriptionIndex, &esd, GF_FALSE);
918 if (!esd) return NULL;
919 decInfo = (GF_Descriptor *)esd->decoderConfig;
920 esd->decoderConfig = NULL;
921 gf_odf_desc_del((GF_Descriptor *)esd);
922 return (GF_DecoderConfig *)decInfo;
923 }
924
925
926 //get the media duration (without edit)
927 //return 0 if bad param
928 GF_EXPORT
gf_isom_get_media_duration(GF_ISOFile * movie,u32 trackNumber)929 u64 gf_isom_get_media_duration(GF_ISOFile *movie, u32 trackNumber)
930 {
931 GF_TrackBox *trak;
932 trak = gf_isom_get_track_from_file(movie, trackNumber);
933 if (!trak) return 0;
934
935
936 #ifndef GPAC_DISABLE_ISOM_WRITE
937
938 /*except in dump mode always recompute the duration*/
939 if (movie->openMode != GF_ISOM_OPEN_READ_DUMP) {
940 if ((movie->LastError = Media_SetDuration(trak))) return 0;
941 }
942
943 #endif
944
945 return trak->Media->mediaHeader->duration;
946 }
947
948 //get the media duration (without edit)
949 //return 0 if bad param
950 GF_EXPORT
gf_isom_get_media_original_duration(GF_ISOFile * movie,u32 trackNumber)951 u64 gf_isom_get_media_original_duration(GF_ISOFile *movie, u32 trackNumber)
952 {
953 GF_TrackBox *trak;
954 trak = gf_isom_get_track_from_file(movie, trackNumber);
955 if (!trak) return 0;
956
957 return trak->Media->mediaHeader->original_duration;
958 }
959
960 //Get the timeScale of the media. All samples DTS/CTS are expressed in this timeScale
961 GF_EXPORT
gf_isom_get_media_timescale(GF_ISOFile * the_file,u32 trackNumber)962 u32 gf_isom_get_media_timescale(GF_ISOFile *the_file, u32 trackNumber)
963 {
964 GF_TrackBox *trak;
965 trak = gf_isom_get_track_from_file(the_file, trackNumber);
966 if (!trak) return 0;
967 return trak->Media->mediaHeader->timeScale;
968 }
969
970
971 GF_EXPORT
gf_isom_get_copyright_count(GF_ISOFile * mov)972 u32 gf_isom_get_copyright_count(GF_ISOFile *mov)
973 {
974 GF_UserDataMap *map;
975 if (!mov || !mov->moov || !mov->moov->udta) return 0;
976 map = udta_getEntry(mov->moov->udta, GF_ISOM_BOX_TYPE_CPRT, NULL);
977 if (!map) return 0;
978 return gf_list_count(map->other_boxes);
979 }
980
981 GF_EXPORT
gf_isom_get_copyright(GF_ISOFile * mov,u32 Index,const char ** threeCharCode,const char ** notice)982 GF_Err gf_isom_get_copyright(GF_ISOFile *mov, u32 Index, const char **threeCharCode, const char **notice)
983 {
984 GF_UserDataMap *map;
985 GF_CopyrightBox *cprt;
986
987 if (!mov || !mov->moov || !Index) return GF_BAD_PARAM;
988
989 if (!mov->moov->udta) return GF_OK;
990 map = udta_getEntry(mov->moov->udta, GF_ISOM_BOX_TYPE_CPRT, NULL);
991 if (!map) return GF_OK;
992
993 if (Index > gf_list_count(map->other_boxes)) return GF_BAD_PARAM;
994
995 cprt = (GF_CopyrightBox*)gf_list_get(map->other_boxes, Index - 1);
996 (*threeCharCode) = cprt->packedLanguageCode;
997 (*notice) = cprt->notice;
998 return GF_OK;
999 }
1000
1001 GF_EXPORT
gf_isom_get_watermark(GF_ISOFile * mov,bin128 UUID,u8 ** data,u32 * length)1002 GF_Err gf_isom_get_watermark(GF_ISOFile *mov, bin128 UUID, u8** data, u32* length)
1003 {
1004 GF_UserDataMap *map;
1005 GF_UnknownUUIDBox *wm;
1006
1007 if (!mov) return GF_BAD_PARAM;
1008 if (!mov->moov || !mov->moov->udta) return GF_NOT_SUPPORTED;
1009
1010 map = udta_getEntry(mov->moov->udta, GF_ISOM_BOX_TYPE_UUID, (bin128 *)& UUID);
1011 if (!map) return GF_NOT_SUPPORTED;
1012
1013 wm = (GF_UnknownUUIDBox*)gf_list_get(map->other_boxes, 0);
1014 if (!wm) return GF_NOT_SUPPORTED;
1015
1016 *data = (u8 *)gf_malloc(sizeof(char)*wm->dataSize);
1017 memcpy(*data, wm->data, wm->dataSize);
1018 *length = wm->dataSize;
1019 return GF_OK;
1020 }
1021
1022 GF_EXPORT
gf_isom_get_chapter_count(GF_ISOFile * movie,u32 trackNumber)1023 u32 gf_isom_get_chapter_count(GF_ISOFile *movie, u32 trackNumber)
1024 {
1025 GF_UserDataMap *map;
1026 GF_ChapterListBox *lst;
1027 GF_UserDataBox *udta;
1028
1029 if (!movie || !movie->moov) return 0;
1030
1031 udta = NULL;
1032 if (trackNumber) {
1033 GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
1034 if (!trak) return 0;
1035 udta = trak->udta;
1036 }
1037 else {
1038 udta = movie->moov->udta;
1039 }
1040 if (!udta) return 0;
1041 map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_CHPL, NULL);
1042 if (!map) return 0;
1043 lst = (GF_ChapterListBox *)gf_list_get(map->other_boxes, 0);
1044 if (!lst) return 0;
1045 return gf_list_count(lst->list);
1046 }
1047
1048 GF_EXPORT
gf_isom_get_chapter(GF_ISOFile * movie,u32 trackNumber,u32 Index,u64 * chapter_time,const char ** name)1049 GF_Err gf_isom_get_chapter(GF_ISOFile *movie, u32 trackNumber, u32 Index, u64 *chapter_time, const char **name)
1050 {
1051 GF_UserDataMap *map;
1052 GF_ChapterListBox *lst;
1053 GF_ChapterEntry *ce;
1054 GF_UserDataBox *udta;
1055
1056 if (!movie || !movie->moov) return GF_BAD_PARAM;
1057
1058 udta = NULL;
1059 if (trackNumber) {
1060 GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
1061 if (!trak) return GF_BAD_PARAM;
1062 udta = trak->udta;
1063 }
1064 else {
1065 udta = movie->moov->udta;
1066 }
1067 if (!udta) return GF_BAD_PARAM;
1068 map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_CHPL, NULL);
1069 if (!map) return GF_BAD_PARAM;
1070 lst = (GF_ChapterListBox *)gf_list_get(map->other_boxes, 0);
1071 if (!lst) return GF_BAD_PARAM;
1072
1073 ce = (GF_ChapterEntry *)gf_list_get(lst->list, Index - 1);
1074 if (!ce) return GF_BAD_PARAM;
1075 if (chapter_time) {
1076 *chapter_time = ce->start_time;
1077 *chapter_time /= 10000L;
1078 }
1079 if (name) *name = ce->name;
1080 return GF_OK;
1081 }
1082
1083
1084 GF_EXPORT
gf_isom_get_media_type(GF_ISOFile * movie,u32 trackNumber)1085 u32 gf_isom_get_media_type(GF_ISOFile *movie, u32 trackNumber)
1086 {
1087 GF_TrackBox *trak;
1088 trak = gf_isom_get_track_from_file(movie, trackNumber);
1089 if (!trak) return GF_BAD_PARAM;
1090 return (trak->Media && trak->Media->handler) ? trak->Media->handler->handlerType : 0;
1091 }
1092
IsMP4Description(u32 entryType)1093 Bool IsMP4Description(u32 entryType)
1094 {
1095 switch (entryType) {
1096 case GF_ISOM_BOX_TYPE_MP4S:
1097 case GF_ISOM_BOX_TYPE_MP4A:
1098 case GF_ISOM_BOX_TYPE_MP4V:
1099 case GF_ISOM_BOX_TYPE_ENCA:
1100 case GF_ISOM_BOX_TYPE_ENCV:
1101 case GF_ISOM_BOX_TYPE_ENCS:
1102 return GF_TRUE;
1103 default:
1104 return GF_FALSE;
1105 }
1106 }
1107
IsMP4EncryptedDescription(u32 entryType)1108 Bool IsMP4EncryptedDescription(u32 entryType)
1109 {
1110 switch (entryType) {
1111 case GF_ISOM_BOX_TYPE_ENCA:
1112 case GF_ISOM_BOX_TYPE_ENCV:
1113 case GF_ISOM_BOX_TYPE_ENCS:
1114 return GF_TRUE;
1115 default:
1116 return GF_FALSE;
1117 }
1118 }
1119
1120 GF_EXPORT
gf_isom_is_track_encrypted(GF_ISOFile * the_file,u32 trackNumber)1121 u8 gf_isom_is_track_encrypted(GF_ISOFile *the_file, u32 trackNumber)
1122 {
1123 GF_TrackBox *trak;
1124 GF_Box *entry;
1125 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1126 if (!trak) return 2;
1127 entry = (GF_Box*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, 0);
1128 if (!entry) return 2;
1129 return IsMP4EncryptedDescription(entry->type);
1130 }
1131
1132 GF_EXPORT
gf_isom_get_media_subtype(GF_ISOFile * the_file,u32 trackNumber,u32 DescriptionIndex)1133 u32 gf_isom_get_media_subtype(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex)
1134 {
1135 GF_TrackBox *trak;
1136 GF_Box *entry;
1137 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1138 if (!trak || !DescriptionIndex || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable) return 0;
1139 entry = (GF_Box*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, DescriptionIndex - 1);
1140 if (!entry) return 0;
1141
1142 //filter MPEG sub-types
1143 if (IsMP4Description(entry->type)) {
1144 if (IsMP4EncryptedDescription(entry->type)) return GF_ISOM_SUBTYPE_MPEG4_CRYP;
1145 else return GF_ISOM_SUBTYPE_MPEG4;
1146 }
1147 if (entry->type == GF_ISOM_BOX_TYPE_GNRV) {
1148 return ((GF_GenericVisualSampleEntryBox *)entry)->EntryType;
1149 }
1150 else if (entry->type == GF_ISOM_BOX_TYPE_GNRA) {
1151 return ((GF_GenericAudioSampleEntryBox *)entry)->EntryType;
1152 }
1153 else if (entry->type == GF_ISOM_BOX_TYPE_GNRM) {
1154 return ((GF_GenericSampleEntryBox *)entry)->EntryType;
1155 }
1156 return entry->type;
1157 }
1158
1159 GF_EXPORT
gf_isom_get_mpeg4_subtype(GF_ISOFile * the_file,u32 trackNumber,u32 DescriptionIndex)1160 u32 gf_isom_get_mpeg4_subtype(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex)
1161 {
1162 GF_TrackBox *trak;
1163 GF_Box *entry;
1164 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1165 if (!trak || !DescriptionIndex) return 0;
1166 entry = (GF_Box*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, DescriptionIndex - 1);
1167 if (!entry) return 0;
1168
1169 //filter MPEG sub-types
1170 if (!IsMP4Description(entry->type)) return 0;
1171 return entry->type;
1172 }
1173
1174 //Get the HandlerDescription name.
1175 GF_EXPORT
gf_isom_get_handler_name(GF_ISOFile * the_file,u32 trackNumber,const char ** outName)1176 GF_Err gf_isom_get_handler_name(GF_ISOFile *the_file, u32 trackNumber, const char **outName)
1177 {
1178 GF_TrackBox *trak;
1179 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1180 if (!trak || !outName) return GF_BAD_PARAM;
1181 *outName = trak->Media->handler->nameUTF8;
1182 return GF_OK;
1183 }
1184
1185 //Check the DataReferences of this track
1186 GF_EXPORT
gf_isom_check_data_reference(GF_ISOFile * the_file,u32 trackNumber,u32 StreamDescriptionIndex)1187 GF_Err gf_isom_check_data_reference(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex)
1188 {
1189 GF_Err e;
1190 u32 drefIndex;
1191 GF_TrackBox *trak;
1192
1193 if (!StreamDescriptionIndex || !trackNumber) return GF_BAD_PARAM;
1194 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1195 if (!trak) return GF_BAD_PARAM;
1196
1197 e = Media_GetSampleDesc(trak->Media, StreamDescriptionIndex, NULL, &drefIndex);
1198 if (e) return e;
1199 if (!drefIndex) return GF_BAD_PARAM;
1200 return Media_CheckDataEntry(trak->Media, drefIndex);
1201 }
1202
1203 //get the location of the data. If URL && URN are NULL, the data is in this file
1204 GF_EXPORT
gf_isom_get_data_reference(GF_ISOFile * the_file,u32 trackNumber,u32 StreamDescriptionIndex,const char ** outURL,const char ** outURN)1205 GF_Err gf_isom_get_data_reference(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex, const char **outURL, const char **outURN)
1206 {
1207 GF_TrackBox *trak;
1208 GF_DataEntryURLBox *url;
1209 GF_DataEntryURNBox *urn;
1210 u32 drefIndex;
1211 GF_Err e;
1212
1213 *outURL = *outURN = NULL;
1214
1215 if (!StreamDescriptionIndex || !trackNumber) return GF_BAD_PARAM;
1216 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1217 if (!trak) return GF_BAD_PARAM;
1218
1219 e = Media_GetSampleDesc(trak->Media, StreamDescriptionIndex, NULL, &drefIndex);
1220 if (e) return e;
1221 if (!drefIndex) return GF_BAD_PARAM;
1222
1223 url = (GF_DataEntryURLBox*)gf_list_get(trak->Media->information->dataInformation->dref->other_boxes, drefIndex - 1);
1224 if (!url) return GF_ISOM_INVALID_FILE;
1225
1226 *outURL = *outURN = NULL;
1227 if (url->type == GF_ISOM_BOX_TYPE_URL) {
1228 *outURL = url->location;
1229 *outURN = NULL;
1230 }
1231 else if (url->type == GF_ISOM_BOX_TYPE_URN) {
1232 urn = (GF_DataEntryURNBox *)url;
1233 *outURN = urn->nameURN;
1234 *outURL = urn->location;
1235 }
1236 else {
1237 *outURN = NULL;
1238 *outURL = NULL;
1239 }
1240 return GF_OK;
1241 }
1242
1243 //Get the number of samples
1244 //return 0 if error or empty
1245 GF_EXPORT
gf_isom_get_sample_count(GF_ISOFile * the_file,u32 trackNumber)1246 u32 gf_isom_get_sample_count(GF_ISOFile *the_file, u32 trackNumber)
1247 {
1248 GF_TrackBox *trak;
1249 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1250 if (!trak || !trak->Media->information->sampleTable->SampleSize) return 0;
1251 return trak->Media->information->sampleTable->SampleSize->sampleCount
1252 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1253 + trak->sample_count_at_seg_start
1254 #endif
1255 ;
1256 }
1257
gf_isom_get_constant_sample_size(GF_ISOFile * the_file,u32 trackNumber)1258 u32 gf_isom_get_constant_sample_size(GF_ISOFile *the_file, u32 trackNumber)
1259 {
1260 GF_TrackBox *trak;
1261 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1262 if (!trak) return 0;
1263 return trak->Media->information->sampleTable->SampleSize->sampleSize;
1264 }
1265
1266 GF_EXPORT
gf_isom_has_time_offset(GF_ISOFile * the_file,u32 trackNumber)1267 u32 gf_isom_has_time_offset(GF_ISOFile *the_file, u32 trackNumber)
1268 {
1269 u32 i;
1270 GF_CompositionOffsetBox *ctts;
1271 GF_TrackBox *trak;
1272 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1273 if (!trak || !trak->Media->information->sampleTable->CompositionOffset) return 0;
1274
1275 //return true at the first offset found
1276 ctts = trak->Media->information->sampleTable->CompositionOffset;
1277 for (i = 0; i<ctts->nb_entries; i++) {
1278 if (ctts->entries[i].decodingOffset && ctts->entries[i].sampleCount) return ctts->version ? 2 : 1;
1279 }
1280 return 0;
1281 }
1282
1283 GF_EXPORT
gf_isom_get_cts_to_dts_shift(GF_ISOFile * the_file,u32 trackNumber)1284 s64 gf_isom_get_cts_to_dts_shift(GF_ISOFile *the_file, u32 trackNumber)
1285 {
1286 GF_TrackBox *trak;
1287 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1288 if (!trak || !trak->Media->information->sampleTable->CompositionToDecode) return 0;
1289 return trak->Media->information->sampleTable->CompositionToDecode->compositionToDTSShift;
1290 }
1291
1292 GF_EXPORT
gf_isom_has_sync_shadows(GF_ISOFile * the_file,u32 trackNumber)1293 Bool gf_isom_has_sync_shadows(GF_ISOFile *the_file, u32 trackNumber)
1294 {
1295 GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1296 if (!trak) return GF_FALSE;
1297 if (!trak->Media->information->sampleTable->ShadowSync) return GF_FALSE;
1298 if (gf_list_count(trak->Media->information->sampleTable->ShadowSync->entries)) return GF_TRUE;
1299 return GF_FALSE;
1300 }
1301
1302 GF_EXPORT
gf_isom_has_sample_dependency(GF_ISOFile * the_file,u32 trackNumber)1303 Bool gf_isom_has_sample_dependency(GF_ISOFile *the_file, u32 trackNumber)
1304 {
1305 GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1306 if (!trak) return GF_FALSE;
1307 if (!trak->Media->information->sampleTable->SampleDep) return GF_FALSE;
1308 return GF_TRUE;
1309 }
1310
1311 GF_EXPORT
gf_isom_get_sample_flags(GF_ISOFile * the_file,u32 trackNumber,u32 sampleNumber,u32 * isLeading,u32 * dependsOn,u32 * dependedOn,u32 * redundant)1312 GF_Err gf_isom_get_sample_flags(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 *isLeading, u32 *dependsOn, u32 *dependedOn, u32 *redundant)
1313 {
1314 GF_TrackBox *trak = NULL;
1315 *isLeading = 0;
1316 *dependsOn = 0;
1317 *dependedOn = 0;
1318 *redundant = 0;
1319 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1320 if (!trak) return GF_BAD_PARAM;
1321 if (!trak->Media->information->sampleTable->SampleDep) return GF_BAD_PARAM;
1322 return stbl_GetSampleDepType(trak->Media->information->sampleTable->SampleDep, sampleNumber, isLeading, dependsOn, dependedOn, redundant);
1323 }
1324
1325 //return a sample give its number, and set the SampleDescIndex of this sample
1326 //this index allows to retrieve the stream description if needed (2 media in 1 track)
1327 //return NULL if error
1328 GF_EXPORT
gf_isom_get_sample(GF_ISOFile * the_file,u32 trackNumber,u32 sampleNumber,u32 * sampleDescriptionIndex)1329 GF_ISOSample *gf_isom_get_sample(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 *sampleDescriptionIndex)
1330 {
1331 GF_Err e;
1332 u32 descIndex;
1333 GF_TrackBox *trak;
1334 GF_ISOSample *samp;
1335 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1336 if (!trak) return NULL;
1337
1338 if (!sampleNumber) return NULL;
1339 samp = gf_isom_sample_new();
1340 if (!samp) return NULL;
1341
1342 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1343 if (sampleNumber <= trak->sample_count_at_seg_start)
1344 return NULL;
1345 sampleNumber -= trak->sample_count_at_seg_start;
1346 #endif
1347
1348 e = Media_GetSample(trak->Media, sampleNumber, &samp, &descIndex, GF_FALSE, NULL);
1349 if (e) {
1350 gf_isom_set_last_error(the_file, e);
1351 gf_isom_sample_del(&samp);
1352 return NULL;
1353 }
1354 if (sampleDescriptionIndex) *sampleDescriptionIndex = descIndex;
1355 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1356 if (samp) samp->DTS += trak->dts_at_seg_start;
1357 #endif
1358
1359 return samp;
1360 }
1361
1362 GF_EXPORT
gf_isom_get_sample_duration(GF_ISOFile * the_file,u32 trackNumber,u32 sampleNumber)1363 u32 gf_isom_get_sample_duration(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber)
1364 {
1365 u32 dur;
1366 u64 dts;
1367 GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1368 if (!trak || !sampleNumber) return 0;
1369 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1370 if (sampleNumber <= trak->sample_count_at_seg_start) return 0;
1371 sampleNumber -= trak->sample_count_at_seg_start;
1372 #endif
1373
1374 stbl_GetSampleDTS_and_Duration(trak->Media->information->sampleTable->TimeToSample, sampleNumber, &dts, &dur);
1375 return dur;
1376 }
1377
1378
1379 GF_EXPORT
gf_isom_get_sample_size(GF_ISOFile * the_file,u32 trackNumber,u32 sampleNumber)1380 u32 gf_isom_get_sample_size(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber)
1381 {
1382 u32 size = 0;
1383 GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1384 if (!trak || !sampleNumber) return 0;
1385 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1386 if (sampleNumber <= trak->sample_count_at_seg_start) return 0;
1387 sampleNumber -= trak->sample_count_at_seg_start;
1388 #endif
1389 stbl_GetSampleSize(trak->Media->information->sampleTable->SampleSize, sampleNumber, &size);
1390 return size;
1391 }
1392
1393 GF_EXPORT
gf_isom_get_sample_sync(GF_ISOFile * the_file,u32 trackNumber,u32 sampleNumber)1394 u8 gf_isom_get_sample_sync(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber)
1395 {
1396 SAPType is_rap;
1397 GF_Err e;
1398 GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1399 if (!trak || !sampleNumber) return 0;
1400
1401 if (!trak->Media->information->sampleTable->SyncSample) return 1;
1402 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1403 if (sampleNumber <= trak->sample_count_at_seg_start) return 0;
1404 sampleNumber -= trak->sample_count_at_seg_start;
1405 #endif
1406 e = stbl_GetSampleRAP(trak->Media->information->sampleTable->SyncSample, sampleNumber, &is_rap, NULL, NULL);
1407 if (e) return 0;
1408 return is_rap;
1409 }
1410
1411 //same as gf_isom_get_sample but doesn't fetch media data
1412 GF_EXPORT
gf_isom_get_sample_info(GF_ISOFile * the_file,u32 trackNumber,u32 sampleNumber,u32 * sampleDescriptionIndex,u64 * data_offset)1413 GF_ISOSample *gf_isom_get_sample_info(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 *sampleDescriptionIndex, u64 *data_offset)
1414 {
1415 GF_Err e;
1416 GF_TrackBox *trak;
1417 GF_ISOSample *samp;
1418 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1419 if (!trak) return NULL;
1420
1421 if (!sampleNumber) return NULL;
1422 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1423 if (sampleNumber <= trak->sample_count_at_seg_start) return NULL;
1424 sampleNumber -= trak->sample_count_at_seg_start;
1425 #endif
1426 samp = gf_isom_sample_new();
1427 if (!samp) return NULL;
1428 e = Media_GetSample(trak->Media, sampleNumber, &samp, sampleDescriptionIndex, GF_TRUE, data_offset);
1429 if (e) {
1430 gf_isom_set_last_error(the_file, e);
1431 gf_isom_sample_del(&samp);
1432 return NULL;
1433 }
1434 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1435 if (samp) samp->DTS += trak->dts_at_seg_start;
1436 #endif
1437 return samp;
1438 }
1439
1440 //same as gf_isom_get_sample but doesn't fetch media data
1441 GF_EXPORT
gf_isom_get_sample_dts(GF_ISOFile * the_file,u32 trackNumber,u32 sampleNumber)1442 u64 gf_isom_get_sample_dts(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber)
1443 {
1444 u64 dts;
1445 GF_TrackBox *trak;
1446 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1447 if (!trak) return 0;
1448
1449 if (!sampleNumber) return 0;
1450 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1451 if (sampleNumber <= trak->sample_count_at_seg_start) return 0;
1452 sampleNumber -= trak->sample_count_at_seg_start;
1453 #endif
1454 if (stbl_GetSampleDTS(trak->Media->information->sampleTable->TimeToSample, sampleNumber, &dts) != GF_OK) return 0;
1455 return dts;
1456 }
1457
1458
1459 GF_EXPORT
gf_isom_is_self_contained(GF_ISOFile * the_file,u32 trackNumber,u32 sampleDescriptionIndex)1460 Bool gf_isom_is_self_contained(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex)
1461 {
1462 GF_TrackBox *trak;
1463 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1464 if (!trak) return GF_FALSE;
1465 return Media_IsSelfContained(trak->Media, sampleDescriptionIndex);
1466 }
1467
1468 /*retrieves given sample DTS*/
gf_isom_get_sample_from_dts(GF_ISOFile * the_file,u32 trackNumber,u64 dts)1469 u32 gf_isom_get_sample_from_dts(GF_ISOFile *the_file, u32 trackNumber, u64 dts)
1470 {
1471 GF_Err e;
1472 u32 sampleNumber, prevSampleNumber;
1473 GF_TrackBox *trak;
1474 GF_SampleTableBox *stbl;
1475
1476 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1477 if (!trak) return 0;
1478
1479 stbl = trak->Media->information->sampleTable;
1480
1481 e = stbl_findEntryForTime(stbl, dts, 1, &sampleNumber, &prevSampleNumber);
1482 if (e) return 0;
1483 return sampleNumber;
1484 }
1485
1486
1487 //return a sample given a desired display time IN MEDIA TIME SCALE
1488 //and set the StreamDescIndex of this sample
1489 //this index allows to retrieve the stream description if needed (2 media in 1 track)
1490 //return NULL if error
1491 //WARNING: the sample may not be sync even though the sync was requested (depends on the media)
1492 GF_EXPORT
gf_isom_get_sample_for_media_time(GF_ISOFile * the_file,u32 trackNumber,u64 desiredTime,u32 * StreamDescriptionIndex,u8 SearchMode,GF_ISOSample ** sample,u32 * SampleNum)1493 GF_Err gf_isom_get_sample_for_media_time(GF_ISOFile *the_file, u32 trackNumber, u64 desiredTime, u32 *StreamDescriptionIndex, u8 SearchMode, GF_ISOSample **sample, u32 *SampleNum)
1494 {
1495 GF_Err e;
1496 u32 sampleNumber, prevSampleNumber, syncNum, shadowSync;
1497 GF_TrackBox *trak;
1498 GF_ISOSample *shadow;
1499 GF_SampleTableBox *stbl;
1500 u8 useShadow, IsSync;
1501
1502 if (!sample) return GF_BAD_PARAM;
1503
1504 if (SampleNum) *SampleNum = 0;
1505 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1506 if (!trak) return GF_BAD_PARAM;
1507
1508 stbl = trak->Media->information->sampleTable;
1509
1510 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1511 if (desiredTime < trak->dts_at_seg_start) {
1512 desiredTime = 0;
1513 }
1514 else {
1515 desiredTime -= trak->dts_at_seg_start;
1516 }
1517 #endif
1518
1519 e = stbl_findEntryForTime(stbl, desiredTime, 0, &sampleNumber, &prevSampleNumber);
1520 if (e) return e;
1521
1522 //if no shadow table, reset to sync only
1523 useShadow = 0;
1524 if (!stbl->ShadowSync && (SearchMode == GF_ISOM_SEARCH_SYNC_SHADOW))
1525 SearchMode = GF_ISOM_SEARCH_SYNC_BACKWARD;
1526
1527 //if no syncTable, disable syncSearching, as all samples ARE sync
1528 if (!trak->Media->information->sampleTable->SyncSample) {
1529 if (SearchMode == GF_ISOM_SEARCH_SYNC_FORWARD) SearchMode = GF_ISOM_SEARCH_FORWARD;
1530 if (SearchMode == GF_ISOM_SEARCH_SYNC_BACKWARD) SearchMode = GF_ISOM_SEARCH_BACKWARD;
1531 }
1532
1533 //not found, return EOF or browse backward
1534 if (!sampleNumber && !prevSampleNumber) {
1535 if (SearchMode == GF_ISOM_SEARCH_SYNC_BACKWARD || SearchMode == GF_ISOM_SEARCH_BACKWARD) {
1536 sampleNumber = trak->Media->information->sampleTable->SampleSize->sampleCount;
1537 }
1538 if (!sampleNumber) return GF_EOS;
1539 }
1540
1541 //check in case we have the perfect sample
1542 IsSync = 0;
1543
1544 //according to the direction adjust the sampleNum value
1545 switch (SearchMode) {
1546 case GF_ISOM_SEARCH_SYNC_FORWARD:
1547 IsSync = 1;
1548 case GF_ISOM_SEARCH_FORWARD:
1549 //not the exact one
1550 if (!sampleNumber) {
1551 if (prevSampleNumber != stbl->SampleSize->sampleCount) {
1552 sampleNumber = prevSampleNumber + 1;
1553 }
1554 else {
1555 sampleNumber = prevSampleNumber;
1556 }
1557 }
1558 break;
1559
1560 //if dummy mode, reset to default browsing
1561 case GF_ISOM_SEARCH_SYNC_BACKWARD:
1562 IsSync = 1;
1563 case GF_ISOM_SEARCH_SYNC_SHADOW:
1564 case GF_ISOM_SEARCH_BACKWARD:
1565 default:
1566 //first case, not found....
1567 if (!sampleNumber && !prevSampleNumber) {
1568 sampleNumber = stbl->SampleSize->sampleCount;
1569 }
1570 else if (!sampleNumber) {
1571 sampleNumber = prevSampleNumber;
1572 }
1573 break;
1574 }
1575
1576 //get the sync sample num
1577 if (IsSync) {
1578 //get the SyncNumber
1579 e = Media_FindSyncSample(trak->Media->information->sampleTable,
1580 sampleNumber, &syncNum, SearchMode);
1581 if (e) return e;
1582 if (syncNum) sampleNumber = syncNum;
1583 syncNum = 0;
1584 }
1585 //if we are in shadow mode, get the previous sync sample
1586 //in case we can't find a good SyncShadow
1587 else if (SearchMode == GF_ISOM_SEARCH_SYNC_SHADOW) {
1588 //get the SyncNumber
1589 e = Media_FindSyncSample(trak->Media->information->sampleTable,
1590 sampleNumber, &syncNum, GF_ISOM_SEARCH_SYNC_BACKWARD);
1591 if (e) return e;
1592 }
1593
1594
1595 //OK sampleNumber is exactly the sample we need (except for shadow)
1596
1597 *sample = gf_isom_sample_new();
1598 if (*sample == NULL) return GF_OUT_OF_MEM;
1599
1600 //we are in shadow mode, we need to browse both SyncSample and ShadowSyncSample to get
1601 //the desired sample...
1602 if (SearchMode == GF_ISOM_SEARCH_SYNC_SHADOW) {
1603 //get the shadowing number
1604 stbl_GetSampleShadow(stbl->ShadowSync, &sampleNumber, &shadowSync);
1605 //now sampleNumber is the closest previous shadowed sample.
1606 //1- If we have a closer sync sample, use it.
1607 //2- if the shadowSync is 0, we don't have any shadowing, use syncNum
1608 if ((sampleNumber < syncNum) || (!shadowSync)) {
1609 sampleNumber = syncNum;
1610 }
1611 else {
1612 //otherwise, we have a better alternate sample in the shadowSync for this sample
1613 useShadow = 1;
1614 }
1615 }
1616
1617 e = Media_GetSample(trak->Media, sampleNumber, sample, StreamDescriptionIndex, GF_FALSE, NULL);
1618 if (e) {
1619 gf_isom_sample_del(sample);
1620 return e;
1621 }
1622 if (!(*sample)->IsRAP) {
1623 Bool has_roll, is_rap;
1624 e = gf_isom_get_sample_rap_roll_info(the_file, trackNumber, sampleNumber, &is_rap, &has_roll, NULL);
1625 if (e) return e;
1626 if (is_rap) (*sample)->IsRAP = SAP_TYPE_3;
1627 }
1628 //optionally get the sample number
1629 if (SampleNum) {
1630 *SampleNum = sampleNumber;
1631 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1632 *SampleNum += trak->sample_count_at_seg_start;
1633 #endif
1634 }
1635
1636 //in shadow mode, we only get the data of the shadowing sample !
1637 if (useShadow) {
1638 //we have to use StreamDescriptionIndex in case the sample data is in another desc
1639 //though this is unlikely as non optimized...
1640 shadow = gf_isom_get_sample(the_file, trackNumber, shadowSync, StreamDescriptionIndex);
1641 //if no sample, the shadowSync is broken, return the sample
1642 if (!shadow) return GF_OK;
1643 (*sample)->IsRAP = RAP;
1644 gf_free((*sample)->data);
1645 (*sample)->dataLength = shadow->dataLength;
1646 (*sample)->data = shadow->data;
1647 //set data length to 0 to keep the buffer alive...
1648 shadow->dataLength = 0;
1649 gf_isom_sample_del(&shadow);
1650 }
1651 return GF_OK;
1652 }
1653
1654 GF_EXPORT
gf_isom_get_sample_for_movie_time(GF_ISOFile * the_file,u32 trackNumber,u64 movieTime,u32 * StreamDescriptionIndex,u8 SearchMode,GF_ISOSample ** sample,u32 * sampleNumber)1655 GF_Err gf_isom_get_sample_for_movie_time(GF_ISOFile *the_file, u32 trackNumber, u64 movieTime, u32 *StreamDescriptionIndex, u8 SearchMode, GF_ISOSample **sample, u32 *sampleNumber)
1656 {
1657 Double tsscale;
1658 GF_Err e;
1659 GF_TrackBox *trak;
1660 u64 mediaTime, nextMediaTime;
1661 s64 segStartTime, mediaOffset;
1662 u32 sampNum;
1663 u8 useEdit;
1664
1665 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1666 if (!trak) return GF_BAD_PARAM;
1667
1668 if (*sample || !sample) return GF_BAD_PARAM;
1669 //check 0-duration tracks (BIFS and co). Check we're not searching forward
1670 if (!trak->Header->duration) {
1671 if (movieTime && ((SearchMode == GF_ISOM_SEARCH_SYNC_FORWARD) || (SearchMode == GF_ISOM_SEARCH_FORWARD))) {
1672 *sample = NULL;
1673 if (sampleNumber) *sampleNumber = 0;
1674 *StreamDescriptionIndex = 0;
1675 return GF_EOS;
1676 }
1677 }
1678 else if ((movieTime * trak->moov->mvhd->timeScale > trak->Header->duration * trak->Media->mediaHeader->timeScale)
1679 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1680 && !trak->dts_at_seg_start
1681 #endif
1682 ) {
1683 *sample = NULL;
1684 if (sampleNumber) *sampleNumber = 0;
1685 *StreamDescriptionIndex = 0;
1686 return GF_EOS;
1687 }
1688
1689 //get the media time for this movie time...
1690 mediaTime = segStartTime = 0;
1691 *StreamDescriptionIndex = 0;
1692 nextMediaTime = 0;
1693
1694 e = GetMediaTime(trak, (SearchMode == GF_ISOM_SEARCH_SYNC_FORWARD) ? GF_TRUE : GF_FALSE, movieTime, &mediaTime, &segStartTime, &mediaOffset, &useEdit, &nextMediaTime);
1695 if (e) return e;
1696
1697 /*here we check if we were playing or not and return no sample in normal search modes*/
1698 if (useEdit && mediaOffset == -1) {
1699 if ((SearchMode == GF_ISOM_SEARCH_FORWARD) || (SearchMode == GF_ISOM_SEARCH_BACKWARD)) {
1700 /*get next sample time in MOVIE timescale*/
1701 if (SearchMode == GF_ISOM_SEARCH_FORWARD)
1702 e = GetNextMediaTime(trak, movieTime, &mediaTime);
1703 else
1704 e = GetPrevMediaTime(trak, movieTime, &mediaTime);
1705 if (e) return e;
1706 return gf_isom_get_sample_for_movie_time(the_file, trackNumber, (u32)mediaTime, StreamDescriptionIndex, GF_ISOM_SEARCH_SYNC_FORWARD, sample, sampleNumber);
1707 }
1708 if (sampleNumber) *sampleNumber = 0;
1709 *sample = gf_isom_sample_new();
1710 if (!*sample) return GF_OUT_OF_MEM;
1711 (*sample)->DTS = movieTime;
1712 return GF_OK;
1713 }
1714 /*dwell edit in non-sync mode, fetch next/prev sample depending on mode.
1715 Otherwise return the dwell entry*/
1716 if (useEdit == 2) {
1717 if ((SearchMode == GF_ISOM_SEARCH_FORWARD) || (SearchMode == GF_ISOM_SEARCH_BACKWARD)) {
1718 /*get next sample time in MOVIE timescale*/
1719 if (SearchMode == GF_ISOM_SEARCH_FORWARD)
1720 e = GetNextMediaTime(trak, movieTime, &mediaTime);
1721 else
1722 e = GetPrevMediaTime(trak, movieTime, &mediaTime);
1723 if (e) return e;
1724 return gf_isom_get_sample_for_movie_time(the_file, trackNumber, (u32)mediaTime, StreamDescriptionIndex, GF_ISOM_SEARCH_SYNC_FORWARD, sample, sampleNumber);
1725 }
1726 }
1727
1728 tsscale = trak->Media->mediaHeader->timeScale;
1729 tsscale /= trak->moov->mvhd->timeScale;
1730
1731 //OK, we have a sample so fetch it
1732 e = gf_isom_get_sample_for_media_time(the_file, trackNumber, mediaTime, StreamDescriptionIndex, SearchMode, sample, &sampNum);
1733 if (e) {
1734 if (e == GF_EOS) {
1735 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1736 //movie is fragmented and samples not yet received, return EOS
1737 if (the_file->moov->mvex && !trak->Media->information->sampleTable->SampleSize->sampleCount)
1738 return e;
1739 #endif
1740
1741 if (nextMediaTime)
1742 return gf_isom_get_sample_for_movie_time(the_file, trackNumber, nextMediaTime - 1, StreamDescriptionIndex, SearchMode, sample, sampleNumber);
1743 }
1744 return e;
1745 }
1746
1747 //OK, now the trick: we have to rebuild the time stamps, according
1748 //to the media time scale (used by SLConfig) - add the edit start time but stay in
1749 //the track TS
1750 if (useEdit) {
1751 u64 _ts = (u64)(segStartTime * tsscale);
1752
1753 (*sample)->DTS += _ts;
1754 /*watchout, the sample fetched may be before the first sample in the edit list (when seeking)*/
1755 if ((*sample)->DTS > (u64)mediaOffset) {
1756 (*sample)->DTS -= (u64)mediaOffset;
1757 }
1758 else {
1759 (*sample)->DTS = 0;
1760 }
1761 }
1762 if (sampleNumber) *sampleNumber = sampNum;
1763 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1764 if ((*sample)) (*sample)->DTS += trak->dts_at_seg_start;
1765 #endif
1766
1767 return GF_OK;
1768 }
1769
1770
1771
1772 GF_EXPORT
gf_isom_get_missing_bytes(GF_ISOFile * the_file,u32 trackNumber)1773 u64 gf_isom_get_missing_bytes(GF_ISOFile *the_file, u32 trackNumber)
1774 {
1775 GF_TrackBox *trak;
1776 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1777 if (!trak) return 0;
1778
1779 return trak->Media->BytesMissing;
1780 }
1781
1782 GF_EXPORT
gf_isom_set_sample_padding(GF_ISOFile * the_file,u32 trackNumber,u32 padding_bytes)1783 GF_Err gf_isom_set_sample_padding(GF_ISOFile *the_file, u32 trackNumber, u32 padding_bytes)
1784 {
1785 GF_TrackBox *trak;
1786 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1787 if (!trak) return GF_BAD_PARAM;
1788 trak->padding_bytes = padding_bytes;
1789 return GF_OK;
1790
1791 }
1792
1793 //get the number of edited segment
1794 GF_EXPORT
gf_isom_get_edit_list_type(GF_ISOFile * the_file,u32 trackNumber,s64 * mediaOffset)1795 Bool gf_isom_get_edit_list_type(GF_ISOFile *the_file, u32 trackNumber, s64 *mediaOffset)
1796 {
1797 GF_EdtsEntry *ent;
1798 GF_TrackBox *trak;
1799 u32 count;
1800 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1801 if (!trak) return GF_FALSE;
1802 *mediaOffset = 0;
1803 if (!trak->editBox || !trak->editBox->editList) return GF_FALSE;
1804
1805 count = gf_list_count(trak->editBox->editList->entryList);
1806 ent = (GF_EdtsEntry*)gf_list_get(trak->editBox->editList->entryList, 0);
1807 if (!ent) return GF_TRUE;
1808 /*mediaRate>0, the track playback shall start at media time>0 -> mediaOffset is < 0 */
1809 if ((count == 1) && (ent->mediaRate == 1)) {
1810 *mediaOffset = -ent->mediaTime;
1811 return GF_FALSE;
1812 }
1813 else if (count == 2) {
1814 /*mediaRate==-1, the track playback shall be empty for segmentDuration -> mediaOffset is > 0 */
1815 if ((ent->mediaRate == -1) || (ent->mediaTime == -1)) {
1816 Double time = (Double)ent->segmentDuration;
1817 time /= trak->moov->mvhd->timeScale;
1818 time *= trak->Media->mediaHeader->timeScale;
1819
1820 *mediaOffset = (s64)time;
1821 return GF_FALSE;
1822 }
1823 }
1824 return GF_TRUE;
1825 }
1826
1827
1828 //get the number of edited segment
1829 GF_EXPORT
gf_isom_get_edit_segment_count(GF_ISOFile * the_file,u32 trackNumber)1830 u32 gf_isom_get_edit_segment_count(GF_ISOFile *the_file, u32 trackNumber)
1831 {
1832 GF_TrackBox *trak;
1833 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1834 if (!trak) return 0;
1835
1836 if (!trak->editBox || !trak->editBox->editList) return 0;
1837 return gf_list_count(trak->editBox->editList->entryList);
1838 }
1839
1840
1841 //Get the desired segment information
1842 GF_EXPORT
gf_isom_get_edit_segment(GF_ISOFile * the_file,u32 trackNumber,u32 SegmentIndex,u64 * EditTime,u64 * SegmentDuration,u64 * MediaTime,u8 * EditMode)1843 GF_Err gf_isom_get_edit_segment(GF_ISOFile *the_file, u32 trackNumber, u32 SegmentIndex, u64 *EditTime, u64 *SegmentDuration, u64 *MediaTime, u8 *EditMode)
1844 {
1845 u32 i;
1846 u64 startTime;
1847 GF_TrackBox *trak;
1848 GF_EditListBox *elst;
1849 GF_EdtsEntry *ent;
1850
1851 ent = NULL;
1852 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1853 if (!trak) return GF_BAD_PARAM;
1854
1855 if (!trak->editBox ||
1856 !trak->editBox->editList ||
1857 (SegmentIndex > gf_list_count(trak->editBox->editList->entryList)) ||
1858 !SegmentIndex)
1859 return GF_BAD_PARAM;
1860
1861 elst = trak->editBox->editList;
1862 startTime = 0;
1863
1864 for (i = 0; i < SegmentIndex; i++) {
1865 ent = (GF_EdtsEntry*)gf_list_get(elst->entryList, i);
1866 if (i < SegmentIndex - 1) startTime += ent->segmentDuration;
1867 }
1868 *EditTime = startTime;
1869 *SegmentDuration = ent->segmentDuration;
1870 if (ent->mediaTime < 0) {
1871 *MediaTime = 0;
1872 *EditMode = GF_ISOM_EDIT_EMPTY;
1873 return GF_OK;
1874 }
1875 if (ent->mediaRate == 0) {
1876 *MediaTime = ent->mediaTime;
1877 *EditMode = GF_ISOM_EDIT_DWELL;
1878 return GF_OK;
1879 }
1880 *MediaTime = ent->mediaTime;
1881 *EditMode = GF_ISOM_EDIT_NORMAL;
1882 return GF_OK;
1883 }
1884
1885 GF_EXPORT
gf_isom_has_sync_points(GF_ISOFile * the_file,u32 trackNumber)1886 u8 gf_isom_has_sync_points(GF_ISOFile *the_file, u32 trackNumber)
1887 {
1888 GF_TrackBox *trak;
1889
1890 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1891 if (!trak) return 0;
1892 if (trak->Media->information->sampleTable->SyncSample) {
1893 if (!trak->Media->information->sampleTable->SyncSample->nb_entries) return 2;
1894 return 1;
1895 }
1896 return 0;
1897 }
1898
1899 /*returns number of sync points*/
1900 GF_EXPORT
gf_isom_get_sync_point_count(GF_ISOFile * the_file,u32 trackNumber)1901 u32 gf_isom_get_sync_point_count(GF_ISOFile *the_file, u32 trackNumber)
1902 {
1903 GF_TrackBox *trak;
1904 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1905 if (!trak) return 0;
1906 if (trak->Media->information->sampleTable->SyncSample) {
1907 return trak->Media->information->sampleTable->SyncSample->nb_entries;
1908 }
1909 return 0;
1910 }
1911
1912
1913 GF_EXPORT
gf_isom_get_brand_info(GF_ISOFile * movie,u32 * brand,u32 * minorVersion,u32 * AlternateBrandsCount)1914 GF_Err gf_isom_get_brand_info(GF_ISOFile *movie, u32 *brand, u32 *minorVersion, u32 *AlternateBrandsCount)
1915 {
1916 if (!movie || !brand) return GF_BAD_PARAM;
1917 if (!movie->brand) {
1918 *brand = 0;
1919 if (minorVersion) *minorVersion = 0;
1920 if (AlternateBrandsCount) *AlternateBrandsCount = 0;
1921 return GF_OK;
1922 }
1923
1924 *brand = movie->brand->majorBrand;
1925 if (minorVersion) *minorVersion = movie->brand->minorVersion;
1926 if (AlternateBrandsCount) *AlternateBrandsCount = movie->brand->altCount;
1927 return GF_OK;
1928 }
1929
1930 GF_EXPORT
gf_isom_get_alternate_brand(GF_ISOFile * movie,u32 BrandIndex,u32 * brand)1931 GF_Err gf_isom_get_alternate_brand(GF_ISOFile *movie, u32 BrandIndex, u32 *brand)
1932 {
1933 if (!movie || !movie->brand || !brand) return GF_BAD_PARAM;
1934 if (BrandIndex > movie->brand->altCount || !BrandIndex) return GF_BAD_PARAM;
1935 *brand = movie->brand->altBrand[BrandIndex - 1];
1936 return GF_OK;
1937 }
1938
gf_isom_get_sample_padding_bits(GF_ISOFile * the_file,u32 trackNumber,u32 sampleNumber,u8 * NbBits)1939 GF_Err gf_isom_get_sample_padding_bits(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u8 *NbBits)
1940 {
1941 GF_TrackBox *trak;
1942
1943 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1944 if (!trak) return GF_BAD_PARAM;
1945
1946
1947 //Padding info
1948 return stbl_GetPaddingBits(trak->Media->information->sampleTable->PaddingBits,
1949 sampleNumber, NbBits);
1950
1951 }
1952
1953
1954 GF_EXPORT
gf_isom_has_padding_bits(GF_ISOFile * the_file,u32 trackNumber)1955 Bool gf_isom_has_padding_bits(GF_ISOFile *the_file, u32 trackNumber)
1956 {
1957 GF_TrackBox *trak;
1958
1959 trak = gf_isom_get_track_from_file(the_file, trackNumber);
1960 if (!trak) return GF_FALSE;
1961
1962 if (trak->Media->information->sampleTable->PaddingBits) return GF_TRUE;
1963 return GF_FALSE;
1964 }
1965
1966 GF_EXPORT
gf_isom_get_udta_count(GF_ISOFile * movie,u32 trackNumber)1967 u32 gf_isom_get_udta_count(GF_ISOFile *movie, u32 trackNumber)
1968 {
1969 GF_TrackBox *trak;
1970 GF_UserDataBox *udta;
1971 if (!movie || !movie->moov) return 0;
1972
1973 if (trackNumber) {
1974 trak = gf_isom_get_track_from_file(movie, trackNumber);
1975 if (!trak) return 0;
1976 udta = trak->udta;
1977 }
1978 else {
1979 udta = movie->moov->udta;
1980 }
1981 if (udta) return gf_list_count(udta->recordList);
1982 return 0;
1983 }
1984
1985 GF_EXPORT
gf_isom_get_udta_type(GF_ISOFile * movie,u32 trackNumber,u32 udta_idx,u32 * UserDataType,bin128 * UUID)1986 GF_Err gf_isom_get_udta_type(GF_ISOFile *movie, u32 trackNumber, u32 udta_idx, u32 *UserDataType, bin128 *UUID)
1987 {
1988 GF_TrackBox *trak;
1989 GF_UserDataBox *udta;
1990 GF_UserDataMap *map;
1991 if (!movie || !movie->moov || !udta_idx) return GF_BAD_PARAM;
1992
1993 if (trackNumber) {
1994 trak = gf_isom_get_track_from_file(movie, trackNumber);
1995 if (!trak) return GF_OK;
1996 udta = trak->udta;
1997 }
1998 else {
1999 udta = movie->moov->udta;
2000 }
2001 if (!udta) return GF_BAD_PARAM;
2002 if (udta_idx>gf_list_count(udta->recordList)) return GF_BAD_PARAM;
2003 map = (GF_UserDataMap*)gf_list_get(udta->recordList, udta_idx - 1);
2004 if (UserDataType) *UserDataType = map->boxType;
2005 if (UUID) memcpy(*UUID, map->uuid, 16);
2006 return GF_OK;
2007 }
2008
2009 GF_EXPORT
gf_isom_get_user_data_count(GF_ISOFile * movie,u32 trackNumber,u32 UserDataType,bin128 UUID)2010 u32 gf_isom_get_user_data_count(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID)
2011 {
2012 GF_UserDataMap *map;
2013 GF_TrackBox *trak;
2014 GF_UserDataBox *udta;
2015 bin128 t;
2016 u32 i, count;
2017
2018 if (!movie || !movie->moov) return 0;
2019
2020 if (UserDataType == GF_ISOM_BOX_TYPE_UUID) UserDataType = 0;
2021 memset(t, 1, 16);
2022
2023 if (trackNumber) {
2024 trak = gf_isom_get_track_from_file(movie, trackNumber);
2025 if (!trak) return 0;
2026 udta = trak->udta;
2027 }
2028 else {
2029 udta = movie->moov->udta;
2030 }
2031 if (!udta) return 0;
2032
2033 i = 0;
2034 while ((map = (GF_UserDataMap*)gf_list_enum(udta->recordList, &i))) {
2035 count = gf_list_count(map->other_boxes);
2036
2037 if ((map->boxType == GF_ISOM_BOX_TYPE_UUID) && !memcmp(map->uuid, UUID, 16)) return count;
2038 else if (map->boxType == UserDataType) return count;
2039 }
2040 return 0;
2041 }
2042
2043 GF_EXPORT
gf_isom_get_user_data(GF_ISOFile * movie,u32 trackNumber,u32 UserDataType,bin128 UUID,u32 UserDataIndex,char ** userData,u32 * userDataSize)2044 GF_Err gf_isom_get_user_data(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID, u32 UserDataIndex, char **userData, u32 *userDataSize)
2045 {
2046 GF_UserDataMap *map;
2047 GF_UnknownBox *ptr;
2048 GF_BitStream *bs;
2049 u32 i;
2050 bin128 t;
2051 GF_TrackBox *trak;
2052 GF_UserDataBox *udta;
2053
2054 if (!movie || !movie->moov) return GF_BAD_PARAM;
2055
2056 if (trackNumber) {
2057 trak = gf_isom_get_track_from_file(movie, trackNumber);
2058 if (!trak) return GF_BAD_PARAM;
2059 udta = trak->udta;
2060 }
2061 else {
2062 udta = movie->moov->udta;
2063 }
2064 if (!udta) return GF_BAD_PARAM;
2065
2066 if (UserDataType == GF_ISOM_BOX_TYPE_UUID) UserDataType = 0;
2067 memset(t, 1, 16);
2068
2069 if (!userData || !userDataSize || *userData) return GF_BAD_PARAM;
2070
2071 i = 0;
2072 while ((map = (GF_UserDataMap*)gf_list_enum(udta->recordList, &i))) {
2073 if ((map->boxType == GF_ISOM_BOX_TYPE_UUID) && !memcmp(map->uuid, UUID, 16)) goto found;
2074 else if (map->boxType == UserDataType) goto found;
2075
2076 }
2077 return GF_BAD_PARAM;
2078
2079 found:
2080 if (UserDataIndex) {
2081 if (UserDataIndex > gf_list_count(map->other_boxes)) return GF_BAD_PARAM;
2082 ptr = (GF_UnknownBox*)gf_list_get(map->other_boxes, UserDataIndex - 1);
2083
2084 //ok alloc the data
2085 *userData = (char *)gf_malloc(sizeof(char)*ptr->dataSize);
2086 if (!*userData) return GF_OUT_OF_MEM;
2087 memcpy(*userData, ptr->data, sizeof(char)*ptr->dataSize);
2088 *userDataSize = ptr->dataSize;
2089 return GF_OK;
2090 }
2091
2092 //serialize all boxes
2093 bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
2094 i = 0;
2095 while ((ptr = (GF_UnknownBox*)gf_list_enum(map->other_boxes, &i))) {
2096 u32 s = ptr->dataSize + 8;
2097 if (ptr->type == GF_ISOM_BOX_TYPE_UUID) s += 16;
2098
2099 gf_bs_write_u32(bs, s);
2100 gf_bs_write_u32(bs, ptr->type);
2101 if (ptr->type == GF_ISOM_BOX_TYPE_UUID) gf_bs_write_data(bs, (char *)map->uuid, 16);
2102 if (ptr->data) {
2103 gf_bs_write_data(bs, ptr->data, ptr->dataSize);
2104 }
2105 else if (ptr->other_boxes) {
2106 #ifndef GPAC_DISABLE_ISOM_WRITE
2107 gf_isom_box_array_write((GF_Box *)ptr, ptr->other_boxes, bs);
2108 #else
2109 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("ISOBMF: udta is a box-list - cannot export in read-only version of libisom in GPAC\n"));
2110 #endif
2111 }
2112 }
2113 gf_bs_get_content(bs, userData, userDataSize);
2114 gf_bs_del(bs);
2115 return GF_OK;
2116 }
2117
2118 GF_EXPORT
gf_isom_delete(GF_ISOFile * movie)2119 void gf_isom_delete(GF_ISOFile *movie)
2120 {
2121 //free and return;
2122 gf_isom_delete_movie(movie);
2123 }
2124
2125 GF_EXPORT
gf_isom_get_chunks_infos(GF_ISOFile * movie,u32 trackNumber,u32 * dur_min,u32 * dur_avg,u32 * dur_max,u32 * size_min,u32 * size_avg,u32 * size_max)2126 GF_Err gf_isom_get_chunks_infos(GF_ISOFile *movie, u32 trackNumber, u32 *dur_min, u32 *dur_avg, u32 *dur_max, u32 *size_min, u32 *size_avg, u32 *size_max)
2127 {
2128 GF_TrackBox *trak;
2129 u32 i, k, sample_idx, dmin, dmax, smin, smax, tot_chunks;
2130 u64 davg, savg;
2131 GF_SampleToChunkBox *stsc;
2132 GF_TimeToSampleBox *stts;
2133 if (!movie || !trackNumber || !movie->moov) return GF_BAD_PARAM;
2134 trak = gf_isom_get_track_from_file(movie, trackNumber);
2135 if (!trak) return GF_BAD_PARAM;
2136
2137 stsc = trak->Media->information->sampleTable->SampleToChunk;
2138 stts = trak->Media->information->sampleTable->TimeToSample;
2139
2140 dmin = smin = (u32)-1;
2141 dmax = smax = 0;
2142 davg = savg = 0;
2143 sample_idx = 1;
2144 tot_chunks = 0;
2145 for (i = 0; i<stsc->nb_entries; i++) {
2146 u32 nb_chunk = 0;
2147 while (1) {
2148 u32 chunk_dur = 0;
2149 u32 chunk_size = 0;
2150 for (k = 0; k<stsc->entries[i].samplesPerChunk; k++) {
2151 u64 dts;
2152 u32 dur;
2153 u32 size;
2154 stbl_GetSampleDTS_and_Duration(stts, k + sample_idx, &dts, &dur);
2155 chunk_dur += dur;
2156 stbl_GetSampleSize(trak->Media->information->sampleTable->SampleSize, k + sample_idx, &size);
2157 chunk_size += size;
2158
2159 }
2160 if (dmin>chunk_dur) dmin = chunk_dur;
2161 if (dmax<chunk_dur) dmax = chunk_dur;
2162 davg += chunk_dur;
2163 if (smin>chunk_size) smin = chunk_size;
2164 if (smax<chunk_size) smax = chunk_size;
2165 savg += chunk_size;
2166
2167 tot_chunks++;
2168 sample_idx += stsc->entries[i].samplesPerChunk;
2169 if (i + 1 == stsc->nb_entries) break;
2170 nb_chunk++;
2171 if (stsc->entries[i].firstChunk + nb_chunk == stsc->entries[i + 1].firstChunk) break;
2172 }
2173 }
2174 if (tot_chunks) {
2175 davg /= tot_chunks;
2176 savg /= tot_chunks;
2177 }
2178 if (dur_min) *dur_min = dmin;
2179 if (dur_avg) *dur_avg = (u32)davg;
2180 if (dur_max) *dur_max = dmax;
2181
2182 if (size_min) *size_min = smin;
2183 if (size_avg) *size_avg = (u32)savg;
2184 if (size_max) *size_max = smax;
2185 return GF_OK;
2186 }
2187
2188 GF_EXPORT
gf_isom_get_sample_fragment_count(GF_ISOFile * the_file,u32 trackNumber,u32 sampleNumber)2189 u32 gf_isom_get_sample_fragment_count(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber)
2190 {
2191 GF_TrackBox *trak;
2192 trak = gf_isom_get_track_from_file(the_file, trackNumber);
2193 if (!trak) return 0;
2194
2195 //Padding info
2196 return stbl_GetSampleFragmentCount(trak->Media->information->sampleTable->Fragments, sampleNumber);
2197 }
2198
2199 GF_EXPORT
gf_isom_get_sample_fragment_size(GF_ISOFile * the_file,u32 trackNumber,u32 sampleNumber,u32 FragmentIndex)2200 u16 gf_isom_get_sample_fragment_size(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 FragmentIndex)
2201 {
2202 GF_TrackBox *trak;
2203 trak = gf_isom_get_track_from_file(the_file, trackNumber);
2204 if (!trak || !FragmentIndex) return 0;
2205
2206 //Padding info
2207 return stbl_GetSampleFragmentSize(trak->Media->information->sampleTable->Fragments, sampleNumber, FragmentIndex);
2208 }
2209
2210
2211 GF_EXPORT
gf_isom_get_fragment_defaults(GF_ISOFile * the_file,u32 trackNumber,u32 * defaultDuration,u32 * defaultSize,u32 * defaultDescriptionIndex,u32 * defaultRandomAccess,u8 * defaultPadding,u16 * defaultDegradationPriority)2212 GF_Err gf_isom_get_fragment_defaults(GF_ISOFile *the_file, u32 trackNumber,
2213 u32 *defaultDuration, u32 *defaultSize, u32 *defaultDescriptionIndex,
2214 u32 *defaultRandomAccess, u8 *defaultPadding, u16 *defaultDegradationPriority)
2215 {
2216 GF_TrackBox *trak;
2217 GF_StscEntry *sc_ent;
2218 u32 i, j, maxValue, value;
2219 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2220 GF_TrackExtendsBox *trex;
2221 #endif
2222 GF_SampleTableBox *stbl;
2223 trak = gf_isom_get_track_from_file(the_file, trackNumber);
2224 if (!trak) return GF_BAD_PARAM;
2225
2226 /*if trex is already set, restore flags*/
2227 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2228 trex = the_file->moov->mvex ? GetTrex(the_file->moov, gf_isom_get_track_id(the_file, trackNumber)) : NULL;
2229 if (trex) {
2230 trex->track = trak;
2231
2232 if (defaultDuration) *defaultDuration = trex->def_sample_duration;
2233 if (defaultSize) *defaultSize = trex->def_sample_size;
2234 if (defaultDescriptionIndex) *defaultDescriptionIndex = trex->def_sample_desc_index;
2235 if (defaultRandomAccess) *defaultRandomAccess = GF_ISOM_GET_FRAG_SYNC(trex->def_sample_flags);
2236 if (defaultPadding) *defaultPadding = GF_ISOM_GET_FRAG_PAD(trex->def_sample_flags);
2237 if (defaultDegradationPriority) *defaultDegradationPriority = GF_ISOM_GET_FRAG_DEG(trex->def_sample_flags);
2238 return GF_OK;
2239 }
2240 #endif
2241
2242
2243 stbl = trak->Media->information->sampleTable;
2244 //duration
2245 if (defaultDuration) {
2246 maxValue = value = 0;
2247 for (i = 0; i<stbl->TimeToSample->nb_entries; i++) {
2248 if (stbl->TimeToSample->entries[i].sampleCount>maxValue) {
2249 value = stbl->TimeToSample->entries[i].sampleDelta;
2250 maxValue = stbl->TimeToSample->entries[i].sampleCount;
2251 }
2252 }
2253 *defaultDuration = value;
2254 }
2255 //size
2256 if (defaultSize) {
2257 *defaultSize = stbl->SampleSize->sampleSize;
2258 }
2259 //descIndex
2260 if (defaultDescriptionIndex) {
2261 GF_SampleToChunkBox *stsc = stbl->SampleToChunk;
2262 maxValue = value = 0;
2263 for (i = 0; i<stsc->nb_entries; i++) {
2264 sc_ent = &stsc->entries[i];
2265 if ((sc_ent->nextChunk - sc_ent->firstChunk) * sc_ent->samplesPerChunk > maxValue) {
2266 value = sc_ent->sampleDescriptionIndex;
2267 maxValue = (sc_ent->nextChunk - sc_ent->firstChunk) * sc_ent->samplesPerChunk;
2268 }
2269 }
2270 *defaultDescriptionIndex = value ? value : 1;
2271 }
2272 //RAP
2273 if (defaultRandomAccess) {
2274 //no sync table is ALL RAP
2275 *defaultRandomAccess = stbl->SyncSample ? 0 : 1;
2276 if (stbl->SyncSample
2277 && (stbl->SyncSample->nb_entries >= stbl->SampleSize->sampleCount / 2)) {
2278 *defaultRandomAccess = 1;
2279 }
2280 }
2281 //defaultPadding
2282 if (defaultPadding) {
2283 *defaultPadding = 0;
2284 if (stbl->PaddingBits) {
2285 maxValue = 0;
2286 for (i = 0; i<stbl->PaddingBits->SampleCount; i++) {
2287 value = 0;
2288 for (j = 0; j<stbl->PaddingBits->SampleCount; j++) {
2289 if (stbl->PaddingBits->padbits[i] == stbl->PaddingBits->padbits[j]) {
2290 value++;
2291 }
2292 }
2293 if (value>maxValue) {
2294 maxValue = value;
2295 *defaultPadding = stbl->PaddingBits->padbits[i];
2296 }
2297 }
2298 }
2299 }
2300 //defaultDegradationPriority
2301 if (defaultDegradationPriority) {
2302 *defaultDegradationPriority = 0;
2303 if (stbl->DegradationPriority) {
2304 maxValue = 0;
2305 for (i = 0; i<stbl->DegradationPriority->nb_entries; i++) {
2306 value = 0;
2307 for (j = 0; j<stbl->DegradationPriority->nb_entries; j++) {
2308 if (stbl->DegradationPriority->priorities[i] == stbl->DegradationPriority->priorities[j]) {
2309 value++;
2310 }
2311 }
2312 if (value>maxValue) {
2313 maxValue = value;
2314 *defaultDegradationPriority = stbl->DegradationPriority->priorities[i];
2315 }
2316 }
2317 }
2318 }
2319 return GF_OK;
2320 }
2321
2322
2323 GF_EXPORT
gf_isom_refresh_fragmented(GF_ISOFile * movie,u64 * MissingBytes,const char * new_location)2324 GF_Err gf_isom_refresh_fragmented(GF_ISOFile *movie, u64 *MissingBytes, const char *new_location)
2325 {
2326 #ifdef GPAC_DISABLE_ISOM_FRAGMENTS
2327 return GF_NOT_SUPPORTED;
2328 #else
2329 u64 prevsize, size;
2330 u32 i;
2331 if (!movie || !movie->movieFileMap || !movie->moov || !movie->moov->mvex) return GF_BAD_PARAM;
2332 if (movie->openMode != GF_ISOM_OPEN_READ) return GF_BAD_PARAM;
2333
2334 /*refresh size*/
2335 size = movie->movieFileMap ? gf_bs_get_size(movie->movieFileMap->bs) : 0;
2336
2337 if (new_location) {
2338 Bool delete_map;
2339 GF_DataMap *previous_movie_fileMap_address = movie->movieFileMap;
2340 GF_Err e;
2341
2342 e = gf_isom_datamap_new(new_location, NULL, GF_ISOM_DATA_MAP_READ_ONLY, &movie->movieFileMap);
2343 if (e) {
2344 movie->movieFileMap = previous_movie_fileMap_address;
2345 return e;
2346 }
2347
2348 delete_map = (previous_movie_fileMap_address != NULL ? GF_TRUE : GF_FALSE);
2349 for (i = 0; i<gf_list_count(movie->moov->trackList); i++) {
2350 GF_TrackBox *trak = (GF_TrackBox *)gf_list_get(movie->moov->trackList, i);
2351 if (trak->Media->information->dataHandler == previous_movie_fileMap_address) {
2352 //reaasign for later destruction
2353 trak->Media->information->scalableDataHandler = movie->movieFileMap;
2354 //reassign for Media_GetSample function
2355 trak->Media->information->dataHandler = movie->movieFileMap;
2356 }
2357 else if (trak->Media->information->scalableDataHandler == previous_movie_fileMap_address) {
2358 delete_map = GF_FALSE;
2359 }
2360 }
2361 if (delete_map) {
2362 gf_isom_datamap_del(previous_movie_fileMap_address);
2363 }
2364 }
2365
2366 prevsize = gf_bs_get_refreshed_size(movie->movieFileMap->bs);
2367 if (prevsize == size) return GF_OK;
2368
2369 //ok parse root boxes
2370 return gf_isom_parse_movie_boxes(movie, MissingBytes, GF_TRUE);
2371 #endif
2372 }
2373
2374 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2375 GF_EXPORT
gf_isom_set_single_moof_mode(GF_ISOFile * movie,Bool mode)2376 void gf_isom_set_single_moof_mode(GF_ISOFile *movie, Bool mode)
2377 {
2378 movie->single_moof_mode = mode;
2379 }
2380 #endif
2381
2382 GF_EXPORT
gf_isom_reset_data_offset(GF_ISOFile * movie,u64 * top_box_start)2383 GF_Err gf_isom_reset_data_offset(GF_ISOFile *movie, u64 *top_box_start)
2384 {
2385 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2386 if (!movie || !movie->moov) return GF_BAD_PARAM;
2387 *top_box_start = movie->current_top_box_start;
2388 movie->current_top_box_start = 0;
2389 if (movie->moov->mvex && movie->single_moof_mode) {
2390 movie->single_moof_state = 0;
2391 }
2392 #endif
2393 return GF_OK;
2394 }
2395
2396 #define RECREATE_BOX(_a, __cast) \
2397 if (_a) { \
2398 type = _a->type;\
2399 gf_isom_box_del((GF_Box *)_a);\
2400 _a = __cast gf_isom_box_new(type);\
2401 }\
2402
2403
2404 GF_EXPORT
gf_isom_reset_tables(GF_ISOFile * movie,Bool reset_sample_count)2405 GF_Err gf_isom_reset_tables(GF_ISOFile *movie, Bool reset_sample_count)
2406 {
2407 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2408 u32 i, j;
2409 GF_Box *a;
2410
2411 if (!movie || !movie->moov || !movie->moov->mvex) return GF_BAD_PARAM;
2412 for (i = 0; i<gf_list_count(movie->moov->trackList); i++) {
2413 GF_TrackBox *trak = (GF_TrackBox *)gf_list_get(movie->moov->trackList, i);
2414
2415 u32 type, dur;
2416 u64 dts;
2417 GF_SampleTableBox *stbl = trak->Media->information->sampleTable;
2418
2419 trak->sample_count_at_seg_start += stbl->SampleSize->sampleCount;
2420 if (trak->sample_count_at_seg_start) {
2421 GF_Err e;
2422 e = stbl_GetSampleDTS_and_Duration(stbl->TimeToSample, stbl->SampleSize->sampleCount, &dts, &dur);
2423 if (e == GF_OK) {
2424 trak->dts_at_seg_start += dts + dur;
2425 }
2426 }
2427
2428 RECREATE_BOX(stbl->ChunkOffset, (GF_Box *));
2429 RECREATE_BOX(stbl->CompositionOffset, (GF_CompositionOffsetBox *));
2430 RECREATE_BOX(stbl->DegradationPriority, (GF_DegradationPriorityBox *));
2431 RECREATE_BOX(stbl->PaddingBits, (GF_PaddingBitsBox *));
2432 RECREATE_BOX(stbl->SampleDep, (GF_SampleDependencyTypeBox *));
2433 RECREATE_BOX(stbl->SampleSize, (GF_SampleSizeBox *));
2434 RECREATE_BOX(stbl->SampleToChunk, (GF_SampleToChunkBox *));
2435 RECREATE_BOX(stbl->ShadowSync, (GF_ShadowSyncBox *));
2436 RECREATE_BOX(stbl->SyncSample, (GF_SyncSampleBox *));
2437 RECREATE_BOX(stbl->TimeToSample, (GF_TimeToSampleBox *));
2438
2439 gf_isom_box_array_del(stbl->sai_offsets);
2440 stbl->sai_offsets = NULL;
2441
2442 gf_isom_box_array_del(stbl->sai_sizes);
2443 stbl->sai_sizes = NULL;
2444
2445 gf_isom_box_array_del(stbl->sampleGroups);
2446 stbl->sampleGroups = NULL;
2447
2448 j = stbl->nb_sgpd_in_stbl;
2449 while ((a = (GF_Box *)gf_list_enum(stbl->sampleGroupsDescription, &j))) {
2450 gf_isom_box_del(a);
2451 j--;
2452 gf_list_rem(stbl->sampleGroupsDescription, j);
2453 }
2454
2455 j = stbl->nb_other_boxes_in_stbl;
2456 while ((a = (GF_Box *)gf_list_enum(stbl->other_boxes, &j))) {
2457 gf_isom_box_del(a);
2458 j--;
2459 gf_list_rem(stbl->other_boxes, j);
2460 }
2461
2462 if (reset_sample_count) {
2463 trak->Media->information->sampleTable->SampleSize->sampleCount = 0;
2464 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2465 trak->sample_count_at_seg_start = 0;
2466 #endif
2467 }
2468
2469 }
2470
2471 #endif
2472 return GF_OK;
2473
2474 }
2475
2476 GF_EXPORT
gf_isom_release_segment(GF_ISOFile * movie,Bool reset_tables)2477 GF_Err gf_isom_release_segment(GF_ISOFile *movie, Bool reset_tables)
2478 {
2479 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2480 u32 i, j, base_track_sample_count;
2481 Bool has_scalable;
2482 GF_Box *a;
2483 if (!movie || !movie->moov || !movie->moov->mvex) return GF_BAD_PARAM;
2484 has_scalable = gf_isom_needs_layer_reconstruction(movie);
2485 base_track_sample_count = 0;
2486 for (i = 0; i<gf_list_count(movie->moov->trackList); i++) {
2487 GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
2488 trak->first_traf_merged = GF_FALSE;
2489 if (trak->Media->information->dataHandler == movie->movieFileMap) {
2490 trak->Media->information->dataHandler = NULL;
2491 }
2492 if (trak->Media->information->scalableDataHandler == movie->movieFileMap) {
2493 trak->Media->information->scalableDataHandler = NULL;
2494 }
2495 else {
2496 if (trak->Media->information->scalableDataHandler == trak->Media->information->dataHandler)
2497 trak->Media->information->dataHandler = NULL;
2498
2499 gf_isom_datamap_del(trak->Media->information->scalableDataHandler);
2500 trak->Media->information->scalableDataHandler = NULL;
2501 }
2502
2503
2504 if (reset_tables) {
2505 u32 type, dur;
2506 u64 dts;
2507 GF_SampleTableBox *stbl = trak->Media->information->sampleTable;
2508
2509 if (has_scalable) {
2510 //check if the base reference is in the file - if not, do not consider the track is scalable.
2511 if (gf_isom_get_reference_count(movie, i + 1, GF_ISOM_REF_BASE) > 0) {
2512 u32 on_track = 0;
2513 GF_TrackBox *base;
2514 gf_isom_get_reference(movie, i + 1, GF_ISOM_REF_BASE, 1, &on_track);
2515
2516 base = gf_isom_get_track_from_file(movie, on_track);
2517 if (!base) {
2518 base_track_sample_count = 0;
2519 }
2520 else {
2521 base_track_sample_count = base->Media->information->sampleTable->SampleSize->sampleCount;
2522 }
2523 }
2524 }
2525
2526 trak->sample_count_at_seg_start += base_track_sample_count ? base_track_sample_count : stbl->SampleSize->sampleCount;
2527
2528 if (trak->sample_count_at_seg_start) {
2529 GF_Err e;
2530 e = stbl_GetSampleDTS_and_Duration(stbl->TimeToSample, stbl->SampleSize->sampleCount, &dts, &dur);
2531 if (e == GF_OK) {
2532 trak->dts_at_seg_start += dts + dur;
2533 }
2534 }
2535
2536 RECREATE_BOX(stbl->ChunkOffset, (GF_Box *));
2537 RECREATE_BOX(stbl->CompositionOffset, (GF_CompositionOffsetBox *));
2538 RECREATE_BOX(stbl->DegradationPriority, (GF_DegradationPriorityBox *));
2539 RECREATE_BOX(stbl->PaddingBits, (GF_PaddingBitsBox *));
2540 RECREATE_BOX(stbl->SampleDep, (GF_SampleDependencyTypeBox *));
2541 RECREATE_BOX(stbl->SampleSize, (GF_SampleSizeBox *));
2542 RECREATE_BOX(stbl->SampleToChunk, (GF_SampleToChunkBox *));
2543 RECREATE_BOX(stbl->ShadowSync, (GF_ShadowSyncBox *));
2544 RECREATE_BOX(stbl->SyncSample, (GF_SyncSampleBox *));
2545 RECREATE_BOX(stbl->TimeToSample, (GF_TimeToSampleBox *));
2546
2547 gf_isom_box_array_del(stbl->sai_offsets);
2548 stbl->sai_offsets = NULL;
2549
2550 gf_isom_box_array_del(stbl->sai_sizes);
2551 stbl->sai_sizes = NULL;
2552
2553 gf_isom_box_array_del(stbl->sampleGroups);
2554 stbl->sampleGroups = NULL;
2555
2556 j = stbl->nb_sgpd_in_stbl;
2557 while ((a = (GF_Box *)gf_list_enum(stbl->sampleGroupsDescription, &j))) {
2558 gf_isom_box_del(a);
2559 j--;
2560 gf_list_rem(stbl->sampleGroupsDescription, j);
2561 }
2562
2563
2564 j = stbl->nb_other_boxes_in_stbl;
2565 while ((a = (GF_Box *)gf_list_enum(stbl->other_boxes, &j))) {
2566 gf_isom_box_del(a);
2567 j--;
2568 gf_list_rem(stbl->other_boxes, j);
2569 }
2570 }
2571
2572
2573 j = 0;
2574 while ((a = (GF_Box *)gf_list_enum(movie->moov->other_boxes, &j))) {
2575 if (a->type == GF_ISOM_BOX_TYPE_PSSH) {
2576 gf_isom_box_del(a);
2577 j--;
2578 gf_list_rem(movie->moov->other_boxes, j);
2579 }
2580 }
2581 }
2582
2583 gf_isom_datamap_del(movie->movieFileMap);
2584 movie->movieFileMap = NULL;
2585 #endif
2586 return GF_OK;
2587 }
2588
2589 GF_EXPORT
gf_isom_open_segment(GF_ISOFile * movie,const char * fileName,u64 start_range,u64 end_range,u32 flags)2590 GF_Err gf_isom_open_segment(GF_ISOFile *movie, const char *fileName, u64 start_range, u64 end_range, u32 flags)
2591 {
2592 #ifdef GPAC_DISABLE_ISOM_FRAGMENTS
2593 return GF_NOT_SUPPORTED;
2594 #else
2595 u64 MissingBytes;
2596 GF_Err e;
2597 u32 i;
2598 Bool segment_map_assigned = GF_FALSE;
2599 Bool is_scalable_segment = (flags & GF_ISOM_SEGMENT_SCALABLE_FLAG) ? GF_TRUE : GF_FALSE;
2600 Bool no_order_check = (flags & GF_ISOM_SEGMENT_NO_ORDER_FLAG) ? GF_TRUE : GF_FALSE;
2601 GF_DataMap *tmp = NULL;
2602 GF_DataMap *orig_file_map = NULL;
2603 if (!movie || !movie->moov || !movie->moov->mvex) return GF_BAD_PARAM;
2604 if (movie->openMode != GF_ISOM_OPEN_READ) return GF_BAD_PARAM;
2605
2606 /*this is a scalable segment - use a temp data map for the associated track(s) but do NOT touch the movie file map*/
2607 if (is_scalable_segment) {
2608 tmp = NULL;
2609 e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_READ_ONLY, &tmp);
2610 if (e) return e;
2611
2612 orig_file_map = movie->movieFileMap;
2613 movie->movieFileMap = tmp;
2614 }
2615 else {
2616 if (movie->movieFileMap)
2617 gf_isom_release_segment(movie, GF_FALSE);
2618
2619 e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_READ_ONLY, &movie->movieFileMap);
2620 if (e) return e;
2621 }
2622 movie->current_top_box_start = 0;
2623
2624 if (end_range > start_range) {
2625 gf_bs_seek(movie->movieFileMap->bs, end_range + 1);
2626 gf_bs_truncate(movie->movieFileMap->bs);
2627 gf_bs_seek(movie->movieFileMap->bs, start_range);
2628 movie->current_top_box_start = start_range;
2629 }
2630
2631 for (i = 0; i<gf_list_count(movie->moov->trackList); i++) {
2632 GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
2633
2634 if (!is_scalable_segment) {
2635 /*reset data handler to new segment*/
2636 if (trak->Media->information->dataHandler == NULL) {
2637 trak->Media->information->dataHandler = movie->movieFileMap;
2638 }
2639 }
2640 else {
2641 trak->present_in_scalable_segment = GF_FALSE;
2642 }
2643 }
2644 if (no_order_check) movie->NextMoofNumber = 0;
2645
2646
2647 //ok parse root boxes
2648 e = gf_isom_parse_movie_boxes(movie, &MissingBytes, GF_TRUE);
2649
2650 if (!is_scalable_segment)
2651 return e;
2652
2653 for (i = 0; i<gf_list_count(movie->moov->trackList); i++) {
2654 GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
2655 if (trak->present_in_scalable_segment) {
2656 /*store the temp dataHandler into scalableDataHandler so that it will not be destroyed
2657 if we append another representation - destruction of this data handler is done in release_segment*/
2658 trak->Media->information->scalableDataHandler = tmp;
2659 if (!segment_map_assigned) {
2660 trak->Media->information->scalableDataHandler = tmp;
2661 segment_map_assigned = GF_TRUE;
2662 }
2663 //and update the regular dataHandler for the Media_GetSample function
2664 trak->Media->information->dataHandler = tmp;
2665 }
2666 }
2667 movie->movieFileMap = orig_file_map;
2668 return e;
2669 #endif
2670 }
2671
2672 GF_EXPORT
gf_isom_get_highest_track_in_scalable_segment(GF_ISOFile * movie,u32 for_base_track)2673 u32 gf_isom_get_highest_track_in_scalable_segment(GF_ISOFile *movie, u32 for_base_track)
2674 {
2675 #ifdef GPAC_DISABLE_ISOM_FRAGMENTS
2676 return 0;
2677 #else
2678 s32 max_ref;
2679 u32 i, j, track_id;
2680
2681 max_ref = 0;
2682 track_id = 0;
2683 for (i = 0; i<gf_list_count(movie->moov->trackList); i++) {
2684 s32 ref;
2685 GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
2686 if (!trak->present_in_scalable_segment) continue;
2687
2688 ref = gf_isom_get_reference_count(movie, i + 1, GF_ISOM_REF_SCAL);
2689 if (ref <= 0) continue;
2690 if (ref <= max_ref) continue;
2691
2692 for (j = 0; j< (u32)ref; j++) {
2693 u32 on_track = 0;
2694 gf_isom_get_reference(movie, i + 1, GF_ISOM_REF_SCAL, j + 1, &on_track);
2695 if (on_track == for_base_track) {
2696 max_ref = ref;
2697 track_id = trak->Header->trackID;
2698 }
2699 }
2700 }
2701 return track_id;
2702 #endif
2703 }
2704
2705
2706 GF_EXPORT
gf_isom_text_set_streaming_mode(GF_ISOFile * movie,Bool do_convert)2707 GF_Err gf_isom_text_set_streaming_mode(GF_ISOFile *movie, Bool do_convert)
2708 {
2709 if (!movie) return GF_BAD_PARAM;
2710 movie->convert_streaming_text = do_convert;
2711 return GF_OK;
2712 }
2713
2714
2715 GF_EXPORT
gf_isom_get_generic_sample_description(GF_ISOFile * movie,u32 trackNumber,u32 StreamDescriptionIndex)2716 GF_GenericSampleDescription *gf_isom_get_generic_sample_description(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex)
2717 {
2718 GF_GenericVisualSampleEntryBox *entry;
2719 GF_GenericAudioSampleEntryBox *gena;
2720 GF_GenericSampleEntryBox *genm;
2721 GF_TrackBox *trak;
2722 GF_GenericSampleDescription *udesc;
2723 trak = gf_isom_get_track_from_file(movie, trackNumber);
2724 if (!trak || !StreamDescriptionIndex || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable) return 0;
2725
2726 entry = (GF_GenericVisualSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, StreamDescriptionIndex - 1);
2727 //no entry or MPEG entry:
2728 if (!entry || IsMP4Description(entry->type)) return NULL;
2729 //if we handle the description return false
2730 switch (entry->type) {
2731 case GF_ISOM_SUBTYPE_3GP_AMR:
2732 case GF_ISOM_SUBTYPE_3GP_AMR_WB:
2733 case GF_ISOM_SUBTYPE_3GP_EVRC:
2734 case GF_ISOM_SUBTYPE_3GP_QCELP:
2735 case GF_ISOM_SUBTYPE_3GP_SMV:
2736 case GF_ISOM_SUBTYPE_3GP_H263:
2737 return NULL;
2738 case GF_ISOM_BOX_TYPE_GNRV:
2739 GF_SAFEALLOC(udesc, GF_GenericSampleDescription);
2740 if (!udesc) return NULL;
2741 if (entry->EntryType == GF_ISOM_BOX_TYPE_UUID) {
2742 memcpy(udesc->UUID, ((GF_UUIDBox*)entry)->uuid, sizeof(bin128));
2743 }
2744 else {
2745 udesc->codec_tag = entry->EntryType;
2746 }
2747 udesc->version = entry->version;
2748 udesc->revision = entry->revision;
2749 udesc->vendor_code = entry->vendor;
2750 udesc->temporal_quality = entry->temporal_quality;
2751 udesc->spatial_quality = entry->spatial_quality;
2752 udesc->width = entry->Width;
2753 udesc->height = entry->Height;
2754 udesc->h_res = entry->horiz_res;
2755 udesc->v_res = entry->vert_res;
2756 strcpy(udesc->compressor_name, entry->compressor_name);
2757 udesc->depth = entry->bit_depth;
2758 udesc->color_table_index = entry->color_table_index;
2759 if (entry->data_size) {
2760 udesc->extension_buf_size = entry->data_size;
2761 udesc->extension_buf = (char*)gf_malloc(sizeof(char) * entry->data_size);
2762 if (!udesc->extension_buf) {
2763 gf_free(udesc);
2764 return NULL;
2765 }
2766 memcpy(udesc->extension_buf, entry->data, entry->data_size);
2767 }
2768 return udesc;
2769 case GF_ISOM_BOX_TYPE_GNRA:
2770 gena = (GF_GenericAudioSampleEntryBox *)entry;
2771 GF_SAFEALLOC(udesc, GF_GenericSampleDescription);
2772 if (!udesc) return NULL;
2773 if (gena->EntryType == GF_ISOM_BOX_TYPE_UUID) {
2774 memcpy(udesc->UUID, ((GF_UUIDBox*)gena)->uuid, sizeof(bin128));
2775 }
2776 else {
2777 udesc->codec_tag = gena->EntryType;
2778 }
2779 udesc->version = gena->version;
2780 udesc->revision = gena->revision;
2781 udesc->vendor_code = gena->vendor;
2782 udesc->samplerate = gena->samplerate_hi;
2783 udesc->bits_per_sample = gena->bitspersample;
2784 udesc->nb_channels = gena->channel_count;
2785 if (gena->data_size) {
2786 udesc->extension_buf_size = gena->data_size;
2787 udesc->extension_buf = (char*)gf_malloc(sizeof(char) * gena->data_size);
2788 if (!udesc->extension_buf) {
2789 gf_free(udesc);
2790 return NULL;
2791 }
2792 memcpy(udesc->extension_buf, gena->data, gena->data_size);
2793 }
2794 return udesc;
2795 case GF_ISOM_BOX_TYPE_GNRM:
2796 genm = (GF_GenericSampleEntryBox *)entry;
2797 GF_SAFEALLOC(udesc, GF_GenericSampleDescription);
2798 if (!udesc) return NULL;
2799 if (genm->EntryType == GF_ISOM_BOX_TYPE_UUID) {
2800 memcpy(udesc->UUID, ((GF_UUIDBox*)genm)->uuid, sizeof(bin128));
2801 }
2802 else {
2803 udesc->codec_tag = genm->EntryType;
2804 }
2805 if (genm->data_size) {
2806 udesc->extension_buf_size = genm->data_size;
2807 udesc->extension_buf = (char*)gf_malloc(sizeof(char) * genm->data_size);
2808 if (!udesc->extension_buf) {
2809 gf_free(udesc);
2810 return NULL;
2811 }
2812 memcpy(udesc->extension_buf, genm->data, genm->data_size);
2813 }
2814 return udesc;
2815 }
2816 return NULL;
2817 }
2818
2819 GF_EXPORT
gf_isom_get_visual_info(GF_ISOFile * movie,u32 trackNumber,u32 StreamDescriptionIndex,u32 * Width,u32 * Height)2820 GF_Err gf_isom_get_visual_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 *Width, u32 *Height)
2821 {
2822 GF_TrackBox *trak;
2823 GF_SampleEntryBox *entry;
2824 GF_SampleDescriptionBox *stsd;
2825
2826 trak = gf_isom_get_track_from_file(movie, trackNumber);
2827 if (!trak) return GF_BAD_PARAM;
2828
2829 stsd = trak->Media->information->sampleTable->SampleDescription;
2830 if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
2831 if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->other_boxes)) return movie->LastError = GF_BAD_PARAM;
2832
2833 entry = (GF_SampleEntryBox *)gf_list_get(stsd->other_boxes, StreamDescriptionIndex - 1);
2834 //no support for generic sample entries (eg, no MPEG4 descriptor)
2835 if (entry == NULL) return GF_BAD_PARAM;
2836
2837 //valid for MPEG visual, JPG and 3GPP H263
2838 switch (entry->type) {
2839 case GF_ISOM_BOX_TYPE_ENCV:
2840 case GF_ISOM_BOX_TYPE_MP4V:
2841 case GF_ISOM_SUBTYPE_3GP_H263:
2842 case GF_ISOM_BOX_TYPE_AVC1:
2843 case GF_ISOM_BOX_TYPE_AVC2:
2844 case GF_ISOM_BOX_TYPE_AVC3:
2845 case GF_ISOM_BOX_TYPE_AVC4:
2846 case GF_ISOM_BOX_TYPE_SVC1:
2847 case GF_ISOM_BOX_TYPE_GNRV:
2848 case GF_ISOM_BOX_TYPE_HVC1:
2849 case GF_ISOM_BOX_TYPE_HEV1:
2850 case GF_ISOM_BOX_TYPE_HVC2:
2851 case GF_ISOM_BOX_TYPE_HEV2:
2852 case GF_ISOM_BOX_TYPE_LHE1:
2853 case GF_ISOM_BOX_TYPE_LHV1:
2854 case GF_ISOM_BOX_TYPE_HVT1:
2855 *Width = ((GF_VisualSampleEntryBox*)entry)->Width;
2856 *Height = ((GF_VisualSampleEntryBox*)entry)->Height;
2857 return GF_OK;
2858 default:
2859 if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_SCENE) {
2860 *Width = trak->Header->width >> 16;
2861 *Height = trak->Header->height >> 16;
2862 return GF_OK;
2863 }
2864 return GF_BAD_PARAM;
2865 }
2866 }
2867
2868 GF_EXPORT
gf_isom_get_audio_info(GF_ISOFile * movie,u32 trackNumber,u32 StreamDescriptionIndex,u32 * SampleRate,u32 * Channels,u8 * bitsPerSample)2869 GF_Err gf_isom_get_audio_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 *SampleRate, u32 *Channels, u8 *bitsPerSample)
2870 {
2871 GF_TrackBox *trak;
2872 GF_SampleEntryBox *entry;
2873 GF_SampleDescriptionBox *stsd;
2874
2875 trak = gf_isom_get_track_from_file(movie, trackNumber);
2876 if (!trak) return GF_BAD_PARAM;
2877
2878 stsd = trak->Media->information->sampleTable->SampleDescription;
2879 if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
2880 if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->other_boxes)) return movie->LastError = GF_BAD_PARAM;
2881
2882 entry = (GF_SampleEntryBox *)gf_list_get(stsd->other_boxes, StreamDescriptionIndex - 1);
2883 //no support for generic sample entries (eg, no MPEG4 descriptor)
2884 if (entry == NULL) return GF_BAD_PARAM;
2885
2886 switch (entry->type) {
2887 case GF_ISOM_BOX_TYPE_ENCA:
2888 case GF_ISOM_BOX_TYPE_MP4A:
2889 case GF_ISOM_SUBTYPE_3GP_AMR:
2890 case GF_ISOM_SUBTYPE_3GP_AMR_WB:
2891 case GF_ISOM_SUBTYPE_3GP_EVRC:
2892 case GF_ISOM_SUBTYPE_3GP_QCELP:
2893 case GF_ISOM_SUBTYPE_3GP_SMV:
2894 case GF_ISOM_BOX_TYPE_AC3:
2895 case GF_ISOM_BOX_TYPE_GNRA:
2896 if (SampleRate) (*SampleRate) = ((GF_AudioSampleEntryBox*)entry)->samplerate_hi;
2897 if (Channels) (*Channels) = ((GF_AudioSampleEntryBox*)entry)->channel_count;
2898 if (bitsPerSample) (*bitsPerSample) = (u8)((GF_AudioSampleEntryBox*)entry)->bitspersample;
2899 return GF_OK;
2900 default:
2901 return GF_BAD_PARAM;
2902 }
2903 }
2904
2905 GF_EXPORT
gf_isom_get_pixel_aspect_ratio(GF_ISOFile * movie,u32 trackNumber,u32 StreamDescriptionIndex,u32 * hSpacing,u32 * vSpacing)2906 GF_Err gf_isom_get_pixel_aspect_ratio(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 *hSpacing, u32 *vSpacing)
2907 {
2908 GF_TrackBox *trak;
2909 GF_VisualSampleEntryBox *entry;
2910 GF_SampleDescriptionBox *stsd;
2911
2912 trak = gf_isom_get_track_from_file(movie, trackNumber);
2913 if (!trak || !hSpacing || !vSpacing) return GF_BAD_PARAM;
2914 *hSpacing = 1;
2915 *vSpacing = 1;
2916
2917 stsd = trak->Media->information->sampleTable->SampleDescription;
2918 if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
2919 if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->other_boxes)) return movie->LastError = GF_BAD_PARAM;
2920
2921 entry = (GF_VisualSampleEntryBox *)gf_list_get(stsd->other_boxes, StreamDescriptionIndex - 1);
2922 //no support for generic sample entries (eg, no MPEG4 descriptor)
2923 if (entry == NULL) return GF_OK;
2924
2925 //valid for MPEG visual, JPG and 3GPP H263
2926 switch (entry->type) {
2927 case GF_ISOM_BOX_TYPE_ENCV:
2928 case GF_ISOM_BOX_TYPE_MP4V:
2929 case GF_ISOM_SUBTYPE_3GP_H263:
2930 case GF_ISOM_BOX_TYPE_AVC1:
2931 case GF_ISOM_BOX_TYPE_AVC2:
2932 case GF_ISOM_BOX_TYPE_AVC3:
2933 case GF_ISOM_BOX_TYPE_AVC4:
2934 case GF_ISOM_BOX_TYPE_SVC1:
2935 case GF_ISOM_BOX_TYPE_GNRV:
2936 case GF_ISOM_BOX_TYPE_HVC1:
2937 case GF_ISOM_BOX_TYPE_HEV1:
2938 case GF_ISOM_BOX_TYPE_HVC2:
2939 case GF_ISOM_BOX_TYPE_HEV2:
2940 case GF_ISOM_BOX_TYPE_LHE1:
2941 case GF_ISOM_BOX_TYPE_LHV1:
2942 case GF_ISOM_BOX_TYPE_HVT1:
2943 if (entry->pasp) {
2944 *hSpacing = entry->pasp->hSpacing;
2945 *vSpacing = entry->pasp->vSpacing;
2946 }
2947 return GF_OK;
2948 default:
2949 return GF_OK;
2950 }
2951 }
2952
2953 GF_EXPORT
gf_isom_get_filename(GF_ISOFile * movie)2954 const char *gf_isom_get_filename(GF_ISOFile *movie)
2955 {
2956 if (!movie) return NULL;
2957 #ifndef GPAC_DISABLE_ISOM_WRITE
2958 if (movie->finalName && !movie->fileName) return movie->finalName;
2959 #endif
2960 return movie->fileName;
2961 }
2962
2963
2964 GF_EXPORT
gf_isom_get_pl_indication(GF_ISOFile * movie,u8 PL_Code)2965 u8 gf_isom_get_pl_indication(GF_ISOFile *movie, u8 PL_Code)
2966 {
2967 GF_IsomInitialObjectDescriptor *iod;
2968 if (!movie || !movie->moov) return 0;
2969 if (!movie->moov->iods || !movie->moov->iods->descriptor) return 0xFF;
2970 if (movie->moov->iods->descriptor->tag != GF_ODF_ISOM_IOD_TAG) return 0xFF;
2971
2972 iod = (GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor;
2973 switch (PL_Code) {
2974 case GF_ISOM_PL_AUDIO:
2975 return iod->audio_profileAndLevel;
2976 case GF_ISOM_PL_VISUAL:
2977 return iod->visual_profileAndLevel;
2978 case GF_ISOM_PL_GRAPHICS:
2979 return iod->graphics_profileAndLevel;
2980 case GF_ISOM_PL_SCENE:
2981 return iod->scene_profileAndLevel;
2982 case GF_ISOM_PL_OD:
2983 return iod->OD_profileAndLevel;
2984 case GF_ISOM_PL_INLINE:
2985 return iod->inlineProfileFlag;
2986 case GF_ISOM_PL_MPEGJ:
2987 default:
2988 return 0xFF;
2989 }
2990 }
2991
2992 GF_EXPORT
gf_isom_get_track_matrix(GF_ISOFile * the_file,u32 trackNumber,u32 matrix[9])2993 GF_Err gf_isom_get_track_matrix(GF_ISOFile *the_file, u32 trackNumber, u32 matrix[9])
2994 {
2995 GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
2996 if (!trak || !trak->Header) return GF_BAD_PARAM;
2997 memcpy(matrix, trak->Header->matrix, sizeof(trak->Header->matrix));
2998 return GF_OK;
2999 }
3000
3001 GF_EXPORT
gf_isom_get_track_layout_info(GF_ISOFile * movie,u32 trackNumber,u32 * width,u32 * height,s32 * translation_x,s32 * translation_y,s16 * layer)3002 GF_Err gf_isom_get_track_layout_info(GF_ISOFile *movie, u32 trackNumber, u32 *width, u32 *height, s32 *translation_x, s32 *translation_y, s16 *layer)
3003 {
3004 GF_TrackBox *tk = gf_isom_get_track_from_file(movie, trackNumber);
3005 if (!tk) return GF_BAD_PARAM;
3006 if (width) *width = tk->Header->width >> 16;
3007 if (height) *height = tk->Header->height >> 16;
3008 if (layer) *layer = tk->Header->layer;
3009 if (translation_x) *translation_x = tk->Header->matrix[6] >> 16;
3010 if (translation_y) *translation_y = tk->Header->matrix[7] >> 16;
3011 return GF_OK;
3012 }
3013
3014
3015 /*returns total amount of media bytes in track*/
3016 GF_EXPORT
gf_isom_get_media_data_size(GF_ISOFile * movie,u32 trackNumber)3017 u64 gf_isom_get_media_data_size(GF_ISOFile *movie, u32 trackNumber)
3018 {
3019 u32 i, size;
3020 GF_SampleSizeBox *stsz;
3021 GF_TrackBox *tk = gf_isom_get_track_from_file(movie, trackNumber);
3022 if (!tk) return 0;
3023 stsz = tk->Media->information->sampleTable->SampleSize;
3024 if (stsz->sampleSize) return stsz->sampleSize*stsz->sampleCount;
3025 size = 0;
3026 for (i = 0; i<stsz->sampleCount; i++) size += stsz->sizes[i];
3027 return size;
3028 }
3029
3030
3031 GF_EXPORT
gf_isom_set_default_sync_track(GF_ISOFile * movie,u32 trackNumber)3032 void gf_isom_set_default_sync_track(GF_ISOFile *movie, u32 trackNumber)
3033 {
3034 GF_TrackBox *tk = gf_isom_get_track_from_file(movie, trackNumber);
3035 if (!tk) movie->es_id_default_sync = -1;
3036 else movie->es_id_default_sync = tk->Header->trackID;
3037 }
3038
3039
3040 GF_EXPORT
gf_isom_is_single_av(GF_ISOFile * file)3041 Bool gf_isom_is_single_av(GF_ISOFile *file)
3042 {
3043 u32 count, i, nb_any, nb_a, nb_v, nb_scene, nb_od, nb_text;
3044 nb_a = nb_v = nb_any = nb_scene = nb_od = nb_text = 0;
3045
3046 if (!file->moov) return GF_FALSE;
3047 count = gf_isom_get_track_count(file);
3048 for (i = 0; i<count; i++) {
3049 u32 mtype = gf_isom_get_media_type(file, i + 1);
3050 switch (mtype) {
3051 case GF_ISOM_MEDIA_SCENE:
3052 if (gf_isom_get_sample_count(file, i + 1)>1) nb_any++;
3053 else nb_scene++;
3054 break;
3055 case GF_ISOM_MEDIA_OD:
3056 if (gf_isom_get_sample_count(file, i + 1)>1) nb_any++;
3057 else nb_od++;
3058 break;
3059 case GF_ISOM_MEDIA_TEXT:
3060 case GF_ISOM_MEDIA_SUBT:
3061 nb_text++;
3062 break;
3063 case GF_ISOM_MEDIA_AUDIO:
3064 nb_a++;
3065 break;
3066 case GF_ISOM_MEDIA_VISUAL:
3067 /*discard file with images*/
3068 if (gf_isom_get_sample_count(file, i + 1) == 1) nb_any++;
3069 else nb_v++;
3070 break;
3071 default:
3072 nb_any++;
3073 break;
3074 }
3075 }
3076 if (nb_any) return GF_FALSE;
3077 if ((nb_scene <= 1) && (nb_od <= 1) && (nb_a <= 1) && (nb_v <= 1) && (nb_text <= 1)) return GF_TRUE;
3078 return GF_FALSE;
3079 }
3080
3081 GF_EXPORT
gf_isom_is_JPEG2000(GF_ISOFile * mov)3082 Bool gf_isom_is_JPEG2000(GF_ISOFile *mov)
3083 {
3084 return (mov && mov->is_jp2) ? GF_TRUE : GF_FALSE;
3085 }
3086
3087 GF_EXPORT
gf_isom_guess_specification(GF_ISOFile * file)3088 u32 gf_isom_guess_specification(GF_ISOFile *file)
3089 {
3090 u32 count, i, nb_any, nb_m4s, nb_a, nb_v, nb_scene, nb_od, nb_mp3, nb_aac, nb_m4v, nb_avc, nb_amr, nb_h263, nb_qcelp, nb_evrc, nb_smv, nb_text;
3091
3092 nb_m4s = nb_a = nb_v = nb_any = nb_scene = nb_od = nb_mp3 = nb_aac = nb_m4v = nb_avc = nb_amr = nb_h263 = nb_qcelp = nb_evrc = nb_smv = nb_text = 0;
3093
3094 if (file->is_jp2) {
3095 if (file->moov) return GF_4CC('m', 'j', 'p', '2');
3096 return GF_4CC('j', 'p', '2', ' ');
3097 }
3098 if (!file->moov) {
3099 if (!file->meta || !file->meta->handler) return 0;
3100 return file->meta->handler->handlerType;
3101 }
3102
3103 count = gf_isom_get_track_count(file);
3104 for (i = 0; i<count; i++) {
3105 u32 mtype = gf_isom_get_media_type(file, i + 1);
3106 u32 mstype = gf_isom_get_media_subtype(file, i + 1, 1);
3107
3108 if (mtype == GF_ISOM_MEDIA_SCENE) {
3109 nb_scene++;
3110 /*forces non-isma*/
3111 if (gf_isom_get_sample_count(file, i + 1)>1) nb_m4s++;
3112 }
3113 else if (mtype == GF_ISOM_MEDIA_OD) {
3114 nb_od++;
3115 /*forces non-isma*/
3116 if (gf_isom_get_sample_count(file, i + 1)>1) nb_m4s++;
3117 }
3118 else if ((mtype == GF_ISOM_MEDIA_TEXT) || (mtype == GF_ISOM_MEDIA_SUBT)) nb_text++;
3119 else if ((mtype == GF_ISOM_MEDIA_AUDIO) || (mtype == GF_ISOM_MEDIA_VISUAL)) {
3120 switch (mstype) {
3121 case GF_ISOM_SUBTYPE_3GP_AMR:
3122 case GF_ISOM_SUBTYPE_3GP_AMR_WB:
3123 nb_amr++;
3124 break;
3125 case GF_ISOM_SUBTYPE_3GP_H263:
3126 nb_h263++;
3127 break;
3128 case GF_ISOM_SUBTYPE_3GP_EVRC:
3129 nb_evrc++;
3130 break;
3131 case GF_ISOM_SUBTYPE_3GP_QCELP:
3132 nb_qcelp++;
3133 break;
3134 case GF_ISOM_SUBTYPE_3GP_SMV:
3135 nb_smv++;
3136 break;
3137 case GF_ISOM_SUBTYPE_AVC_H264:
3138 case GF_ISOM_SUBTYPE_AVC2_H264:
3139 case GF_ISOM_SUBTYPE_AVC3_H264:
3140 case GF_ISOM_SUBTYPE_AVC4_H264:
3141 nb_avc++;
3142 break;
3143 case GF_ISOM_SUBTYPE_SVC_H264:
3144 nb_avc++;
3145 break;
3146 case GF_ISOM_SUBTYPE_MPEG4:
3147 case GF_ISOM_SUBTYPE_MPEG4_CRYP:
3148 {
3149 GF_DecoderConfig *dcd = gf_isom_get_decoder_config(file, i + 1, 1);
3150 switch (dcd->streamType) {
3151 case GF_STREAM_VISUAL:
3152 if (dcd->objectTypeIndication == GPAC_OTI_VIDEO_MPEG4_PART2) nb_m4v++;
3153 else if ((dcd->objectTypeIndication == GPAC_OTI_VIDEO_AVC) || (dcd->objectTypeIndication == GPAC_OTI_VIDEO_SVC)) nb_avc++;
3154 else nb_v++;
3155 break;
3156 case GF_STREAM_AUDIO:
3157 switch (dcd->objectTypeIndication) {
3158 case GPAC_OTI_AUDIO_AAC_MPEG2_MP:
3159 case GPAC_OTI_AUDIO_AAC_MPEG2_LCP:
3160 case GPAC_OTI_AUDIO_AAC_MPEG2_SSRP:
3161 case GPAC_OTI_AUDIO_AAC_MPEG4:
3162 nb_aac++;
3163 break;
3164 case GPAC_OTI_AUDIO_MPEG2_PART3:
3165 case GPAC_OTI_AUDIO_MPEG1:
3166 nb_mp3++;
3167 break;
3168 case GPAC_OTI_AUDIO_EVRC_VOICE:
3169 nb_evrc++;
3170 break;
3171 case GPAC_OTI_AUDIO_SMV_VOICE:
3172 nb_smv++;
3173 break;
3174 case GPAC_OTI_AUDIO_13K_VOICE:
3175 nb_qcelp++;
3176 break;
3177 default:
3178 nb_a++;
3179 break;
3180 }
3181 break;
3182 /*SHOULD NEVER HAPPEN - IF SO, BROKEN MPEG4 FILE*/
3183 default:
3184 nb_any++;
3185 break;
3186 }
3187 gf_odf_desc_del((GF_Descriptor *)dcd);
3188 }
3189 break;
3190 default:
3191 if (mtype == GF_ISOM_MEDIA_VISUAL) nb_v++;
3192 else nb_a++;
3193 break;
3194 }
3195 }
3196 else if ((mtype == GF_ISOM_SUBTYPE_MPEG4) || (mtype == GF_ISOM_SUBTYPE_MPEG4_CRYP)) nb_m4s++;
3197 else nb_any++;
3198 }
3199 if (nb_any) return GF_ISOM_BRAND_ISOM;
3200 if (nb_qcelp || nb_evrc || nb_smv) {
3201 /*non std mix of streams*/
3202 if (nb_m4s || nb_avc || nb_scene || nb_od || nb_mp3 || nb_a || nb_v) return GF_ISOM_BRAND_ISOM;
3203 return GF_ISOM_BRAND_3G2A;
3204 }
3205 /*other a/v/s streams*/
3206 if (nb_v || nb_a || nb_m4s) return GF_ISOM_BRAND_MP42;
3207
3208 nb_v = nb_m4v + nb_avc + nb_h263;
3209 nb_a = nb_mp3 + nb_aac + nb_amr;
3210
3211 /*avc file: whatever has AVC and no systems*/
3212 if (nb_avc) {
3213 if (!nb_scene && !nb_od) return GF_ISOM_BRAND_AVC1;
3214 return GF_ISOM_BRAND_MP42;
3215 }
3216 /*MP3: ISMA and MPEG4*/
3217 if (nb_mp3) {
3218 if (!nb_text && (nb_v <= 1) && (nb_a <= 1) && (nb_scene == 1) && (nb_od == 1))
3219 return GF_4CC('I', 'S', 'M', 'A');
3220 return GF_ISOM_BRAND_MP42;
3221 }
3222 /*MP4*/
3223 if (nb_scene || nb_od) {
3224 /*issue with AMR and H263 which don't have MPEG mapping: non compliant file*/
3225 if (nb_amr || nb_h263) return GF_ISOM_BRAND_ISOM;
3226 return GF_ISOM_BRAND_MP42;
3227 }
3228 /*use ISMA (3GP fine too)*/
3229 if (!nb_amr && !nb_h263 && !nb_text) {
3230 if ((nb_v <= 1) && (nb_a <= 1)) return GF_4CC('I', 'S', 'M', 'A');
3231 return GF_ISOM_BRAND_MP42;
3232 }
3233
3234 if ((nb_v <= 1) && (nb_a <= 1) && (nb_text <= 1)) return nb_text ? GF_ISOM_BRAND_3GP6 : GF_ISOM_BRAND_3GP5;
3235 return GF_ISOM_BRAND_3GG6;
3236 }
3237
gf_ismo_locate_box(GF_List * list,u32 boxType,bin128 UUID)3238 GF_ItemListBox *gf_ismo_locate_box(GF_List *list, u32 boxType, bin128 UUID)
3239 {
3240 u32 i;
3241 GF_Box *box;
3242 i = 0;
3243 while ((box = (GF_Box *)gf_list_enum(list, &i))) {
3244 if (box->type == boxType) {
3245 GF_UUIDBox* box2 = (GF_UUIDBox*)box;
3246 if (boxType != GF_ISOM_BOX_TYPE_UUID) return (GF_ItemListBox *)box;
3247 if (!memcmp(box2->uuid, UUID, 16)) return (GF_ItemListBox *)box;
3248 }
3249 }
3250 return NULL;
3251 }
3252
3253 /*Apple extensions*/
3254
3255
3256 GF_EXPORT
gf_isom_apple_get_tag(GF_ISOFile * mov,u32 tag,const char ** data,u32 * data_len)3257 GF_Err gf_isom_apple_get_tag(GF_ISOFile *mov, u32 tag, const char **data, u32 *data_len)
3258 {
3259 u32 i;
3260 GF_ListItemBox *info;
3261 GF_ItemListBox *ilst;
3262 GF_MetaBox *meta;
3263
3264 *data = NULL;
3265 *data_len = 0;
3266
3267 meta = gf_isom_apple_get_meta_extensions(mov);
3268 if (!meta) return GF_URL_ERROR;
3269
3270 ilst = gf_ismo_locate_box(meta->other_boxes, GF_ISOM_BOX_TYPE_ILST, NULL);
3271 if (!ilst) return GF_URL_ERROR;
3272
3273 if (tag == GF_ISOM_ITUNE_PROBE) return GF_OK;
3274
3275 i = 0;
3276 while ((info = (GF_ListItemBox*)gf_list_enum(ilst->other_boxes, &i))) {
3277 if (info->type == tag) break;
3278 /*special cases*/
3279 if ((tag == GF_ISOM_ITUNE_GENRE) && (info->type == (u32)GF_ISOM_BOX_TYPE_0xA9GEN)) break;
3280 info = NULL;
3281 }
3282 if (!info || !info->data || !info->data->data) return GF_URL_ERROR;
3283
3284 if ((tag == GF_ISOM_ITUNE_GENRE) && (info->data->flags == 0)) {
3285 if (info->data->dataSize && (info->data->dataSize>2) && (info->data->dataSize < 5)) {
3286 GF_BitStream* bs = gf_bs_new(info->data->data, info->data->dataSize, GF_BITSTREAM_READ);
3287 *data_len = gf_bs_read_int(bs, info->data->dataSize * 8);
3288 gf_bs_del(bs);
3289 return GF_OK;
3290 }
3291 }
3292 // if (info->data->flags != 0x1) return GF_URL_ERROR;
3293 *data = info->data->data;
3294 *data_len = info->data->dataSize;
3295 if ((tag == GF_ISOM_ITUNE_COVER_ART) && (info->data->flags == 14)) *data_len |= (1 << 31);
3296 return GF_OK;
3297 }
3298
3299
3300
3301
3302 GF_EXPORT
gf_isom_get_track_switch_group_count(GF_ISOFile * movie,u32 trackNumber,u32 * alternateGroupID,u32 * nb_groups)3303 GF_Err gf_isom_get_track_switch_group_count(GF_ISOFile *movie, u32 trackNumber, u32 *alternateGroupID, u32 *nb_groups)
3304 {
3305 GF_UserDataMap *map;
3306 GF_TrackBox *trak;
3307
3308 trak = gf_isom_get_track_from_file(movie, trackNumber);
3309 if (!trak) return GF_BAD_PARAM;
3310 *alternateGroupID = trak->Header->alternate_group;
3311 *nb_groups = 0;
3312 if (!trak->udta) return GF_OK;
3313
3314 map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_TSEL, NULL);
3315 if (!map) return GF_OK;
3316 *nb_groups = gf_list_count(map->other_boxes);
3317 return GF_OK;
3318 }
3319
3320 GF_EXPORT
gf_isom_get_track_switch_parameter(GF_ISOFile * movie,u32 trackNumber,u32 group_index,u32 * switchGroupID,u32 * criteriaListSize)3321 const u32 *gf_isom_get_track_switch_parameter(GF_ISOFile *movie, u32 trackNumber, u32 group_index, u32 *switchGroupID, u32 *criteriaListSize)
3322 {
3323 GF_TrackBox *trak;
3324 GF_UserDataMap *map;
3325 GF_TrackSelectionBox *tsel;
3326
3327 trak = gf_isom_get_track_from_file(movie, trackNumber);
3328 if (!group_index || !trak || !trak->udta) return NULL;
3329
3330 map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_TSEL, NULL);
3331 if (!map) return NULL;
3332 tsel = (GF_TrackSelectionBox*)gf_list_get(map->other_boxes, group_index - 1);
3333 *switchGroupID = tsel->switchGroup;
3334 *criteriaListSize = tsel->attributeListCount;
3335 return (const u32 *)tsel->attributeList;
3336 }
3337
3338 GF_EXPORT
gf_isom_get_next_alternate_group_id(GF_ISOFile * movie)3339 u32 gf_isom_get_next_alternate_group_id(GF_ISOFile *movie)
3340 {
3341 u32 id = 0;
3342 u32 i = 0;
3343
3344 while (i< gf_isom_get_track_count(movie)) {
3345 GF_TrackBox *trak = gf_isom_get_track_from_file(movie, i + 1);
3346 if (trak->Header->alternate_group > id)
3347 id = trak->Header->alternate_group;
3348 i++;
3349 }
3350 return id + 1;
3351 }
3352
3353
gf_isom_sample_has_subsamples(GF_ISOFile * movie,u32 track,u32 sampleNumber,u32 flags)3354 u32 gf_isom_sample_has_subsamples(GF_ISOFile *movie, u32 track, u32 sampleNumber, u32 flags)
3355 {
3356 GF_TrackBox *trak = gf_isom_get_track_from_file(movie, track);
3357 if (!trak) return GF_BAD_PARAM;
3358 if (!trak->Media->information->sampleTable->sub_samples) return 0;
3359 return gf_isom_sample_get_subsample_entry(movie, track, sampleNumber, flags, NULL);
3360 }
3361
gf_isom_sample_get_subsample(GF_ISOFile * movie,u32 track,u32 sampleNumber,u32 flags,u32 subSampleNumber,u32 * size,u8 * priority,u32 * reserved,Bool * discardable)3362 GF_Err gf_isom_sample_get_subsample(GF_ISOFile *movie, u32 track, u32 sampleNumber, u32 flags, u32 subSampleNumber, u32 *size, u8 *priority, u32 *reserved, Bool *discardable)
3363 {
3364 GF_SubSampleEntry *entry;
3365 GF_SubSampleInfoEntry *sub_sample;
3366 u32 count = gf_isom_sample_get_subsample_entry(movie, track, sampleNumber, flags, &sub_sample);
3367 if (!size || !priority || !discardable) return GF_BAD_PARAM;
3368
3369 if (!subSampleNumber || (subSampleNumber>count)) return GF_BAD_PARAM;
3370 entry = (GF_SubSampleEntry*)gf_list_get(sub_sample->SubSamples, subSampleNumber - 1);
3371 *size = entry->subsample_size;
3372 *priority = entry->subsample_priority;
3373 *reserved = entry->reserved;
3374 *discardable = entry->discardable ? GF_TRUE : GF_FALSE;
3375 return GF_OK;
3376 }
3377
3378 GF_EXPORT
gf_isom_get_rvc_config(GF_ISOFile * movie,u32 track,u32 sampleDescriptionIndex,u16 * rvc_predefined,char ** data,u32 * size,const char ** mime)3379 GF_Err gf_isom_get_rvc_config(GF_ISOFile *movie, u32 track, u32 sampleDescriptionIndex, u16 *rvc_predefined, char **data, u32 *size, const char **mime)
3380 {
3381 GF_MPEGVisualSampleEntryBox *entry;
3382 GF_TrackBox *trak;
3383
3384 if (!rvc_predefined || !data || !size) return GF_BAD_PARAM;
3385 *rvc_predefined = 0;
3386
3387 trak = gf_isom_get_track_from_file(movie, track);
3388 if (!trak) return GF_BAD_PARAM;
3389
3390
3391 entry = (GF_MPEGVisualSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, sampleDescriptionIndex - 1);
3392 if (!entry) return GF_BAD_PARAM;
3393 switch (entry->type) {
3394 case GF_ISOM_BOX_TYPE_MP4V:
3395 case GF_ISOM_BOX_TYPE_AVC1:
3396 case GF_ISOM_BOX_TYPE_AVC2:
3397 case GF_ISOM_BOX_TYPE_AVC3:
3398 case GF_ISOM_BOX_TYPE_AVC4:
3399 case GF_ISOM_BOX_TYPE_SVC1:
3400 case GF_ISOM_BOX_TYPE_ENCV:
3401 case GF_ISOM_BOX_TYPE_HVC1:
3402 case GF_ISOM_BOX_TYPE_HEV1:
3403 case GF_ISOM_BOX_TYPE_HVC2:
3404 case GF_ISOM_BOX_TYPE_HEV2:
3405 case GF_ISOM_BOX_TYPE_LHE1:
3406 case GF_ISOM_BOX_TYPE_LHV1:
3407 case GF_ISOM_BOX_TYPE_HVT1:
3408 break;
3409 default:
3410 return GF_BAD_PARAM;
3411 }
3412 if (!entry->rvcc) return GF_BAD_PARAM;
3413
3414 *rvc_predefined = entry->rvcc->predefined_rvc_config;
3415 if (entry->rvcc->rvc_meta_idx) {
3416 if (!data || !size) return GF_OK;
3417 return gf_isom_extract_meta_item_mem(movie, GF_FALSE, track, entry->rvcc->rvc_meta_idx, data, size, mime);
3418 }
3419 return GF_OK;
3420 }
3421
3422 GF_EXPORT
gf_isom_moov_first(GF_ISOFile * movie)3423 Bool gf_isom_moov_first(GF_ISOFile *movie)
3424 {
3425 u32 i;
3426 for (i = 0; i<gf_list_count(movie->TopBoxes); i++) {
3427 GF_Box *b = (GF_Box*)gf_list_get(movie->TopBoxes, i);
3428 if (b->type == GF_ISOM_BOX_TYPE_MOOV) return GF_TRUE;
3429 if (b->type == GF_ISOM_BOX_TYPE_MDAT) return GF_FALSE;
3430 }
3431 return GF_FALSE;
3432 }
3433
3434 GF_EXPORT
gf_isom_reset_fragment_info(GF_ISOFile * movie,Bool keep_sample_count)3435 void gf_isom_reset_fragment_info(GF_ISOFile *movie, Bool keep_sample_count)
3436 {
3437 u32 i;
3438 if (!movie) return;
3439 for (i = 0; i<gf_list_count(movie->moov->trackList); i++) {
3440 GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
3441 trak->Media->information->sampleTable->SampleSize->sampleCount = 0;
3442 #ifdef GPAC_DISABLE_ISOM_FRAGMENTS
3443 }
3444 #else
3445 trak->dts_at_seg_start = 0;
3446 if (!keep_sample_count)
3447 trak->sample_count_at_seg_start = 0;
3448 }
3449 movie->NextMoofNumber = 0;
3450 #endif
3451 }
3452
3453 GF_EXPORT
gf_isom_get_sample_rap_roll_info(GF_ISOFile * the_file,u32 trackNumber,u32 sample_number,Bool * is_rap,Bool * has_roll,s32 * roll_distance)3454 GF_Err gf_isom_get_sample_rap_roll_info(GF_ISOFile *the_file, u32 trackNumber, u32 sample_number, Bool *is_rap, Bool *has_roll, s32 *roll_distance)
3455 {
3456 GF_TrackBox *trak;
3457 u32 i, count;
3458
3459 if (is_rap) *is_rap = GF_FALSE;
3460 if (has_roll) *has_roll = GF_FALSE;
3461 if (roll_distance) *roll_distance = 0;
3462
3463 trak = gf_isom_get_track_from_file(the_file, trackNumber);
3464 if (!trak) return GF_BAD_PARAM;
3465 if (!trak->Media->information->sampleTable->sampleGroups) return GF_OK;
3466
3467 if (!sample_number) {
3468 count = gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription);
3469 for (i = 0; i<count; i++) {
3470 GF_SampleGroupDescriptionBox *sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, i);
3471 switch (sgdesc->grouping_type) {
3472 case GF_4CC('r', 'a', 'p', ' '):
3473 if (is_rap) *is_rap = GF_TRUE;
3474 break;
3475 case GF_4CC('r', 'o', 'l', 'l'):
3476 if (has_roll) *has_roll = GF_TRUE;
3477 if (roll_distance) {
3478 s32 max_roll = 0;
3479 u32 j;
3480 for (j = 0; j<gf_list_count(sgdesc->group_descriptions); j++) {
3481 GF_RollRecoveryEntry *roll_entry = (GF_RollRecoveryEntry*)gf_list_get(sgdesc->group_descriptions, j);
3482 if (max_roll < roll_entry->roll_distance)
3483 max_roll = roll_entry->roll_distance;
3484 }
3485 if (*roll_distance < max_roll) *roll_distance = max_roll;
3486 }
3487 break;
3488 }
3489 }
3490 return GF_OK;
3491 }
3492
3493 count = gf_list_count(trak->Media->information->sampleTable->sampleGroups);
3494 for (i = 0; i<count; i++) {
3495 GF_SampleGroupBox *sg;
3496 u32 j, group_desc_index;
3497 GF_SampleGroupDescriptionBox *sgdesc;
3498 u32 first_sample_in_entry, last_sample_in_entry;
3499 first_sample_in_entry = 1;
3500 group_desc_index = 0;
3501 sg = (GF_SampleGroupBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroups, i);
3502 for (j = 0; j<sg->entry_count; j++) {
3503 last_sample_in_entry = first_sample_in_entry + sg->sample_entries[j].sample_count - 1;
3504 if ((sample_number<first_sample_in_entry) || (sample_number>last_sample_in_entry)) {
3505 first_sample_in_entry = last_sample_in_entry + 1;
3506 continue;
3507 }
3508 /*we found our sample*/
3509 group_desc_index = 1 + sg->sample_entries[j].group_description_index;
3510 break;
3511 }
3512 /*no sampleGroup info associated*/
3513 if (!group_desc_index) continue;
3514
3515 sgdesc = NULL;
3516 for (j = 0; j<gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription); j++) {
3517 sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, j);
3518 if (sgdesc->grouping_type == sg->grouping_type) break;
3519 sgdesc = NULL;
3520 }
3521 /*no sampleGroup description found for this group (invalid file)*/
3522 if (!sgdesc) continue;
3523
3524 switch (sgdesc->grouping_type) {
3525 case GF_4CC('r', 'a', 'p', ' '):
3526 if (is_rap) *is_rap = GF_TRUE;
3527 break;
3528 case GF_4CC('r', 'o', 'l', 'l'):
3529 if (has_roll) *has_roll = GF_TRUE;
3530 if (roll_distance) {
3531 GF_RollRecoveryEntry *roll_entry = (GF_RollRecoveryEntry *)gf_list_get(sgdesc->group_descriptions, group_desc_index - 1);
3532 if (roll_entry) *roll_distance = roll_entry->roll_distance;
3533 }
3534 break;
3535 }
3536 }
3537 return GF_OK;
3538 }
3539
gf_isom_get_sample_group_info_entry(GF_ISOFile * the_file,GF_TrackBox * trak,u32 grouping_type,u32 sample_description_index,u32 * default_index,GF_SampleGroupDescriptionBox ** out_sgdp)3540 GF_DefaultSampleGroupDescriptionEntry * gf_isom_get_sample_group_info_entry(GF_ISOFile *the_file, GF_TrackBox *trak, u32 grouping_type, u32 sample_description_index, u32 *default_index, GF_SampleGroupDescriptionBox **out_sgdp)
3541 {
3542 u32 i, count;
3543
3544 if (!trak || !sample_description_index) return NULL;
3545 if (!trak->Media->information->sampleTable->sampleGroupsDescription) return NULL;
3546
3547 count = gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription);
3548 for (i = 0; i<count; i++) {
3549 GF_SampleGroupDescriptionBox *sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, i);
3550 if (sgdesc->grouping_type != grouping_type) continue;
3551
3552 if (sgdesc->default_description_index && !sample_description_index) sample_description_index = sgdesc->default_description_index;
3553
3554 if (default_index) *default_index = sgdesc->default_description_index;
3555 if (out_sgdp) *out_sgdp = sgdesc;
3556
3557 if (!sample_description_index) return NULL;
3558 return (GF_DefaultSampleGroupDescriptionEntry*)gf_list_get(sgdesc->group_descriptions, sample_description_index - 1);
3559 }
3560 return NULL;
3561 }
3562
3563 GF_EXPORT
gf_isom_get_sample_group_info(GF_ISOFile * the_file,u32 trackNumber,u32 sample_description_index,u32 grouping_type,u32 * default_index,const char ** data,u32 * size)3564 Bool gf_isom_get_sample_group_info(GF_ISOFile *the_file, u32 trackNumber, u32 sample_description_index, u32 grouping_type, u32 *default_index, const char **data, u32 *size)
3565 {
3566 GF_DefaultSampleGroupDescriptionEntry *sg_entry;
3567 GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
3568
3569 if (default_index) *default_index = 0;
3570 if (size) *size = 0;
3571 if (data) *data = NULL;
3572
3573 sg_entry = gf_isom_get_sample_group_info_entry(the_file, trak, grouping_type, sample_description_index, default_index, NULL);
3574 if (!sg_entry) return GF_FALSE;
3575
3576 switch (grouping_type) {
3577 case GF_4CC('r', 'a', 'p', ' '):
3578 case GF_4CC('r', 'o', 'l', 'l'):
3579 case GF_4CC('s', 'e', 'i', 'g'):
3580 case GF_4CC('o', 'i', 'n', 'f'):
3581 case GF_4CC('l', 'i', 'n', 'f'):
3582 return GF_TRUE;
3583 default:
3584 if (sg_entry && data) *data = (char *)sg_entry->data;
3585 if (sg_entry && size) *size = sg_entry->length;
3586 return GF_TRUE;
3587 }
3588 return GF_FALSE;
3589 }
3590
3591 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3592 //return the duration of the movie+fragments if known, 0 if error
3593 GF_EXPORT
gf_isom_get_fragmented_duration(GF_ISOFile * movie)3594 u64 gf_isom_get_fragmented_duration(GF_ISOFile *movie)
3595 {
3596 if (movie->moov->mvex && movie->moov->mvex->mehd)
3597 return movie->moov->mvex->mehd->fragment_duration;
3598
3599 return 0;
3600 }
3601 //return the duration of the movie+fragments if known, 0 if error
3602 GF_EXPORT
gf_isom_get_fragments_count(GF_ISOFile * movie,Bool segments_only)3603 u32 gf_isom_get_fragments_count(GF_ISOFile *movie, Bool segments_only)
3604 {
3605 u32 i = 0;
3606 u32 nb_frags = 0;
3607 GF_Box *b;
3608 while ((b = (GF_Box*)gf_list_enum(movie->TopBoxes, &i))) {
3609 if (segments_only) {
3610 if (b->type == GF_ISOM_BOX_TYPE_SIDX)
3611 nb_frags++;
3612 }
3613 else {
3614 if (b->type == GF_ISOM_BOX_TYPE_MOOF)
3615 nb_frags++;
3616 }
3617 }
3618 return nb_frags;
3619 }
3620
3621 GF_EXPORT
gf_isom_get_fragmented_samples_info(GF_ISOFile * movie,u32 trackID,u32 * nb_samples,u64 * duration)3622 GF_Err gf_isom_get_fragmented_samples_info(GF_ISOFile *movie, u32 trackID, u32 *nb_samples, u64 *duration)
3623 {
3624 u32 i = 0;
3625 u32 k, l;
3626 u64 def_duration, samp_dur;
3627 GF_MovieFragmentBox *moof;
3628 GF_TrackFragmentBox *traf;
3629
3630 *nb_samples = 0;
3631 *duration = 0;
3632 while ((moof = (GF_MovieFragmentBox*)gf_list_enum(movie->TopBoxes, &i))) {
3633 if (moof->type == GF_ISOM_BOX_TYPE_MOOF) {
3634 u32 j = 0;
3635 while ((traf = (GF_TrackFragmentBox*)gf_list_enum(moof->TrackList, &j))) {
3636 if (traf->tfhd->trackID != trackID)
3637 continue;
3638
3639 def_duration = 0;
3640 if (traf->tfhd->flags & GF_ISOM_TRAF_SAMPLE_DUR) def_duration = traf->tfhd->def_sample_duration;
3641 else if (traf->trex) def_duration = traf->trex->def_sample_duration;
3642
3643 for (k = 0; k<gf_list_count(traf->TrackRuns); k++) {
3644 GF_TrackFragmentRunBox *trun = (GF_TrackFragmentRunBox*)gf_list_get(traf->TrackRuns, k);
3645 *nb_samples += gf_list_count(trun->entries);
3646
3647 for (l = 0; l<gf_list_count(trun->entries); l++) {
3648 GF_TrunEntry *ent = (GF_TrunEntry*)gf_list_get(trun->entries, l);
3649
3650 samp_dur = def_duration;
3651 if (trun->flags & GF_ISOM_TRUN_DURATION) samp_dur = ent->Duration;
3652 *duration += samp_dur;
3653 }
3654 }
3655 }
3656 }
3657 }
3658 return GF_OK;
3659 }
3660 #endif
3661
3662 GF_EXPORT
gf_isom_set_nalu_extract_mode(GF_ISOFile * the_file,u32 trackNumber,u32 nalu_extract_mode)3663 GF_Err gf_isom_set_nalu_extract_mode(GF_ISOFile *the_file, u32 trackNumber, u32 nalu_extract_mode)
3664 {
3665 GF_TrackReferenceTypeBox *dpnd;
3666 GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
3667 if (!trak) return GF_BAD_PARAM;
3668 trak->extractor_mode = nalu_extract_mode;
3669
3670 if (!trak->References) return GF_OK;
3671
3672 /*get base*/
3673 dpnd = NULL;
3674 trak->has_base_layer = GF_FALSE;
3675 Track_FindRef(trak, GF_ISOM_REF_SCAL, &dpnd);
3676 if (dpnd) trak->has_base_layer = GF_TRUE;
3677 return GF_OK;
3678 }
3679
3680 GF_EXPORT
gf_isom_get_nalu_extract_mode(GF_ISOFile * the_file,u32 trackNumber)3681 u32 gf_isom_get_nalu_extract_mode(GF_ISOFile *the_file, u32 trackNumber)
3682 {
3683 GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
3684 if (!trak) return 0;
3685 return trak->extractor_mode;
3686 }
3687
3688 GF_EXPORT
gf_isom_get_composition_offset_shift(GF_ISOFile * file,u32 track)3689 s32 gf_isom_get_composition_offset_shift(GF_ISOFile *file, u32 track)
3690 {
3691 GF_TrackBox *trak = gf_isom_get_track_from_file(file, track);
3692 if (!trak) return 0;
3693 if (!trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->CompositionToDecode) return 0;
3694 return trak->Media->information->sampleTable->CompositionToDecode->compositionToDTSShift;
3695 }
3696
3697 GF_EXPORT
gf_isom_needs_layer_reconstruction(GF_ISOFile * file)3698 Bool gf_isom_needs_layer_reconstruction(GF_ISOFile *file)
3699 {
3700 u32 count, i;
3701 if (!file)
3702 return GF_FALSE;
3703 count = gf_isom_get_track_count(file);
3704 for (i = 0; i < count; i++) {
3705 if (gf_isom_get_reference_count(file, i + 1, GF_ISOM_REF_SCAL) > 0) {
3706 return GF_TRUE;
3707 }
3708 if (gf_isom_get_reference_count(file, i + 1, GF_ISOM_REF_SABT) > 0) {
3709 return GF_TRUE;
3710 }
3711 switch (gf_isom_get_media_subtype(file, i + 1, 1)) {
3712 case GF_ISOM_SUBTYPE_LHV1:
3713 case GF_ISOM_SUBTYPE_LHE1:
3714 if (gf_isom_get_reference_count(file, i + 1, GF_ISOM_REF_BASE) > 0) {
3715 return GF_TRUE;
3716 }
3717 }
3718 }
3719 return GF_FALSE;
3720 }
3721
3722 GF_EXPORT
gf_isom_keep_utc_times(GF_ISOFile * file,Bool keep_utc)3723 void gf_isom_keep_utc_times(GF_ISOFile *file, Bool keep_utc)
3724 {
3725 if (!file) return;
3726 file->keep_utc = keep_utc;
3727 }
3728
3729
3730 GF_EXPORT
gf_isom_no_version_date_info(GF_ISOFile * file,Bool drop_info)3731 void gf_isom_no_version_date_info(GF_ISOFile *file, Bool drop_info)
3732 {
3733 if (!file) return;
3734 file->drop_date_version_info = drop_info;
3735 }
3736
3737 GF_EXPORT
gf_isom_get_pssh_count(GF_ISOFile * file)3738 u32 gf_isom_get_pssh_count(GF_ISOFile *file)
3739 {
3740 u32 count = 0;
3741 u32 i = 0;
3742 GF_Box *a_box;
3743 while ((a_box = (GF_Box*)gf_list_enum(file->moov->other_boxes, &i))) {
3744 if (a_box->type != GF_ISOM_BOX_TYPE_PSSH) continue;
3745 count++;
3746 }
3747 return count;
3748 }
3749
3750 GF_EXPORT
gf_isom_get_pssh_info(GF_ISOFile * file,u32 pssh_index,bin128 SystemID,u32 * KID_count,const bin128 ** KIDs,const u8 ** private_data,u32 * private_data_size)3751 GF_Err gf_isom_get_pssh_info(GF_ISOFile *file, u32 pssh_index, bin128 SystemID, u32 *KID_count, const bin128 **KIDs, const u8 **private_data, u32 *private_data_size)
3752 {
3753 u32 count = 1;
3754 u32 i = 0;
3755 GF_ProtectionSystemHeaderBox *pssh;
3756 while ((pssh = (GF_ProtectionSystemHeaderBox *)gf_list_enum(file->moov->other_boxes, &i))) {
3757 if (pssh->type != GF_ISOM_BOX_TYPE_PSSH) continue;
3758 if (count == pssh_index) break;
3759 count++;
3760 }
3761 if (!pssh) return GF_BAD_PARAM;
3762
3763 memcpy(SystemID, pssh->SystemID, 16);
3764 *KID_count = pssh->KID_count;
3765 *KIDs = (const bin128 *)pssh->KIDs;
3766 *private_data_size = pssh->private_data_size;
3767 *private_data = pssh->private_data;
3768 return GF_OK;
3769 }
3770
3771 GF_EXPORT
3772 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
gf_isom_get_sample_cenc_info_ex(GF_TrackBox * trak,GF_TrackFragmentBox * traf,u32 sample_number,u32 * IsEncrypted,u8 * IV_size,bin128 * KID,u8 * crypt_byte_block,u8 * skip_byte_block,u8 * constant_IV_size,bin128 * constant_IV)3773 GF_Err gf_isom_get_sample_cenc_info_ex(GF_TrackBox *trak, GF_TrackFragmentBox *traf, u32 sample_number, u32 *IsEncrypted, u8 *IV_size, bin128 *KID, u8 *crypt_byte_block, u8 *skip_byte_block, u8 *constant_IV_size, bin128 *constant_IV)
3774 #else
3775 GF_Err gf_isom_get_sample_cenc_info_ex(GF_TrackBox *trak, void *traf, u32 sample_number, u32 *IsEncrypted, u8 *IV_size, bin128 *KID, u8 *crypt_byte_block, u8 *skip_byte_block, u8 *constant_IV_size, bin128 *constant_IV)
3776 #endif
3777 {
3778 GF_SampleGroupBox *sample_group;
3779 u32 j, group_desc_index;
3780 GF_SampleGroupDescriptionBox *sgdesc;
3781 u32 i, count;
3782 u32 descIndex, chunkNum;
3783 u64 offset;
3784 u8 edit;
3785 u32 first_sample_in_entry, last_sample_in_entry;
3786 GF_CENCSampleEncryptionGroupEntry *entry;
3787
3788 if (IsEncrypted) *IsEncrypted = 0;
3789 if (IV_size) *IV_size = 0;
3790 if (KID) memset(*KID, 0, 16);
3791 if (crypt_byte_block) *crypt_byte_block = 0;
3792 if (skip_byte_block) *skip_byte_block = 0;
3793 if (constant_IV_size) *constant_IV_size = 0;
3794 if (constant_IV) memset(*constant_IV, 0, 16);
3795
3796 #ifdef GPAC_DISABLE_ISOM_FRAGMENTS
3797 if (traf)
3798 return GF_BAD_PARAM;
3799 #endif
3800
3801 if (trak->Media->information->sampleTable->SampleSize && trak->Media->information->sampleTable->SampleSize->sampleCount >= sample_number) {
3802 stbl_GetSampleInfos(trak->Media->information->sampleTable, sample_number, &offset, &chunkNum, &descIndex, &edit);
3803 }
3804 else {
3805 //this is dump mode of fragments, we haven't merged tables yet :(
3806 descIndex = 1;
3807 }
3808 gf_isom_cenc_get_default_info_ex(trak, descIndex, IsEncrypted, IV_size, KID);
3809
3810
3811 sample_group = NULL;
3812 group_desc_index = 0;
3813 if (trak->Media->information->sampleTable->sampleGroups) {
3814 count = gf_list_count(trak->Media->information->sampleTable->sampleGroups);
3815 for (i = 0; i<count; i++) {
3816 sample_group = (GF_SampleGroupBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroups, i);
3817 if (sample_group->grouping_type == GF_4CC('s', 'e', 'i', 'g'))
3818 break;
3819 sample_group = NULL;
3820 }
3821 if (sample_group) {
3822 first_sample_in_entry = 1;
3823 for (j = 0; j<sample_group->entry_count; j++) {
3824 last_sample_in_entry = first_sample_in_entry + sample_group->sample_entries[j].sample_count - 1;
3825 if ((sample_number<first_sample_in_entry) || (sample_number>last_sample_in_entry)) {
3826 first_sample_in_entry = last_sample_in_entry + 1;
3827 continue;
3828 }
3829 /*we found our sample*/
3830 group_desc_index = sample_group->sample_entries[j].group_description_index;
3831 break;
3832 }
3833 }
3834 }
3835 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3836 if (!group_desc_index && traf && traf->sampleGroups) {
3837 count = gf_list_count(traf->sampleGroups);
3838 for (i = 0; i<count; i++) {
3839 group_desc_index = 0;
3840 sample_group = (GF_SampleGroupBox*)gf_list_get(traf->sampleGroups, i);
3841 if (sample_group->grouping_type == GF_4CC('s', 'e', 'i', 'g'))
3842 break;
3843 sample_group = NULL;
3844 }
3845 if (sample_group) {
3846 first_sample_in_entry = 1;
3847 for (j = 0; j<sample_group->entry_count; j++) {
3848 last_sample_in_entry = first_sample_in_entry + sample_group->sample_entries[j].sample_count - 1;
3849 if ((sample_number<first_sample_in_entry) || (sample_number>last_sample_in_entry)) {
3850 first_sample_in_entry = last_sample_in_entry + 1;
3851 continue;
3852 }
3853 /*we found our sample*/
3854 group_desc_index = sample_group->sample_entries[j].group_description_index;
3855 break;
3856 }
3857 }
3858 }
3859 #endif
3860 /*no sampleGroup info associated*/
3861 if (!group_desc_index) return GF_OK;
3862
3863 sgdesc = NULL;
3864
3865 if (group_desc_index <= 0x10000) {
3866 for (j = 0; j<gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription); j++) {
3867 sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, j);
3868 if (sgdesc->grouping_type == sample_group->grouping_type) break;
3869 sgdesc = NULL;
3870 }
3871 }
3872 else if (traf) {
3873 group_desc_index -= 0x10000;
3874 #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3875 for (j = 0; j<gf_list_count(traf->sampleGroupsDescription); j++) {
3876 sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(traf->sampleGroupsDescription, j);
3877 if (sgdesc->grouping_type == sample_group->grouping_type) break;
3878 sgdesc = NULL;
3879 }
3880 #endif
3881 }
3882 /*no sampleGroup description found for this group (invalid file)*/
3883 if (!sgdesc) return GF_ISOM_INVALID_FILE;
3884
3885 entry = (GF_CENCSampleEncryptionGroupEntry *)gf_list_get(sgdesc->group_descriptions, group_desc_index - 1);
3886 if (!entry) return GF_ISOM_INVALID_FILE;
3887
3888 if (IsEncrypted) *IsEncrypted = entry->IsProtected;
3889 if (IV_size) *IV_size = entry->Per_Sample_IV_size;
3890 if (KID) memmove(*KID, entry->KID, 16);
3891 if (crypt_byte_block) *crypt_byte_block = entry->crypt_byte_block;
3892 if (skip_byte_block) *skip_byte_block = entry->skip_byte_block;
3893 if (constant_IV_size) *constant_IV_size = entry->constant_IV_size;
3894 if (constant_IV) memmove(*constant_IV, entry->constant_IV, 16);
3895
3896 return GF_OK;
3897 }
3898
3899 GF_EXPORT
gf_isom_get_sample_cenc_info(GF_ISOFile * movie,u32 track,u32 sample_number,u32 * IsEncrypted,u8 * IV_size,bin128 * KID,u8 * crypt_byte_block,u8 * skip_byte_block,u8 * constant_IV_size,bin128 * constant_IV)3900 GF_Err gf_isom_get_sample_cenc_info(GF_ISOFile *movie, u32 track, u32 sample_number, u32 *IsEncrypted, u8 *IV_size, bin128 *KID,
3901 u8 *crypt_byte_block, u8 *skip_byte_block, u8 *constant_IV_size, bin128 *constant_IV)
3902 {
3903 GF_TrackBox *trak;
3904 trak = gf_isom_get_track_from_file(movie, track);
3905 return gf_isom_get_sample_cenc_info_ex(trak, NULL, sample_number, IsEncrypted, IV_size, KID, crypt_byte_block, skip_byte_block, constant_IV_size, constant_IV);
3906 }
3907
3908 GF_EXPORT
gf_isom_get_last_producer_time_box(GF_ISOFile * file,u32 * refTrackID,u64 * ntp,u64 * timestamp,Bool reset_info)3909 Bool gf_isom_get_last_producer_time_box(GF_ISOFile *file, u32 *refTrackID, u64 *ntp, u64 *timestamp, Bool reset_info)
3910 {
3911 if (!file) return GF_FALSE;
3912 if (refTrackID) *refTrackID = 0;
3913 if (ntp) *ntp = 0;
3914 if (timestamp) *timestamp = 0;
3915
3916 if (file->last_producer_ref_time) {
3917 if (refTrackID) *refTrackID = file->last_producer_ref_time->refTrackID;
3918 if (ntp) *ntp = file->last_producer_ref_time->ntp;
3919 if (timestamp) *timestamp = file->last_producer_ref_time->timestamp;
3920
3921 if (reset_info) {
3922 file->last_producer_ref_time = NULL;
3923 }
3924 return GF_TRUE;
3925 }
3926 return GF_FALSE;
3927 }
3928
3929 GF_EXPORT
gf_isom_get_current_tfdt(GF_ISOFile * the_file,u32 trackNumber)3930 u64 gf_isom_get_current_tfdt(GF_ISOFile *the_file, u32 trackNumber)
3931 {
3932 #ifdef GPAC_DISABLE_ISOM_FRAGMENTS
3933 return 0;
3934 #else
3935 GF_TrackBox *trak;
3936 trak = gf_isom_get_track_from_file(the_file, trackNumber);
3937 if (!trak) return 0;
3938 return trak->dts_at_seg_start;
3939 #endif
3940 }
3941
gf_isom_parse_trif_info(const char * data,u32 size,u32 * id,u32 * independent,Bool * full_picture,u32 * x,u32 * y,u32 * w,u32 * h)3942 void gf_isom_parse_trif_info(const char *data, u32 size, u32 *id, u32 *independent, Bool *full_picture, u32 *x, u32 *y, u32 *w, u32 *h)
3943 {
3944 GF_BitStream *bs;
3945 bs = gf_bs_new(data, size, GF_BITSTREAM_READ);
3946 *id = gf_bs_read_u16(bs);
3947 if (!gf_bs_read_int(bs, 1)) {
3948 *independent = 0;
3949 *full_picture = 0;
3950 *x = *y = *w = *h = 0;
3951 }
3952 else {
3953 *independent = gf_bs_read_int(bs, 2);
3954 *full_picture = (Bool)gf_bs_read_int(bs, 1);
3955 /*filter_disabled*/ gf_bs_read_int(bs, 1);
3956 /*has_dependency_list*/ gf_bs_read_int(bs, 1);
3957 gf_bs_read_int(bs, 2);
3958 *x = *full_picture ? 0 : gf_bs_read_u16(bs);
3959 *y = *full_picture ? 0 : gf_bs_read_u16(bs);
3960 *w = gf_bs_read_u16(bs);
3961 *h = gf_bs_read_u16(bs);
3962 }
3963 gf_bs_del(bs);
3964 }
3965
3966 GF_EXPORT
gf_isom_get_tile_info(GF_ISOFile * file,u32 trackNumber,u32 sample_description_index,u32 * default_sample_group_index,u32 * id,u32 * independent,Bool * full_picture,u32 * x,u32 * y,u32 * w,u32 * h)3967 Bool gf_isom_get_tile_info(GF_ISOFile *file, u32 trackNumber, u32 sample_description_index, u32 *default_sample_group_index, u32 *id, u32 *independent, Bool *full_picture, u32 *x, u32 *y, u32 *w, u32 *h)
3968 {
3969 const char *data;
3970 u32 size;
3971
3972 if (!gf_isom_get_sample_group_info(file, trackNumber, sample_description_index, GF_4CC('t', 'r', 'i', 'f'), default_sample_group_index, &data, &size))
3973 return GF_FALSE;
3974 gf_isom_parse_trif_info(data, size, id, independent, full_picture, x, y, w, h);
3975 return GF_TRUE;
3976 }
3977
3978 GF_EXPORT
gf_isom_drop_date_version_info_enabled(GF_ISOFile * file)3979 Bool gf_isom_drop_date_version_info_enabled(GF_ISOFile *file)
3980 {
3981 return file->drop_date_version_info;
3982 }
3983
3984 GF_EXPORT
gf_isom_get_oinf_info(GF_ISOFile * file,u32 trackNumber,GF_OperatingPointsInformation ** ptr)3985 Bool gf_isom_get_oinf_info(GF_ISOFile *file, u32 trackNumber, GF_OperatingPointsInformation **ptr)
3986 {
3987 u32 oref_track, def_index = 0;
3988 GF_TrackBox *trak = gf_isom_get_track_from_file(file, trackNumber);
3989
3990 if (!ptr) return GF_FALSE;
3991
3992 oref_track = 0;
3993 gf_isom_get_reference(file, trackNumber, GF_ISOM_REF_OREF, 1, &oref_track);
3994 if (oref_track) {
3995 trak = gf_isom_get_track_from_file(file, oref_track);
3996 if (!trak) return GF_FALSE;
3997 }
3998
3999 *ptr = (GF_OperatingPointsInformation *)gf_isom_get_sample_group_info_entry(file, trak, GF_4CC('o', 'i', 'n', 'f'), 1, &def_index, NULL);
4000
4001 return *ptr ? GF_TRUE : GF_FALSE;
4002 }
4003
4004 #endif /*GPAC_DISABLE_ISOM*/
4005