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