Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / ISO Media File Format sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 :
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 :
35 199 : void gf_isom_set_last_error(GF_ISOFile *movie, GF_Err error)
36 : {
37 272590 : if (!movie) {
38 5 : MP4_API_IO_Err = error;
39 : } else {
40 272585 : movie->LastError = error;
41 : }
42 199 : }
43 :
44 :
45 : GF_EXPORT
46 288 : GF_Err gf_isom_last_error(GF_ISOFile *the_file)
47 : {
48 288 : if (!the_file) return MP4_API_IO_Err;
49 283 : return the_file->LastError;
50 : }
51 :
52 : GF_EXPORT
53 1672 : u8 gf_isom_get_mode(GF_ISOFile *the_file)
54 : {
55 1672 : if (!the_file) return 0;
56 1672 : return the_file->openMode;
57 : }
58 :
59 : #if 0 //unused
60 : /*! gets file size of an ISO file
61 : \param isom_file the target ISO file
62 : \return the file size in bytes
63 : */
64 : u64 gf_isom_get_file_size(GF_ISOFile *the_file)
65 : {
66 : if (!the_file) return 0;
67 : if (the_file->movieFileMap) return gf_bs_get_size(the_file->movieFileMap->bs);
68 : #ifndef GPAC_DISABLE_ISOM_WRITE
69 : if (the_file->editFileMap) return gf_bs_get_size(the_file->editFileMap->bs);
70 : #endif
71 : return 0;
72 : }
73 : #endif
74 :
75 : GF_EXPORT
76 4 : GF_Err gf_isom_freeze_order(GF_ISOFile *file)
77 : {
78 4 : u32 i=0;
79 : GF_Box *box;
80 4 : if (!file) return GF_BAD_PARAM;
81 12 : while ((box=gf_list_enum(file->TopBoxes, &i))) {
82 8 : gf_isom_box_freeze_order(box);
83 : }
84 : return GF_OK;
85 : }
86 :
87 : GF_EXPORT
88 0 : GF_Err gf_isom_set_inplace_padding(GF_ISOFile *file, u32 padding)
89 : {
90 0 : if (!file) return GF_BAD_PARAM;
91 0 : file->padding = padding;
92 0 : return GF_OK;
93 : }
94 : /**************************************************************
95 : Sample Manip
96 : **************************************************************/
97 :
98 : //creates a new empty sample
99 : GF_EXPORT
100 357459 : GF_ISOSample *gf_isom_sample_new()
101 : {
102 : GF_ISOSample *tmp;
103 357459 : GF_SAFEALLOC(tmp, GF_ISOSample);
104 357459 : return tmp;
105 : }
106 :
107 : //delete a sample
108 : GF_EXPORT
109 357458 : void gf_isom_sample_del(GF_ISOSample **samp)
110 : {
111 357458 : if (!samp || ! *samp) return;
112 357456 : if ((*samp)->data && (*samp)->dataLength) gf_free((*samp)->data);
113 357456 : gf_free(*samp);
114 357456 : *samp = NULL;
115 : }
116 :
117 10474 : static u32 gf_isom_probe_type(u32 type)
118 : {
119 10474 : switch (type) {
120 : case GF_ISOM_BOX_TYPE_FTYP:
121 : case GF_ISOM_BOX_TYPE_MOOV:
122 : return 2;
123 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
124 3188 : case GF_ISOM_BOX_TYPE_MOOF:
125 : case GF_ISOM_BOX_TYPE_STYP:
126 : case GF_ISOM_BOX_TYPE_SIDX:
127 : case GF_ISOM_BOX_TYPE_EMSG:
128 : case GF_ISOM_BOX_TYPE_PRFT:
129 : //we map free as segment when it is first in the file - a regular file shall start with ftyp or a file sig, not free
130 : //since our route stack may patch boxes to free for incomplete segments, we must map this to free
131 : case GF_ISOM_BOX_TYPE_FREE:
132 3188 : return 3;
133 : #ifndef GPAC_DISABLE_ISOM_ADOBE
134 : /*Adobe specific*/
135 11 : case GF_ISOM_BOX_TYPE_AFRA:
136 : case GF_ISOM_BOX_TYPE_ABST:
137 : #endif
138 : #endif
139 : case GF_ISOM_BOX_TYPE_MDAT:
140 : case GF_ISOM_BOX_TYPE_SKIP:
141 : case GF_ISOM_BOX_TYPE_UDTA:
142 : case GF_ISOM_BOX_TYPE_META:
143 : case GF_ISOM_BOX_TYPE_VOID:
144 : case GF_ISOM_BOX_TYPE_JP:
145 : case GF_QT_BOX_TYPE_WIDE:
146 11 : return 1;
147 5045 : default:
148 5045 : return 0;
149 : }
150 : }
151 :
152 : GF_EXPORT
153 7472 : u32 gf_isom_probe_file_range(const char *fileName, u64 start_range, u64 end_range)
154 : {
155 : u32 type = 0;
156 :
157 7472 : if (!strncmp(fileName, "gmem://", 7)) {
158 : u32 size;
159 : u8 *mem_address;
160 498 : if (gf_blob_get(fileName, &mem_address, &size, NULL) != GF_OK) {
161 0 : return 0;
162 : }
163 498 : if (size && (size > start_range + 8)) {
164 498 : type = GF_4CC(mem_address[start_range + 4], mem_address[start_range + 5], mem_address[start_range + 6], mem_address[start_range + 7]);
165 : }
166 498 : gf_blob_release(fileName);
167 6974 : } else if (!strncmp(fileName, "isobmff://", 10)) {
168 : return 2;
169 : } else {
170 : u32 nb_read;
171 : unsigned char data[4];
172 6973 : FILE *f = gf_fopen(fileName, "rb");
173 7042 : if (!f) return 0;
174 6907 : if (start_range) gf_fseek(f, start_range, SEEK_SET);
175 : type = 0;
176 6907 : nb_read = (u32) gf_fread(data, 4, f);
177 6907 : if (nb_read == 4) {
178 6904 : if (gf_fread(data, 4, f) == 4) {
179 6899 : type = GF_4CC(data[0], data[1], data[2], data[3]);
180 : }
181 : }
182 6907 : gf_fclose(f);
183 6907 : if (!nb_read) return 0;
184 : }
185 7402 : return gf_isom_probe_type(type);
186 : }
187 :
188 : GF_EXPORT
189 4459 : u32 gf_isom_probe_file(const char *fileName)
190 : {
191 4459 : return gf_isom_probe_file_range(fileName, 0, 0);
192 : }
193 :
194 : GF_EXPORT
195 3074 : u32 gf_isom_probe_data(const u8*inBuf, u32 inSize)
196 : {
197 : u32 type;
198 3074 : if (inSize < 8) return 0;
199 3072 : type = GF_4CC(inBuf[4], inBuf[5], inBuf[6], inBuf[7]);
200 3072 : return gf_isom_probe_type(type);
201 : }
202 :
203 :
204 : #ifndef GPAC_DISABLE_AV_PARSERS
205 : #include <gpac/internal/media_dev.h>
206 : #endif
207 :
208 6 : static GF_Err isom_create_init_from_mem(const char *fileName, GF_ISOFile *file)
209 : {
210 : u32 sample_rate=0;
211 : u32 nb_channels=0;
212 : u32 bps=0;
213 : //u32 atag=0;
214 : u32 nal_len=4;
215 : u32 width = 0;
216 : u32 height = 0;
217 : u32 timescale = 10000000;
218 6 : u64 tfdt = 0;
219 : char sz4cc[5];
220 : char CodecParams[2048];
221 : u32 CodecParamLen=0;
222 : char *sep, *val;
223 : GF_TrackBox *trak;
224 : GF_TrackExtendsBox *trex;
225 : GF_SampleTableBox *stbl;
226 :
227 6 : sz4cc[0] = 0;
228 :
229 6 : val = (char*) ( fileName + strlen("isobmff://") );
230 : while (1) {
231 76 : sep = strchr(val, ' ');
232 41 : if (sep) sep[0] = 0;
233 :
234 41 : if (!strncmp(val, "4cc=", 4)) strcpy(sz4cc, val+4);
235 35 : else if (!strncmp(val, "init=", 5)) {
236 6 : char szH[3], *data = val+5;
237 6 : u32 i, len = (u32) strlen(data);
238 194 : for (i=0; i<len; i+=2) {
239 : u32 v;
240 : //init is hex-encoded so 2 input bytes for one output char
241 188 : szH[0] = data[i];
242 188 : szH[1] = data[i+1];
243 188 : szH[2] = 0;
244 188 : sscanf(szH, "%X", &v);
245 188 : CodecParams[CodecParamLen] = (char) v;
246 188 : CodecParamLen++;
247 : }
248 : }
249 29 : else if (!strncmp(val, "nal=", 4)) nal_len = atoi(val+4);
250 32 : else if (!strncmp(val, "bps=", 4)) bps = atoi(val+4);
251 : //else if (!strncmp(val, "atag=", 5)) atag = atoi(val+5);
252 29 : else if (!strncmp(val, "ch=", 3)) nb_channels = atoi(val+3);
253 26 : else if (!strncmp(val, "srate=", 6)) sample_rate = atoi(val+6);
254 23 : else if (!strncmp(val, "w=", 2)) width = atoi(val+2);
255 20 : else if (!strncmp(val, "h=", 2)) height = atoi(val+2);
256 14 : else if (!strncmp(val, "scale=", 6)) timescale = atoi(val+6);
257 14 : else if (!strncmp(val, "tfdt=", 5)) {
258 6 : sscanf(val+5, LLX, &tfdt);
259 : }
260 41 : if (!sep) break;
261 35 : sep[0] = ' ';
262 35 : val = sep+1;
263 : }
264 6 : if (!stricmp(sz4cc, "H264") || !stricmp(sz4cc, "AVC1")) {
265 : }
266 3 : else if (!stricmp(sz4cc, "AACL")) {
267 : }
268 : else {
269 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Cannot convert smooth media type %s to ISO init segment\n", sz4cc));
270 : return GF_NOT_SUPPORTED;
271 : }
272 :
273 6 : file->moov = (GF_MovieBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MOOV);
274 6 : if (!file->moov) return GF_OUT_OF_MEM;
275 6 : gf_list_add(file->TopBoxes, file->moov);
276 6 : file->moov->mov = file;
277 6 : file->is_smooth = GF_TRUE;
278 6 : file->moov->mvhd = (GF_MovieHeaderBox *) gf_isom_box_new_parent(&file->moov->child_boxes, GF_ISOM_BOX_TYPE_MVHD);
279 6 : if (!file->moov->mvhd) return GF_OUT_OF_MEM;
280 6 : file->moov->mvhd->timeScale = timescale;
281 6 : file->moov->mvex = (GF_MovieExtendsBox *) gf_isom_box_new_parent(&file->moov->child_boxes, GF_ISOM_BOX_TYPE_MVEX);
282 6 : if (!file->moov->mvex) return GF_OUT_OF_MEM;
283 6 : trex = (GF_TrackExtendsBox *) gf_isom_box_new_parent(&file->moov->mvex->child_boxes, GF_ISOM_BOX_TYPE_TREX);
284 6 : if (!trex) return GF_OUT_OF_MEM;
285 :
286 6 : trex->def_sample_desc_index = 1;
287 6 : trex->trackID = 1;
288 6 : gf_list_add(file->moov->mvex->TrackExList, trex);
289 :
290 6 : trak = (GF_TrackBox *) gf_isom_box_new_parent(&file->moov->child_boxes, GF_ISOM_BOX_TYPE_TRAK);
291 6 : if (!trak) return GF_OUT_OF_MEM;
292 6 : trak->moov = file->moov;
293 6 : gf_list_add(file->moov->trackList, trak);
294 :
295 6 : trak->Header = (GF_TrackHeaderBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_TKHD);
296 6 : if (!trak->Header) return GF_OUT_OF_MEM;
297 6 : trak->Header->trackID = 1;
298 6 : trak->Header->flags |= 1;
299 6 : trak->Header->width = width;
300 6 : trak->Header->height = height;
301 :
302 6 : trak->Media = (GF_MediaBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_MDIA);
303 6 : if (!trak->Media) return GF_OUT_OF_MEM;
304 6 : trak->Media->mediaTrack = trak;
305 6 : trak->Media->mediaHeader = (GF_MediaHeaderBox *) gf_isom_box_new_parent(&trak->Media->child_boxes, GF_ISOM_BOX_TYPE_MDHD);
306 6 : if (!trak->Media->mediaHeader) return GF_OUT_OF_MEM;
307 6 : trak->Media->mediaHeader->timeScale = timescale;
308 :
309 6 : trak->Media->handler = (GF_HandlerBox *) gf_isom_box_new_parent(&trak->Media->child_boxes,GF_ISOM_BOX_TYPE_HDLR);
310 6 : if (!trak->Media->handler) return GF_OUT_OF_MEM;
311 : //we assume by default vide for handler type (only used for smooth streaming)
312 6 : trak->Media->handler->handlerType = width ? GF_ISOM_MEDIA_VISUAL : GF_ISOM_MEDIA_AUDIO;
313 :
314 6 : trak->Media->information = (GF_MediaInformationBox *) gf_isom_box_new_parent(&trak->Media->child_boxes, GF_ISOM_BOX_TYPE_MINF);
315 6 : if (!trak->Media->information) return GF_OUT_OF_MEM;
316 6 : trak->Media->information->sampleTable = (GF_SampleTableBox *) gf_isom_box_new_parent(&trak->Media->information->child_boxes, GF_ISOM_BOX_TYPE_STBL);
317 6 : if (!trak->Media->information->sampleTable) return GF_OUT_OF_MEM;
318 :
319 : stbl = trak->Media->information->sampleTable;
320 6 : stbl->SampleSize = (GF_SampleSizeBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSZ);
321 6 : if (!stbl->SampleSize) return GF_OUT_OF_MEM;
322 6 : stbl->TimeToSample = (GF_TimeToSampleBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STTS);
323 6 : if (!stbl->TimeToSample) return GF_OUT_OF_MEM;
324 6 : stbl->ChunkOffset = (GF_Box *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STCO);
325 6 : if (!stbl->ChunkOffset) return GF_OUT_OF_MEM;
326 6 : stbl->SampleToChunk = (GF_SampleToChunkBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSC);
327 6 : if (!stbl->SampleToChunk) return GF_OUT_OF_MEM;
328 6 : stbl->SyncSample = (GF_SyncSampleBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSS);
329 6 : if (!stbl->SyncSample) return GF_OUT_OF_MEM;
330 6 : stbl->SampleDescription = (GF_SampleDescriptionBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSD);
331 6 : if (!stbl->SampleDescription) return GF_OUT_OF_MEM;
332 :
333 6 : trak->dts_at_seg_start = tfdt;
334 6 : trak->dts_at_next_seg_start = tfdt;
335 :
336 :
337 9 : if (!stricmp(sz4cc, "H264") || !stricmp(sz4cc, "AVC1")) {
338 : #ifndef GPAC_DISABLE_AV_PARSERS
339 : u32 pos = 0;
340 3 : u32 end, sc_size=0;
341 : #endif
342 3 : GF_MPEGVisualSampleEntryBox *avc = (GF_MPEGVisualSampleEntryBox *) gf_isom_box_new_parent(&stbl->SampleDescription->child_boxes, GF_ISOM_BOX_TYPE_AVC1);
343 3 : if (!avc) return GF_OUT_OF_MEM;
344 3 : avc->avc_config = (GF_AVCConfigurationBox *) gf_isom_box_new_parent(&avc->child_boxes, GF_ISOM_BOX_TYPE_AVCC);
345 3 : if (!avc->avc_config) return GF_OUT_OF_MEM;
346 :
347 3 : avc->Width = width;
348 3 : avc->Height = height;
349 :
350 3 : avc->avc_config->config = gf_odf_avc_cfg_new();
351 3 : avc->avc_config->config->nal_unit_size = nal_len;
352 3 : avc->avc_config->config->configurationVersion = 1;
353 :
354 : #ifndef GPAC_DISABLE_AV_PARSERS
355 : //locate pps and sps
356 3 : gf_media_nalu_next_start_code((u8 *) CodecParams, CodecParamLen, &sc_size);
357 3 : pos += sc_size;
358 12 : while (pos<CodecParamLen) {
359 : GF_NALUFFParam *slc;
360 : u8 nal_type;
361 6 : char *nal = &CodecParams[pos];
362 6 : end = gf_media_nalu_next_start_code(nal, CodecParamLen-pos, &sc_size);
363 6 : if (!end) end = CodecParamLen;
364 :
365 6 : GF_SAFEALLOC(slc, GF_NALUFFParam);
366 6 : if (!slc) break;
367 6 : slc->size = end;
368 6 : slc->data = gf_malloc(sizeof(char)*slc->size);
369 6 : if (!slc->data) return GF_OUT_OF_MEM;
370 6 : memcpy(slc->data, nal, sizeof(char)*slc->size);
371 :
372 6 : nal_type = nal[0] & 0x1F;
373 6 : if (nal_type == GF_AVC_NALU_SEQ_PARAM) {
374 : /* AVCState avcc;
375 : u32 idx = gf_avc_read_sps(slc->data, slc->size, &avcc, 0, NULL);
376 : avc->avc_config->config->profile_compatibility = avcc.sps[idx].prof_compat;
377 : avc->avc_config->config->AVCProfileIndication = avcc.sps[idx].profile_idc;
378 : avc->avc_config->config->AVCLevelIndication = avcc.sps[idx].level_idc;
379 : avc->avc_config->config->chroma_format = avcc.sps[idx].chroma_format;
380 : avc->avc_config->config->luma_bit_depth = 8 + avcc.sps[idx].luma_bit_depth_m8;
381 : avc->avc_config->config->chroma_bit_depth = 8 + avcc.sps[idx].chroma_bit_depth_m8;
382 : */
383 :
384 3 : gf_list_add(avc->avc_config->config->sequenceParameterSets, slc);
385 : } else {
386 3 : gf_list_add(avc->avc_config->config->pictureParameterSets, slc);
387 : }
388 6 : pos += slc->size + sc_size;
389 : }
390 : #endif
391 :
392 3 : AVC_RewriteESDescriptor(avc);
393 : }
394 3 : else if (!stricmp(sz4cc, "AACL")) {
395 : #ifndef GPAC_DISABLE_AV_PARSERS
396 : GF_M4ADecSpecInfo aacinfo;
397 : #endif
398 :
399 3 : GF_MPEGAudioSampleEntryBox *aac = (GF_MPEGAudioSampleEntryBox *) gf_isom_box_new_parent(&stbl->SampleDescription->child_boxes, GF_ISOM_BOX_TYPE_MP4A);
400 3 : if (!aac) return GF_OUT_OF_MEM;
401 3 : aac->esd = (GF_ESDBox *) gf_isom_box_new_parent(&aac->child_boxes, GF_ISOM_BOX_TYPE_ESDS);
402 3 : if (!aac->esd) return GF_OUT_OF_MEM;
403 3 : aac->esd->desc = gf_odf_desc_esd_new(2);
404 3 : if (!aac->esd->desc) return GF_OUT_OF_MEM;
405 : #ifndef GPAC_DISABLE_AV_PARSERS
406 : memset(&aacinfo, 0, sizeof(GF_M4ADecSpecInfo));
407 3 : aacinfo.nb_chan = nb_channels;
408 3 : aacinfo.base_object_type = GF_M4A_AAC_LC;
409 3 : aacinfo.base_sr = sample_rate;
410 3 : gf_m4a_write_config(&aacinfo, &aac->esd->desc->decoderConfig->decoderSpecificInfo->data, &aac->esd->desc->decoderConfig->decoderSpecificInfo->dataLength);
411 : #endif
412 3 : aac->esd->desc->decoderConfig->streamType = GF_STREAM_AUDIO;
413 3 : aac->esd->desc->decoderConfig->objectTypeIndication = GF_CODECID_AAC_MPEG4;
414 3 : aac->bitspersample = bps;
415 3 : aac->samplerate_hi = sample_rate;
416 3 : aac->channel_count = nb_channels;
417 : }
418 :
419 : return GF_OK;
420 : }
421 :
422 : /**************************************************************
423 : File Opening in streaming mode
424 : the file map is regular (through FILE handles)
425 : **************************************************************/
426 : GF_EXPORT
427 737 : GF_Err gf_isom_open_progressive_ex(const char *fileName, u64 start_range, u64 end_range, Bool enable_frag_bounds, GF_ISOFile **the_file, u64 *BytesMissing, u32 *outBoxType)
428 : {
429 : GF_Err e;
430 : GF_ISOFile *movie;
431 :
432 737 : if (!BytesMissing || !the_file)
433 : return GF_BAD_PARAM;
434 737 : *BytesMissing = 0;
435 737 : *the_file = NULL;
436 :
437 737 : movie = gf_isom_new_movie();
438 737 : if (!movie) return GF_OUT_OF_MEM;
439 :
440 737 : movie->fileName = gf_strdup(fileName);
441 737 : movie->openMode = GF_ISOM_OPEN_READ;
442 737 : movie->signal_frag_bounds = enable_frag_bounds;
443 :
444 : #ifndef GPAC_DISABLE_ISOM_WRITE
445 737 : movie->editFileMap = NULL;
446 737 : movie->finalName = NULL;
447 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
448 :
449 737 : if (!strncmp(fileName, "isobmff://", 10)) {
450 6 : movie->movieFileMap = NULL;
451 6 : e = isom_create_init_from_mem(fileName, movie);
452 : } else {
453 : //do NOT use FileMapping on incomplete files
454 731 : e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_READ, &movie->movieFileMap);
455 731 : if (e) {
456 0 : gf_isom_delete_movie(movie);
457 0 : return e;
458 : }
459 :
460 731 : if (start_range || end_range) {
461 14 : if (end_range>start_range) {
462 14 : gf_bs_seek(movie->movieFileMap->bs, end_range+1);
463 14 : gf_bs_truncate(movie->movieFileMap->bs);
464 : }
465 14 : gf_bs_seek(movie->movieFileMap->bs, start_range);
466 : }
467 731 : e = gf_isom_parse_movie_boxes(movie, outBoxType, BytesMissing, GF_TRUE);
468 :
469 : }
470 737 : if (e == GF_ISOM_INCOMPLETE_FILE) {
471 : //if we have a moov, we're fine
472 42 : if (movie->moov) {
473 13 : *the_file = (GF_ISOFile *)movie;
474 13 : return GF_OK;
475 : }
476 : //if not, delete the movie
477 29 : gf_isom_delete_movie(movie);
478 29 : return e;
479 695 : } else if (e) {
480 : //if not, delete the movie
481 0 : gf_isom_delete_movie(movie);
482 0 : return e;
483 : }
484 :
485 : //OK, let's return
486 695 : *the_file = (GF_ISOFile *)movie;
487 695 : return GF_OK;
488 : }
489 :
490 : GF_EXPORT
491 729 : GF_Err gf_isom_open_progressive(const char *fileName, u64 start_range, u64 end_range, Bool enable_frag_bounds, GF_ISOFile **the_file, u64 *BytesMissing)
492 : {
493 729 : return gf_isom_open_progressive_ex(fileName, start_range, end_range, enable_frag_bounds, the_file, BytesMissing, NULL);
494 : }
495 :
496 : /**************************************************************
497 : File Reading
498 : **************************************************************/
499 :
500 : GF_EXPORT
501 2317 : GF_ISOFile *gf_isom_open(const char *fileName, GF_ISOOpenMode OpenMode, const char *tmp_dir)
502 : {
503 : GF_ISOFile *movie;
504 2317 : MP4_API_IO_Err = GF_OK;
505 :
506 2317 : switch (OpenMode & 0xFF) {
507 798 : case GF_ISOM_OPEN_READ_DUMP:
508 : case GF_ISOM_OPEN_READ:
509 798 : movie = gf_isom_open_file(fileName, OpenMode, NULL);
510 798 : break;
511 :
512 : #ifndef GPAC_DISABLE_ISOM_WRITE
513 :
514 349 : case GF_ISOM_OPEN_WRITE:
515 349 : movie = gf_isom_create_movie(fileName, OpenMode, tmp_dir);
516 349 : break;
517 222 : case GF_ISOM_OPEN_EDIT:
518 : case GF_ISOM_OPEN_READ_EDIT:
519 : case GF_ISOM_OPEN_KEEP_FRAGMENTS:
520 222 : movie = gf_isom_open_file(fileName, OpenMode, tmp_dir);
521 222 : break;
522 948 : case GF_ISOM_WRITE_EDIT:
523 948 : movie = gf_isom_create_movie(fileName, OpenMode, tmp_dir);
524 948 : break;
525 :
526 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
527 :
528 : default:
529 : return NULL;
530 : }
531 : return (GF_ISOFile *) movie;
532 : }
533 :
534 :
535 : #if 0
536 : /*! gets access to the data bitstream - see \ref gf_isom_open
537 : \param isom_file the target ISO file
538 : \param out_bs set to the file input bitstream - do NOT destroy
539 : \return error if any
540 : */
541 : GF_Err gf_isom_get_bs(GF_ISOFile *movie, GF_BitStream **out_bs)
542 : {
543 : #ifndef GPAC_DISABLE_ISOM_WRITE
544 : if (!movie || movie->openMode != GF_ISOM_OPEN_WRITE || !movie->editFileMap) //memory mode
545 : return GF_NOT_SUPPORTED;
546 :
547 : if (movie->segment_bs)
548 : *out_bs = movie->segment_bs;
549 : else
550 : *out_bs = movie->editFileMap->bs;
551 :
552 : if (movie->moof)
553 : movie->moof->fragment_offset = 0;
554 :
555 : return GF_OK;
556 : #else
557 : return GF_NOT_SUPPORTED;
558 : #endif
559 : }
560 : #endif
561 :
562 :
563 : GF_EXPORT
564 1858 : GF_Err gf_isom_write(GF_ISOFile *movie) {
565 : GF_Err e;
566 1858 : if (movie == NULL) return GF_ISOM_INVALID_FILE;
567 : e = GF_OK;
568 :
569 : #ifndef GPAC_DISABLE_ISOM_WRITE
570 : //write our movie to the file
571 1858 : if ((movie->openMode != GF_ISOM_OPEN_READ) && (movie->openMode != GF_ISOM_OPEN_READ_EDIT)) {
572 1149 : gf_isom_get_duration(movie);
573 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
574 : //movie fragment mode, just store the fragment
575 1149 : if ( (movie->openMode == GF_ISOM_OPEN_WRITE) && (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY) ) {
576 30 : e = gf_isom_close_fragments(movie);
577 30 : if (e) return e;
578 : //in case of mfra box usage -> create mfro, calculate box sizes and write it out
579 30 : if (movie->mfra) {
580 1 : if (!movie->mfra->mfro) {
581 1 : movie->mfra->mfro = (GF_MovieFragmentRandomAccessOffsetBox *)gf_isom_box_new_parent(&movie->mfra->child_boxes, GF_ISOM_BOX_TYPE_MFRO);
582 1 : if (!movie->mfra->mfro) return GF_OUT_OF_MEM;
583 : }
584 1 : e = gf_isom_box_size((GF_Box *)movie->mfra);
585 1 : if (e) return e;
586 1 : movie->mfra->mfro->container_size = (u32) movie->mfra->size;
587 :
588 : //write mfra
589 2 : if (!strcmp(movie->fileName, "_gpac_isobmff_redirect") && movie->on_block_out) {
590 1 : GF_BitStream *bs = gf_bs_new_cbk(movie->on_block_out, movie->on_block_out_usr_data, movie->on_block_out_block_size);
591 :
592 1 : e = gf_isom_box_write((GF_Box *)movie->mfra, bs);
593 1 : gf_bs_del(bs);
594 : } else {
595 0 : e = gf_isom_box_write((GF_Box *)movie->mfra, movie->editFileMap->bs);
596 : }
597 : }
598 : } else
599 : #endif
600 1119 : e = WriteToFile(movie, GF_FALSE);
601 : }
602 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
603 :
604 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
605 1858 : if (movie->moov) {
606 : u32 i;
607 2532 : for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
608 2532 : GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
609 : /*delete any pending dataHandler of scalable enhancements*/
610 2532 : if (trak->Media && trak->Media->information && trak->Media->information->scalableDataHandler && (trak->Media->information->scalableDataHandler != movie->movieFileMap))
611 0 : gf_isom_datamap_del(trak->Media->information->scalableDataHandler);
612 : }
613 : }
614 : #endif
615 :
616 : return e;
617 : }
618 :
619 : GF_EXPORT
620 1858 : GF_Err gf_isom_close(GF_ISOFile *movie)
621 : {
622 : GF_Err e=GF_OK;
623 1858 : if (movie == NULL) return GF_ISOM_INVALID_FILE;
624 1858 : e = gf_isom_write(movie);
625 : //free and return;
626 1858 : gf_isom_delete_movie(movie);
627 1858 : return e;
628 : }
629 :
630 :
631 : #if 0 //unused
632 : /*! checks if files has root OD/IOD or not
633 : \param isom_file the target ISO file
634 : \return GF_TRUE if the file has a root OD or IOD */
635 : Bool gf_isom_has_root_od(GF_ISOFile *movie)
636 : {
637 : if (!movie || !movie->moov || !movie->moov->iods || !movie->moov->iods->descriptor) return GF_FALSE;
638 : return GF_TRUE;
639 : }
640 : #endif
641 :
642 : GF_EXPORT
643 1 : void gf_isom_disable_odf_conversion(GF_ISOFile *movie, Bool disable)
644 : {
645 1 : if (movie) movie->disable_odf_translate = disable;
646 1 : }
647 :
648 : //this funct is used for exchange files, where the iods contains an OD
649 : GF_EXPORT
650 1278 : GF_Descriptor *gf_isom_get_root_od(GF_ISOFile *movie)
651 : {
652 : GF_Descriptor *desc;
653 : GF_ObjectDescriptor *od;
654 : GF_InitialObjectDescriptor *iod;
655 : GF_IsomObjectDescriptor *isom_od;
656 : GF_IsomInitialObjectDescriptor *isom_iod;
657 : GF_ESD *esd;
658 : GF_ES_ID_Inc *inc;
659 : u32 i;
660 : u8 useIOD;
661 :
662 1278 : if (!movie || !movie->moov) return NULL;
663 1248 : if (!movie->moov->iods) return NULL;
664 :
665 574 : if (movie->disable_odf_translate) {
666 : //duplicate our descriptor
667 1 : movie->LastError = gf_odf_desc_copy((GF_Descriptor *) movie->moov->iods->descriptor, &desc);
668 1 : if (movie->LastError) return NULL;
669 1 : return desc;
670 : }
671 : od = NULL;
672 : iod = NULL;
673 :
674 573 : switch (movie->moov->iods->descriptor->tag) {
675 0 : case GF_ODF_ISOM_OD_TAG:
676 0 : od = (GF_ObjectDescriptor*)gf_malloc(sizeof(GF_ObjectDescriptor));
677 0 : if (!od) return NULL;
678 :
679 : memset(od, 0, sizeof(GF_ObjectDescriptor));
680 0 : od->ESDescriptors = gf_list_new();
681 : useIOD = 0;
682 0 : break;
683 573 : case GF_ODF_ISOM_IOD_TAG:
684 573 : iod = (GF_InitialObjectDescriptor*)gf_malloc(sizeof(GF_InitialObjectDescriptor));
685 573 : if (!iod) return NULL;
686 :
687 : memset(iod, 0, sizeof(GF_InitialObjectDescriptor));
688 573 : iod->ESDescriptors = gf_list_new();
689 : useIOD = 1;
690 573 : break;
691 : default:
692 : return NULL;
693 : }
694 :
695 : //duplicate our descriptor
696 573 : movie->LastError = gf_odf_desc_copy((GF_Descriptor *) movie->moov->iods->descriptor, &desc);
697 573 : if (movie->LastError) return NULL;
698 :
699 573 : if (!useIOD) {
700 0 : isom_od = (GF_IsomObjectDescriptor *)desc;
701 0 : od->objectDescriptorID = isom_od->objectDescriptorID;
702 0 : od->extensionDescriptors = isom_od->extensionDescriptors;
703 0 : isom_od->extensionDescriptors = NULL;
704 0 : od->IPMP_Descriptors = isom_od->IPMP_Descriptors;
705 0 : isom_od->IPMP_Descriptors = NULL;
706 0 : od->OCIDescriptors = isom_od->OCIDescriptors;
707 0 : isom_od->OCIDescriptors = NULL;
708 0 : od->URLString = isom_od->URLString;
709 0 : isom_od->URLString = NULL;
710 0 : od->tag = GF_ODF_OD_TAG;
711 : //then recreate the desc in Inc
712 0 : i=0;
713 0 : while ((inc = (GF_ES_ID_Inc*)gf_list_enum(isom_od->ES_ID_IncDescriptors, &i))) {
714 0 : movie->LastError = GetESDForTime(movie->moov, inc->trackID, 0, &esd);
715 0 : if (!movie->LastError) movie->LastError = gf_list_add(od->ESDescriptors, esd);
716 0 : if (movie->LastError) {
717 0 : gf_odf_desc_del(desc);
718 0 : gf_odf_desc_del((GF_Descriptor *) od);
719 0 : return NULL;
720 : }
721 : }
722 0 : gf_odf_desc_del(desc);
723 0 : return (GF_Descriptor *)od;
724 : } else {
725 573 : isom_iod = (GF_IsomInitialObjectDescriptor *)desc;
726 573 : iod->objectDescriptorID = isom_iod->objectDescriptorID;
727 573 : iod->extensionDescriptors = isom_iod->extensionDescriptors;
728 573 : isom_iod->extensionDescriptors = NULL;
729 573 : iod->IPMP_Descriptors = isom_iod->IPMP_Descriptors;
730 573 : isom_iod->IPMP_Descriptors = NULL;
731 573 : iod->OCIDescriptors = isom_iod->OCIDescriptors;
732 573 : isom_iod->OCIDescriptors = NULL;
733 573 : iod->URLString = isom_iod->URLString;
734 573 : isom_iod->URLString = NULL;
735 573 : iod->tag = GF_ODF_IOD_TAG;
736 :
737 573 : iod->audio_profileAndLevel = isom_iod->audio_profileAndLevel;
738 573 : iod->graphics_profileAndLevel = isom_iod->graphics_profileAndLevel;
739 573 : iod->inlineProfileFlag = isom_iod->inlineProfileFlag;
740 573 : iod->OD_profileAndLevel = isom_iod->OD_profileAndLevel;
741 573 : iod->scene_profileAndLevel = isom_iod->scene_profileAndLevel;
742 573 : iod->visual_profileAndLevel = isom_iod->visual_profileAndLevel;
743 573 : iod->IPMPToolList = isom_iod->IPMPToolList;
744 573 : isom_iod->IPMPToolList = NULL;
745 :
746 : //then recreate the desc in Inc
747 573 : i=0;
748 1231 : while ((inc = (GF_ES_ID_Inc*)gf_list_enum(isom_iod->ES_ID_IncDescriptors, &i))) {
749 85 : movie->LastError = GetESDForTime(movie->moov, inc->trackID, 0, &esd);
750 85 : if (!movie->LastError) movie->LastError = gf_list_add(iod->ESDescriptors, esd);
751 85 : if (movie->LastError) {
752 0 : gf_odf_desc_del(desc);
753 0 : gf_odf_desc_del((GF_Descriptor *) iod);
754 0 : return NULL;
755 : }
756 : }
757 573 : gf_odf_desc_del(desc);
758 573 : return (GF_Descriptor *)iod;
759 : }
760 : }
761 :
762 :
763 : GF_EXPORT
764 18182 : u32 gf_isom_get_track_count(GF_ISOFile *movie)
765 : {
766 18182 : if (!movie || !movie->moov) return 0;
767 :
768 18052 : if (!movie->moov->trackList) {
769 0 : movie->LastError = GF_ISOM_INVALID_FILE;
770 0 : return 0;
771 : }
772 18052 : return gf_list_count(movie->moov->trackList);
773 : }
774 :
775 :
776 : GF_EXPORT
777 9777 : GF_ISOTrackID gf_isom_get_track_id(GF_ISOFile *movie, u32 trackNumber)
778 : {
779 : GF_TrackBox *trak;
780 9777 : if (!movie) return 0;
781 9777 : trak = gf_isom_get_track_from_file(movie, trackNumber);
782 9777 : if (!trak || !trak->Header) return 0;
783 9731 : return trak->Header->trackID;
784 : }
785 :
786 :
787 : GF_EXPORT
788 2427 : u32 gf_isom_get_track_by_id(GF_ISOFile *the_file, GF_ISOTrackID trackID)
789 : {
790 : u32 count;
791 : u32 i;
792 2427 : if (the_file == NULL) return 0;
793 :
794 2427 : count = gf_isom_get_track_count(the_file);
795 2427 : if (!count) return 0;
796 4803 : for (i = 0; i < count; i++) {
797 4657 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, i+1);
798 4657 : if (!trak || !trak->Header) return 0;
799 4657 : if (trak->Header->trackID == trackID) return i+1;
800 : }
801 : return 0;
802 : }
803 :
804 : GF_EXPORT
805 24 : GF_ISOTrackID gf_isom_get_track_original_id(GF_ISOFile *movie, u32 trackNumber)
806 : {
807 : GF_TrackBox *trak;
808 24 : if (!movie) return 0;
809 24 : trak = gf_isom_get_track_from_file(movie, trackNumber);
810 24 : if (!trak) return 0;
811 24 : return trak->originalID;
812 : }
813 :
814 : //return the timescale of the movie, 0 if error
815 : GF_EXPORT
816 186 : Bool gf_isom_has_movie(GF_ISOFile *file)
817 : {
818 186 : if (file && file->moov) return GF_TRUE;
819 1 : return GF_FALSE;
820 : }
821 :
822 : #ifndef GPAC_DISABLE_ISOM
823 : GF_EXPORT
824 1 : Bool gf_isom_has_segment(GF_ISOFile *file, u32 *brand, u32 *version)
825 : {
826 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
827 : u32 i;
828 : GF_Box *a;
829 1 : i = 0;
830 2 : while (NULL != (a = (GF_Box*)gf_list_enum(file->TopBoxes, &i))) {
831 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
832 1 : if (a->type == GF_ISOM_BOX_TYPE_STYP) {
833 : GF_FileTypeBox *styp = (GF_FileTypeBox *)a;
834 1 : *brand = styp->majorBrand;
835 1 : *version = styp->minorVersion;
836 1 : return GF_TRUE;
837 : }
838 : #endif
839 : }
840 : #endif
841 : return GF_FALSE;
842 : }
843 :
844 : GF_EXPORT
845 1 : u32 gf_isom_segment_get_fragment_count(GF_ISOFile *file)
846 : {
847 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
848 1 : if (file) {
849 : u32 i, count = 0;
850 4 : for (i=0; i<gf_list_count(file->TopBoxes); i++) {
851 4 : GF_Box *a = (GF_Box*)gf_list_get(file->TopBoxes, i);
852 4 : if (a->type==GF_ISOM_BOX_TYPE_MOOF) count++;
853 : }
854 : return count;
855 : }
856 : #endif
857 : return 0;
858 : }
859 :
860 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
861 2 : static GF_MovieFragmentBox *gf_isom_get_moof(GF_ISOFile *file, u32 moof_index)
862 : {
863 : u32 i;
864 4 : for (i=0; i<gf_list_count(file->TopBoxes); i++) {
865 6 : GF_Box *a = (GF_Box*)gf_list_get(file->TopBoxes, i);
866 6 : if (a->type==GF_ISOM_BOX_TYPE_MOOF) {
867 2 : moof_index--;
868 2 : if (!moof_index) return (GF_MovieFragmentBox *) a;
869 : }
870 : }
871 : return NULL;
872 : }
873 : #endif /* GPAC_DISABLE_ISOM_FRAGMENTS */
874 :
875 : GF_EXPORT
876 1 : u32 gf_isom_segment_get_track_fragment_count(GF_ISOFile *file, u32 moof_index)
877 : {
878 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
879 : GF_MovieFragmentBox *moof;
880 1 : if (!file) return 0;
881 1 : gf_list_count(file->TopBoxes);
882 1 : moof = gf_isom_get_moof(file, moof_index);
883 1 : return moof ? gf_list_count(moof->TrackList) : 0;
884 : #endif
885 : return 0;
886 : }
887 :
888 : GF_EXPORT
889 1 : u32 gf_isom_segment_get_track_fragment_decode_time(GF_ISOFile *file, u32 moof_index, u32 traf_index, u64 *decode_time)
890 : {
891 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
892 : GF_MovieFragmentBox *moof;
893 : GF_TrackFragmentBox *traf;
894 1 : if (!file) return 0;
895 1 : gf_list_count(file->TopBoxes);
896 1 : moof = gf_isom_get_moof(file, moof_index);
897 1 : traf = moof ? (GF_TrackFragmentBox*)gf_list_get(moof->TrackList, traf_index-1) : NULL;
898 1 : if (!traf) return 0;
899 1 : if (decode_time) {
900 1 : *decode_time = traf->tfdt ? traf->tfdt->baseMediaDecodeTime : 0;
901 : }
902 1 : return traf->tfhd->trackID;
903 : #endif
904 : return 0;
905 : }
906 : #endif
907 :
908 : //return the timescale of the movie, 0 if error
909 : GF_EXPORT
910 4286 : u32 gf_isom_get_timescale(GF_ISOFile *movie)
911 : {
912 4286 : if (!movie || !movie->moov || !movie->moov->mvhd) return 0;
913 4163 : return movie->moov->mvhd->timeScale;
914 : }
915 :
916 :
917 : //return the duration of the movie, 0 if error
918 : GF_EXPORT
919 2780 : u64 gf_isom_get_duration(GF_ISOFile *movie)
920 : {
921 2780 : if (!movie || !movie->moov || !movie->moov->mvhd) return 0;
922 :
923 : //if file was open in Write or Edit mode, recompute the duration
924 : //the duration of a movie is the MaxDuration of all the tracks...
925 :
926 : #ifndef GPAC_DISABLE_ISOM_WRITE
927 2687 : gf_isom_update_duration(movie);
928 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
929 :
930 2687 : return movie->moov->mvhd->duration;
931 : }
932 : //return the duration of the movie, 0 if error
933 : GF_EXPORT
934 185 : u64 gf_isom_get_original_duration(GF_ISOFile *movie)
935 : {
936 185 : if (!movie || !movie->moov|| !movie->moov->mvhd) return 0;
937 185 : return movie->moov->mvhd->original_duration;
938 : }
939 :
940 : //return the creation info of the movie
941 : GF_EXPORT
942 208 : GF_Err gf_isom_get_creation_time(GF_ISOFile *movie, u64 *creationTime, u64 *modificationTime)
943 : {
944 208 : if (!movie || !movie->moov) return GF_BAD_PARAM;
945 :
946 208 : if (creationTime) *creationTime = movie->moov->mvhd->creationTime;
947 208 : if (creationTime) *modificationTime = movie->moov->mvhd->modificationTime;
948 : return GF_OK;
949 : }
950 :
951 : GF_EXPORT
952 0 : GF_Err gf_isom_get_track_creation_time(GF_ISOFile *movie, u32 trackNumber, u64 *creationTime, u64 *modificationTime)
953 : {
954 : GF_TrackBox *trak;
955 0 : if (!movie || !movie->moov) return GF_BAD_PARAM;
956 0 : trak = gf_isom_get_track_from_file(movie, trackNumber);
957 0 : if (!trak) return 0;
958 :
959 0 : if (creationTime) *creationTime = trak->Media->mediaHeader->creationTime;
960 0 : if (creationTime) *modificationTime = trak->Media->mediaHeader->modificationTime;
961 : return GF_OK;
962 : }
963 :
964 : //check the presence of a track in IOD. 0: NO, 1: YES, 2: ERROR
965 : GF_EXPORT
966 1679 : u8 gf_isom_is_track_in_root_od(GF_ISOFile *movie, u32 trackNumber)
967 : {
968 : u32 i;
969 : GF_ISOTrackID trackID;
970 : GF_Descriptor *desc;
971 : GF_ES_ID_Inc *inc;
972 : GF_List *inc_list;
973 1679 : if (!movie) return 2;
974 1679 : if (!movie->moov || !movie->moov->iods) return 0;
975 :
976 902 : desc = movie->moov->iods->descriptor;
977 902 : switch (desc->tag) {
978 866 : case GF_ODF_ISOM_IOD_TAG:
979 866 : inc_list = ((GF_IsomInitialObjectDescriptor *)desc)->ES_ID_IncDescriptors;
980 866 : break;
981 36 : case GF_ODF_ISOM_OD_TAG:
982 36 : inc_list = ((GF_IsomObjectDescriptor *)desc)->ES_ID_IncDescriptors;
983 36 : break;
984 : //files without IOD are possible !
985 : default:
986 : return 0;
987 : }
988 902 : trackID = gf_isom_get_track_id(movie, trackNumber);
989 902 : if (!trackID) return 2;
990 902 : i=0;
991 2004 : while ((inc = (GF_ES_ID_Inc*)gf_list_enum(inc_list, &i))) {
992 275 : if (inc->trackID == (u32) trackID) return 1;
993 : }
994 : return 0;
995 : }
996 :
997 :
998 :
999 : //gets the enable flag of a track
1000 : //0: NO, 1: YES, 2: ERROR
1001 : GF_EXPORT
1002 1479 : u8 gf_isom_is_track_enabled(GF_ISOFile *the_file, u32 trackNumber)
1003 : {
1004 : GF_TrackBox *trak;
1005 1479 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1006 :
1007 1479 : if (!trak || !trak->Header) return 2;
1008 1479 : return (trak->Header->flags & 1) ? 1 : 0;
1009 : }
1010 :
1011 : GF_EXPORT
1012 23 : u32 gf_isom_get_track_flags(GF_ISOFile *the_file, u32 trackNumber)
1013 : {
1014 : GF_TrackBox *trak;
1015 23 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1016 23 : if (!trak) return 0;
1017 23 : return trak->Header->flags;
1018 : }
1019 :
1020 :
1021 : //get the track duration
1022 : //return 0 if bad param
1023 : GF_EXPORT
1024 1312 : u64 gf_isom_get_track_duration(GF_ISOFile *movie, u32 trackNumber)
1025 : {
1026 : GF_TrackBox *trak;
1027 1312 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1028 1312 : if (!trak) return 0;
1029 :
1030 : #ifndef GPAC_DISABLE_ISOM_WRITE
1031 : /*in all modes except dump recompute duration in case headers are wrong*/
1032 1312 : if (movie->openMode != GF_ISOM_OPEN_READ_DUMP) {
1033 1312 : SetTrackDuration(trak);
1034 : }
1035 : #endif
1036 1312 : return trak->Header->duration;
1037 : }
1038 :
1039 : GF_EXPORT
1040 818 : GF_Err gf_isom_get_media_language(GF_ISOFile *the_file, u32 trackNumber, char **lang)
1041 : {
1042 : u32 count;
1043 : Bool elng_found = GF_FALSE;
1044 : GF_TrackBox *trak;
1045 818 : if (!lang) {
1046 : return GF_BAD_PARAM;
1047 : }
1048 818 : *lang = NULL;
1049 818 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1050 818 : if (!trak || !trak->Media) return GF_BAD_PARAM;
1051 818 : count = gf_list_count(trak->Media->child_boxes);
1052 818 : if (count>0) {
1053 : u32 i;
1054 2454 : for (i = 0; i < count; i++) {
1055 2467 : GF_Box *box = (GF_Box *)gf_list_get(trak->Media->child_boxes, i);
1056 2467 : if (box->type == GF_ISOM_BOX_TYPE_ELNG) {
1057 13 : *lang = gf_strdup(((GF_ExtendedLanguageBox *)box)->extended_language);
1058 13 : return GF_OK;
1059 : }
1060 : }
1061 : }
1062 : if (!elng_found) {
1063 805 : *lang = gf_strdup(trak->Media->mediaHeader->packedLanguage);
1064 : }
1065 805 : return GF_OK;
1066 : }
1067 :
1068 : GF_EXPORT
1069 219 : u32 gf_isom_get_track_kind_count(GF_ISOFile *the_file, u32 trackNumber)
1070 : {
1071 : GF_UserDataBox *udta;
1072 : GF_UserDataMap *map;
1073 219 : if (trackNumber) {
1074 219 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1075 219 : if (!trak) return 0;
1076 219 : if (!trak->udta) {
1077 : return 0;
1078 : }
1079 : udta = trak->udta;
1080 : } else {
1081 : return 0;
1082 : }
1083 14 : map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_KIND, NULL);
1084 14 : if (!map) return 0;
1085 :
1086 2 : return gf_list_count(map->boxes);
1087 : }
1088 :
1089 : GF_EXPORT
1090 2 : GF_Err gf_isom_get_track_kind(GF_ISOFile *the_file, u32 trackNumber, u32 index, char **scheme, char **value)
1091 : {
1092 : GF_Err e;
1093 : GF_UserDataBox *udta;
1094 : GF_UserDataMap *map;
1095 : GF_KindBox *kindBox;
1096 2 : if (!scheme || !value) {
1097 : return GF_BAD_PARAM;
1098 : }
1099 2 : *scheme = NULL;
1100 2 : *value = NULL;
1101 :
1102 2 : if (trackNumber) {
1103 2 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1104 2 : if (!trak) return GF_BAD_PARAM;
1105 2 : if (!trak->udta) {
1106 0 : e = trak_on_child_box((GF_Box*)trak, gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_UDTA), GF_FALSE);
1107 0 : if (e) return e;
1108 : }
1109 2 : udta = trak->udta;
1110 : } else {
1111 : return GF_BAD_PARAM;
1112 : }
1113 2 : map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_KIND, NULL);
1114 2 : if (!map) return GF_BAD_PARAM;
1115 :
1116 2 : kindBox = (GF_KindBox *)gf_list_get(map->boxes, index);
1117 2 : if (!kindBox) return GF_BAD_PARAM;
1118 :
1119 2 : *scheme = gf_strdup(kindBox->schemeURI);
1120 2 : if (kindBox->value) {
1121 0 : *value = gf_strdup(kindBox->value);
1122 : }
1123 : return GF_OK;
1124 : }
1125 :
1126 :
1127 : //Return the number of track references of a track for a given ReferenceType
1128 : //return 0 if error
1129 : GF_EXPORT
1130 347372 : s32 gf_isom_get_reference_count(GF_ISOFile *movie, u32 trackNumber, u32 referenceType)
1131 : {
1132 : GF_TrackBox *trak;
1133 : GF_TrackReferenceTypeBox *dpnd;
1134 347372 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1135 347372 : if (!trak) return -1;
1136 347372 : if (!trak->References) return 0;
1137 108300 : if (movie->openMode == GF_ISOM_OPEN_WRITE) {
1138 0 : movie->LastError = GF_ISOM_INVALID_MODE;
1139 0 : return -1;
1140 : }
1141 :
1142 108300 : dpnd = NULL;
1143 108300 : if ( (movie->LastError = Track_FindRef(trak, referenceType, &dpnd)) ) return -1;
1144 108300 : if (!dpnd) return 0;
1145 72448 : return dpnd->trackIDCount;
1146 : }
1147 :
1148 :
1149 : //Return the number of track references of a track for a given ReferenceType
1150 : //return 0 if error
1151 : GF_EXPORT
1152 0 : const GF_ISOTrackID *gf_isom_enum_track_references(GF_ISOFile *movie, u32 trackNumber, u32 idx, u32 *referenceType, u32 *referenceCount)
1153 : {
1154 : GF_TrackBox *trak;
1155 : GF_TrackReferenceTypeBox *dpnd;
1156 0 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1157 0 : if (!trak) return NULL;
1158 0 : if (!trak->References) return NULL;
1159 0 : dpnd = gf_list_get(trak->References->child_boxes, idx);
1160 0 : if (!dpnd) return NULL;
1161 0 : *referenceType = dpnd->reference_type;
1162 0 : *referenceCount = dpnd->trackIDCount;
1163 0 : return dpnd->trackIDs;
1164 : }
1165 :
1166 :
1167 : //Return the referenced track number for a track and a given ReferenceType and Index
1168 : //return -1 if error, 0 if the reference is a NULL one, or the trackNumber
1169 : GF_EXPORT
1170 96883 : GF_Err gf_isom_get_reference(GF_ISOFile *movie, u32 trackNumber, u32 referenceType, u32 referenceIndex, u32 *refTrack)
1171 : {
1172 : GF_Err e;
1173 : GF_TrackBox *trak;
1174 : GF_TrackReferenceTypeBox *dpnd;
1175 : GF_ISOTrackID refTrackNum;
1176 96883 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1177 :
1178 96883 : *refTrack = 0;
1179 96883 : if (!trak || !trak->References) return GF_BAD_PARAM;
1180 :
1181 95251 : dpnd = NULL;
1182 95251 : e = Track_FindRef(trak, referenceType, &dpnd);
1183 95251 : if (e) return e;
1184 95251 : if (!dpnd) return GF_BAD_PARAM;
1185 :
1186 94985 : if (!referenceIndex || (referenceIndex > dpnd->trackIDCount)) return GF_BAD_PARAM;
1187 :
1188 : //the spec allows a NULL reference
1189 : //(ex, to force desync of a track, set a sync ref with ID = 0)
1190 94985 : if (dpnd->trackIDs[referenceIndex - 1] == 0) return GF_OK;
1191 :
1192 94985 : refTrackNum = gf_isom_get_tracknum_from_id(movie->moov, dpnd->trackIDs[referenceIndex-1]);
1193 :
1194 : //if the track was not found, this means the file is broken !!!
1195 94985 : if (! refTrackNum) return GF_ISOM_INVALID_FILE;
1196 94985 : *refTrack = refTrackNum;
1197 94985 : return GF_OK;
1198 : }
1199 :
1200 : //Return the referenced track ID for a track and a given ReferenceType and Index
1201 : //return -1 if error, 0 if the reference is a NULL one, or the trackNumber
1202 : GF_EXPORT
1203 2789 : GF_Err gf_isom_get_reference_ID(GF_ISOFile *movie, u32 trackNumber, u32 referenceType, u32 referenceIndex, GF_ISOTrackID *refTrackID)
1204 : {
1205 : GF_Err e;
1206 : GF_TrackBox *trak;
1207 : GF_TrackReferenceTypeBox *dpnd;
1208 2789 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1209 :
1210 2789 : *refTrackID = 0;
1211 2789 : if (!trak || !trak->References || !referenceIndex) return GF_BAD_PARAM;
1212 :
1213 1248 : dpnd = NULL;
1214 1248 : e = Track_FindRef(trak, referenceType, &dpnd);
1215 1248 : if (e) return e;
1216 1248 : if (!dpnd) return GF_BAD_PARAM;
1217 :
1218 6 : if (referenceIndex > dpnd->trackIDCount) return GF_BAD_PARAM;
1219 :
1220 6 : *refTrackID = dpnd->trackIDs[referenceIndex-1];
1221 :
1222 6 : return GF_OK;
1223 : }
1224 :
1225 : //Return referenceIndex if the given track has a reference to the given TreckID of a given ReferenceType
1226 : //return 0 if error
1227 : GF_EXPORT
1228 33905 : u32 gf_isom_has_track_reference(GF_ISOFile *movie, u32 trackNumber, u32 referenceType, GF_ISOTrackID refTrackID)
1229 : {
1230 : u32 i;
1231 : GF_TrackBox *trak;
1232 : GF_TrackReferenceTypeBox *dpnd;
1233 33905 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1234 33905 : if (!trak) return 0;
1235 33905 : if (!trak->References) return 0;
1236 :
1237 30761 : dpnd = NULL;
1238 30761 : if ( (movie->LastError = Track_FindRef(trak, referenceType, &dpnd)) ) return 0;
1239 30761 : if (!dpnd) return 0;
1240 108275 : for (i=0; i<dpnd->trackIDCount; i++) {
1241 136504 : if (dpnd->trackIDs[i]==refTrackID) return i+1;
1242 : }
1243 : return 0;
1244 : }
1245 :
1246 :
1247 :
1248 : //Return the media time given the absolute time in the Movie
1249 : GF_EXPORT
1250 1 : GF_Err gf_isom_get_media_time(GF_ISOFile *the_file, u32 trackNumber, u32 movieTime, u64 *MediaTime)
1251 : {
1252 : GF_TrackBox *trak;
1253 : u8 useEdit;
1254 : s64 SegmentStartTime, mediaOffset;
1255 1 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1256 1 : if (!trak || !MediaTime) return GF_BAD_PARAM;
1257 :
1258 0 : SegmentStartTime = 0;
1259 0 : return GetMediaTime(trak, GF_FALSE, movieTime, MediaTime, &SegmentStartTime, &mediaOffset, &useEdit, NULL);
1260 : }
1261 :
1262 :
1263 : //Get the stream description index (eg, the ESD) for a given time IN MEDIA TIMESCALE
1264 : //return 0 if error or if empty
1265 : GF_EXPORT
1266 1 : u32 gf_isom_get_sample_description_index(GF_ISOFile *movie, u32 trackNumber, u64 for_time)
1267 : {
1268 : u32 streamDescIndex;
1269 : GF_TrackBox *trak;
1270 1 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1271 1 : if (!trak) return 0;
1272 :
1273 0 : if ( (movie->LastError = Media_GetSampleDescIndex(trak->Media, for_time, &streamDescIndex)) ) {
1274 : return 0;
1275 : }
1276 0 : return streamDescIndex;
1277 : }
1278 :
1279 : //Get the number of "streams" stored in the media - a media can have several stream descriptions...
1280 : GF_EXPORT
1281 1870 : u32 gf_isom_get_sample_description_count(GF_ISOFile *the_file, u32 trackNumber)
1282 : {
1283 : GF_TrackBox *trak;
1284 1870 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1285 1870 : if (!trak) return 0;
1286 :
1287 1867 : return gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes);
1288 : }
1289 :
1290 :
1291 : //Get the GF_ESD given the StreamDescriptionIndex
1292 : //THE DESCRIPTOR IS DUPLICATED, SO HAS TO BE DELETED BY THE APP
1293 : GF_EXPORT
1294 1715 : GF_ESD *gf_isom_get_esd(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex)
1295 : {
1296 : GF_ESD *esd;
1297 : GF_Err e;
1298 1715 : e = GetESD(movie->moov, gf_isom_get_track_id(movie, trackNumber), StreamDescriptionIndex, &esd);
1299 1715 : if (e && (e!= GF_ISOM_INVALID_MEDIA)) {
1300 0 : movie->LastError = e;
1301 0 : if (esd) gf_odf_desc_del((GF_Descriptor *)esd);
1302 : return NULL;
1303 : }
1304 :
1305 1715 : return esd;
1306 : }
1307 :
1308 : //Get the decoderConfigDescriptor given the SampleDescriptionIndex
1309 : //THE DESCRIPTOR IS DUPLICATED, SO HAS TO BE DELETED BY THE APP
1310 : GF_EXPORT
1311 35 : GF_DecoderConfig *gf_isom_get_decoder_config(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex)
1312 : {
1313 : GF_TrackBox *trak;
1314 : GF_ESD *esd;
1315 : GF_Descriptor *decInfo;
1316 35 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1317 35 : if (!trak) return NULL;
1318 : //get the ESD (possibly emulated)
1319 35 : Media_GetESD(trak->Media, StreamDescriptionIndex, &esd, GF_FALSE);
1320 35 : if (!esd) return NULL;
1321 35 : decInfo = (GF_Descriptor *) esd->decoderConfig;
1322 35 : esd->decoderConfig = NULL;
1323 35 : gf_odf_desc_del((GF_Descriptor *) esd);
1324 35 : return (GF_DecoderConfig *)decInfo;
1325 : }
1326 :
1327 :
1328 : //get the media duration (without edit)
1329 : //return 0 if bad param
1330 : GF_EXPORT
1331 11845 : u64 gf_isom_get_media_duration(GF_ISOFile *movie, u32 trackNumber)
1332 : {
1333 : GF_TrackBox *trak;
1334 11845 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1335 11845 : if (!trak) return 0;
1336 :
1337 :
1338 : #ifndef GPAC_DISABLE_ISOM_WRITE
1339 :
1340 : /*except in dump mode always recompute the duration*/
1341 11845 : if (movie->openMode != GF_ISOM_OPEN_READ_DUMP) {
1342 11845 : if ( (movie->LastError = Media_SetDuration(trak)) ) return 0;
1343 : }
1344 :
1345 : #endif
1346 :
1347 11845 : return trak->Media->mediaHeader->duration;
1348 : }
1349 :
1350 : //get the media duration (without edit)
1351 : //return 0 if bad param
1352 : GF_EXPORT
1353 219 : u64 gf_isom_get_media_original_duration(GF_ISOFile *movie, u32 trackNumber)
1354 : {
1355 : GF_TrackBox *trak;
1356 219 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1357 219 : if (!trak || !trak->Media || !trak->Media->mediaHeader) return 0;
1358 :
1359 219 : return trak->Media->mediaHeader->original_duration;
1360 : }
1361 :
1362 : //Get the timeScale of the media. All samples DTS/CTS are expressed in this timeScale
1363 : GF_EXPORT
1364 4493 : u32 gf_isom_get_media_timescale(GF_ISOFile *the_file, u32 trackNumber)
1365 : {
1366 : GF_TrackBox *trak;
1367 4493 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1368 4493 : if (!trak || !trak->Media || !trak->Media->mediaHeader) return 0;
1369 4447 : return trak->Media->mediaHeader->timeScale;
1370 : }
1371 :
1372 :
1373 : GF_EXPORT
1374 185 : u32 gf_isom_get_copyright_count(GF_ISOFile *mov)
1375 : {
1376 : GF_UserDataMap *map;
1377 185 : if (!mov || !mov->moov || !mov->moov->udta) return 0;
1378 2 : map = udta_getEntry(mov->moov->udta, GF_ISOM_BOX_TYPE_CPRT, NULL);
1379 2 : if (!map) return 0;
1380 1 : return gf_list_count(map->boxes);
1381 : }
1382 :
1383 : GF_EXPORT
1384 1 : GF_Err gf_isom_get_copyright(GF_ISOFile *mov, u32 Index, const char **threeCharCode, const char **notice)
1385 : {
1386 : GF_UserDataMap *map;
1387 : GF_CopyrightBox *cprt;
1388 :
1389 1 : if (!mov || !mov->moov || !Index) return GF_BAD_PARAM;
1390 :
1391 1 : if (!mov->moov->udta) return GF_OK;
1392 1 : map = udta_getEntry(mov->moov->udta, GF_ISOM_BOX_TYPE_CPRT, NULL);
1393 1 : if (!map) return GF_OK;
1394 :
1395 1 : if (Index > gf_list_count(map->boxes)) return GF_BAD_PARAM;
1396 :
1397 1 : cprt = (GF_CopyrightBox*)gf_list_get(map->boxes, Index-1);
1398 1 : (*threeCharCode) = cprt->packedLanguageCode;
1399 1 : (*notice) = cprt->notice;
1400 1 : return GF_OK;
1401 : }
1402 :
1403 : #if 0
1404 : GF_Err gf_isom_get_watermark(GF_ISOFile *mov, bin128 UUID, u8** data, u32* length)
1405 : {
1406 : GF_UserDataMap *map;
1407 : GF_UnknownUUIDBox *wm;
1408 :
1409 : if (!mov) return GF_BAD_PARAM;
1410 : if (!mov->moov || !mov->moov->udta) return GF_NOT_SUPPORTED;
1411 :
1412 : map = udta_getEntry(mov->moov->udta, GF_ISOM_BOX_TYPE_UUID, (bin128 *) & UUID);
1413 : if (!map) return GF_NOT_SUPPORTED;
1414 :
1415 : wm = (GF_UnknownUUIDBox*)gf_list_get(map->boxes, 0);
1416 : if (!wm) return GF_NOT_SUPPORTED;
1417 :
1418 : *data = (u8 *) gf_malloc(sizeof(char)*wm->dataSize);
1419 : if (! *data) return GF_OUT_OF_MEM;
1420 : memcpy(*data, wm->data, wm->dataSize);
1421 : *length = wm->dataSize;
1422 : return GF_OK;
1423 : }
1424 : #endif
1425 :
1426 : GF_EXPORT
1427 216 : u32 gf_isom_get_chapter_count(GF_ISOFile *movie, u32 trackNumber)
1428 : {
1429 : GF_UserDataMap *map;
1430 : GF_ChapterListBox *lst;
1431 : GF_UserDataBox *udta;
1432 :
1433 216 : if (!movie || !movie->moov) return 0;
1434 :
1435 : udta = NULL;
1436 216 : if (trackNumber) {
1437 4 : GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
1438 4 : if (!trak) return 0;
1439 4 : udta = trak->udta;
1440 : } else {
1441 212 : udta = movie->moov->udta;
1442 : }
1443 216 : if (!udta) return 0;
1444 7 : map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_CHPL, NULL);
1445 7 : if (!map) return 0;
1446 4 : lst = (GF_ChapterListBox *)gf_list_get(map->boxes, 0);
1447 4 : if (!lst) return 0;
1448 4 : return gf_list_count(lst->list);
1449 : }
1450 :
1451 : GF_EXPORT
1452 19 : GF_Err gf_isom_get_chapter(GF_ISOFile *movie, u32 trackNumber, u32 Index, u64 *chapter_time, const char **name)
1453 : {
1454 : GF_UserDataMap *map;
1455 : GF_ChapterListBox *lst;
1456 : GF_ChapterEntry *ce;
1457 : GF_UserDataBox *udta;
1458 :
1459 19 : if (!movie || !movie->moov) return GF_BAD_PARAM;
1460 :
1461 : udta = NULL;
1462 19 : if (trackNumber) {
1463 0 : GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
1464 0 : if (!trak) return GF_BAD_PARAM;
1465 0 : udta = trak->udta;
1466 : } else {
1467 19 : udta = movie->moov->udta;
1468 : }
1469 19 : if (!udta) return GF_BAD_PARAM;
1470 19 : map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_CHPL, NULL);
1471 19 : if (!map) return GF_BAD_PARAM;
1472 19 : lst = (GF_ChapterListBox *)gf_list_get(map->boxes, 0);
1473 19 : if (!lst) return GF_BAD_PARAM;
1474 :
1475 19 : ce = (GF_ChapterEntry *)gf_list_get(lst->list, Index-1);
1476 19 : if (!ce) return GF_BAD_PARAM;
1477 19 : if (chapter_time) {
1478 19 : *chapter_time = ce->start_time;
1479 19 : *chapter_time /= 10000L;
1480 : }
1481 19 : if (name) *name = ce->name;
1482 : return GF_OK;
1483 : }
1484 :
1485 :
1486 : GF_EXPORT
1487 6703 : u32 gf_isom_get_media_type(GF_ISOFile *movie, u32 trackNumber)
1488 : {
1489 : GF_TrackBox *trak;
1490 6703 : trak = gf_isom_get_track_from_file(movie, trackNumber);
1491 6703 : if (!trak) return GF_BAD_PARAM;
1492 6657 : return (trak->Media && trak->Media->handler) ? trak->Media->handler->handlerType : 0;
1493 : }
1494 :
1495 7840 : Bool IsMP4Description(u32 entryType)
1496 : {
1497 7840 : switch (entryType) {
1498 : case GF_ISOM_BOX_TYPE_MP4S:
1499 : case GF_ISOM_BOX_TYPE_LSR1:
1500 : case GF_ISOM_BOX_TYPE_MP4A:
1501 : case GF_ISOM_BOX_TYPE_MP4V:
1502 : case GF_ISOM_BOX_TYPE_ENCA:
1503 : case GF_ISOM_BOX_TYPE_ENCV:
1504 : case GF_ISOM_BOX_TYPE_RESV:
1505 : case GF_ISOM_BOX_TYPE_ENCS:
1506 : return GF_TRUE;
1507 5070 : default:
1508 5070 : return GF_FALSE;
1509 : }
1510 : }
1511 :
1512 320123 : Bool gf_isom_is_encrypted_entry(u32 entryType)
1513 : {
1514 : switch (entryType) {
1515 : case GF_ISOM_BOX_TYPE_ENCA:
1516 : case GF_ISOM_BOX_TYPE_ENCV:
1517 : case GF_ISOM_BOX_TYPE_ENCS:
1518 : return GF_TRUE;
1519 299941 : default:
1520 299941 : return GF_FALSE;
1521 : }
1522 : }
1523 :
1524 : GF_EXPORT
1525 1357 : Bool gf_isom_is_track_encrypted(GF_ISOFile *the_file, u32 trackNumber)
1526 : {
1527 : GF_TrackBox *trak;
1528 : u32 i=0;
1529 1357 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1530 1357 : if (!trak) return 2;
1531 : while (1) {
1532 2422 : GF_Box *entry = (GF_Box*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, i);
1533 2422 : if (!entry) break;
1534 1361 : if (gf_isom_is_encrypted_entry(entry->type)) return GF_TRUE;
1535 :
1536 1065 : if (gf_isom_is_cenc_media(the_file, trackNumber, i+1))
1537 : return GF_TRUE;
1538 :
1539 : i++;
1540 : }
1541 : return GF_FALSE;
1542 : }
1543 :
1544 : GF_EXPORT
1545 6650 : u32 gf_isom_get_media_subtype(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex)
1546 : {
1547 : GF_TrackBox *trak;
1548 : GF_Box *entry;
1549 6650 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1550 6650 : if (!trak || !DescriptionIndex || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable) return 0;
1551 6650 : entry = (GF_Box*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, DescriptionIndex-1);
1552 6650 : if (!entry) return 0;
1553 :
1554 : //filter MPEG sub-types
1555 6650 : if (IsMP4Description(entry->type)) {
1556 : if (gf_isom_is_encrypted_entry(entry->type)) return GF_ISOM_SUBTYPE_MPEG4_CRYP;
1557 : else return GF_ISOM_SUBTYPE_MPEG4;
1558 : }
1559 4361 : if (entry->type == GF_ISOM_BOX_TYPE_GNRV) {
1560 18 : return ((GF_GenericVisualSampleEntryBox *)entry)->EntryType;
1561 : }
1562 4343 : else if (entry->type == GF_ISOM_BOX_TYPE_GNRA) {
1563 20 : return ((GF_GenericAudioSampleEntryBox *)entry)->EntryType;
1564 : }
1565 4323 : else if (entry->type == GF_ISOM_BOX_TYPE_GNRM) {
1566 0 : return ((GF_GenericSampleEntryBox *)entry)->EntryType;
1567 : }
1568 : return entry->type;
1569 : }
1570 :
1571 : GF_EXPORT
1572 1065 : u32 gf_isom_get_mpeg4_subtype(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex)
1573 : {
1574 : GF_TrackBox *trak;
1575 : GF_Box *entry=NULL;
1576 1065 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1577 1065 : if (!trak || !DescriptionIndex) return 0;
1578 :
1579 1065 : if (trak->Media
1580 1065 : && trak->Media->information
1581 1065 : && trak->Media->information->sampleTable
1582 1065 : && trak->Media->information->sampleTable->SampleDescription
1583 : ) {
1584 1065 : entry = (GF_Box*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, DescriptionIndex-1);
1585 : }
1586 1065 : if (!entry) return 0;
1587 :
1588 : //filter MPEG sub-types
1589 1065 : if (!IsMP4Description(entry->type)) return 0;
1590 440 : return entry->type;
1591 : }
1592 :
1593 : //Get the HandlerDescription name.
1594 : GF_EXPORT
1595 28 : GF_Err gf_isom_get_handler_name(GF_ISOFile *the_file, u32 trackNumber, const char **outName)
1596 : {
1597 : GF_TrackBox *trak;
1598 28 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1599 28 : if (!trak || !outName) return GF_BAD_PARAM;
1600 28 : *outName = trak->Media->handler->nameUTF8;
1601 28 : return GF_OK;
1602 : }
1603 :
1604 : //Check the DataReferences of this track
1605 : GF_EXPORT
1606 219 : GF_Err gf_isom_check_data_reference(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex)
1607 : {
1608 : GF_Err e;
1609 : u32 drefIndex;
1610 : GF_TrackBox *trak;
1611 :
1612 219 : if (!StreamDescriptionIndex || !trackNumber) return GF_BAD_PARAM;
1613 219 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1614 219 : if (!trak) return GF_BAD_PARAM;
1615 :
1616 219 : e = Media_GetSampleDesc(trak->Media, StreamDescriptionIndex , NULL, &drefIndex);
1617 219 : if (e) return e;
1618 219 : if (!drefIndex) return GF_BAD_PARAM;
1619 219 : return Media_CheckDataEntry(trak->Media, drefIndex);
1620 : }
1621 :
1622 : //get the location of the data. If URL && URN are NULL, the data is in this file
1623 : GF_EXPORT
1624 73 : GF_Err gf_isom_get_data_reference(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex, const char **outURL, const char **outURN)
1625 : {
1626 : GF_TrackBox *trak;
1627 : GF_DataEntryURLBox *url=NULL;
1628 : GF_DataEntryURNBox *urn;
1629 : u32 drefIndex;
1630 : GF_Err e;
1631 :
1632 73 : *outURL = *outURN = NULL;
1633 :
1634 73 : if (!StreamDescriptionIndex || !trackNumber) return GF_BAD_PARAM;
1635 73 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1636 73 : if (!trak) return GF_BAD_PARAM;
1637 :
1638 73 : e = Media_GetSampleDesc(trak->Media, StreamDescriptionIndex , NULL, &drefIndex);
1639 73 : if (e) return e;
1640 73 : if (!drefIndex) return GF_BAD_PARAM;
1641 :
1642 73 : if (trak->Media
1643 73 : && trak->Media->information
1644 73 : && trak->Media->information->dataInformation
1645 73 : && trak->Media->information->dataInformation->dref
1646 : ) {
1647 73 : url = (GF_DataEntryURLBox*)gf_list_get(trak->Media->information->dataInformation->dref->child_boxes, drefIndex - 1);
1648 : }
1649 73 : if (!url) return GF_ISOM_INVALID_FILE;
1650 :
1651 73 : if (url->type == GF_ISOM_BOX_TYPE_URL) {
1652 73 : *outURL = url->location;
1653 73 : *outURN = NULL;
1654 0 : } else if (url->type == GF_ISOM_BOX_TYPE_URN) {
1655 : urn = (GF_DataEntryURNBox *) url;
1656 0 : *outURN = urn->nameURN;
1657 0 : *outURL = urn->location;
1658 : } else {
1659 0 : *outURN = NULL;
1660 0 : *outURL = NULL;
1661 : }
1662 : return GF_OK;
1663 : }
1664 :
1665 : //Get the number of samples
1666 : //return 0 if error or empty
1667 : GF_EXPORT
1668 278347 : u32 gf_isom_get_sample_count(GF_ISOFile *the_file, u32 trackNumber)
1669 : {
1670 : GF_TrackBox *trak;
1671 278347 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1672 278347 : if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleSize) return 0;
1673 278347 : return trak->Media->information->sampleTable->SampleSize->sampleCount
1674 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1675 278347 : + trak->sample_count_at_seg_start
1676 : #endif
1677 : ;
1678 : }
1679 :
1680 : GF_EXPORT
1681 1378 : u32 gf_isom_get_constant_sample_size(GF_ISOFile *the_file, u32 trackNumber)
1682 : {
1683 : GF_TrackBox *trak;
1684 1378 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1685 1378 : if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleSize) return 0;
1686 1378 : return trak->Media->information->sampleTable->SampleSize->sampleSize;
1687 : }
1688 :
1689 : GF_EXPORT
1690 1186 : u32 gf_isom_get_constant_sample_duration(GF_ISOFile *the_file, u32 trackNumber)
1691 : {
1692 : GF_TrackBox *trak;
1693 1186 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1694 1186 : if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->TimeToSample) return 0;
1695 1186 : if (trak->Media->information->sampleTable->TimeToSample->nb_entries != 1) return 0;
1696 1092 : return trak->Media->information->sampleTable->TimeToSample->entries[0].sampleDelta;
1697 : }
1698 :
1699 : GF_EXPORT
1700 114 : Bool gf_isom_enable_raw_pack(GF_ISOFile *the_file, u32 trackNumber, u32 pack_num_samples)
1701 : {
1702 : u32 afmt, bps, nb_ch;
1703 : Bool from_qt=GF_FALSE;
1704 : GF_TrackBox *trak;
1705 : GF_MPEGAudioSampleEntryBox *entry;
1706 114 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1707 114 : if (!trak) return GF_FALSE;
1708 114 : trak->pack_num_samples = 0;
1709 : //we only activate sample packing for raw audio
1710 114 : if (!trak->Media || !trak->Media->handler) return GF_FALSE;
1711 114 : if (trak->Media->handler->handlerType != GF_ISOM_MEDIA_AUDIO) return GF_FALSE;
1712 : //and sample duration of 1
1713 51 : if (!trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->TimeToSample) return GF_FALSE;
1714 51 : if (trak->Media->information->sampleTable->TimeToSample->nb_entries != 1) return GF_FALSE;
1715 50 : if (!trak->Media->information->sampleTable->TimeToSample->entries) return GF_FALSE;
1716 50 : if (trak->Media->information->sampleTable->TimeToSample->entries[0].sampleDelta != 1) return GF_FALSE;
1717 : //and sample with constant size
1718 45 : if (!trak->Media->information->sampleTable->SampleSize || !trak->Media->information->sampleTable->SampleSize->sampleSize) return GF_FALSE;
1719 45 : trak->pack_num_samples = pack_num_samples;
1720 :
1721 45 : if (!pack_num_samples) return GF_FALSE;
1722 :
1723 45 : entry = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, 0);
1724 45 : if (!entry) return GF_FALSE;
1725 :
1726 45 : if (entry->internal_type!=GF_ISOM_SAMPLE_ENTRY_AUDIO) return GF_FALSE;
1727 :
1728 : //sanity check, some files have wrong stsz sampleSize for raw audio !
1729 45 : afmt = gf_audio_fmt_from_isobmf(entry->type);
1730 45 : bps = gf_audio_fmt_bit_depth(afmt) / 8;
1731 45 : if (!bps) {
1732 : //unknown format, try QTv2
1733 5 : if (entry->qtff_mode && (entry->internal_type==GF_ISOM_SAMPLE_ENTRY_AUDIO)) {
1734 0 : bps = entry->extensions[8]<<24 | entry->extensions[9]<<16 | entry->extensions[10]<<8 | entry->extensions[11];
1735 : from_qt = GF_TRUE;
1736 : }
1737 : }
1738 45 : nb_ch = entry->channel_count;
1739 45 : if (entry->qtff_mode && (entry->version==2)) {
1740 : //QTFFv2 audio, channel count is 32 bit, after 32bit size of struct and 64 bit samplerate
1741 : //hence start at 12 in extensions
1742 0 : nb_ch = entry->extensions[11]<<24 | entry->extensions[12]<<16 | entry->extensions[13]<<8 | entry->extensions[14];
1743 : }
1744 :
1745 45 : if (bps) {
1746 40 : u32 res = trak->Media->information->sampleTable->SampleSize->sampleSize % bps;
1747 40 : if (res) {
1748 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("ISOBMF: size mismatch for raw audio sample description: constant sample size %d but %d bytes per channel for %s%s!\n", trak->Media->information->sampleTable->SampleSize->sampleSize,
1749 : bps,
1750 : gf_4cc_to_str(entry->type),
1751 : from_qt ? " (as indicated in QT sample description)" : ""
1752 : ));
1753 0 : trak->Media->information->sampleTable->SampleSize->sampleSize = bps * nb_ch;
1754 : }
1755 : }
1756 : return GF_TRUE;
1757 : }
1758 :
1759 1114 : Bool gf_isom_has_time_offset_table(GF_ISOFile *the_file, u32 trackNumber)
1760 : {
1761 : GF_TrackBox *trak;
1762 1114 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1763 1114 : if (!trak || !trak->Media->information->sampleTable->CompositionOffset) return GF_FALSE;
1764 228 : return GF_TRUE;
1765 : }
1766 :
1767 : GF_EXPORT
1768 202 : u32 gf_isom_has_time_offset(GF_ISOFile *the_file, u32 trackNumber)
1769 : {
1770 : u32 i;
1771 : GF_CompositionOffsetBox *ctts;
1772 : GF_TrackBox *trak;
1773 202 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1774 202 : if (!trak || !trak->Media->information->sampleTable->CompositionOffset) return 0;
1775 :
1776 : //return true at the first offset found
1777 : ctts = trak->Media->information->sampleTable->CompositionOffset;
1778 5 : for (i=0; i<ctts->nb_entries; i++) {
1779 55 : if (ctts->entries[i].decodingOffset && ctts->entries[i].sampleCount) return ctts->version ? 2 : 1;
1780 : }
1781 : return 0;
1782 : }
1783 :
1784 : GF_EXPORT
1785 1252 : s64 gf_isom_get_cts_to_dts_shift(GF_ISOFile *the_file, u32 trackNumber)
1786 : {
1787 : GF_TrackBox *trak;
1788 1252 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1789 1252 : if (!trak || !trak->Media->information->sampleTable->CompositionToDecode) return 0;
1790 7 : return trak->Media->information->sampleTable->CompositionToDecode->compositionToDTSShift;
1791 : }
1792 :
1793 : GF_EXPORT
1794 7 : Bool gf_isom_has_sync_shadows(GF_ISOFile *the_file, u32 trackNumber)
1795 : {
1796 7 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1797 7 : if (!trak) return GF_FALSE;
1798 7 : if (!trak->Media->information->sampleTable->ShadowSync) return GF_FALSE;
1799 0 : if (gf_list_count(trak->Media->information->sampleTable->ShadowSync->entries) ) return GF_TRUE;
1800 0 : return GF_FALSE;
1801 : }
1802 :
1803 : GF_EXPORT
1804 7 : Bool gf_isom_has_sample_dependency(GF_ISOFile *the_file, u32 trackNumber)
1805 : {
1806 7 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1807 7 : if (!trak) return GF_FALSE;
1808 7 : if (!trak->Media->information->sampleTable->SampleDep) return GF_FALSE;
1809 0 : return GF_TRUE;
1810 : }
1811 :
1812 : GF_EXPORT
1813 493550 : GF_Err gf_isom_get_sample_flags(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 *isLeading, u32 *dependsOn, u32 *dependedOn, u32 *redundant)
1814 : {
1815 : GF_TrackBox *trak;
1816 493550 : *isLeading = 0;
1817 493550 : *dependsOn = 0;
1818 493550 : *dependedOn = 0;
1819 493550 : *redundant = 0;
1820 493550 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1821 493550 : if (!trak) return GF_BAD_PARAM;
1822 493550 : if (!trak->Media->information->sampleTable->SampleDep) return GF_BAD_PARAM;
1823 :
1824 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1825 112825 : if (sampleNumber <= trak->sample_count_at_seg_start)
1826 : return GF_BAD_PARAM;
1827 112825 : sampleNumber -= trak->sample_count_at_seg_start;
1828 : #endif
1829 :
1830 112825 : return stbl_GetSampleDepType(trak->Media->information->sampleTable->SampleDep, sampleNumber, isLeading, dependsOn, dependedOn, redundant);
1831 : }
1832 :
1833 : //return a sample give its number, and set the SampleDescIndex of this sample
1834 : //this index allows to retrieve the stream description if needed (2 media in 1 track)
1835 : //return NULL if error
1836 : GF_EXPORT
1837 782830 : GF_ISOSample *gf_isom_get_sample_ex(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 *sampleDescriptionIndex, GF_ISOSample *static_sample, u64 *data_offset)
1838 : {
1839 : GF_Err e;
1840 : u32 descIndex;
1841 : GF_TrackBox *trak;
1842 : GF_ISOSample *samp;
1843 782830 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1844 782830 : if (!trak) return NULL;
1845 :
1846 782830 : if (!sampleNumber) return NULL;
1847 782830 : if (static_sample) {
1848 669165 : samp = static_sample;
1849 669165 : if (static_sample->dataLength && !static_sample->alloc_size)
1850 0 : static_sample->alloc_size = static_sample->dataLength;
1851 : } else {
1852 113665 : samp = gf_isom_sample_new();
1853 : }
1854 782830 : if (!samp) return NULL;
1855 :
1856 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1857 782830 : if (sampleNumber<=trak->sample_count_at_seg_start)
1858 : return NULL;
1859 782830 : sampleNumber -= trak->sample_count_at_seg_start;
1860 : #endif
1861 :
1862 782830 : e = Media_GetSample(trak->Media, sampleNumber, &samp, &descIndex, GF_FALSE, data_offset);
1863 782830 : if (static_sample && !static_sample->alloc_size)
1864 30288 : static_sample->alloc_size = static_sample->dataLength;
1865 :
1866 782830 : if (e) {
1867 : gf_isom_set_last_error(the_file, e);
1868 272387 : if (!static_sample) gf_isom_sample_del(&samp);
1869 : return NULL;
1870 : }
1871 510443 : if (sampleDescriptionIndex) *sampleDescriptionIndex = descIndex;
1872 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1873 510443 : if (samp) samp->DTS += trak->dts_at_seg_start;
1874 : #endif
1875 :
1876 : return samp;
1877 : }
1878 :
1879 : GF_EXPORT
1880 113665 : GF_ISOSample *gf_isom_get_sample(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 *sampleDescriptionIndex)
1881 : {
1882 113665 : return gf_isom_get_sample_ex(the_file, trackNumber, sampleNumber, sampleDescriptionIndex, NULL, NULL);
1883 : }
1884 :
1885 : GF_EXPORT
1886 463112 : u32 gf_isom_get_sample_duration(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber)
1887 : {
1888 : u32 dur;
1889 : u64 dts;
1890 463112 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1891 463112 : if (!trak || !sampleNumber) return 0;
1892 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1893 463108 : if (sampleNumber<=trak->sample_count_at_seg_start) return 0;
1894 463108 : sampleNumber -= trak->sample_count_at_seg_start;
1895 : #endif
1896 :
1897 463108 : stbl_GetSampleDTS_and_Duration(trak->Media->information->sampleTable->TimeToSample, sampleNumber, &dts, &dur);
1898 463108 : return dur;
1899 : }
1900 :
1901 :
1902 : GF_EXPORT
1903 2 : u32 gf_isom_get_sample_size(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber)
1904 : {
1905 2 : u32 size = 0;
1906 2 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1907 2 : if (!trak || !sampleNumber) return 0;
1908 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1909 2 : if (sampleNumber<=trak->sample_count_at_seg_start) return 0;
1910 2 : sampleNumber -= trak->sample_count_at_seg_start;
1911 : #endif
1912 2 : stbl_GetSampleSize(trak->Media->information->sampleTable->SampleSize, sampleNumber, &size);
1913 2 : return size;
1914 : }
1915 :
1916 : GF_EXPORT
1917 883 : u32 gf_isom_get_max_sample_size(GF_ISOFile *the_file, u32 trackNumber)
1918 : {
1919 883 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1920 883 : if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleSize) return 0;
1921 :
1922 883 : return trak->Media->information->sampleTable->SampleSize->max_size;
1923 : }
1924 :
1925 : GF_EXPORT
1926 883 : u32 gf_isom_get_avg_sample_size(GF_ISOFile *the_file, u32 trackNumber)
1927 : {
1928 883 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1929 883 : if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleSize) return 0;
1930 :
1931 883 : if ( trak->Media->information->sampleTable->SampleSize->sampleSize)
1932 : return trak->Media->information->sampleTable->SampleSize->sampleSize;
1933 :
1934 777 : if (!trak->Media->information->sampleTable->SampleSize->total_samples) return 0;
1935 762 : return (u32) (trak->Media->information->sampleTable->SampleSize->total_size / trak->Media->information->sampleTable->SampleSize->total_samples);
1936 : }
1937 :
1938 : GF_EXPORT
1939 1102 : u32 gf_isom_get_max_sample_delta(GF_ISOFile *the_file, u32 trackNumber)
1940 : {
1941 1102 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1942 1102 : if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->TimeToSample) return 0;
1943 :
1944 1102 : return trak->Media->information->sampleTable->TimeToSample->max_ts_delta;
1945 : }
1946 :
1947 : GF_EXPORT
1948 883 : u32 gf_isom_get_max_sample_cts_offset(GF_ISOFile *the_file, u32 trackNumber)
1949 : {
1950 883 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1951 883 : if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->CompositionOffset) return 0;
1952 :
1953 228 : return trak->Media->information->sampleTable->CompositionOffset->max_ts_delta;
1954 : }
1955 :
1956 :
1957 : GF_EXPORT
1958 72 : Bool gf_isom_get_sample_sync(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber)
1959 : {
1960 : GF_ISOSAPType is_rap;
1961 : GF_Err e;
1962 72 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
1963 72 : if (!trak || !sampleNumber) return GF_FALSE;
1964 :
1965 72 : if (! trak->Media->information->sampleTable->SyncSample) return GF_TRUE;
1966 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1967 6 : if (sampleNumber<=trak->sample_count_at_seg_start) return GF_FALSE;
1968 6 : sampleNumber -= trak->sample_count_at_seg_start;
1969 : #endif
1970 6 : e = stbl_GetSampleRAP(trak->Media->information->sampleTable->SyncSample, sampleNumber, &is_rap, NULL, NULL);
1971 6 : if (e) return GF_FALSE;
1972 6 : return is_rap ? GF_TRUE : GF_FALSE;
1973 : }
1974 :
1975 : //same as gf_isom_get_sample but doesn't fetch media data
1976 : GF_EXPORT
1977 587993 : GF_ISOSample *gf_isom_get_sample_info_ex(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 *sampleDescriptionIndex, u64 *data_offset, GF_ISOSample *static_sample)
1978 : {
1979 : GF_Err e;
1980 : GF_TrackBox *trak;
1981 : GF_ISOSample *samp;
1982 587993 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
1983 587993 : if (!trak) return NULL;
1984 :
1985 587993 : if (!sampleNumber) return NULL;
1986 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
1987 587993 : if (sampleNumber<=trak->sample_count_at_seg_start) return NULL;
1988 587993 : sampleNumber -= trak->sample_count_at_seg_start;
1989 : #endif
1990 587993 : if (static_sample) {
1991 423386 : samp = static_sample;
1992 : } else {
1993 164607 : samp = gf_isom_sample_new();
1994 164607 : if (!samp) return NULL;
1995 : }
1996 :
1997 587993 : e = Media_GetSample(trak->Media, sampleNumber, &samp, sampleDescriptionIndex, GF_TRUE, data_offset);
1998 587993 : if (e) {
1999 : gf_isom_set_last_error(the_file, e);
2000 4 : if (!static_sample)
2001 0 : gf_isom_sample_del(&samp);
2002 : return NULL;
2003 : }
2004 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2005 587989 : if (samp) samp->DTS += trak->dts_at_seg_start;
2006 : #endif
2007 : return samp;
2008 : }
2009 :
2010 : GF_EXPORT
2011 164607 : GF_ISOSample *gf_isom_get_sample_info(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u32 *sampleDescriptionIndex, u64 *data_offset)
2012 : {
2013 164607 : return gf_isom_get_sample_info_ex(the_file, trackNumber, sampleNumber, sampleDescriptionIndex, data_offset, NULL);
2014 : }
2015 :
2016 :
2017 : //get sample dts
2018 : GF_EXPORT
2019 1 : u64 gf_isom_get_sample_dts(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber)
2020 : {
2021 : u64 dts;
2022 : GF_TrackBox *trak;
2023 1 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
2024 1 : if (!trak) return 0;
2025 :
2026 1 : if (!sampleNumber) return 0;
2027 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2028 1 : if (sampleNumber<=trak->sample_count_at_seg_start) return 0;
2029 1 : sampleNumber -= trak->sample_count_at_seg_start;
2030 : #endif
2031 1 : if (stbl_GetSampleDTS(trak->Media->information->sampleTable->TimeToSample, sampleNumber, &dts) != GF_OK) return 0;
2032 1 : return dts;
2033 : }
2034 :
2035 : GF_EXPORT
2036 10668 : Bool gf_isom_is_self_contained(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex)
2037 : {
2038 : GF_TrackBox *trak;
2039 10668 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
2040 10668 : if (!trak) return GF_FALSE;
2041 10668 : return Media_IsSelfContained(trak->Media, sampleDescriptionIndex);
2042 : }
2043 :
2044 : /*retrieves given sample DTS*/
2045 : GF_EXPORT
2046 1 : u32 gf_isom_get_sample_from_dts(GF_ISOFile *the_file, u32 trackNumber, u64 dts)
2047 : {
2048 : GF_Err e;
2049 : u32 sampleNumber, prevSampleNumber;
2050 : GF_TrackBox *trak;
2051 : GF_SampleTableBox *stbl;
2052 :
2053 1 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
2054 1 : if (!trak) return 0;
2055 :
2056 1 : stbl = trak->Media->information->sampleTable;
2057 :
2058 1 : e = stbl_findEntryForTime(stbl, dts, 1, &sampleNumber, &prevSampleNumber);
2059 1 : if (e) return 0;
2060 1 : return sampleNumber;
2061 : }
2062 :
2063 :
2064 : //return a sample given a desired display time IN MEDIA TIME SCALE
2065 : //and set the StreamDescIndex of this sample
2066 : //this index allows to retrieve the stream description if needed (2 media in 1 track)
2067 : //return NULL if error
2068 : //WARNING: the sample may not be sync even though the sync was requested (depends on the media)
2069 : GF_EXPORT
2070 241 : GF_Err gf_isom_get_sample_for_media_time(GF_ISOFile *the_file, u32 trackNumber, u64 desiredTime, u32 *StreamDescriptionIndex, GF_ISOSearchMode SearchMode, GF_ISOSample **sample, u32 *SampleNum, u64 *data_offset)
2071 : {
2072 : GF_Err e;
2073 : u32 sampleNumber, prevSampleNumber, syncNum, shadowSync;
2074 : GF_TrackBox *trak;
2075 : GF_ISOSample *shadow;
2076 : GF_SampleTableBox *stbl;
2077 : Bool static_sample = GF_FALSE;
2078 : u8 useShadow, IsSync;
2079 :
2080 241 : if (SampleNum) *SampleNum = 0;
2081 241 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
2082 241 : if (!trak) return GF_BAD_PARAM;
2083 :
2084 241 : stbl = trak->Media->information->sampleTable;
2085 :
2086 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2087 241 : if (desiredTime < trak->dts_at_seg_start) {
2088 : desiredTime = 0;
2089 : } else {
2090 241 : desiredTime -= trak->dts_at_seg_start;
2091 : }
2092 : #endif
2093 :
2094 241 : e = stbl_findEntryForTime(stbl, desiredTime, 0, &sampleNumber, &prevSampleNumber);
2095 241 : if (e) return e;
2096 :
2097 : //if no shadow table, reset to sync only
2098 : useShadow = 0;
2099 241 : if (!stbl->ShadowSync && (SearchMode == GF_ISOM_SEARCH_SYNC_SHADOW))
2100 : SearchMode = GF_ISOM_SEARCH_SYNC_BACKWARD;
2101 :
2102 : //if no syncTable, disable syncSearching, as all samples ARE sync
2103 241 : if (! trak->Media->information->sampleTable->SyncSample) {
2104 115 : if (SearchMode == GF_ISOM_SEARCH_SYNC_FORWARD) SearchMode = GF_ISOM_SEARCH_FORWARD;
2105 64 : if (SearchMode == GF_ISOM_SEARCH_SYNC_BACKWARD) SearchMode = GF_ISOM_SEARCH_BACKWARD;
2106 : }
2107 :
2108 : //not found, return EOF or browse backward
2109 241 : if (!sampleNumber && !prevSampleNumber) {
2110 19 : if (SearchMode == GF_ISOM_SEARCH_SYNC_BACKWARD || SearchMode == GF_ISOM_SEARCH_BACKWARD) {
2111 16 : sampleNumber = trak->Media->information->sampleTable->SampleSize->sampleCount;
2112 : }
2113 19 : if (!sampleNumber) return GF_EOS;
2114 : }
2115 :
2116 : //check in case we have the perfect sample
2117 : IsSync = 0;
2118 :
2119 : //according to the direction adjust the sampleNum value
2120 225 : switch (SearchMode) {
2121 63 : case GF_ISOM_SEARCH_SYNC_FORWARD:
2122 : IsSync = 1;
2123 157 : case GF_ISOM_SEARCH_FORWARD:
2124 : //not the exact one
2125 157 : if (!sampleNumber) {
2126 63 : if (prevSampleNumber != stbl->SampleSize->sampleCount) {
2127 63 : sampleNumber = prevSampleNumber + 1;
2128 : } else {
2129 0 : sampleNumber = prevSampleNumber;
2130 : }
2131 : }
2132 : break;
2133 :
2134 : //if dummy mode, reset to default browsing
2135 36 : case GF_ISOM_SEARCH_SYNC_BACKWARD:
2136 : IsSync = 1;
2137 68 : case GF_ISOM_SEARCH_SYNC_SHADOW:
2138 : case GF_ISOM_SEARCH_BACKWARD:
2139 : default:
2140 : //first case, not found....
2141 68 : if (!sampleNumber && !prevSampleNumber) {
2142 0 : sampleNumber = stbl->SampleSize->sampleCount;
2143 68 : } else if (!sampleNumber) {
2144 21 : sampleNumber = prevSampleNumber;
2145 : }
2146 : break;
2147 : }
2148 :
2149 : //get the sync sample num
2150 225 : if (IsSync) {
2151 : //get the SyncNumber
2152 99 : e = Media_FindSyncSample(trak->Media->information->sampleTable,
2153 : sampleNumber, &syncNum, SearchMode);
2154 99 : if (e) return e;
2155 99 : if (syncNum) sampleNumber = syncNum;
2156 99 : syncNum = 0;
2157 : }
2158 : //if we are in shadow mode, get the previous sync sample
2159 : //in case we can't find a good SyncShadow
2160 126 : else if (SearchMode == GF_ISOM_SEARCH_SYNC_SHADOW) {
2161 : //get the SyncNumber
2162 0 : e = Media_FindSyncSample(trak->Media->information->sampleTable,
2163 : sampleNumber, &syncNum, GF_ISOM_SEARCH_SYNC_BACKWARD);
2164 0 : if (e) return e;
2165 : }
2166 :
2167 :
2168 : //OK sampleNumber is exactly the sample we need (except for shadow)
2169 :
2170 225 : if (sample) {
2171 222 : if (*sample) {
2172 : static_sample = GF_TRUE;
2173 : } else {
2174 114 : *sample = gf_isom_sample_new();
2175 114 : if (*sample == NULL) return GF_OUT_OF_MEM;
2176 : }
2177 : }
2178 : //we are in shadow mode, we need to browse both SyncSample and ShadowSyncSample to get
2179 : //the desired sample...
2180 225 : if (SearchMode == GF_ISOM_SEARCH_SYNC_SHADOW) {
2181 : //get the shadowing number
2182 0 : stbl_GetSampleShadow(stbl->ShadowSync, &sampleNumber, &shadowSync);
2183 : //now sampleNumber is the closest previous shadowed sample.
2184 : //1- If we have a closer sync sample, use it.
2185 : //2- if the shadowSync is 0, we don't have any shadowing, use syncNum
2186 0 : if ((sampleNumber < syncNum) || (!shadowSync)) {
2187 0 : sampleNumber = syncNum;
2188 : } else {
2189 : //otherwise, we have a better alternate sample in the shadowSync for this sample
2190 : useShadow = 1;
2191 : }
2192 : }
2193 :
2194 225 : e = Media_GetSample(trak->Media, sampleNumber, sample, StreamDescriptionIndex, GF_FALSE, data_offset);
2195 225 : if (e) {
2196 25 : if (!static_sample)
2197 0 : gf_isom_sample_del(sample);
2198 25 : else if (! (*sample)->alloc_size && (*sample)->data && (*sample)->dataLength )
2199 2 : (*sample)->alloc_size = (*sample)->dataLength;
2200 :
2201 : return e;
2202 : }
2203 200 : if (sample && ! (*sample)->IsRAP) {
2204 : Bool is_rap;
2205 : GF_ISOSampleRollType roll_type;
2206 25 : e = gf_isom_get_sample_rap_roll_info(the_file, trackNumber, sampleNumber, &is_rap, &roll_type, NULL);
2207 25 : if (e) return e;
2208 25 : if (is_rap) (*sample)->IsRAP = SAP_TYPE_3;
2209 : }
2210 : //optionally get the sample number
2211 200 : if (SampleNum) {
2212 200 : *SampleNum = sampleNumber;
2213 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2214 200 : *SampleNum += trak->sample_count_at_seg_start;
2215 : #endif
2216 : }
2217 :
2218 : //in shadow mode, we only get the data of the shadowing sample !
2219 200 : if (sample && useShadow) {
2220 : //we have to use StreamDescriptionIndex in case the sample data is in another desc
2221 : //though this is unlikely as non optimized...
2222 0 : shadow = gf_isom_get_sample(the_file, trackNumber, shadowSync, StreamDescriptionIndex);
2223 : //if no sample, the shadowSync is broken, return the sample
2224 0 : if (!shadow) return GF_OK;
2225 0 : (*sample)->IsRAP = RAP;
2226 0 : gf_free((*sample)->data);
2227 0 : (*sample)->dataLength = shadow->dataLength;
2228 0 : (*sample)->data = shadow->data;
2229 : //set data length to 0 to keep the buffer alive...
2230 0 : shadow->dataLength = 0;
2231 0 : gf_isom_sample_del(&shadow);
2232 : }
2233 200 : if (static_sample && ! (*sample)->alloc_size )
2234 20 : (*sample)->alloc_size = (*sample)->dataLength;
2235 :
2236 : return GF_OK;
2237 : }
2238 :
2239 : GF_EXPORT
2240 127 : GF_Err gf_isom_get_sample_for_movie_time(GF_ISOFile *the_file, u32 trackNumber, u64 movieTime, u32 *StreamDescriptionIndex, GF_ISOSearchMode SearchMode, GF_ISOSample **sample, u32 *sampleNumber, u64 *data_offset)
2241 : {
2242 : Double tsscale;
2243 : GF_Err e;
2244 : GF_TrackBox *trak;
2245 : u64 mediaTime, nextMediaTime;
2246 : s64 segStartTime, mediaOffset;
2247 : u32 sampNum;
2248 : u8 useEdit;
2249 :
2250 127 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
2251 127 : if (!trak) return GF_BAD_PARAM;
2252 :
2253 : //only check duration if initially set - do not check duration as updated after fragment merge since that duration does not take
2254 : //into account tfdt
2255 127 : if (trak->Header->initial_duration
2256 80 : && (movieTime * trak->moov->mvhd->timeScale > trak->Header->initial_duration * trak->Media->mediaHeader->timeScale)
2257 : ) {
2258 0 : if (sampleNumber) *sampleNumber = 0;
2259 0 : *StreamDescriptionIndex = 0;
2260 0 : return GF_EOS;
2261 : }
2262 :
2263 : //get the media time for this movie time...
2264 127 : mediaTime = segStartTime = 0;
2265 127 : *StreamDescriptionIndex = 0;
2266 127 : nextMediaTime = 0;
2267 :
2268 127 : e = GetMediaTime(trak, (SearchMode==GF_ISOM_SEARCH_SYNC_FORWARD) ? GF_TRUE : GF_FALSE, movieTime, &mediaTime, &segStartTime, &mediaOffset, &useEdit, &nextMediaTime);
2269 127 : if (e) return e;
2270 :
2271 : /*here we check if we were playing or not and return no sample in normal search modes*/
2272 127 : if (useEdit && mediaOffset == -1) {
2273 1 : if ((SearchMode==GF_ISOM_SEARCH_FORWARD) || (SearchMode==GF_ISOM_SEARCH_BACKWARD)) {
2274 : /*get next sample time in MOVIE timescale*/
2275 1 : if (SearchMode==GF_ISOM_SEARCH_FORWARD)
2276 1 : e = GetNextMediaTime(trak, movieTime, &mediaTime);
2277 : else
2278 0 : e = GetPrevMediaTime(trak, movieTime, &mediaTime);
2279 1 : if (e) return e;
2280 0 : return gf_isom_get_sample_for_movie_time(the_file, trackNumber, (u32) mediaTime, StreamDescriptionIndex, GF_ISOM_SEARCH_SYNC_FORWARD, sample, sampleNumber, data_offset);
2281 : }
2282 0 : if (sampleNumber) *sampleNumber = 0;
2283 0 : if (sample) {
2284 0 : if (! (*sample)) {
2285 0 : *sample = gf_isom_sample_new();
2286 0 : if (! *sample) return GF_OUT_OF_MEM;
2287 : }
2288 0 : (*sample)->DTS = movieTime;
2289 0 : (*sample)->dataLength = 0;
2290 0 : (*sample)->CTS_Offset = 0;
2291 : }
2292 : return GF_OK;
2293 : }
2294 : /*dwell edit in non-sync mode, fetch next/prev sample depending on mode.
2295 : Otherwise return the dwell entry*/
2296 126 : if (useEdit==2) {
2297 0 : if ((SearchMode==GF_ISOM_SEARCH_FORWARD) || (SearchMode==GF_ISOM_SEARCH_BACKWARD)) {
2298 : /*get next sample time in MOVIE timescale*/
2299 0 : if (SearchMode==GF_ISOM_SEARCH_FORWARD)
2300 0 : e = GetNextMediaTime(trak, movieTime, &mediaTime);
2301 : else
2302 0 : e = GetPrevMediaTime(trak, movieTime, &mediaTime);
2303 0 : if (e) return e;
2304 0 : return gf_isom_get_sample_for_movie_time(the_file, trackNumber, (u32) mediaTime, StreamDescriptionIndex, GF_ISOM_SEARCH_SYNC_FORWARD, sample, sampleNumber, data_offset);
2305 : }
2306 : }
2307 :
2308 126 : tsscale = trak->Media->mediaHeader->timeScale;
2309 126 : tsscale /= trak->moov->mvhd->timeScale;
2310 :
2311 : //OK, we have a sample so fetch it
2312 126 : e = gf_isom_get_sample_for_media_time(the_file, trackNumber, mediaTime, StreamDescriptionIndex, SearchMode, sample, &sampNum, data_offset);
2313 126 : if (e) {
2314 40 : if (e==GF_EOS) {
2315 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2316 : //movie is fragmented and samples not yet received, return EOS
2317 15 : if (the_file->moov->mvex && !trak->Media->information->sampleTable->SampleSize->sampleCount)
2318 : return e;
2319 : #endif
2320 :
2321 2 : if (nextMediaTime && (nextMediaTime-1 != movieTime))
2322 1 : return gf_isom_get_sample_for_movie_time(the_file, trackNumber, nextMediaTime-1, StreamDescriptionIndex, SearchMode, sample, sampleNumber, data_offset);
2323 : }
2324 : return e;
2325 : }
2326 :
2327 : //OK, now the trick: we have to rebuild the time stamps, according
2328 : //to the media time scale (used by SLConfig) - add the edit start time but stay in
2329 : //the track TS
2330 86 : if (sample && useEdit) {
2331 27 : u64 _ts = (u64)(segStartTime * tsscale);
2332 :
2333 27 : (*sample)->DTS += _ts;
2334 : /*watchout, the sample fetched may be before the first sample in the edit list (when seeking)*/
2335 27 : if ( (*sample)->DTS > (u64) mediaOffset) {
2336 25 : (*sample)->DTS -= (u64) mediaOffset;
2337 : } else {
2338 2 : (*sample)->DTS = 0;
2339 : }
2340 : }
2341 86 : if (sampleNumber) *sampleNumber = sampNum;
2342 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2343 86 : if (sample && (*sample) ) (*sample)->DTS += trak->dts_at_seg_start;
2344 : #endif
2345 :
2346 : return GF_OK;
2347 : }
2348 :
2349 :
2350 :
2351 : GF_EXPORT
2352 245751 : u64 gf_isom_get_missing_bytes(GF_ISOFile *the_file, u32 trackNumber)
2353 : {
2354 : GF_TrackBox *trak;
2355 245751 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
2356 245751 : if (!trak) return 0;
2357 :
2358 245751 : return trak->Media->BytesMissing;
2359 : }
2360 :
2361 : GF_EXPORT
2362 1 : GF_Err gf_isom_set_sample_padding(GF_ISOFile *the_file, u32 trackNumber, u32 padding_bytes)
2363 : {
2364 : GF_TrackBox *trak;
2365 1 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
2366 1 : if (!trak) return GF_BAD_PARAM;
2367 1 : trak->padding_bytes = padding_bytes;
2368 1 : return GF_OK;
2369 :
2370 : }
2371 :
2372 : //get the number of edited segment
2373 : GF_EXPORT
2374 2848 : Bool gf_isom_get_edit_list_type(GF_ISOFile *the_file, u32 trackNumber, s64 *mediaOffset)
2375 : {
2376 : GF_EdtsEntry *ent;
2377 : GF_TrackBox *trak;
2378 : u32 count;
2379 2848 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
2380 2848 : if (!trak) return GF_FALSE;
2381 2802 : *mediaOffset = 0;
2382 2802 : if (!trak->editBox || !trak->editBox->editList) return GF_FALSE;
2383 :
2384 464 : count = gf_list_count(trak->editBox->editList->entryList);
2385 464 : ent = (GF_EdtsEntry*)gf_list_get(trak->editBox->editList->entryList, 0);
2386 464 : if (!ent) return GF_TRUE;
2387 : /*mediaRate>0, the track playback shall start at media time>0 -> mediaOffset is < 0 */
2388 464 : if ((count==1) && (ent->mediaRate == 0x10000)) {
2389 437 : *mediaOffset = - ent->mediaTime;
2390 437 : return GF_FALSE;
2391 27 : } else if (count==2) {
2392 : /*mediaRate==-1, the track playback shall be empty for segmentDuration -> mediaOffset is > 0 */
2393 27 : if ((ent->mediaRate == -0x10000) || (ent->mediaTime==-1)) {
2394 27 : Double time = (Double) ent->segmentDuration;
2395 27 : time /= trak->moov->mvhd->timeScale;
2396 27 : time *= trak->Media->mediaHeader->timeScale;
2397 27 : *mediaOffset = (s64) time;
2398 :
2399 : //check next entry, if we start from mediaOffset > 0 this may still result in a skip
2400 27 : ent = (GF_EdtsEntry*)gf_list_get(trak->editBox->editList->entryList, 1);
2401 : //next entry playback rate is not nominal, we need edit list handling
2402 27 : if (ent->mediaRate != 0x10000)
2403 : return GF_TRUE;
2404 :
2405 27 : if (ent->mediaTime > 0) {
2406 0 : *mediaOffset -= ent->mediaTime;
2407 : }
2408 : return GF_FALSE;
2409 : }
2410 : }
2411 : return GF_TRUE;
2412 : }
2413 :
2414 :
2415 : //get the number of edited segment
2416 : GF_EXPORT
2417 1330 : u32 gf_isom_get_edits_count(GF_ISOFile *the_file, u32 trackNumber)
2418 : {
2419 : GF_TrackBox *trak;
2420 1330 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
2421 1330 : if (!trak) return 0;
2422 :
2423 1330 : if (!trak->editBox || !trak->editBox->editList) return 0;
2424 126 : return gf_list_count(trak->editBox->editList->entryList);
2425 : }
2426 :
2427 :
2428 : //Get the desired segment information
2429 : GF_EXPORT
2430 1478 : GF_Err gf_isom_get_edit(GF_ISOFile *the_file, u32 trackNumber, u32 SegmentIndex, u64 *EditTime, u64 *SegmentDuration, u64 *MediaTime, GF_ISOEditType *EditMode)
2431 : {
2432 : u32 i;
2433 : u64 startTime;
2434 : GF_TrackBox *trak;
2435 : GF_EditListBox *elst;
2436 : GF_EdtsEntry *ent;
2437 :
2438 : ent = NULL;
2439 1478 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
2440 1478 : if (!trak) return GF_BAD_PARAM;
2441 :
2442 1637 : if (!trak->editBox ||
2443 318 : !trak->editBox->editList ||
2444 318 : (SegmentIndex > gf_list_count(trak->editBox->editList->entryList)) ||
2445 : !SegmentIndex)
2446 : return GF_BAD_PARAM;
2447 :
2448 159 : elst = trak->editBox->editList;
2449 : startTime = 0;
2450 :
2451 318 : for (i = 0; i < SegmentIndex; i++) {
2452 159 : ent = (GF_EdtsEntry*)gf_list_get(elst->entryList, i);
2453 159 : if (i < SegmentIndex-1) startTime += ent->segmentDuration;
2454 : }
2455 159 : *EditTime = startTime;
2456 159 : *SegmentDuration = ent->segmentDuration;
2457 159 : if (ent->mediaTime < 0) {
2458 0 : *MediaTime = 0;
2459 0 : *EditMode = GF_ISOM_EDIT_EMPTY;
2460 0 : return GF_OK;
2461 : }
2462 159 : if (ent->mediaRate == 0) {
2463 0 : *MediaTime = ent->mediaTime;
2464 0 : *EditMode = GF_ISOM_EDIT_DWELL;
2465 0 : return GF_OK;
2466 : }
2467 159 : *MediaTime = ent->mediaTime;
2468 159 : *EditMode = GF_ISOM_EDIT_NORMAL;
2469 159 : return GF_OK;
2470 : }
2471 :
2472 : GF_EXPORT
2473 29435 : u8 gf_isom_has_sync_points(GF_ISOFile *the_file, u32 trackNumber)
2474 : {
2475 : GF_TrackBox *trak;
2476 :
2477 29435 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
2478 29435 : if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable) return 0;
2479 29389 : if (trak->Media->information->sampleTable->SyncSample) {
2480 1521 : if (!trak->Media->information->sampleTable->SyncSample->nb_entries) return 2;
2481 1500 : return 1;
2482 : }
2483 : return 0;
2484 : }
2485 :
2486 : /*returns number of sync points*/
2487 : GF_EXPORT
2488 112 : u32 gf_isom_get_sync_point_count(GF_ISOFile *the_file, u32 trackNumber)
2489 : {
2490 : GF_TrackBox *trak;
2491 112 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
2492 112 : if (!trak) return 0;
2493 112 : if (trak->Media->information->sampleTable->SyncSample) {
2494 112 : return trak->Media->information->sampleTable->SyncSample->nb_entries;
2495 : }
2496 : return 0;
2497 : }
2498 :
2499 :
2500 : GF_EXPORT
2501 1681 : GF_Err gf_isom_get_brand_info(GF_ISOFile *movie, u32 *brand, u32 *minorVersion, u32 *AlternateBrandsCount)
2502 : {
2503 1681 : if (!movie) return GF_BAD_PARAM;
2504 1681 : if (!movie->brand) {
2505 7 : if (brand) *brand = GF_ISOM_BRAND_ISOM;
2506 7 : if (minorVersion) *minorVersion = 1;
2507 7 : if (AlternateBrandsCount) *AlternateBrandsCount = 0;
2508 : return GF_OK;
2509 : }
2510 :
2511 1674 : if (brand) *brand = movie->brand->majorBrand;
2512 1674 : if (minorVersion) *minorVersion = movie->brand->minorVersion;
2513 1674 : if (AlternateBrandsCount) *AlternateBrandsCount = movie->brand->altCount;
2514 : return GF_OK;
2515 : }
2516 :
2517 : GF_EXPORT
2518 779 : GF_Err gf_isom_get_alternate_brand(GF_ISOFile *movie, u32 BrandIndex, u32 *brand)
2519 : {
2520 779 : if (!movie || !movie->brand || !brand) return GF_BAD_PARAM;
2521 779 : if (BrandIndex > movie->brand->altCount || !BrandIndex) return GF_BAD_PARAM;
2522 779 : *brand = movie->brand->altBrand[BrandIndex-1];
2523 779 : return GF_OK;
2524 : }
2525 :
2526 : GF_EXPORT
2527 1138 : const u32 *gf_isom_get_brands(GF_ISOFile *movie)
2528 : {
2529 1138 : if (!movie || !movie->brand) return NULL;
2530 1131 : return movie->brand->altBrand;
2531 : }
2532 :
2533 : GF_EXPORT
2534 1 : GF_Err gf_isom_get_sample_padding_bits(GF_ISOFile *the_file, u32 trackNumber, u32 sampleNumber, u8 *NbBits)
2535 : {
2536 : GF_TrackBox *trak;
2537 :
2538 1 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
2539 1 : if (!trak) return GF_BAD_PARAM;
2540 :
2541 :
2542 : //Padding info
2543 1 : return stbl_GetPaddingBits(trak->Media->information->sampleTable->PaddingBits,
2544 : sampleNumber, NbBits);
2545 :
2546 : }
2547 :
2548 :
2549 : GF_EXPORT
2550 1 : Bool gf_isom_has_padding_bits(GF_ISOFile *the_file, u32 trackNumber)
2551 : {
2552 : GF_TrackBox *trak;
2553 :
2554 1 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
2555 1 : if (!trak) return GF_FALSE;
2556 :
2557 1 : if (trak->Media->information->sampleTable->PaddingBits) return GF_TRUE;
2558 1 : return GF_FALSE;
2559 : }
2560 :
2561 : GF_EXPORT
2562 427 : u32 gf_isom_get_udta_count(GF_ISOFile *movie, u32 trackNumber)
2563 : {
2564 : GF_TrackBox *trak;
2565 : GF_UserDataBox *udta;
2566 427 : if (!movie || !movie->moov) return 0;
2567 :
2568 427 : if (trackNumber) {
2569 242 : trak = gf_isom_get_track_from_file(movie, trackNumber);
2570 242 : if (!trak) return 0;
2571 242 : udta = trak->udta;
2572 : } else {
2573 185 : udta = movie->moov->udta;
2574 : }
2575 427 : if (udta) return gf_list_count(udta->recordList);
2576 : return 0;
2577 : }
2578 :
2579 : GF_EXPORT
2580 14 : GF_Err gf_isom_get_udta_type(GF_ISOFile *movie, u32 trackNumber, u32 udta_idx, u32 *UserDataType, bin128 *UUID)
2581 : {
2582 : GF_TrackBox *trak;
2583 : GF_UserDataBox *udta;
2584 : GF_UserDataMap *map;
2585 14 : if (!movie || !movie->moov || !udta_idx) return GF_BAD_PARAM;
2586 :
2587 14 : if (trackNumber) {
2588 12 : trak = gf_isom_get_track_from_file(movie, trackNumber);
2589 12 : if (!trak) return GF_OK;
2590 12 : udta = trak->udta;
2591 : } else {
2592 2 : udta = movie->moov->udta;
2593 : }
2594 14 : if (!udta) return GF_BAD_PARAM;
2595 14 : if (udta_idx>gf_list_count(udta->recordList)) return GF_BAD_PARAM;
2596 14 : map = (GF_UserDataMap*)gf_list_get(udta->recordList, udta_idx - 1);
2597 14 : if (UserDataType) *UserDataType = map->boxType;
2598 14 : if (UUID) memcpy(*UUID, map->uuid, 16);
2599 : return GF_OK;
2600 : }
2601 :
2602 : GF_EXPORT
2603 15 : u32 gf_isom_get_user_data_count(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID)
2604 : {
2605 : GF_UserDataMap *map;
2606 : GF_TrackBox *trak;
2607 : GF_UserDataBox *udta;
2608 : bin128 t;
2609 : u32 i, count;
2610 :
2611 15 : if (!movie || !movie->moov) return 0;
2612 :
2613 15 : if (UserDataType == GF_ISOM_BOX_TYPE_UUID) UserDataType = 0;
2614 : memset(t, 1, 16);
2615 :
2616 15 : if (trackNumber) {
2617 13 : trak = gf_isom_get_track_from_file(movie, trackNumber);
2618 13 : if (!trak) return 0;
2619 13 : udta = trak->udta;
2620 : } else {
2621 2 : udta = movie->moov->udta;
2622 : }
2623 15 : if (!udta) return 0;
2624 :
2625 15 : i=0;
2626 30 : while ((map = (GF_UserDataMap*)gf_list_enum(udta->recordList, &i))) {
2627 15 : count = gf_list_count(map->boxes);
2628 :
2629 15 : if ((map->boxType == GF_ISOM_BOX_TYPE_UUID) && !memcmp(map->uuid, UUID, 16)) return count;
2630 15 : else if (map->boxType == UserDataType) return count;
2631 : }
2632 : return 0;
2633 : }
2634 :
2635 : GF_EXPORT
2636 15 : GF_Err gf_isom_get_user_data(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID, u32 UserDataIndex, u8 **userData, u32 *userDataSize)
2637 : {
2638 : GF_UserDataMap *map;
2639 : GF_UnknownBox *ptr;
2640 : GF_BitStream *bs;
2641 : u32 i;
2642 : bin128 t;
2643 : GF_TrackBox *trak;
2644 : GF_UserDataBox *udta;
2645 :
2646 15 : if (!movie || !movie->moov) return GF_BAD_PARAM;
2647 :
2648 15 : if (trackNumber) {
2649 13 : trak = gf_isom_get_track_from_file(movie, trackNumber);
2650 13 : if (!trak) return GF_BAD_PARAM;
2651 13 : udta = trak->udta;
2652 : } else {
2653 2 : udta = movie->moov->udta;
2654 : }
2655 15 : if (!udta) return GF_BAD_PARAM;
2656 :
2657 15 : if (UserDataType == GF_ISOM_BOX_TYPE_UUID) UserDataType = 0;
2658 : memset(t, 1, 16);
2659 :
2660 15 : if (!userData || !userDataSize || *userData) return GF_BAD_PARAM;
2661 :
2662 15 : i=0;
2663 30 : while ((map = (GF_UserDataMap*)gf_list_enum(udta->recordList, &i))) {
2664 15 : if ((map->boxType == GF_ISOM_BOX_TYPE_UUID) && !memcmp(map->uuid, UUID, 16)) goto found;
2665 15 : else if (map->boxType == UserDataType) goto found;
2666 :
2667 : }
2668 : return GF_BAD_PARAM;
2669 :
2670 15 : found:
2671 15 : if (UserDataIndex) {
2672 13 : if (UserDataIndex > gf_list_count(map->boxes) ) return GF_BAD_PARAM;
2673 13 : ptr = (GF_UnknownBox*)gf_list_get(map->boxes, UserDataIndex-1);
2674 :
2675 13 : if (ptr->type == GF_ISOM_BOX_TYPE_UNKNOWN) {
2676 9 : *userData = (char *)gf_malloc(sizeof(char)*ptr->dataSize);
2677 9 : if (!*userData) return GF_OUT_OF_MEM;
2678 9 : memcpy(*userData, ptr->data, sizeof(char)*ptr->dataSize);
2679 9 : *userDataSize = ptr->dataSize;
2680 9 : return GF_OK;
2681 4 : } else if (ptr->type == GF_ISOM_BOX_TYPE_UUID) {
2682 : GF_UnknownUUIDBox *p_uuid = (GF_UnknownUUIDBox *)ptr;
2683 0 : *userData = (char *)gf_malloc(sizeof(char)*p_uuid->dataSize);
2684 0 : if (!*userData) return GF_OUT_OF_MEM;
2685 0 : memcpy(*userData, p_uuid->data, sizeof(char)*p_uuid->dataSize);
2686 0 : *userDataSize = p_uuid->dataSize;
2687 0 : return GF_OK;
2688 : } else {
2689 : char *str = NULL;
2690 4 : switch (ptr->type) {
2691 0 : case GF_ISOM_BOX_TYPE_NAME:
2692 : //case GF_QT_BOX_TYPE_NAME: same as above
2693 0 : str = ((GF_NameBox *)ptr)->string;
2694 0 : break;
2695 2 : case GF_ISOM_BOX_TYPE_KIND:
2696 2 : str = ((GF_KindBox *)ptr)->value;
2697 2 : break;
2698 : }
2699 2 : if (str) {
2700 0 : u32 len = (u32) strlen(str) + 1;
2701 0 : *userData = (char *)gf_malloc(sizeof(char) * len);
2702 0 : if (!*userData) return GF_OUT_OF_MEM;
2703 : memcpy(*userData, str, sizeof(char)*len);
2704 0 : *userDataSize = len;
2705 0 : return GF_OK;
2706 : }
2707 : return GF_NOT_SUPPORTED;
2708 : }
2709 : }
2710 :
2711 : //serialize all boxes
2712 2 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
2713 2 : i=0;
2714 6 : while ( (ptr = (GF_UnknownBox*)gf_list_enum(map->boxes, &i))) {
2715 : u32 type, s, data_size;
2716 : char *data=NULL;
2717 2 : if (ptr->type == GF_ISOM_BOX_TYPE_UNKNOWN) {
2718 2 : type = ptr->original_4cc;
2719 2 : data_size = ptr->dataSize;
2720 2 : data = ptr->data;
2721 0 : } else if (ptr->type == GF_ISOM_BOX_TYPE_UUID) {
2722 : GF_UnknownUUIDBox *p_uuid = (GF_UnknownUUIDBox *)ptr;
2723 : type = p_uuid->type;
2724 0 : data_size = p_uuid->dataSize;
2725 0 : data = p_uuid->data;
2726 : } else {
2727 0 : gf_isom_box_write((GF_Box *)ptr, bs);
2728 0 : continue;
2729 : }
2730 2 : s = data_size+8;
2731 2 : if (ptr->type==GF_ISOM_BOX_TYPE_UUID) s += 16;
2732 :
2733 2 : gf_bs_write_u32(bs, s);
2734 2 : gf_bs_write_u32(bs, type);
2735 2 : if (type==GF_ISOM_BOX_TYPE_UUID) gf_bs_write_data(bs, (char *) map->uuid, 16);
2736 2 : if (data) {
2737 2 : gf_bs_write_data(bs, data, data_size);
2738 0 : } else if (ptr->child_boxes) {
2739 : #ifndef GPAC_DISABLE_ISOM_WRITE
2740 0 : gf_isom_box_array_write((GF_Box *)ptr, ptr->child_boxes, bs);
2741 : #else
2742 : 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" ));
2743 : #endif
2744 : }
2745 : }
2746 2 : gf_bs_get_content(bs, userData, userDataSize);
2747 2 : gf_bs_del(bs);
2748 2 : return GF_OK;
2749 : }
2750 :
2751 : GF_EXPORT
2752 1188 : void gf_isom_delete(GF_ISOFile *movie)
2753 : {
2754 : //free and return;
2755 1188 : gf_isom_delete_movie(movie);
2756 1188 : }
2757 :
2758 : GF_EXPORT
2759 4 : 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)
2760 : {
2761 : GF_TrackBox *trak;
2762 : u32 i, k, sample_idx, dmin, dmax, smin, smax, tot_chunks;
2763 : u64 davg, savg;
2764 : GF_SampleToChunkBox *stsc;
2765 : GF_TimeToSampleBox *stts;
2766 4 : if (!movie || !trackNumber || !movie->moov) return GF_BAD_PARAM;
2767 4 : trak = gf_isom_get_track_from_file(movie, trackNumber);
2768 4 : if (!trak) return GF_BAD_PARAM;
2769 :
2770 4 : stsc = trak->Media->information->sampleTable->SampleToChunk;
2771 4 : stts = trak->Media->information->sampleTable->TimeToSample;
2772 4 : if (!stsc || !stts) return GF_ISOM_INVALID_FILE;
2773 :
2774 : dmin = smin = (u32) -1;
2775 : dmax = smax = 0;
2776 : davg = savg = 0;
2777 : sample_idx = 1;
2778 : tot_chunks = 0;
2779 16 : for (i=0; i<stsc->nb_entries; i++) {
2780 : u32 nb_chunk = 0;
2781 12 : if (stsc->entries[i].samplesPerChunk > 2*trak->Media->information->sampleTable->SampleSize->sampleCount) {
2782 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] likely broken stco entry (%u samples per chunk but %u samples total)\n", stsc->entries[i].samplesPerChunk, trak->Media->information->sampleTable->SampleSize->sampleCount));
2783 : return GF_ISOM_INVALID_FILE;
2784 : }
2785 : while (1) {
2786 : u32 chunk_dur = 0;
2787 : u32 chunk_size = 0;
2788 960 : for (k=0; k<stsc->entries[i].samplesPerChunk; k++) {
2789 : u64 dts;
2790 : u32 dur;
2791 : u32 size;
2792 899 : stbl_GetSampleDTS_and_Duration(stts, k+sample_idx, &dts, &dur);
2793 899 : chunk_dur += dur;
2794 899 : stbl_GetSampleSize(trak->Media->information->sampleTable->SampleSize, k+sample_idx, &size);
2795 899 : chunk_size += size;
2796 :
2797 : }
2798 61 : if (dmin>chunk_dur) dmin = chunk_dur;
2799 61 : if (dmax<chunk_dur) dmax = chunk_dur;
2800 61 : davg += chunk_dur;
2801 61 : if (smin>chunk_size) smin = chunk_size;
2802 61 : if (smax<chunk_size) smax = chunk_size;
2803 61 : savg += chunk_size;
2804 :
2805 61 : tot_chunks ++;
2806 61 : sample_idx += stsc->entries[i].samplesPerChunk;
2807 61 : if (i+1==stsc->nb_entries) break;
2808 57 : nb_chunk ++;
2809 57 : if (stsc->entries[i].firstChunk + nb_chunk == stsc->entries[i+1].firstChunk) break;
2810 : }
2811 : }
2812 4 : if (tot_chunks) {
2813 4 : davg /= tot_chunks;
2814 4 : savg /= tot_chunks;
2815 : }
2816 4 : if (dur_min) *dur_min = dmin;
2817 4 : if (dur_avg) *dur_avg = (u32) davg;
2818 4 : if (dur_max) *dur_max = dmax;
2819 :
2820 4 : if (size_min) *size_min = smin;
2821 4 : if (size_avg) *size_avg = (u32) savg;
2822 4 : if (size_max) *size_max = smax;
2823 : return GF_OK;
2824 : }
2825 :
2826 : GF_EXPORT
2827 3 : GF_Err gf_isom_get_fragment_defaults(GF_ISOFile *the_file, u32 trackNumber,
2828 : u32 *defaultDuration, u32 *defaultSize, u32 *defaultDescriptionIndex,
2829 : u32 *defaultRandomAccess, u8 *defaultPadding, u16 *defaultDegradationPriority)
2830 : {
2831 : GF_TrackBox *trak;
2832 : GF_StscEntry *sc_ent;
2833 : u32 i, j, maxValue, value;
2834 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2835 : GF_TrackExtendsBox *trex;
2836 : #endif
2837 : GF_SampleTableBox *stbl;
2838 3 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
2839 3 : if (!trak) return GF_BAD_PARAM;
2840 :
2841 : /*if trex is already set, restore flags*/
2842 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2843 3 : trex = the_file->moov->mvex ? GetTrex(the_file->moov, gf_isom_get_track_id(the_file,trackNumber) ) : NULL;
2844 3 : if (trex) {
2845 3 : trex->track = trak;
2846 :
2847 3 : if (defaultDuration) *defaultDuration = trex->def_sample_duration;
2848 3 : if (defaultSize) *defaultSize = trex->def_sample_size;
2849 3 : if (defaultDescriptionIndex) *defaultDescriptionIndex = trex->def_sample_desc_index;
2850 3 : if (defaultRandomAccess) *defaultRandomAccess = GF_ISOM_GET_FRAG_SYNC(trex->def_sample_flags);
2851 3 : if (defaultPadding) *defaultPadding = GF_ISOM_GET_FRAG_PAD(trex->def_sample_flags);
2852 3 : if (defaultDegradationPriority) *defaultDegradationPriority = GF_ISOM_GET_FRAG_DEG(trex->def_sample_flags);
2853 : return GF_OK;
2854 : }
2855 : #endif
2856 :
2857 0 : stbl = trak->Media->information->sampleTable;
2858 0 : if (!stbl->TimeToSample || !stbl->SampleSize || !stbl->SampleToChunk) return GF_ISOM_INVALID_FILE;
2859 :
2860 :
2861 : //duration
2862 0 : if (defaultDuration) {
2863 : maxValue = value = 0;
2864 0 : for (i=0; i<stbl->TimeToSample->nb_entries; i++) {
2865 0 : if (stbl->TimeToSample->entries[i].sampleCount>maxValue) {
2866 0 : value = stbl->TimeToSample->entries[i].sampleDelta;
2867 : maxValue = stbl->TimeToSample->entries[i].sampleCount;
2868 : }
2869 : }
2870 0 : *defaultDuration = value;
2871 : }
2872 : //size
2873 0 : if (defaultSize) {
2874 0 : *defaultSize = stbl->SampleSize->sampleSize;
2875 : }
2876 : //descIndex
2877 0 : if (defaultDescriptionIndex) {
2878 0 : GF_SampleToChunkBox *stsc= stbl->SampleToChunk;
2879 : maxValue = value = 0;
2880 0 : for (i=0; i<stsc->nb_entries; i++) {
2881 0 : sc_ent = &stsc->entries[i];
2882 0 : if ((sc_ent->nextChunk - sc_ent->firstChunk) * sc_ent->samplesPerChunk > maxValue) {
2883 0 : value = sc_ent->sampleDescriptionIndex;
2884 : maxValue = (sc_ent->nextChunk - sc_ent->firstChunk) * sc_ent->samplesPerChunk;
2885 : }
2886 : }
2887 0 : *defaultDescriptionIndex = value ? value : 1;
2888 : }
2889 : //RAP
2890 0 : if (defaultRandomAccess) {
2891 : //no sync table is ALL RAP
2892 0 : *defaultRandomAccess = stbl->SyncSample ? 0 : 1;
2893 0 : if (stbl->SyncSample
2894 0 : && (stbl->SyncSample->nb_entries == stbl->SampleSize->sampleCount)) {
2895 0 : *defaultRandomAccess = 1;
2896 : }
2897 : }
2898 : //defaultPadding
2899 0 : if (defaultPadding) {
2900 0 : *defaultPadding = 0;
2901 0 : if (stbl->PaddingBits) {
2902 : maxValue = 0;
2903 0 : for (i=0; i<stbl->PaddingBits->SampleCount; i++) {
2904 : value = 0;
2905 0 : for (j=0; j<stbl->PaddingBits->SampleCount; j++) {
2906 0 : if (stbl->PaddingBits->padbits[i]==stbl->PaddingBits->padbits[j]) {
2907 0 : value ++;
2908 : }
2909 : }
2910 0 : if (value>maxValue) {
2911 : maxValue = value;
2912 0 : *defaultPadding = stbl->PaddingBits->padbits[i];
2913 : }
2914 : }
2915 : }
2916 : }
2917 : //defaultDegradationPriority
2918 0 : if (defaultDegradationPriority) {
2919 0 : *defaultDegradationPriority = 0;
2920 0 : if (stbl->DegradationPriority) {
2921 : maxValue = 0;
2922 0 : for (i=0; i<stbl->DegradationPriority->nb_entries; i++) {
2923 : value = 0;
2924 0 : for (j=0; j<stbl->DegradationPriority->nb_entries; j++) {
2925 0 : if (stbl->DegradationPriority->priorities[i]==stbl->DegradationPriority->priorities[j]) {
2926 0 : value ++;
2927 : }
2928 : }
2929 0 : if (value>maxValue) {
2930 : maxValue = value;
2931 0 : *defaultDegradationPriority = stbl->DegradationPriority->priorities[i];
2932 : }
2933 : }
2934 : }
2935 : }
2936 : return GF_OK;
2937 : }
2938 :
2939 :
2940 : GF_EXPORT
2941 7693 : GF_Err gf_isom_refresh_fragmented(GF_ISOFile *movie, u64 *MissingBytes, const char *new_location)
2942 : {
2943 : #ifdef GPAC_DISABLE_ISOM_FRAGMENTS
2944 : return GF_NOT_SUPPORTED;
2945 : #else
2946 : u64 prevsize, size;
2947 : u32 i;
2948 7693 : if (!movie || !movie->movieFileMap || !movie->moov) return GF_BAD_PARAM;
2949 7693 : if (movie->openMode != GF_ISOM_OPEN_READ) return GF_BAD_PARAM;
2950 :
2951 : /*refresh size*/
2952 7693 : size = movie->movieFileMap ? gf_bs_get_size(movie->movieFileMap->bs) : 0;
2953 :
2954 7693 : if (new_location) {
2955 : Bool delete_map;
2956 7693 : GF_DataMap *previous_movie_fileMap_address = movie->movieFileMap;
2957 : GF_Err e;
2958 :
2959 7693 : e = gf_isom_datamap_new(new_location, NULL, GF_ISOM_DATA_MAP_READ_ONLY, &movie->movieFileMap);
2960 7693 : if (e) {
2961 0 : movie->movieFileMap = previous_movie_fileMap_address;
2962 0 : return e;
2963 : }
2964 :
2965 7693 : delete_map = (previous_movie_fileMap_address != NULL ? GF_TRUE: GF_FALSE);
2966 29879 : for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
2967 22186 : GF_TrackBox *trak = (GF_TrackBox *)gf_list_get(movie->moov->trackList, i);
2968 22186 : if (trak->Media->information->dataHandler == previous_movie_fileMap_address) {
2969 : //reaasign for later destruction
2970 22183 : trak->Media->information->scalableDataHandler = movie->movieFileMap;
2971 : //reassign for Media_GetSample function
2972 22183 : trak->Media->information->dataHandler = movie->movieFileMap;
2973 3 : } else if (trak->Media->information->scalableDataHandler == previous_movie_fileMap_address) {
2974 : delete_map = GF_FALSE;
2975 : }
2976 : }
2977 7693 : if (delete_map) {
2978 7693 : gf_isom_datamap_del(previous_movie_fileMap_address);
2979 : }
2980 : }
2981 :
2982 7693 : prevsize = gf_bs_get_refreshed_size(movie->movieFileMap->bs);
2983 7693 : if (prevsize==size) return GF_OK;
2984 :
2985 4999 : if (!movie->moov->mvex)
2986 : return GF_OK;
2987 :
2988 : //ok parse root boxes
2989 4488 : return gf_isom_parse_movie_boxes(movie, NULL, MissingBytes, GF_TRUE);
2990 : #endif
2991 : }
2992 :
2993 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
2994 : GF_EXPORT
2995 1 : void gf_isom_set_single_moof_mode(GF_ISOFile *movie, Bool mode)
2996 : {
2997 1 : movie->single_moof_mode = mode;
2998 1 : }
2999 : #endif
3000 :
3001 : GF_EXPORT
3002 242 : GF_Err gf_isom_reset_data_offset(GF_ISOFile *movie, u64 *top_box_start)
3003 : {
3004 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3005 : u32 i, count;
3006 242 : if (!movie || !movie->moov) return GF_BAD_PARAM;
3007 242 : if (top_box_start) *top_box_start = movie->current_top_box_start;
3008 242 : movie->current_top_box_start = 0;
3009 242 : movie->NextMoofNumber = 0;
3010 242 : if (movie->moov->mvex && movie->single_moof_mode) {
3011 0 : movie->single_moof_state = 0;
3012 : }
3013 242 : count = gf_list_count(movie->moov->trackList);
3014 1128 : for (i=0; i<count; i++) {
3015 886 : GF_TrackBox *tk = gf_list_get(movie->moov->trackList, i);
3016 886 : tk->first_traf_merged = GF_FALSE;
3017 : }
3018 : #endif
3019 : return GF_OK;
3020 : }
3021 :
3022 : GF_EXPORT
3023 82 : GF_Err gf_isom_get_current_top_box_offset(GF_ISOFile *movie, u64 *current_top_box_offset)
3024 : {
3025 82 : if (!movie || !movie->moov || !current_top_box_offset) return GF_BAD_PARAM;
3026 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3027 82 : *current_top_box_offset = movie->current_top_box_start;
3028 82 : return GF_OK;
3029 : #else
3030 : return GF_NOT_SUPPORTED;
3031 : #endif
3032 : }
3033 :
3034 : GF_EXPORT
3035 354 : GF_Err gf_isom_set_removed_bytes(GF_ISOFile *movie, u64 bytes_removed)
3036 : {
3037 354 : if (!movie || !movie->moov) return GF_BAD_PARAM;
3038 354 : movie->bytes_removed = bytes_removed;
3039 354 : return GF_OK;
3040 : }
3041 :
3042 75 : GF_Err gf_isom_purge_samples(GF_ISOFile *the_file, u32 trackNumber, u32 nb_samples)
3043 : {
3044 : GF_TrackBox *trak;
3045 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3046 : GF_Err e;
3047 : GF_TrackExtendsBox *trex;
3048 : GF_SampleTableBox *stbl;
3049 : #endif
3050 75 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
3051 75 : if (!trak) return GF_BAD_PARAM;
3052 :
3053 : /*if trex is already set, restore flags*/
3054 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3055 75 : trex = the_file->moov->mvex ? GetTrex(the_file->moov, gf_isom_get_track_id(the_file,trackNumber) ) : NULL;
3056 75 : if (!trex) return GF_BAD_PARAM;
3057 :
3058 : //first unpack chunk offsets and CTS
3059 75 : e = stbl_UnpackOffsets(trak->Media->information->sampleTable);
3060 75 : if (e) return e;
3061 75 : e = stbl_unpackCTS(trak->Media->information->sampleTable);
3062 75 : if (e) return e;
3063 :
3064 75 : stbl = trak->Media->information->sampleTable;
3065 75 : if (!stbl->TimeToSample || !stbl->SampleSize || !stbl->SampleToChunk) return GF_ISOM_INVALID_FILE;
3066 :
3067 : //remove at once nb_samples in stts, ctts, stsz, stco, stsc and stdp (n-times removal is way too slow)
3068 : //do NOT change the order DTS, CTS, size chunk
3069 75 : stbl_RemoveDTS(stbl, 1, nb_samples, 0);
3070 75 : stbl_RemoveCTS(stbl, 1, nb_samples);
3071 75 : stbl_RemoveSize(stbl, 1, nb_samples);
3072 75 : stbl_RemoveChunk(stbl, 1, nb_samples);
3073 75 : stbl_RemoveRedundant(stbl, 1, nb_samples);
3074 :
3075 : //then remove sample per sample for the rest, which is either
3076 : //- sparse data
3077 : //- allocated structure rather than memmove-able array
3078 : //- not very frequent info (paddind bits)
3079 15092 : while (nb_samples) {
3080 14942 : stbl_RemoveRAP(stbl, 1);
3081 14942 : stbl_RemoveShadow(stbl, 1);
3082 14942 : stbl_RemoveSubSample(stbl, 1);
3083 14942 : stbl_RemovePaddingBits(stbl, 1);
3084 14942 : stbl_RemoveSampleGroup(stbl, 1);
3085 14942 : nb_samples--;
3086 : }
3087 : return GF_OK;
3088 : #else
3089 : return GF_NOT_SUPPORTED;
3090 : #endif
3091 : }
3092 :
3093 :
3094 : #define RECREATE_BOX(_a, __cast) \
3095 : if (_a) { \
3096 : type = _a->type;\
3097 : gf_isom_box_del_parent(&stbl->child_boxes, (GF_Box *)_a);\
3098 : _a = __cast gf_isom_box_new_parent(&stbl->child_boxes, type);\
3099 : }\
3100 :
3101 :
3102 : GF_EXPORT
3103 242 : GF_Err gf_isom_reset_tables(GF_ISOFile *movie, Bool reset_sample_count)
3104 : {
3105 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3106 : u32 i, j;
3107 :
3108 242 : if (!movie || !movie->moov || !movie->moov->mvex) return GF_BAD_PARAM;
3109 886 : for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
3110 : GF_Box *a;
3111 886 : GF_TrackBox *trak = (GF_TrackBox *)gf_list_get(movie->moov->trackList, i);
3112 :
3113 : u32 type, dur;
3114 : u64 dts;
3115 886 : GF_SampleTableBox *stbl = trak->Media->information->sampleTable;
3116 :
3117 886 : trak->sample_count_at_seg_start += stbl->SampleSize->sampleCount;
3118 886 : if (trak->sample_count_at_seg_start) {
3119 : GF_Err e;
3120 1 : e = stbl_GetSampleDTS_and_Duration(stbl->TimeToSample, stbl->SampleSize->sampleCount, &dts, &dur);
3121 1 : if (e == GF_OK) {
3122 1 : trak->dts_at_seg_start += dts + dur;
3123 : }
3124 : }
3125 :
3126 886 : RECREATE_BOX(stbl->ChunkOffset, (GF_Box *));
3127 886 : RECREATE_BOX(stbl->CompositionOffset, (GF_CompositionOffsetBox *));
3128 886 : RECREATE_BOX(stbl->DegradationPriority, (GF_DegradationPriorityBox *));
3129 886 : RECREATE_BOX(stbl->PaddingBits, (GF_PaddingBitsBox *));
3130 886 : RECREATE_BOX(stbl->SampleDep, (GF_SampleDependencyTypeBox *));
3131 886 : RECREATE_BOX(stbl->SampleSize, (GF_SampleSizeBox *));
3132 886 : RECREATE_BOX(stbl->SampleToChunk, (GF_SampleToChunkBox *));
3133 886 : RECREATE_BOX(stbl->ShadowSync, (GF_ShadowSyncBox *));
3134 886 : RECREATE_BOX(stbl->SyncSample, (GF_SyncSampleBox *));
3135 886 : RECREATE_BOX(stbl->TimeToSample, (GF_TimeToSampleBox *));
3136 :
3137 886 : gf_isom_box_array_del_parent(&stbl->child_boxes, stbl->sai_offsets);
3138 886 : stbl->sai_offsets = NULL;
3139 :
3140 886 : gf_isom_box_array_del_parent(&stbl->child_boxes, stbl->sai_sizes);
3141 886 : stbl->sai_sizes = NULL;
3142 :
3143 886 : gf_isom_box_array_del_parent(&stbl->child_boxes, stbl->sampleGroups);
3144 886 : stbl->sampleGroups = NULL;
3145 :
3146 886 : j = stbl->nb_sgpd_in_stbl;
3147 1772 : while ((a = (GF_Box *)gf_list_enum(stbl->sampleGroupsDescription, &j))) {
3148 0 : gf_isom_box_del_parent(&stbl->child_boxes, a);
3149 0 : j--;
3150 0 : gf_list_rem(stbl->sampleGroupsDescription, j);
3151 : }
3152 :
3153 : #if 0
3154 : j = stbl->nb_stbl_boxes;
3155 : while ((a = (GF_Box *)gf_list_enum(stbl->child_boxes, &j))) {
3156 : gf_isom_box_del_parent(&stbl->child_boxes, a);
3157 : j--;
3158 : }
3159 : #endif
3160 :
3161 886 : if (reset_sample_count) {
3162 886 : trak->Media->information->sampleTable->SampleSize->sampleCount = 0;
3163 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3164 886 : trak->sample_count_at_seg_start = 0;
3165 886 : trak->dts_at_seg_start = 0;
3166 886 : trak->first_traf_merged = GF_FALSE;
3167 : #endif
3168 : }
3169 :
3170 : }
3171 242 : if (reset_sample_count) {
3172 242 : movie->NextMoofNumber = 0;
3173 : }
3174 : #endif
3175 : return GF_OK;
3176 :
3177 : }
3178 :
3179 : GF_EXPORT
3180 2966 : GF_Err gf_isom_release_segment(GF_ISOFile *movie, Bool reset_tables)
3181 : {
3182 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3183 : u32 i, j, base_track_sample_count;
3184 : Bool has_scalable;
3185 : GF_Box *a;
3186 2966 : if (!movie || !movie->moov || !movie->moov->mvex) return GF_BAD_PARAM;
3187 2966 : has_scalable = gf_isom_needs_layer_reconstruction(movie);
3188 : base_track_sample_count = 0;
3189 2966 : movie->moov->compressed_diff = 0;
3190 20526 : for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
3191 17560 : GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
3192 17560 : trak->first_traf_merged = GF_FALSE;
3193 17560 : if (trak->Media->information->dataHandler == movie->movieFileMap) {
3194 17263 : trak->Media->information->dataHandler = NULL;
3195 : }
3196 17560 : if (trak->Media->information->scalableDataHandler == movie->movieFileMap) {
3197 16900 : trak->Media->information->scalableDataHandler = NULL;
3198 : } else {
3199 660 : if (trak->Media->information->scalableDataHandler==trak->Media->information->dataHandler)
3200 660 : trak->Media->information->dataHandler = NULL;
3201 :
3202 660 : gf_isom_datamap_del(trak->Media->information->scalableDataHandler);
3203 660 : trak->Media->information->scalableDataHandler = NULL;
3204 : }
3205 :
3206 :
3207 17560 : if (reset_tables) {
3208 : u32 type, dur;
3209 : u64 dts;
3210 17555 : GF_SampleTableBox *stbl = trak->Media->information->sampleTable;
3211 :
3212 17555 : if (has_scalable) {
3213 : //check if the base reference is in the file - if not, do not consider the track is scalable.
3214 16142 : if (gf_isom_get_reference_count(movie, i+1, GF_ISOM_REF_BASE) > 0) {
3215 0 : u32 on_track=0;
3216 : GF_TrackBox *base;
3217 0 : gf_isom_get_reference(movie, i+1, GF_ISOM_REF_BASE, 1, &on_track);
3218 :
3219 0 : base = gf_isom_get_track_from_file(movie, on_track);
3220 0 : if (!base) {
3221 : base_track_sample_count=0;
3222 : } else {
3223 0 : base_track_sample_count = base->Media->information->sampleTable->SampleSize->sampleCount;
3224 : }
3225 : }
3226 : }
3227 :
3228 17555 : trak->sample_count_at_seg_start += base_track_sample_count ? base_track_sample_count : stbl->SampleSize->sampleCount;
3229 :
3230 17555 : if (trak->sample_count_at_seg_start) {
3231 : GF_Err e;
3232 16938 : e = stbl_GetSampleDTS_and_Duration(stbl->TimeToSample, stbl->SampleSize->sampleCount, &dts, &dur);
3233 16938 : if (e == GF_OK) {
3234 2853 : trak->dts_at_seg_start += dts + dur;
3235 : }
3236 : }
3237 :
3238 17555 : RECREATE_BOX(stbl->ChunkOffset, (GF_Box *));
3239 17555 : RECREATE_BOX(stbl->CompositionOffset, (GF_CompositionOffsetBox *));
3240 17555 : RECREATE_BOX(stbl->DegradationPriority, (GF_DegradationPriorityBox *));
3241 17555 : RECREATE_BOX(stbl->PaddingBits, (GF_PaddingBitsBox *));
3242 17555 : RECREATE_BOX(stbl->SampleDep, (GF_SampleDependencyTypeBox *));
3243 17555 : RECREATE_BOX(stbl->SampleSize, (GF_SampleSizeBox *));
3244 17555 : RECREATE_BOX(stbl->SampleToChunk, (GF_SampleToChunkBox *));
3245 17555 : RECREATE_BOX(stbl->ShadowSync, (GF_ShadowSyncBox *));
3246 17555 : RECREATE_BOX(stbl->SyncSample, (GF_SyncSampleBox *));
3247 17555 : RECREATE_BOX(stbl->TimeToSample, (GF_TimeToSampleBox *));
3248 :
3249 17555 : gf_isom_box_array_del_parent(&stbl->child_boxes, stbl->sai_offsets);
3250 17555 : stbl->sai_offsets = NULL;
3251 :
3252 17555 : gf_isom_box_array_del_parent(&stbl->child_boxes, stbl->sai_sizes);
3253 17555 : stbl->sai_sizes = NULL;
3254 :
3255 17555 : gf_isom_box_array_del_parent(&stbl->child_boxes, stbl->sampleGroups);
3256 17555 : stbl->sampleGroups = NULL;
3257 :
3258 17555 : if (trak->sample_encryption) {
3259 40 : if (trak->Media->information->sampleTable->child_boxes) {
3260 40 : gf_list_del_item(trak->Media->information->sampleTable->child_boxes, trak->sample_encryption);
3261 : }
3262 40 : gf_isom_box_del_parent(&trak->child_boxes, (GF_Box*)trak->sample_encryption);
3263 40 : trak->sample_encryption = NULL;
3264 : }
3265 :
3266 17555 : j = stbl->nb_sgpd_in_stbl;
3267 35128 : while ((a = (GF_Box *)gf_list_enum(stbl->sampleGroupsDescription, &j))) {
3268 18 : gf_isom_box_del_parent(&stbl->child_boxes, a);
3269 18 : j--;
3270 18 : gf_list_rem(stbl->sampleGroupsDescription, j);
3271 : }
3272 :
3273 17555 : if (stbl->traf_map) {
3274 129 : for (j=0; j<stbl->traf_map->nb_entries; j++) {
3275 78 : if (stbl->traf_map->frag_starts[j].moof_template)
3276 51 : gf_free(stbl->traf_map->frag_starts[j].moof_template);
3277 : }
3278 51 : memset(stbl->traf_map->frag_starts, 0, sizeof(GF_TrafMapEntry)*stbl->traf_map->nb_alloc);
3279 51 : stbl->traf_map->nb_entries = 0;
3280 : }
3281 :
3282 : #if 0 // TO CHECK
3283 : j = ptr->nb_stbl_boxes;
3284 : while ((a = (GF_Box *)gf_list_enum(stbl->child_boxes, &j))) {
3285 : gf_isom_box_del_parent(&stbl->child_boxes, a);
3286 : j--;
3287 : }
3288 : #endif
3289 : }
3290 :
3291 :
3292 17560 : j = 0;
3293 232792 : while ((a = (GF_Box *)gf_list_enum(movie->moov->child_boxes, &j))) {
3294 197672 : if (a->type == GF_ISOM_BOX_TYPE_PSSH) {
3295 29 : gf_isom_box_del_parent(&movie->moov->child_boxes, a);
3296 29 : j--;
3297 : }
3298 : }
3299 : }
3300 :
3301 2966 : gf_isom_datamap_del(movie->movieFileMap);
3302 2966 : movie->movieFileMap = NULL;
3303 : #endif
3304 2966 : return GF_OK;
3305 : }
3306 :
3307 : GF_EXPORT
3308 2966 : GF_Err gf_isom_open_segment(GF_ISOFile *movie, const char *fileName, u64 start_range, u64 end_range, GF_ISOSegOpenMode flags)
3309 : {
3310 : #ifdef GPAC_DISABLE_ISOM_FRAGMENTS
3311 : return GF_NOT_SUPPORTED;
3312 : #else
3313 : u64 MissingBytes;
3314 : GF_Err e;
3315 : u32 i;
3316 : Bool segment_map_assigned = GF_FALSE;
3317 2966 : Bool is_scalable_segment = (flags & GF_ISOM_SEGMENT_SCALABLE_FLAG) ? GF_TRUE : GF_FALSE;
3318 2966 : Bool no_order_check = (flags & GF_ISOM_SEGMENT_NO_ORDER_FLAG) ? GF_TRUE: GF_FALSE;
3319 2966 : GF_DataMap *tmp = NULL;
3320 : GF_DataMap *orig_file_map = NULL;
3321 2966 : if (!movie || !movie->moov || !movie->moov->mvex) return GF_BAD_PARAM;
3322 2966 : if (movie->openMode != GF_ISOM_OPEN_READ) return GF_BAD_PARAM;
3323 :
3324 : /*this is a scalable segment - use a temp data map for the associated track(s) but do NOT touch the movie file map*/
3325 2966 : if (is_scalable_segment) {
3326 : tmp = NULL;
3327 0 : e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_READ_ONLY, &tmp);
3328 0 : if (e) return e;
3329 :
3330 0 : orig_file_map = movie->movieFileMap;
3331 0 : movie->movieFileMap = tmp;
3332 : } else {
3333 2966 : if (movie->movieFileMap)
3334 5 : gf_isom_release_segment(movie, GF_FALSE);
3335 :
3336 2966 : e = gf_isom_datamap_new(fileName, NULL, GF_ISOM_DATA_MAP_READ_ONLY, &movie->movieFileMap);
3337 2966 : if (e) return e;
3338 : }
3339 2966 : movie->moov->compressed_diff = 0;
3340 2966 : movie->current_top_box_start = 0;
3341 :
3342 2966 : if (start_range || end_range) {
3343 281 : if (end_range > start_range) {
3344 281 : gf_bs_seek(movie->movieFileMap->bs, end_range+1);
3345 281 : gf_bs_truncate(movie->movieFileMap->bs);
3346 : }
3347 281 : gf_bs_seek(movie->movieFileMap->bs, start_range);
3348 281 : movie->current_top_box_start = start_range;
3349 : }
3350 :
3351 17560 : for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
3352 17560 : GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
3353 :
3354 17560 : if (!is_scalable_segment) {
3355 : /*reset data handler to new segment*/
3356 17560 : if (trak->Media->information->dataHandler == NULL) {
3357 17560 : trak->Media->information->dataHandler = movie->movieFileMap;
3358 : }
3359 : } else {
3360 0 : trak->present_in_scalable_segment = GF_FALSE;
3361 : }
3362 : }
3363 2966 : if (no_order_check) movie->NextMoofNumber = 0;
3364 :
3365 : //ok parse root boxes
3366 2966 : e = gf_isom_parse_movie_boxes(movie, NULL, &MissingBytes, GF_TRUE);
3367 :
3368 2966 : if (!is_scalable_segment)
3369 : return e;
3370 :
3371 0 : for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
3372 0 : GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
3373 0 : if (trak->present_in_scalable_segment) {
3374 : /*store the temp dataHandler into scalableDataHandler so that it will not be destroyed
3375 : if we append another representation - destruction of this data handler is done in release_segment*/
3376 0 : trak->Media->information->scalableDataHandler = tmp;
3377 0 : if (!segment_map_assigned) {
3378 0 : trak->Media->information->scalableDataHandler = tmp;
3379 : segment_map_assigned = GF_TRUE;
3380 : }
3381 : //and update the regular dataHandler for the Media_GetSample function
3382 0 : trak->Media->information->dataHandler = tmp;
3383 : }
3384 : }
3385 0 : movie->movieFileMap = orig_file_map;
3386 0 : return e;
3387 : #endif
3388 : }
3389 :
3390 : GF_EXPORT
3391 0 : GF_ISOTrackID gf_isom_get_highest_track_in_scalable_segment(GF_ISOFile *movie, u32 for_base_track)
3392 : {
3393 : #ifdef GPAC_DISABLE_ISOM_FRAGMENTS
3394 : return 0;
3395 : #else
3396 : s32 max_ref;
3397 : u32 i, j;
3398 : GF_ISOTrackID track_id;
3399 :
3400 : max_ref = 0;
3401 : track_id = 0;
3402 0 : for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
3403 : s32 ref;
3404 : u32 ref_type = GF_ISOM_REF_SCAL;
3405 0 : GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
3406 0 : if (! trak->present_in_scalable_segment) continue;
3407 :
3408 0 : ref = gf_isom_get_reference_count(movie, i+1, ref_type);
3409 0 : if (ref<=0) {
3410 : //handle implicit reconstruction for LHE1/LHV1, check sbas track ref
3411 0 : u32 subtype = gf_isom_get_media_subtype(movie, i+1, 1);
3412 0 : switch (subtype) {
3413 0 : case GF_ISOM_SUBTYPE_LHE1:
3414 : case GF_ISOM_SUBTYPE_LHV1:
3415 0 : ref = gf_isom_get_reference_count(movie, i+1, GF_ISOM_REF_BASE);
3416 0 : if (ref<=0) continue;
3417 : break;
3418 0 : default:
3419 0 : continue;
3420 : }
3421 0 : }
3422 0 : if (ref<=max_ref) continue;
3423 :
3424 0 : for (j=0; j< (u32) ref; j++) {
3425 0 : u32 on_track=0;
3426 0 : gf_isom_get_reference(movie, i+1, GF_ISOM_REF_BASE, j+1, &on_track);
3427 0 : if (on_track==for_base_track) {
3428 : max_ref = ref;
3429 0 : track_id = trak->Header->trackID;
3430 : }
3431 : }
3432 : }
3433 0 : return track_id;
3434 : #endif
3435 : }
3436 :
3437 :
3438 : GF_EXPORT
3439 37 : GF_Err gf_isom_text_set_streaming_mode(GF_ISOFile *movie, Bool do_convert)
3440 : {
3441 37 : if (!movie) return GF_BAD_PARAM;
3442 37 : movie->convert_streaming_text = do_convert;
3443 37 : return GF_OK;
3444 : }
3445 :
3446 :
3447 : GF_EXPORT
3448 33 : GF_GenericSampleDescription *gf_isom_get_generic_sample_description(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex)
3449 : {
3450 : GF_GenericVisualSampleEntryBox *entry;
3451 : GF_GenericAudioSampleEntryBox *gena;
3452 : GF_GenericSampleEntryBox *genm;
3453 : GF_TrackBox *trak;
3454 : GF_GenericSampleDescription *udesc;
3455 33 : trak = gf_isom_get_track_from_file(movie, trackNumber);
3456 33 : if (!trak || !StreamDescriptionIndex || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable) return 0;
3457 :
3458 33 : entry = (GF_GenericVisualSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, StreamDescriptionIndex-1);
3459 : //no entry or MPEG entry:
3460 33 : if (!entry || IsMP4Description(entry->type) ) return NULL;
3461 : //if we handle the description return false
3462 8 : switch (entry->type) {
3463 : case GF_ISOM_SUBTYPE_3GP_AMR:
3464 : case GF_ISOM_SUBTYPE_3GP_AMR_WB:
3465 : case GF_ISOM_SUBTYPE_3GP_EVRC:
3466 : case GF_ISOM_SUBTYPE_3GP_QCELP:
3467 : case GF_ISOM_SUBTYPE_3GP_SMV:
3468 : case GF_ISOM_SUBTYPE_3GP_H263:
3469 : return NULL;
3470 0 : case GF_ISOM_BOX_TYPE_GNRV:
3471 0 : GF_SAFEALLOC(udesc, GF_GenericSampleDescription);
3472 0 : if (!udesc) return NULL;
3473 0 : if (entry->EntryType == GF_ISOM_BOX_TYPE_UUID) {
3474 0 : memcpy(udesc->UUID, ((GF_UUIDBox*)entry)->uuid, sizeof(bin128));
3475 : } else {
3476 0 : udesc->codec_tag = entry->EntryType;
3477 : }
3478 0 : udesc->version = entry->version;
3479 0 : udesc->revision = entry->revision;
3480 0 : udesc->vendor_code = entry->vendor;
3481 0 : udesc->temporal_quality = entry->temporal_quality;
3482 0 : udesc->spatial_quality = entry->spatial_quality;
3483 0 : udesc->width = entry->Width;
3484 0 : udesc->height = entry->Height;
3485 0 : udesc->h_res = entry->horiz_res;
3486 0 : udesc->v_res = entry->vert_res;
3487 0 : strcpy(udesc->compressor_name, entry->compressor_name);
3488 0 : udesc->depth = entry->bit_depth;
3489 0 : udesc->color_table_index = entry->color_table_index;
3490 0 : if (entry->data_size) {
3491 0 : udesc->extension_buf_size = entry->data_size;
3492 0 : udesc->extension_buf = (char*)gf_malloc(sizeof(char) * entry->data_size);
3493 0 : if (!udesc->extension_buf) {
3494 0 : gf_free(udesc);
3495 0 : return NULL;
3496 : }
3497 0 : memcpy(udesc->extension_buf, entry->data, entry->data_size);
3498 : }
3499 : return udesc;
3500 0 : case GF_ISOM_BOX_TYPE_GNRA:
3501 : gena = (GF_GenericAudioSampleEntryBox *)entry;
3502 0 : GF_SAFEALLOC(udesc, GF_GenericSampleDescription);
3503 0 : if (!udesc) return NULL;
3504 0 : if (gena->EntryType == GF_ISOM_BOX_TYPE_UUID) {
3505 0 : memcpy(udesc->UUID, ((GF_UUIDBox*)gena)->uuid, sizeof(bin128));
3506 : } else {
3507 0 : udesc->codec_tag = gena->EntryType;
3508 : }
3509 0 : udesc->version = gena->version;
3510 0 : udesc->revision = gena->revision;
3511 0 : udesc->vendor_code = gena->vendor;
3512 0 : udesc->samplerate = gena->samplerate_hi;
3513 0 : udesc->bits_per_sample = gena->bitspersample;
3514 0 : udesc->nb_channels = gena->channel_count;
3515 0 : if (gena->data_size) {
3516 0 : udesc->extension_buf_size = gena->data_size;
3517 0 : udesc->extension_buf = (char*)gf_malloc(sizeof(char) * gena->data_size);
3518 0 : if (!udesc->extension_buf) {
3519 0 : gf_free(udesc);
3520 0 : return NULL;
3521 : }
3522 0 : memcpy(udesc->extension_buf, gena->data, gena->data_size);
3523 : }
3524 : return udesc;
3525 0 : case GF_ISOM_BOX_TYPE_GNRM:
3526 : genm = (GF_GenericSampleEntryBox *)entry;
3527 0 : GF_SAFEALLOC(udesc, GF_GenericSampleDescription);
3528 0 : if (!udesc) return NULL;
3529 0 : if (genm->EntryType == GF_ISOM_BOX_TYPE_UUID) {
3530 0 : memcpy(udesc->UUID, ((GF_UUIDBox*)genm)->uuid, sizeof(bin128));
3531 : } else {
3532 0 : udesc->codec_tag = genm->EntryType;
3533 : }
3534 0 : if (genm->data_size) {
3535 0 : udesc->extension_buf_size = genm->data_size;
3536 0 : udesc->extension_buf = (char*)gf_malloc(sizeof(char) * genm->data_size);
3537 0 : if (!udesc->extension_buf) {
3538 0 : gf_free(udesc);
3539 0 : return NULL;
3540 : }
3541 0 : memcpy(udesc->extension_buf, genm->data, genm->data_size);
3542 : }
3543 : return udesc;
3544 : }
3545 : return NULL;
3546 : }
3547 :
3548 : GF_EXPORT
3549 1738 : GF_Err gf_isom_get_visual_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 *Width, u32 *Height)
3550 : {
3551 : GF_TrackBox *trak;
3552 : GF_SampleEntryBox *entry;
3553 : GF_SampleDescriptionBox *stsd;
3554 :
3555 1738 : trak = gf_isom_get_track_from_file(movie, trackNumber);
3556 1738 : if (!trak) return GF_BAD_PARAM;
3557 :
3558 1738 : stsd = trak->Media->information->sampleTable->SampleDescription;
3559 1738 : if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
3560 1738 : if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) return movie->LastError = GF_BAD_PARAM;
3561 :
3562 1738 : entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
3563 : //no support for generic sample entries (eg, no MPEG4 descriptor)
3564 1738 : if (entry == NULL) return GF_BAD_PARAM;
3565 :
3566 : //valid for MPEG visual, JPG and 3GPP H263
3567 1738 : if (entry->internal_type == GF_ISOM_SAMPLE_ENTRY_VIDEO) {
3568 1350 : *Width = ((GF_VisualSampleEntryBox*)entry)->Width;
3569 1350 : *Height = ((GF_VisualSampleEntryBox*)entry)->Height;
3570 388 : } else if (trak->Media->handler->handlerType==GF_ISOM_MEDIA_SCENE) {
3571 21 : *Width = trak->Header->width>>16;
3572 21 : *Height = trak->Header->height>>16;
3573 : } else {
3574 : return GF_BAD_PARAM;
3575 : }
3576 : return GF_OK;
3577 : }
3578 :
3579 : GF_EXPORT
3580 110 : GF_Err gf_isom_get_visual_bit_depth(GF_ISOFile* movie, u32 trackNumber, u32 StreamDescriptionIndex, u16* bitDepth)
3581 : {
3582 : GF_TrackBox* trak;
3583 : GF_SampleEntryBox* entry;
3584 : GF_SampleDescriptionBox* stsd;
3585 :
3586 110 : trak = gf_isom_get_track_from_file(movie, trackNumber);
3587 110 : if (!trak) return GF_BAD_PARAM;
3588 :
3589 110 : stsd = trak->Media->information->sampleTable->SampleDescription;
3590 110 : if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
3591 110 : if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) return movie->LastError = GF_BAD_PARAM;
3592 :
3593 110 : entry = (GF_SampleEntryBox*)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
3594 :
3595 : //no support for generic sample entries (eg, no MPEG4 descriptor)
3596 110 : if (entry == NULL) return GF_BAD_PARAM;
3597 :
3598 : //valid for MPEG visual, JPG and 3GPP H263
3599 110 : if (entry->internal_type == GF_ISOM_SAMPLE_ENTRY_VIDEO) {
3600 110 : *bitDepth = ((GF_VisualSampleEntryBox*)entry)->bit_depth;
3601 : } else {
3602 : return GF_BAD_PARAM;
3603 : }
3604 110 : return GF_OK;
3605 : }
3606 :
3607 : GF_EXPORT
3608 1481 : GF_Err gf_isom_get_audio_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 *SampleRate, u32 *Channels, u32 *bitsPerSample)
3609 : {
3610 : GF_TrackBox *trak;
3611 : GF_AudioSampleEntryBox *entry;
3612 : GF_SampleDescriptionBox *stsd = NULL;
3613 :
3614 1481 : trak = gf_isom_get_track_from_file(movie, trackNumber);
3615 1481 : if (!trak) return GF_BAD_PARAM;
3616 :
3617 1481 : if (trak->Media && trak->Media->information && trak->Media->information->sampleTable && trak->Media->information->sampleTable->SampleDescription)
3618 : stsd = trak->Media->information->sampleTable->SampleDescription;
3619 0 : if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
3620 1481 : if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) return movie->LastError = GF_BAD_PARAM;
3621 :
3622 1481 : entry = (GF_AudioSampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
3623 : //no support for generic sample entries (eg, no MPEG4 descriptor)
3624 1481 : if (entry == NULL) return GF_BAD_PARAM;
3625 :
3626 1481 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO) return GF_BAD_PARAM;
3627 :
3628 409 : if (SampleRate) {
3629 408 : (*SampleRate) = entry->samplerate_hi;
3630 408 : if (entry->type==GF_ISOM_BOX_TYPE_MLPA) {
3631 2 : u32 sr = entry->samplerate_hi;
3632 2 : sr <<= 16;
3633 2 : sr |= entry->samplerate_lo;
3634 2 : (*SampleRate) = sr;
3635 : }
3636 : }
3637 409 : if (Channels) (*Channels) = entry->channel_count;
3638 409 : if (bitsPerSample) (*bitsPerSample) = (u8) entry->bitspersample;
3639 :
3640 : return GF_OK;
3641 : }
3642 :
3643 : GF_EXPORT
3644 2 : GF_Err gf_isom_get_audio_layout(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_AudioChannelLayout *layout)
3645 : {
3646 : GF_TrackBox *trak;
3647 : GF_SampleEntryBox *entry;
3648 : GF_SampleDescriptionBox *stsd;
3649 : GF_ChannelLayoutBox *chnl;
3650 :
3651 2 : trak = gf_isom_get_track_from_file(movie, trackNumber);
3652 2 : if (!trak || !layout) return GF_BAD_PARAM;
3653 : memset(layout, 0, sizeof(GF_AudioChannelLayout));
3654 :
3655 2 : stsd = trak->Media->information->sampleTable->SampleDescription;
3656 2 : if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
3657 2 : if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) return movie->LastError = GF_BAD_PARAM;
3658 :
3659 2 : entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
3660 : //no support for generic sample entries (eg, no MPEG4 descriptor)
3661 2 : if (entry == NULL) return GF_BAD_PARAM;
3662 :
3663 2 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO) return GF_BAD_PARAM;
3664 1 : chnl = (GF_ChannelLayoutBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_CHNL);
3665 1 : if (!chnl) return GF_NOT_FOUND;
3666 :
3667 0 : memcpy(layout, &chnl->layout, sizeof(GF_AudioChannelLayout));
3668 0 : return GF_OK;
3669 : }
3670 : GF_EXPORT
3671 970 : GF_Err gf_isom_get_pixel_aspect_ratio(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 *hSpacing, u32 *vSpacing)
3672 : {
3673 : GF_TrackBox *trak;
3674 : GF_VisualSampleEntryBox *entry;
3675 : GF_SampleDescriptionBox *stsd;
3676 :
3677 970 : trak = gf_isom_get_track_from_file(movie, trackNumber);
3678 970 : if (!trak || !hSpacing || !vSpacing) return GF_BAD_PARAM;
3679 970 : *hSpacing = 1;
3680 970 : *vSpacing = 1;
3681 :
3682 970 : stsd = trak->Media->information->sampleTable->SampleDescription;
3683 970 : if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
3684 970 : if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) return movie->LastError = GF_BAD_PARAM;
3685 :
3686 970 : entry = (GF_VisualSampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
3687 : //no support for generic sample entries (eg, no MPEG4 descriptor)
3688 970 : if (entry == NULL) return GF_OK;
3689 :
3690 : //valid for MPEG visual, JPG and 3GPP H263
3691 970 : if (entry->internal_type==GF_ISOM_SAMPLE_ENTRY_VIDEO) {
3692 952 : GF_PixelAspectRatioBox *pasp = (GF_PixelAspectRatioBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_PASP);
3693 952 : if (pasp) {
3694 35 : *hSpacing = pasp->hSpacing;
3695 35 : *vSpacing = pasp->vSpacing;
3696 : }
3697 : return GF_OK;
3698 : } else {
3699 : return GF_BAD_PARAM;
3700 : }
3701 : }
3702 :
3703 : GF_EXPORT
3704 4 : GF_Err gf_isom_get_color_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 *colour_type, u16 *colour_primaries, u16 *transfer_characteristics, u16 *matrix_coefficients, Bool *full_range_flag)
3705 : {
3706 : GF_TrackBox *trak;
3707 : GF_VisualSampleEntryBox *entry;
3708 : GF_SampleDescriptionBox *stsd;
3709 :
3710 4 : trak = gf_isom_get_track_from_file(movie, trackNumber);
3711 4 : if (!trak) return GF_BAD_PARAM;
3712 :
3713 4 : stsd = trak->Media->information->sampleTable->SampleDescription;
3714 4 : if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
3715 4 : if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) return movie->LastError = GF_BAD_PARAM;
3716 :
3717 4 : entry = (GF_VisualSampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
3718 : //no support for generic sample entries (eg, no MPEG4 descriptor)
3719 4 : if (entry == NULL) return GF_OK;
3720 :
3721 : //valid for MPEG visual, JPG and 3GPP H263
3722 4 : if (entry->internal_type!=GF_ISOM_SAMPLE_ENTRY_VIDEO) {
3723 : return GF_BAD_PARAM;
3724 : }
3725 4 : GF_ColourInformationBox *clr = (GF_ColourInformationBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_COLR);
3726 4 : if (!clr) return GF_NOT_FOUND;
3727 :
3728 3 : if (colour_type) *colour_type = clr->colour_type;
3729 3 : if (colour_primaries) *colour_primaries = clr->colour_primaries;
3730 3 : if (transfer_characteristics) *transfer_characteristics = clr->transfer_characteristics;
3731 3 : if (matrix_coefficients) *matrix_coefficients = clr->matrix_coefficients;
3732 3 : if (full_range_flag) *full_range_flag = clr->full_range_flag;
3733 : return GF_OK;
3734 : }
3735 :
3736 : GF_EXPORT
3737 1058 : const char *gf_isom_get_filename(GF_ISOFile *movie)
3738 : {
3739 1058 : if (!movie) return NULL;
3740 : #ifndef GPAC_DISABLE_ISOM_WRITE
3741 1058 : if (movie->finalName && !movie->fileName) return movie->finalName;
3742 : #endif
3743 953 : return movie->fileName;
3744 : }
3745 :
3746 :
3747 : GF_EXPORT
3748 3893 : u8 gf_isom_get_pl_indication(GF_ISOFile *movie, GF_ISOProfileLevelType PL_Code)
3749 : {
3750 : GF_IsomInitialObjectDescriptor *iod;
3751 3893 : if (!movie || !movie->moov) return 0xFF;
3752 2625 : if (!movie->moov->iods || !movie->moov->iods->descriptor) return 0xFF;
3753 931 : if (movie->moov->iods->descriptor->tag != GF_ODF_ISOM_IOD_TAG) return 0xFF;
3754 :
3755 : iod = (GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor;
3756 931 : switch (PL_Code) {
3757 552 : case GF_ISOM_PL_AUDIO:
3758 552 : return iod->audio_profileAndLevel;
3759 379 : case GF_ISOM_PL_VISUAL:
3760 379 : return iod->visual_profileAndLevel;
3761 0 : case GF_ISOM_PL_GRAPHICS:
3762 0 : return iod->graphics_profileAndLevel;
3763 0 : case GF_ISOM_PL_SCENE:
3764 0 : return iod->scene_profileAndLevel;
3765 0 : case GF_ISOM_PL_OD:
3766 0 : return iod->OD_profileAndLevel;
3767 0 : case GF_ISOM_PL_INLINE:
3768 0 : return iod->inlineProfileFlag;
3769 : case GF_ISOM_PL_MPEGJ:
3770 : default:
3771 : return 0xFF;
3772 : }
3773 : }
3774 :
3775 : GF_EXPORT
3776 22 : GF_Err gf_isom_get_track_matrix(GF_ISOFile *the_file, u32 trackNumber, u32 matrix[9])
3777 : {
3778 22 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
3779 22 : if (!trak || !trak->Header) return GF_BAD_PARAM;
3780 22 : memcpy(matrix, trak->Header->matrix, sizeof(trak->Header->matrix));
3781 22 : return GF_OK;
3782 : }
3783 :
3784 : GF_EXPORT
3785 1425 : 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)
3786 : {
3787 1425 : GF_TrackBox *tk = gf_isom_get_track_from_file(movie, trackNumber);
3788 1425 : if (!tk) return GF_BAD_PARAM;
3789 1425 : if (width) *width = tk->Header->width>>16;
3790 1425 : if (height) *height = tk->Header->height>>16;
3791 1425 : if (layer) *layer = tk->Header->layer;
3792 1425 : if (translation_x) *translation_x = tk->Header->matrix[6] >> 16;
3793 1425 : if (translation_y) *translation_y = tk->Header->matrix[7] >> 16;
3794 : return GF_OK;
3795 : }
3796 :
3797 :
3798 : /*returns total amount of media bytes in track*/
3799 : GF_EXPORT
3800 1227 : u64 gf_isom_get_media_data_size(GF_ISOFile *movie, u32 trackNumber)
3801 : {
3802 : u32 i;
3803 : u64 size;
3804 : GF_SampleSizeBox *stsz;
3805 1227 : GF_TrackBox *tk = gf_isom_get_track_from_file(movie, trackNumber);
3806 1227 : if (!tk) return 0;
3807 1227 : stsz = tk->Media->information->sampleTable->SampleSize;
3808 1227 : if (!stsz) return 0;
3809 1227 : if (stsz->sampleSize) return stsz->sampleSize*stsz->sampleCount;
3810 : size = 0;
3811 439710 : for (i=0; i<stsz->sampleCount; i++) size += stsz->sizes[i];
3812 : return size;
3813 : }
3814 :
3815 :
3816 : GF_EXPORT
3817 5 : void gf_isom_set_default_sync_track(GF_ISOFile *movie, u32 trackNumber)
3818 : {
3819 5 : GF_TrackBox *tk = gf_isom_get_track_from_file(movie, trackNumber);
3820 5 : if (!tk) movie->es_id_default_sync = -1;
3821 5 : else movie->es_id_default_sync = tk->Header->trackID;
3822 5 : }
3823 :
3824 :
3825 : GF_EXPORT
3826 56 : Bool gf_isom_is_single_av(GF_ISOFile *file)
3827 : {
3828 : u32 count, i, nb_any, nb_a, nb_v, nb_auxv, nb_pict, nb_scene, nb_od, nb_text;
3829 : nb_auxv = nb_pict = nb_a = nb_v = nb_any = nb_scene = nb_od = nb_text = 0;
3830 :
3831 56 : if (!file->moov) return GF_FALSE;
3832 56 : count = gf_isom_get_track_count(file);
3833 194 : for (i=0; i<count; i++) {
3834 82 : u32 mtype = gf_isom_get_media_type(file, i+1);
3835 82 : switch (mtype) {
3836 9 : case GF_ISOM_MEDIA_SCENE:
3837 9 : if (gf_isom_get_sample_count(file, i+1)>1) nb_any++;
3838 6 : else nb_scene++;
3839 : break;
3840 5 : case GF_ISOM_MEDIA_OD:
3841 5 : if (gf_isom_get_sample_count(file, i+1)>1) nb_any++;
3842 2 : else nb_od++;
3843 : break;
3844 7 : case GF_ISOM_MEDIA_TEXT:
3845 : case GF_ISOM_MEDIA_SUBT:
3846 7 : nb_text++;
3847 7 : break;
3848 29 : case GF_ISOM_MEDIA_AUDIO:
3849 29 : nb_a++;
3850 29 : break;
3851 0 : case GF_ISOM_MEDIA_AUXV:
3852 : /*discard file with images*/
3853 0 : if (gf_isom_get_sample_count(file, i+1)==1) nb_any++;
3854 0 : else nb_auxv++;
3855 : break;
3856 0 : case GF_ISOM_MEDIA_PICT:
3857 : /*discard file with images*/
3858 0 : if (gf_isom_get_sample_count(file, i+1)==1) nb_any++;
3859 0 : else nb_pict++;
3860 : break;
3861 32 : case GF_ISOM_MEDIA_VISUAL:
3862 : /*discard file with images*/
3863 32 : if (gf_isom_get_sample_count(file, i+1)==1) nb_any++;
3864 25 : else nb_v++;
3865 : break;
3866 0 : default:
3867 0 : nb_any++;
3868 0 : break;
3869 : }
3870 : }
3871 56 : if (nb_any) return GF_FALSE;
3872 53 : if ((nb_scene<=1) && (nb_od<=1) && (nb_a<=1) && (nb_v+nb_pict+nb_auxv<=1) && (nb_text<=1) ) return GF_TRUE;
3873 0 : return GF_FALSE;
3874 : }
3875 :
3876 : GF_EXPORT
3877 185 : Bool gf_isom_is_JPEG2000(GF_ISOFile *mov)
3878 : {
3879 185 : return (mov && mov->is_jp2) ? GF_TRUE : GF_FALSE;
3880 : }
3881 :
3882 : GF_EXPORT
3883 56 : u32 gf_isom_guess_specification(GF_ISOFile *file)
3884 : {
3885 : u32 count, i, nb_any, nb_m4s, nb_a, nb_v, nb_auxv,nb_scene, nb_od, nb_mp3, nb_aac, nb_m4v, nb_avc, nb_amr, nb_h263, nb_qcelp, nb_evrc, nb_smv, nb_text, nb_pict;
3886 :
3887 : nb_m4s = nb_a = nb_v = nb_auxv = 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 = nb_pict = 0;
3888 :
3889 56 : if (file->is_jp2) {
3890 0 : if (file->moov) return GF_ISOM_BRAND_MJP2;
3891 0 : return GF_ISOM_BRAND_JP2;
3892 : }
3893 56 : if (!file->moov) {
3894 0 : if (!file->meta || !file->meta->handler) return 0;
3895 0 : return file->meta->handler->handlerType;
3896 : }
3897 :
3898 56 : count = gf_isom_get_track_count(file);
3899 194 : for (i=0; i<count; i++) {
3900 82 : u32 mtype = gf_isom_get_media_type(file, i+1);
3901 82 : u32 mstype = gf_isom_get_media_subtype(file, i+1, 1);
3902 :
3903 82 : if (mtype==GF_ISOM_MEDIA_SCENE) {
3904 9 : nb_scene++;
3905 : /*forces non-isma*/
3906 9 : if (gf_isom_get_sample_count(file, i+1)>1) nb_m4s++;
3907 73 : } else if (mtype==GF_ISOM_MEDIA_OD) {
3908 5 : nb_od++;
3909 : /*forces non-isma*/
3910 5 : if (gf_isom_get_sample_count(file, i+1)>1) nb_m4s++;
3911 : }
3912 68 : else if ((mtype==GF_ISOM_MEDIA_TEXT) || (mtype==GF_ISOM_MEDIA_SUBT)) nb_text++;
3913 61 : else if ((mtype==GF_ISOM_MEDIA_AUDIO) || gf_isom_is_video_handler_type(mtype) ) {
3914 61 : switch (mstype) {
3915 2 : case GF_ISOM_SUBTYPE_3GP_AMR:
3916 : case GF_ISOM_SUBTYPE_3GP_AMR_WB:
3917 2 : nb_amr++;
3918 2 : break;
3919 1 : case GF_ISOM_SUBTYPE_3GP_H263:
3920 1 : nb_h263++;
3921 1 : break;
3922 1 : case GF_ISOM_SUBTYPE_3GP_EVRC:
3923 1 : nb_evrc++;
3924 1 : break;
3925 1 : case GF_ISOM_SUBTYPE_3GP_QCELP:
3926 1 : nb_qcelp++;
3927 1 : break;
3928 0 : case GF_ISOM_SUBTYPE_3GP_SMV:
3929 0 : nb_smv++;
3930 0 : break;
3931 11 : case GF_ISOM_SUBTYPE_AVC_H264:
3932 : case GF_ISOM_SUBTYPE_AVC2_H264:
3933 : case GF_ISOM_SUBTYPE_AVC3_H264:
3934 : case GF_ISOM_SUBTYPE_AVC4_H264:
3935 11 : nb_avc++;
3936 11 : break;
3937 0 : case GF_ISOM_SUBTYPE_SVC_H264:
3938 : case GF_ISOM_SUBTYPE_MVC_H264:
3939 0 : nb_avc++;
3940 0 : break;
3941 35 : case GF_ISOM_SUBTYPE_MPEG4:
3942 : case GF_ISOM_SUBTYPE_MPEG4_CRYP:
3943 : {
3944 35 : GF_DecoderConfig *dcd = gf_isom_get_decoder_config(file, i+1, 1);
3945 35 : if (!dcd) break;
3946 35 : switch (dcd->streamType) {
3947 19 : case GF_STREAM_VISUAL:
3948 19 : if (dcd->objectTypeIndication==GF_CODECID_MPEG4_PART2) nb_m4v++;
3949 14 : else if ((dcd->objectTypeIndication==GF_CODECID_AVC) || (dcd->objectTypeIndication==GF_CODECID_SVC) || (dcd->objectTypeIndication==GF_CODECID_MVC)) nb_avc++;
3950 13 : else nb_v++;
3951 : break;
3952 16 : case GF_STREAM_AUDIO:
3953 16 : switch (dcd->objectTypeIndication) {
3954 15 : case GF_CODECID_AAC_MPEG2_MP:
3955 : case GF_CODECID_AAC_MPEG2_LCP:
3956 : case GF_CODECID_AAC_MPEG2_SSRP:
3957 : case GF_CODECID_AAC_MPEG4:
3958 15 : nb_aac++;
3959 15 : break;
3960 0 : case GF_CODECID_MPEG2_PART3:
3961 : case GF_CODECID_MPEG_AUDIO:
3962 0 : nb_mp3++;
3963 0 : break;
3964 0 : case GF_CODECID_EVRC:
3965 0 : nb_evrc++;
3966 0 : break;
3967 0 : case GF_CODECID_SMV:
3968 0 : nb_smv++;
3969 0 : break;
3970 0 : case GF_CODECID_QCELP:
3971 0 : nb_qcelp++;
3972 0 : break;
3973 1 : default:
3974 1 : nb_a++;
3975 1 : break;
3976 : }
3977 : break;
3978 : /*SHOULD NEVER HAPPEN - IF SO, BROKEN MPEG4 FILE*/
3979 0 : default:
3980 0 : nb_any++;
3981 0 : break;
3982 : }
3983 35 : gf_odf_desc_del((GF_Descriptor *)dcd);
3984 : }
3985 35 : break;
3986 10 : default:
3987 10 : if (mtype==GF_ISOM_MEDIA_VISUAL) nb_v++;
3988 9 : else if (mtype==GF_ISOM_MEDIA_AUXV) nb_auxv++;
3989 9 : else if (mtype==GF_ISOM_MEDIA_PICT) nb_pict++;
3990 9 : else nb_a++;
3991 : break;
3992 : }
3993 0 : } else if ((mtype==GF_ISOM_SUBTYPE_MPEG4) || (mtype==GF_ISOM_SUBTYPE_MPEG4_CRYP)) nb_m4s++;
3994 0 : else nb_any++;
3995 : }
3996 56 : if (nb_any) return GF_ISOM_BRAND_ISOM;
3997 56 : if (nb_qcelp || nb_evrc || nb_smv) {
3998 : /*non std mix of streams*/
3999 2 : if (nb_m4s || nb_avc || nb_scene || nb_od || nb_mp3 || nb_a || nb_v) return GF_ISOM_BRAND_ISOM;
4000 2 : return GF_ISOM_BRAND_3G2A;
4001 : }
4002 : /*other a/v/s streams*/
4003 54 : if (nb_v || nb_a || nb_m4s) return GF_ISOM_BRAND_MP42;
4004 :
4005 36 : nb_v = nb_m4v + nb_avc + nb_h263;
4006 36 : nb_a = nb_mp3 + nb_aac + nb_amr;
4007 :
4008 : /*avc file: whatever has AVC and no systems*/
4009 36 : if (nb_avc) {
4010 12 : if (!nb_scene && !nb_od) return GF_ISOM_BRAND_AVC1;
4011 2 : return GF_ISOM_BRAND_MP42;
4012 : }
4013 : /*MP3: ISMA and MPEG4*/
4014 24 : if (nb_mp3) {
4015 0 : if (!nb_text && (nb_v<=1) && (nb_a<=1) && (nb_scene==1) && (nb_od==1))
4016 : return GF_ISOM_BRAND_ISMA;
4017 0 : return GF_ISOM_BRAND_MP42;
4018 : }
4019 : /*MP4*/
4020 24 : if (nb_scene || nb_od) {
4021 : /*issue with AMR and H263 which don't have MPEG mapping: non compliant file*/
4022 0 : if (nb_amr || nb_h263) return GF_ISOM_BRAND_ISOM;
4023 0 : return GF_ISOM_BRAND_MP42;
4024 : }
4025 : /*use ISMA (3GP fine too)*/
4026 24 : if (!nb_amr && !nb_h263 && !nb_text) {
4027 14 : if ((nb_v<=1) && (nb_a<=1)) return GF_ISOM_BRAND_ISMA;
4028 0 : return GF_ISOM_BRAND_MP42;
4029 : }
4030 :
4031 10 : if ((nb_v<=1) && (nb_a<=1) && (nb_text<=1)) return nb_text ? GF_ISOM_BRAND_3GP6 : GF_ISOM_BRAND_3GP5;
4032 : return GF_ISOM_BRAND_3GG6;
4033 : }
4034 :
4035 25 : GF_ItemListBox *gf_ismo_locate_box(GF_List *list, u32 boxType, bin128 UUID)
4036 : {
4037 : u32 i;
4038 : GF_Box *box;
4039 25 : i=0;
4040 75 : while ((box = (GF_Box *)gf_list_enum(list, &i))) {
4041 50 : if (box->type == boxType) {
4042 : GF_UUIDBox* box2 = (GF_UUIDBox* )box;
4043 25 : if (boxType != GF_ISOM_BOX_TYPE_UUID) return (GF_ItemListBox *)box;
4044 0 : if (!memcmp(box2->uuid, UUID, 16)) return (GF_ItemListBox *)box;
4045 : }
4046 : }
4047 : return NULL;
4048 : }
4049 :
4050 : /*Apple extensions*/
4051 :
4052 :
4053 : GF_EXPORT
4054 1133 : GF_Err gf_isom_apple_get_tag(GF_ISOFile *mov, GF_ISOiTunesTag tag, const u8 **data, u32 *data_len)
4055 : {
4056 : u32 i;
4057 : GF_ListItemBox *info;
4058 : GF_ItemListBox *ilst;
4059 : GF_MetaBox *meta;
4060 :
4061 1133 : *data = NULL;
4062 1133 : *data_len = 0;
4063 :
4064 1133 : meta = (GF_MetaBox *) gf_isom_get_meta_extensions(mov, GF_FALSE);
4065 1133 : if (!meta) return GF_URL_ERROR;
4066 :
4067 8 : ilst = gf_ismo_locate_box(meta->child_boxes, GF_ISOM_BOX_TYPE_ILST, NULL);
4068 8 : if (!ilst) return GF_URL_ERROR;
4069 :
4070 8 : if (tag==GF_ISOM_ITUNE_PROBE) return gf_list_count(ilst->child_boxes) ? GF_OK : GF_URL_ERROR;
4071 :
4072 7 : i=0;
4073 20 : while ( (info=(GF_ListItemBox*)gf_list_enum(ilst->child_boxes, &i))) {
4074 7 : if (info->type==tag) break;
4075 : /*special cases*/
4076 6 : if ((tag==GF_ISOM_ITUNE_GENRE) && (info->type==(u32) GF_ISOM_ITUNE_GENRE_USER)) break;
4077 : info = NULL;
4078 : }
4079 7 : if (!info || !info->data || !info->data->data) return GF_URL_ERROR;
4080 :
4081 1 : if ((tag == GF_ISOM_ITUNE_GENRE) && (info->data->flags == 0)) {
4082 0 : if (info->data->dataSize && (info->data->dataSize>2) && (info->data->dataSize < 5)) {
4083 0 : GF_BitStream* bs = gf_bs_new(info->data->data, info->data->dataSize, GF_BITSTREAM_READ);
4084 0 : *data_len = gf_bs_read_int(bs, info->data->dataSize * 8);
4085 0 : gf_bs_del(bs);
4086 0 : return GF_OK;
4087 : }
4088 : }
4089 : // if (info->data->flags != 0x1) return GF_URL_ERROR;
4090 1 : *data = info->data->data;
4091 1 : *data_len = info->data->dataSize;
4092 1 : if ((tag==GF_ISOM_ITUNE_COVER_ART) && (info->data->flags==14)) *data_len |= 0x80000000; //(1<<31);
4093 : return GF_OK;
4094 : }
4095 :
4096 : GF_EXPORT
4097 1147 : GF_Err gf_isom_apple_enum_tag(GF_ISOFile *mov, u32 idx, GF_ISOiTunesTag *out_tag, const u8 **data, u32 *data_len, u64 *out_int_val, u32 *out_int_val2, u32 *out_flags)
4098 : {
4099 : u32 i, child_index;
4100 : GF_ListItemBox *info;
4101 : GF_ItemListBox *ilst;
4102 : GF_MetaBox *meta;
4103 : GF_DataBox *dbox = NULL;
4104 : u32 itype, tag_val;
4105 : s32 tag_idx;
4106 1147 : *data = NULL;
4107 1147 : *data_len = 0;
4108 :
4109 1147 : meta = (GF_MetaBox *) gf_isom_get_meta_extensions(mov, GF_FALSE);
4110 1147 : if (!meta) return GF_URL_ERROR;
4111 :
4112 15 : ilst = gf_ismo_locate_box(meta->child_boxes, GF_ISOM_BOX_TYPE_ILST, NULL);
4113 15 : if (!ilst) return GF_URL_ERROR;
4114 :
4115 15 : child_index = i = 0;
4116 39 : while ( (info=(GF_ListItemBox*)gf_list_enum(ilst->child_boxes, &i))) {
4117 : GF_DataBox *data_box = NULL;
4118 17 : if (gf_itags_find_by_itag(info->type)<0) {
4119 0 : if (info->type==GF_ISOM_BOX_TYPE_UNKNOWN) {
4120 0 : data_box = (GF_DataBox *) gf_isom_box_find_child(info->child_boxes, GF_ISOM_BOX_TYPE_DATA);
4121 0 : if (!data_box) continue;
4122 0 : tag_val = ((GF_UnknownBox *)info)->original_4cc;
4123 : }
4124 : } else {
4125 17 : data_box = info->data;
4126 17 : tag_val = info->type;
4127 : }
4128 17 : if (child_index==idx) {
4129 : dbox = data_box;
4130 : break;
4131 : }
4132 9 : child_index++;
4133 : }
4134 15 : if (!dbox) return GF_URL_ERROR;
4135 :
4136 8 : *out_flags = dbox->flags;
4137 8 : *out_tag = tag_val;
4138 8 : if (!dbox->data) {
4139 0 : *data = NULL;
4140 0 : *data_len = 1;
4141 0 : return GF_OK;
4142 : }
4143 :
4144 8 : tag_idx = gf_itags_find_by_itag(info->type);
4145 8 : if (tag_idx<0) {
4146 0 : *data = dbox->data;
4147 0 : *data_len = dbox->dataSize;
4148 0 : return GF_OK;
4149 : }
4150 :
4151 8 : if ((tag_val == GF_ISOM_ITUNE_GENRE) && (dbox->flags == 0) && (dbox->dataSize>2)) {
4152 0 : u32 int_val = dbox->data[0];
4153 0 : int_val <<= 8;
4154 0 : int_val |= dbox->data[1];
4155 0 : *data = NULL;
4156 0 : *data_len = 0;
4157 0 : *out_int_val = int_val;
4158 0 : return GF_OK;
4159 : }
4160 :
4161 8 : itype = gf_itags_get_type((u32) tag_idx);
4162 8 : switch (itype) {
4163 0 : case GF_ITAG_BOOL:
4164 : case GF_ITAG_INT8:
4165 0 : if (dbox->dataSize) *out_int_val = dbox->data[0];
4166 : break;
4167 0 : case GF_ITAG_INT16:
4168 0 : if (dbox->dataSize>1) {
4169 0 : u16 v = dbox->data[0];
4170 0 : v<<=8;
4171 0 : v |= dbox->data[1];
4172 0 : *out_int_val = v;
4173 : }
4174 : break;
4175 0 : case GF_ITAG_INT32:
4176 0 : if (dbox->dataSize>3) {
4177 0 : u32 v = dbox->data[0];
4178 0 : v<<=8;
4179 0 : v |= dbox->data[1];
4180 0 : v<<=8;
4181 0 : v |= dbox->data[2];
4182 0 : v<<=8;
4183 0 : v |= dbox->data[3];
4184 0 : *out_int_val = v;
4185 : }
4186 : break;
4187 0 : case GF_ITAG_INT64:
4188 0 : if (dbox->dataSize>3) {
4189 0 : u64 v = dbox->data[0];
4190 0 : v<<=8;
4191 0 : v |= dbox->data[1];
4192 0 : v<<=8;
4193 0 : v |= dbox->data[2];
4194 0 : v<<=8;
4195 0 : v |= dbox->data[3];
4196 0 : v<<=8;
4197 0 : v |= dbox->data[4];
4198 0 : v<<=8;
4199 0 : v |= dbox->data[5];
4200 0 : v<<=8;
4201 0 : v |= dbox->data[6];
4202 0 : v<<=8;
4203 0 : v |= dbox->data[7];
4204 0 : *out_int_val = v;
4205 : }
4206 : break;
4207 0 : case GF_ITAG_FRAC6:
4208 : case GF_ITAG_FRAC8:
4209 0 : if (dbox->dataSize>3) {
4210 0 : u32 v = dbox->data[2];
4211 0 : v<<=8;
4212 0 : v |= dbox->data[3];
4213 0 : *out_int_val = v;
4214 0 : v = dbox->data[4];
4215 0 : v<<=8;
4216 0 : v |= dbox->data[5];
4217 0 : *out_int_val2 = v;
4218 : }
4219 : break;
4220 8 : default:
4221 8 : *data = dbox->data;
4222 8 : *data_len = dbox->dataSize;
4223 8 : break;
4224 : }
4225 : return GF_OK;
4226 : }
4227 :
4228 :
4229 : GF_EXPORT
4230 185 : GF_Err gf_isom_wma_enum_tag(GF_ISOFile *mov, u32 idx, char **out_tag, const u8 **data, u32 *data_len, u32 *version, u32 *data_type)
4231 : {
4232 : GF_XtraBox *xtra;
4233 : GF_XtraTag *tag;
4234 :
4235 185 : *out_tag = NULL;
4236 185 : *data = NULL;
4237 185 : *data_len = 0;
4238 185 : *version = 0;
4239 185 : *data_type = 0;
4240 :
4241 185 : xtra = (GF_XtraBox *) gf_isom_get_meta_extensions(mov, GF_TRUE);
4242 185 : if (!xtra) return GF_URL_ERROR;
4243 :
4244 0 : tag = gf_list_get(xtra->tags, idx);
4245 0 : if (!tag) return GF_NOT_FOUND;
4246 0 : *out_tag = tag->name;
4247 0 : *data_len = tag->prop_size;
4248 0 : *data = tag->prop_value;
4249 0 : *version = tag->flags;
4250 0 : *data_type = tag->prop_type;
4251 0 : return GF_OK;
4252 : }
4253 :
4254 :
4255 : GF_EXPORT
4256 219 : GF_Err gf_isom_get_track_switch_group_count(GF_ISOFile *movie, u32 trackNumber, u32 *alternateGroupID, u32 *nb_groups)
4257 : {
4258 : GF_UserDataMap *map;
4259 : GF_TrackBox *trak;
4260 :
4261 219 : trak = gf_isom_get_track_from_file(movie, trackNumber);
4262 219 : if (!trak || !trak->Header) return GF_BAD_PARAM;
4263 219 : *alternateGroupID = trak->Header->alternate_group;
4264 219 : *nb_groups = 0;
4265 219 : if (!trak->udta) return GF_OK;
4266 :
4267 14 : map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_TSEL, NULL);
4268 14 : if (!map) return GF_OK;
4269 0 : *nb_groups = gf_list_count(map->boxes);
4270 0 : return GF_OK;
4271 : }
4272 :
4273 : GF_EXPORT
4274 1 : const u32 *gf_isom_get_track_switch_parameter(GF_ISOFile *movie, u32 trackNumber, u32 group_index, u32 *switchGroupID, u32 *criteriaListSize)
4275 : {
4276 : GF_TrackBox *trak;
4277 : GF_UserDataMap *map;
4278 : GF_TrackSelectionBox *tsel;
4279 :
4280 1 : trak = gf_isom_get_track_from_file(movie, trackNumber);
4281 1 : if (!group_index || !trak || !trak->udta) return NULL;
4282 :
4283 0 : map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_TSEL, NULL);
4284 0 : if (!map) return NULL;
4285 0 : tsel = (GF_TrackSelectionBox*)gf_list_get(map->boxes, group_index-1);
4286 0 : if (!tsel) return NULL;
4287 :
4288 0 : *switchGroupID = tsel->switchGroup;
4289 0 : *criteriaListSize = tsel->attributeListCount;
4290 0 : return (const u32 *) tsel->attributeList;
4291 : }
4292 :
4293 : GF_EXPORT
4294 2 : u32 gf_isom_get_next_alternate_group_id(GF_ISOFile *movie)
4295 : {
4296 : u32 id = 0;
4297 : u32 i=0;
4298 :
4299 12 : while (i< gf_isom_get_track_count(movie) ) {
4300 8 : GF_TrackBox *trak = gf_isom_get_track_from_file(movie, i+1);
4301 8 : if (trak->Header->alternate_group > id)
4302 : id = trak->Header->alternate_group;
4303 : i++;
4304 : }
4305 2 : return id+1;
4306 : }
4307 :
4308 : GF_EXPORT
4309 396918 : u8 *gf_isom_sample_get_subsamples_buffer(GF_ISOFile *movie, u32 track, u32 sampleNumber, u32 *osize)
4310 : {
4311 : u8 *data;
4312 : u32 size;
4313 : u32 i, count;
4314 : GF_BitStream *bs = NULL;
4315 396918 : GF_TrackBox *trak = gf_isom_get_track_from_file(movie, track);
4316 396918 : if (!trak || !osize) return NULL;
4317 396846 : if (!trak->Media || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->sub_samples) return NULL;
4318 :
4319 768 : count = gf_list_count(trak->Media->information->sampleTable->sub_samples);
4320 1536 : for (i=0; i<count; i++) {
4321 : u32 j, sub_count, last_sample = 0;
4322 768 : GF_SubSampleInformationBox *sub_samples = gf_list_get(trak->Media->information->sampleTable->sub_samples, i);
4323 :
4324 768 : sub_count = gf_list_count(sub_samples->Samples);
4325 290716 : for (j=0; j<sub_count; j++) {
4326 290716 : GF_SubSampleInfoEntry *pSamp = (GF_SubSampleInfoEntry *) gf_list_get(sub_samples->Samples, j);
4327 290716 : if (last_sample + pSamp->sample_delta == sampleNumber) {
4328 768 : u32 scount = gf_list_count(pSamp->SubSamples);
4329 2305 : for (j=0; j<scount; j++) {
4330 1537 : GF_SubSampleEntry *sent = gf_list_get(pSamp->SubSamples, j);
4331 1537 : if (!bs) bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
4332 :
4333 1537 : gf_bs_write_u32(bs, sub_samples->flags);
4334 1537 : gf_bs_write_u32(bs, sent->subsample_size);
4335 1537 : gf_bs_write_u32(bs, sent->reserved);
4336 1537 : gf_bs_write_u8(bs, sent->subsample_priority);
4337 1537 : gf_bs_write_u8(bs, sent->discardable);
4338 : }
4339 : break;
4340 : }
4341 : last_sample += pSamp->sample_delta;
4342 : }
4343 : }
4344 768 : if (!bs) return NULL;
4345 768 : gf_bs_get_content(bs, &data, &size);
4346 768 : gf_bs_del(bs);
4347 768 : *osize = size;
4348 768 : return data;
4349 : }
4350 :
4351 : GF_EXPORT
4352 11 : u32 gf_isom_sample_has_subsamples(GF_ISOFile *movie, u32 track, u32 sampleNumber, u32 flags)
4353 : {
4354 11 : GF_TrackBox *trak = gf_isom_get_track_from_file(movie, track);
4355 11 : if (!trak) return GF_BAD_PARAM;
4356 11 : if (!trak->Media->information->sampleTable->sub_samples) return 0;
4357 2 : if (!sampleNumber) return 1;
4358 0 : return gf_isom_sample_get_subsample_entry(movie, track, sampleNumber, flags, NULL);
4359 : }
4360 :
4361 : GF_EXPORT
4362 1 : 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)
4363 : {
4364 : GF_SubSampleEntry *entry;
4365 : GF_SubSampleInfoEntry *sub_sample;
4366 1 : u32 count = gf_isom_sample_get_subsample_entry(movie, track, sampleNumber, flags, &sub_sample);
4367 1 : if (!size || !priority || !discardable) return GF_BAD_PARAM;
4368 :
4369 1 : if (!subSampleNumber || (subSampleNumber>count)) return GF_BAD_PARAM;
4370 0 : entry = (GF_SubSampleEntry*)gf_list_get(sub_sample->SubSamples, subSampleNumber-1);
4371 0 : *size = entry->subsample_size;
4372 0 : *priority = entry->subsample_priority;
4373 0 : *reserved = entry->reserved;
4374 0 : *discardable = entry->discardable ? GF_TRUE : GF_FALSE;
4375 0 : return GF_OK;
4376 : }
4377 :
4378 : GF_EXPORT
4379 1832 : GF_Err gf_isom_get_rvc_config(GF_ISOFile *movie, u32 track, u32 sampleDescriptionIndex, u16 *rvc_predefined, u8 **data, u32 *size, const char **mime)
4380 : {
4381 : GF_MPEGVisualSampleEntryBox *entry;
4382 : GF_TrackBox *trak;
4383 :
4384 1832 : if (!rvc_predefined || !data || !size) return GF_BAD_PARAM;
4385 1781 : *rvc_predefined = 0;
4386 :
4387 1781 : trak = gf_isom_get_track_from_file(movie, track);
4388 1781 : if (!trak) return GF_BAD_PARAM;
4389 :
4390 :
4391 1781 : entry = (GF_MPEGVisualSampleEntryBox *) gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDescriptionIndex-1);
4392 1781 : if (!entry ) return GF_BAD_PARAM;
4393 1781 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
4394 :
4395 1078 : GF_RVCConfigurationBox *rvcc = (GF_RVCConfigurationBox *)gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_RVCC);
4396 1078 : if (!rvcc) return GF_NOT_FOUND;
4397 :
4398 0 : *rvc_predefined = rvcc->predefined_rvc_config;
4399 0 : if (rvcc->rvc_meta_idx) {
4400 0 : if (!data || !size) return GF_OK;
4401 0 : return gf_isom_extract_meta_item_mem(movie, GF_FALSE, track, rvcc->rvc_meta_idx, data, size, NULL, mime, GF_FALSE);
4402 : }
4403 : return GF_OK;
4404 : }
4405 :
4406 : GF_EXPORT
4407 185 : Bool gf_isom_moov_first(GF_ISOFile *movie)
4408 : {
4409 : u32 i;
4410 371 : for (i=0; i<gf_list_count(movie->TopBoxes); i++) {
4411 371 : GF_Box *b = (GF_Box*)gf_list_get(movie->TopBoxes, i);
4412 371 : if (b->type == GF_ISOM_BOX_TYPE_MOOV) return GF_TRUE;
4413 186 : if (b->type == GF_ISOM_BOX_TYPE_MDAT) return GF_FALSE;
4414 : }
4415 : return GF_FALSE;
4416 : }
4417 :
4418 : GF_EXPORT
4419 2961 : void gf_isom_reset_fragment_info(GF_ISOFile *movie, Bool keep_sample_count)
4420 : {
4421 : u32 i;
4422 2961 : if (!movie) return;
4423 17555 : for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
4424 17555 : GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
4425 17555 : trak->Media->information->sampleTable->SampleSize->sampleCount = 0;
4426 : #ifdef GPAC_DISABLE_ISOM_FRAGMENTS
4427 : }
4428 : #else
4429 : //do not reset tfdt for LL-HLS case where parts do not contain a TFDT
4430 : //trak->dts_at_seg_start = 0;
4431 17555 : if (!keep_sample_count)
4432 0 : trak->sample_count_at_seg_start = 0;
4433 : }
4434 2961 : movie->NextMoofNumber = 0;
4435 : #endif
4436 : }
4437 :
4438 : GF_EXPORT
4439 1005 : void gf_isom_reset_seq_num(GF_ISOFile *movie)
4440 : {
4441 : #ifdef GPAC_DISABLE_ISOM_FRAGMENTS
4442 : movie->NextMoofNumber = 0;
4443 : #endif
4444 1005 : }
4445 :
4446 : GF_EXPORT
4447 1 : void gf_isom_reset_sample_count(GF_ISOFile *movie)
4448 : {
4449 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
4450 : u32 i;
4451 1 : if (!movie) return;
4452 0 : for (i=0; i<gf_list_count(movie->moov->trackList); i++) {
4453 0 : GF_TrackBox *trak = (GF_TrackBox*)gf_list_get(movie->moov->trackList, i);
4454 0 : trak->Media->information->sampleTable->SampleSize->sampleCount = 0;
4455 0 : trak->sample_count_at_seg_start = 0;
4456 : }
4457 0 : movie->NextMoofNumber = 0;
4458 : #endif
4459 : }
4460 :
4461 : GF_EXPORT
4462 0 : Bool gf_isom_has_cenc_sample_group(GF_ISOFile *the_file, u32 trackNumber)
4463 : {
4464 : GF_TrackBox *trak;
4465 : u32 i, count;
4466 :
4467 0 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
4468 0 : if (!trak) return GF_FALSE;
4469 0 : if (!trak->Media->information->sampleTable->sampleGroups) return GF_FALSE;
4470 :
4471 0 : count = gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription);
4472 0 : for (i=0; i<count; i++) {
4473 0 : GF_SampleGroupDescriptionBox *sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, i);
4474 0 : if (sgdesc->grouping_type==GF_ISOM_SAMPLE_GROUP_SEIG) {
4475 : return GF_TRUE;
4476 : }
4477 : }
4478 : return GF_FALSE;
4479 : }
4480 :
4481 : GF_EXPORT
4482 495099 : GF_Err gf_isom_get_sample_rap_roll_info(GF_ISOFile *the_file, u32 trackNumber, u32 sample_number, Bool *is_rap, GF_ISOSampleRollType *roll_type, s32 *roll_distance)
4483 : {
4484 : GF_TrackBox *trak;
4485 : u32 i, count;
4486 :
4487 495099 : if (is_rap) *is_rap = GF_FALSE;
4488 495099 : if (roll_type) *roll_type = 0;
4489 495099 : if (roll_distance) *roll_distance = 0;
4490 :
4491 495099 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
4492 495099 : if (!trak) return GF_BAD_PARAM;
4493 495099 : if (!trak->Media->information->sampleTable->sampleGroups) return GF_OK;
4494 :
4495 22111 : if (!sample_number) {
4496 0 : count = gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription);
4497 0 : for (i=0; i<count; i++) {
4498 0 : GF_SampleGroupDescriptionBox *sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, i);
4499 0 : switch (sgdesc->grouping_type) {
4500 0 : case GF_ISOM_SAMPLE_GROUP_RAP:
4501 : case GF_ISOM_SAMPLE_GROUP_SYNC:
4502 0 : if (is_rap) *is_rap = GF_TRUE;
4503 : break;
4504 0 : case GF_ISOM_SAMPLE_GROUP_ROLL:
4505 : case GF_ISOM_SAMPLE_GROUP_PROL:
4506 0 : if (roll_type)
4507 0 : *roll_type = (sgdesc->grouping_type==GF_ISOM_SAMPLE_GROUP_PROL) ? GF_ISOM_SAMPLE_PREROLL : GF_ISOM_SAMPLE_ROLL;
4508 0 : if (roll_distance) {
4509 : s32 max_roll = 0;
4510 : u32 j;
4511 0 : for (j=0; j<gf_list_count(sgdesc->group_descriptions); j++) {
4512 0 : GF_RollRecoveryEntry *roll_entry = (GF_RollRecoveryEntry*)gf_list_get(sgdesc->group_descriptions, j);
4513 0 : if (max_roll < roll_entry->roll_distance)
4514 : max_roll = roll_entry->roll_distance;
4515 : }
4516 0 : if (*roll_distance < max_roll) *roll_distance = max_roll;
4517 : }
4518 : break;
4519 : }
4520 : }
4521 : return GF_OK;
4522 : }
4523 :
4524 22111 : count = gf_list_count(trak->Media->information->sampleTable->sampleGroups);
4525 44222 : for (i=0; i<count; i++) {
4526 : GF_SampleGroupBox *sg;
4527 : u32 j, group_desc_index;
4528 : GF_SampleGroupDescriptionBox *sgdesc;
4529 : u32 first_sample_in_entry, last_sample_in_entry;
4530 : first_sample_in_entry = 1;
4531 : group_desc_index = 0;
4532 22111 : sg = (GF_SampleGroupBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroups, i);
4533 420607 : for (j=0; j<sg->entry_count; j++) {
4534 418149 : last_sample_in_entry = first_sample_in_entry + sg->sample_entries[j].sample_count - 1;
4535 418149 : if ((sample_number<first_sample_in_entry) || (sample_number>last_sample_in_entry)) {
4536 : first_sample_in_entry = last_sample_in_entry+1;
4537 398496 : continue;
4538 : }
4539 : /*we found our sample*/
4540 19653 : group_desc_index = sg->sample_entries[j].group_description_index;
4541 19653 : break;
4542 : }
4543 : /*no sampleGroup info associated*/
4544 22111 : if (!group_desc_index) continue;
4545 :
4546 : sgdesc = NULL;
4547 0 : for (j=0; j<gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription); j++) {
4548 8042 : sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, j);
4549 8042 : if (sgdesc->grouping_type==sg->grouping_type) break;
4550 : sgdesc = NULL;
4551 : }
4552 : /*no sampleGroup description found for this group (invalid file)*/
4553 8042 : if (!sgdesc) continue;
4554 :
4555 8042 : switch (sgdesc->grouping_type) {
4556 376 : case GF_ISOM_SAMPLE_GROUP_RAP:
4557 : case GF_ISOM_SAMPLE_GROUP_SYNC:
4558 376 : if (is_rap) *is_rap = GF_TRUE;
4559 : break;
4560 93 : case GF_ISOM_SAMPLE_GROUP_ROLL:
4561 : case GF_ISOM_SAMPLE_GROUP_PROL:
4562 93 : if (roll_type)
4563 93 : *roll_type = (sgdesc->grouping_type==GF_ISOM_SAMPLE_GROUP_PROL) ? GF_ISOM_SAMPLE_PREROLL : GF_ISOM_SAMPLE_ROLL;
4564 :
4565 93 : if (roll_distance) {
4566 93 : GF_RollRecoveryEntry *roll_entry = (GF_RollRecoveryEntry *) gf_list_get(sgdesc->group_descriptions, group_desc_index - 1);
4567 93 : if (roll_entry)
4568 93 : *roll_distance = roll_entry->roll_distance;
4569 : }
4570 : break;
4571 : }
4572 : }
4573 : return GF_OK;
4574 : }
4575 :
4576 150 : GF_DefaultSampleGroupDescriptionEntry * gf_isom_get_sample_group_info_entry(GF_ISOFile *the_file, GF_TrackBox *trak, u32 grouping_type, u32 sample_group_description_index, u32 *default_index, GF_SampleGroupDescriptionBox **out_sgdp)
4577 : {
4578 : u32 i, count;
4579 :
4580 150 : if (!trak || !sample_group_description_index) return NULL;
4581 150 : if (!trak->Media->information->sampleTable->sampleGroupsDescription) return NULL;
4582 :
4583 113 : count = gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription);
4584 123 : for (i=0; i<count; i++) {
4585 119 : GF_SampleGroupDescriptionBox *sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, i);
4586 119 : if (sgdesc->grouping_type != grouping_type) continue;
4587 :
4588 109 : if (sgdesc->default_description_index && !sample_group_description_index) sample_group_description_index = sgdesc->default_description_index;
4589 :
4590 109 : if (default_index) *default_index = sgdesc->default_description_index ;
4591 109 : if (out_sgdp) *out_sgdp = sgdesc;
4592 :
4593 109 : if (!sample_group_description_index) return NULL;
4594 109 : return (GF_DefaultSampleGroupDescriptionEntry*)gf_list_get(sgdesc->group_descriptions, sample_group_description_index-1);
4595 : }
4596 : return NULL;
4597 : }
4598 :
4599 : GF_EXPORT
4600 105 : Bool gf_isom_get_sample_group_info(GF_ISOFile *the_file, u32 trackNumber, u32 sample_description_index, u32 grouping_type, u32 *default_index, const u8 **data, u32 *size)
4601 : {
4602 : GF_DefaultSampleGroupDescriptionEntry *sg_entry;
4603 105 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
4604 :
4605 105 : if (default_index) *default_index = 0;
4606 105 : if (size) *size = 0;
4607 105 : if (data) *data = NULL;
4608 :
4609 105 : sg_entry = gf_isom_get_sample_group_info_entry(the_file, trak, grouping_type, sample_description_index, default_index, NULL);
4610 105 : if (!sg_entry) return GF_FALSE;
4611 :
4612 81 : switch (grouping_type) {
4613 : case GF_ISOM_SAMPLE_GROUP_RAP:
4614 : case GF_ISOM_SAMPLE_GROUP_SYNC:
4615 : case GF_ISOM_SAMPLE_GROUP_ROLL:
4616 : case GF_ISOM_SAMPLE_GROUP_SEIG:
4617 : case GF_ISOM_SAMPLE_GROUP_OINF:
4618 : case GF_ISOM_SAMPLE_GROUP_LINF:
4619 : return GF_TRUE;
4620 81 : default:
4621 81 : if (sg_entry && data) *data = (char *) sg_entry->data;
4622 81 : if (sg_entry && size) *size = sg_entry->length;
4623 : return GF_TRUE;
4624 : }
4625 : return GF_FALSE;
4626 : }
4627 :
4628 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
4629 : //return the duration of the movie+fragments if known, 0 if error
4630 : GF_EXPORT
4631 1 : u64 gf_isom_get_fragmented_duration(GF_ISOFile *movie)
4632 : {
4633 1 : if (movie->moov->mvex && movie->moov->mvex->mehd)
4634 1 : return movie->moov->mvex->mehd->fragment_duration;
4635 :
4636 : return 0;
4637 : }
4638 : //return the duration of the movie+fragments if known, 0 if error
4639 : GF_EXPORT
4640 2 : u32 gf_isom_get_fragments_count(GF_ISOFile *movie, Bool segments_only)
4641 : {
4642 2 : u32 i=0;
4643 : u32 nb_frags = 0;
4644 : GF_Box *b;
4645 24 : while ((b=(GF_Box*)gf_list_enum(movie->TopBoxes, &i))) {
4646 20 : if (segments_only) {
4647 10 : if (b->type==GF_ISOM_BOX_TYPE_SIDX)
4648 0 : nb_frags++;
4649 : } else {
4650 10 : if (b->type==GF_ISOM_BOX_TYPE_MOOF)
4651 3 : nb_frags++;
4652 : }
4653 : }
4654 2 : return nb_frags;
4655 : }
4656 :
4657 : GF_EXPORT
4658 3 : GF_Err gf_isom_get_fragmented_samples_info(GF_ISOFile *movie, GF_ISOTrackID trackID, u32 *nb_samples, u64 *duration)
4659 : {
4660 3 : u32 i=0;
4661 : u32 k, l;
4662 : GF_MovieFragmentBox *moof;
4663 : GF_TrackFragmentBox *traf;
4664 :
4665 3 : *nb_samples = 0;
4666 3 : *duration = 0;
4667 36 : while ((moof=(GF_MovieFragmentBox*)gf_list_enum(movie->TopBoxes, &i))) {
4668 30 : u32 j=0;
4669 30 : if (moof->type!=GF_ISOM_BOX_TYPE_MOOF) continue;
4670 :
4671 18 : while ((traf=(GF_TrackFragmentBox*)gf_list_enum( moof->TrackList, &j))) {
4672 : u64 def_duration, samp_dur=0;
4673 :
4674 9 : if (traf->tfhd->trackID != trackID)
4675 6 : continue;
4676 :
4677 : def_duration = 0;
4678 3 : if (traf->tfhd->flags & GF_ISOM_TRAF_SAMPLE_DUR) def_duration = traf->tfhd->def_sample_duration;
4679 3 : else if (traf->trex) def_duration = traf->trex->def_sample_duration;
4680 :
4681 6 : for (k=0; k<gf_list_count(traf->TrackRuns); k++) {
4682 3 : GF_TrackFragmentRunBox *trun = (GF_TrackFragmentRunBox*)gf_list_get(traf->TrackRuns, k);
4683 3 : *nb_samples += trun->sample_count;
4684 :
4685 6 : for (l=0; l<trun->nb_samples; l++) {
4686 3 : GF_TrunEntry *ent = &trun->samples[l];
4687 :
4688 : samp_dur = def_duration;
4689 3 : if (trun->flags & GF_ISOM_TRUN_DURATION) samp_dur = ent->Duration;
4690 3 : if (trun->nb_samples == trun->sample_count)
4691 3 : *duration += samp_dur;
4692 : }
4693 3 : if (trun->nb_samples != trun->sample_count)
4694 0 : *duration += samp_dur * trun->sample_count;
4695 : }
4696 : }
4697 : }
4698 3 : return GF_OK;
4699 : }
4700 : #endif
4701 :
4702 : GF_EXPORT
4703 1486 : GF_Err gf_isom_set_nalu_extract_mode(GF_ISOFile *the_file, u32 trackNumber, GF_ISONaluExtractMode nalu_extract_mode)
4704 : {
4705 : GF_TrackReferenceTypeBox *dpnd;
4706 1486 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
4707 1486 : if (!trak) return GF_BAD_PARAM;
4708 1440 : trak->extractor_mode = nalu_extract_mode;
4709 :
4710 1440 : if (!trak->References) return GF_OK;
4711 :
4712 : /*get base*/
4713 176 : dpnd = NULL;
4714 176 : trak->has_base_layer = GF_FALSE;
4715 176 : Track_FindRef(trak, GF_ISOM_REF_SCAL, &dpnd);
4716 176 : if (dpnd) trak->has_base_layer = GF_TRUE;
4717 : return GF_OK;
4718 : }
4719 :
4720 : GF_EXPORT
4721 79 : GF_ISONaluExtractMode gf_isom_get_nalu_extract_mode(GF_ISOFile *the_file, u32 trackNumber)
4722 : {
4723 79 : GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
4724 79 : if (!trak) return 0;
4725 79 : return trak->extractor_mode;
4726 : }
4727 :
4728 : GF_EXPORT
4729 219 : s32 gf_isom_get_composition_offset_shift(GF_ISOFile *file, u32 track)
4730 : {
4731 219 : GF_TrackBox *trak = gf_isom_get_track_from_file(file, track);
4732 219 : if (!trak) return 0;
4733 219 : if (!trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->CompositionToDecode) return 0;
4734 0 : return trak->Media->information->sampleTable->CompositionToDecode->compositionToDTSShift;
4735 : }
4736 :
4737 : GF_EXPORT
4738 2966 : Bool gf_isom_needs_layer_reconstruction(GF_ISOFile *file)
4739 : {
4740 : u32 count, i;
4741 2966 : if (!file)
4742 : return GF_FALSE;
4743 2966 : count = gf_isom_get_track_count(file);
4744 7381 : for (i = 0; i < count; i++) {
4745 3087 : if (gf_isom_get_reference_count(file, i+1, GF_ISOM_REF_SCAL) > 0) {
4746 : return GF_TRUE;
4747 : }
4748 3056 : if (gf_isom_get_reference_count(file, i+1, GF_ISOM_REF_SABT) > 0) {
4749 : return GF_TRUE;
4750 : }
4751 1449 : switch (gf_isom_get_media_subtype(file, i+1, 1)) {
4752 0 : case GF_ISOM_SUBTYPE_LHV1:
4753 : case GF_ISOM_SUBTYPE_LHE1:
4754 : case GF_ISOM_SUBTYPE_HVC2:
4755 : case GF_ISOM_SUBTYPE_HEV2:
4756 0 : if (gf_isom_get_reference_count(file, i+1, GF_ISOM_REF_BASE) > 0) {
4757 : return GF_TRUE;
4758 : }
4759 : }
4760 : }
4761 : return GF_FALSE;
4762 : }
4763 :
4764 : GF_EXPORT
4765 1 : void gf_isom_keep_utc_times(GF_ISOFile *file, Bool keep_utc)
4766 : {
4767 1 : if (!file) return;
4768 1 : file->keep_utc = keep_utc;
4769 : }
4770 :
4771 : GF_EXPORT
4772 259 : Bool gf_isom_has_keep_utc_times(GF_ISOFile *file)
4773 : {
4774 259 : if (!file) return GF_FALSE;
4775 259 : return file->keep_utc;
4776 : }
4777 :
4778 :
4779 :
4780 : GF_EXPORT
4781 219 : u32 gf_isom_get_pssh_count(GF_ISOFile *file)
4782 : {
4783 : u32 count=0;
4784 219 : u32 i=0;
4785 : GF_Box *a_box;
4786 219 : if (file->moov) {
4787 999 : while ((a_box = (GF_Box*)gf_list_enum(file->moov->child_boxes, &i))) {
4788 793 : if (a_box->type != GF_ISOM_BOX_TYPE_PSSH) continue;
4789 276 : count++;
4790 : }
4791 : }
4792 219 : if (file->meta) {
4793 109 : while ((a_box = (GF_Box*)gf_list_enum(file->meta->child_boxes, &i))) {
4794 96 : if (a_box->type != GF_ISOM_BOX_TYPE_PSSH) continue;
4795 18 : count++;
4796 : }
4797 : }
4798 219 : return count;
4799 : }
4800 :
4801 : #if 0 //unused
4802 : /*! gets serialized PSS
4803 : \param isom_file the target ISO file
4804 : \param pssh_index 1-based index of PSSH to query, see \ref gf_isom_get_pssh_count
4805 : \param pssh_data set to a newly allocated buffer containing serialized PSSH - shall be freeed by caller
4806 : \param pssh_size set to the size of the allocated buffer
4807 : \return error if any
4808 : */
4809 : GF_Err gf_isom_get_pssh(GF_ISOFile *file, u32 pssh_index, u8 **pssh_data, u32 *pssh_size)
4810 : {
4811 : GF_Err e;
4812 : u32 i=0;
4813 : GF_BitStream *bs;
4814 : u32 count=1;
4815 : GF_Box *pssh;
4816 : while ((pssh = (GF_Box *)gf_list_enum(file->moov->child_boxes, &i))) {
4817 : if (pssh->type != GF_ISOM_BOX_TYPE_PSSH) continue;
4818 : if (count == pssh_index) break;
4819 : count++;
4820 : }
4821 : if (!pssh) return GF_BAD_PARAM;
4822 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
4823 : e = gf_isom_box_write(pssh, bs);
4824 : if (!e) {
4825 : gf_bs_get_content(bs, pssh_data, pssh_size);
4826 : }
4827 : gf_bs_del(bs);
4828 : return e;
4829 : }
4830 : #endif
4831 :
4832 : GF_EXPORT
4833 294 : GF_Err gf_isom_get_pssh_info(GF_ISOFile *file, u32 pssh_index, bin128 SystemID, u32 *version, u32 *KID_count, const bin128 **KIDs, const u8 **private_data, u32 *private_data_size)
4834 : {
4835 : u32 count=1;
4836 294 : u32 i=0;
4837 : GF_ProtectionSystemHeaderBox *pssh=NULL;
4838 294 : if (file->moov) {
4839 1039 : while ((pssh = (GF_ProtectionSystemHeaderBox *)gf_list_enum(file->moov->child_boxes, &i))) {
4840 1039 : if (pssh->type != GF_ISOM_BOX_TYPE_PSSH) continue;
4841 348 : if (count == pssh_index) break;
4842 72 : count++;
4843 : }
4844 : }
4845 276 : if (!pssh && file->meta) {
4846 131 : while ((pssh = (GF_ProtectionSystemHeaderBox *)gf_list_enum(file->meta->child_boxes, &i))) {
4847 131 : if (pssh->type != GF_ISOM_BOX_TYPE_PSSH) continue;
4848 23 : if (count == pssh_index) break;
4849 5 : count++;
4850 : }
4851 : }
4852 294 : if (!pssh) return GF_BAD_PARAM;
4853 :
4854 294 : if (SystemID) memcpy(SystemID, pssh->SystemID, 16);
4855 294 : if (version) *version = pssh->version;
4856 294 : if (KID_count) *KID_count = pssh->KID_count;
4857 294 : if (KIDs) *KIDs = (const bin128 *) pssh->KIDs;
4858 294 : if (private_data_size) *private_data_size = pssh->private_data_size;
4859 294 : if (private_data) *private_data = pssh->private_data;
4860 : return GF_OK;
4861 : }
4862 :
4863 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
4864 57565 : GF_Err gf_isom_get_sample_cenc_info_internal(GF_TrackBox *trak, GF_TrackFragmentBox *traf, GF_SampleEncryptionBox *senc, u32 sample_number, Bool *IsEncrypted, u8 *crypt_byte_block, u8 *skip_byte_block, const u8 **key_info, u32 *key_info_size)
4865 : #else
4866 : GF_Err gf_isom_get_sample_cenc_info_internal(GF_TrackBox *trak, void *traf, GF_SampleEncryptionBox *senc, u32 sample_number, Bool *IsEncrypted, u8 *crypt_byte_block, u8 *skip_byte_block, const u8 **key_info, u32 *key_info_size)
4867 : #endif
4868 : {
4869 : GF_SampleGroupBox *sample_group;
4870 : u32 j, group_desc_index;
4871 : GF_SampleGroupDescriptionBox *sgdesc;
4872 : u32 i, count;
4873 : u32 descIndex, chunkNum;
4874 : u64 offset;
4875 : u32 first_sample_in_entry, last_sample_in_entry;
4876 : GF_CENCSampleEncryptionGroupEntry *entry;
4877 :
4878 57565 : if (IsEncrypted) *IsEncrypted = GF_FALSE;
4879 57565 : if (crypt_byte_block) *crypt_byte_block = 0;
4880 57565 : if (skip_byte_block) *skip_byte_block = 0;
4881 57565 : if (key_info) *key_info = NULL;
4882 57565 : if (key_info_size) *key_info_size = 0;
4883 :
4884 57565 : if (!trak) return GF_BAD_PARAM;
4885 :
4886 : #ifdef GPAC_DISABLE_ISOM_FRAGMENTS
4887 : if (traf)
4888 : return GF_NOT_SUPPORTED;
4889 : #else
4890 57565 : sample_number -= trak->sample_count_at_seg_start;
4891 : #endif
4892 :
4893 57565 : if (trak->Media->information->sampleTable->SampleSize && trak->Media->information->sampleTable->SampleSize->sampleCount>=sample_number) {
4894 55746 : stbl_GetSampleInfos(trak->Media->information->sampleTable, sample_number, &offset, &chunkNum, &descIndex, NULL);
4895 : } else {
4896 : //this is dump mode of fragments, we haven't merged tables yet - use current stsd idx indicated in trak
4897 1819 : descIndex = trak->current_traf_stsd_idx;
4898 1819 : if (!descIndex) descIndex = 1;
4899 : }
4900 :
4901 57565 : gf_isom_cenc_get_default_info_internal(trak, descIndex, NULL, IsEncrypted, crypt_byte_block, skip_byte_block, key_info, key_info_size);
4902 :
4903 : sample_group = NULL;
4904 : group_desc_index = 0;
4905 57565 : if (trak->Media->information->sampleTable->sampleGroups) {
4906 12054 : count = gf_list_count(trak->Media->information->sampleTable->sampleGroups);
4907 12065 : for (i=0; i<count; i++) {
4908 12054 : sample_group = (GF_SampleGroupBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroups, i);
4909 12054 : if (sample_group->grouping_type == GF_ISOM_SAMPLE_GROUP_SEIG)
4910 : break;
4911 : sample_group = NULL;
4912 : }
4913 12054 : if (sample_group) {
4914 : first_sample_in_entry = 1;
4915 233663 : for (j=0; j<sample_group->entry_count; j++) {
4916 122128 : last_sample_in_entry = first_sample_in_entry + sample_group->sample_entries[j].sample_count - 1;
4917 122128 : if ((sample_number<first_sample_in_entry) || (sample_number>last_sample_in_entry)) {
4918 : first_sample_in_entry = last_sample_in_entry+1;
4919 110810 : continue;
4920 : }
4921 : /*we found our sample*/
4922 11318 : group_desc_index = sample_group->sample_entries[j].group_description_index;
4923 11318 : break;
4924 : }
4925 : }
4926 : }
4927 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
4928 57565 : if (!group_desc_index && traf && traf->sampleGroups) {
4929 726 : count = gf_list_count(traf->sampleGroups);
4930 726 : for (i=0; i<count; i++) {
4931 : group_desc_index = 0;
4932 726 : sample_group = (GF_SampleGroupBox*)gf_list_get(traf->sampleGroups, i);
4933 726 : if (sample_group->grouping_type == GF_ISOM_SAMPLE_GROUP_SEIG)
4934 : break;
4935 : sample_group = NULL;
4936 : }
4937 726 : if (sample_group) {
4938 : first_sample_in_entry = 1;
4939 3626 : for (j=0; j<sample_group->entry_count; j++) {
4940 1451 : last_sample_in_entry = first_sample_in_entry + sample_group->sample_entries[j].sample_count - 1;
4941 1451 : if ((sample_number<first_sample_in_entry) || (sample_number>last_sample_in_entry)) {
4942 : first_sample_in_entry = last_sample_in_entry+1;
4943 1450 : continue;
4944 : }
4945 : /*we found our sample*/
4946 1 : group_desc_index = sample_group->sample_entries[j].group_description_index;
4947 1 : break;
4948 : }
4949 : }
4950 : }
4951 : #endif
4952 : /*no sampleGroup info associated*/
4953 57565 : if (!group_desc_index) goto exit;
4954 :
4955 : sgdesc = NULL;
4956 :
4957 10215 : if (group_desc_index<=0x10000) {
4958 0 : for (j=0; j<gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription); j++) {
4959 10215 : sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, j);
4960 10215 : if (sgdesc->grouping_type==sample_group->grouping_type) break;
4961 : sgdesc = NULL;
4962 : }
4963 : }
4964 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
4965 0 : else if (traf) {
4966 0 : group_desc_index -= 0x10000;
4967 0 : for (j=0; j<gf_list_count(traf->sampleGroupsDescription); j++) {
4968 0 : sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(traf->sampleGroupsDescription, j);
4969 0 : if (sgdesc->grouping_type==sample_group->grouping_type) break;
4970 : sgdesc = NULL;
4971 : }
4972 : }
4973 : #endif
4974 : /*no sampleGroup description found for this group (invalid file)*/
4975 10215 : if (!sgdesc) return GF_ISOM_INVALID_FILE;
4976 :
4977 10215 : entry = (GF_CENCSampleEncryptionGroupEntry *) gf_list_get(sgdesc->group_descriptions, group_desc_index - 1);
4978 10215 : if (!entry) return GF_ISOM_INVALID_FILE;
4979 :
4980 10215 : if (IsEncrypted) *IsEncrypted = entry->IsProtected;
4981 10215 : if (crypt_byte_block) *crypt_byte_block = entry->crypt_byte_block;
4982 10215 : if (skip_byte_block) *skip_byte_block = entry->skip_byte_block;
4983 :
4984 10215 : if (key_info) *key_info = entry->key_info;
4985 20430 : if (key_info_size) *key_info_size = entry->key_info_size;
4986 :
4987 104915 : exit:
4988 : //in PIFF we may have default values if no TENC is present: 8 bytes for IV size
4989 57565 : if (( (senc && senc->piff_type==1) || (trak->moov && trak->moov->mov->is_smooth) ) && key_info && ! (*key_info) ) {
4990 288 : if (!senc) {
4991 0 : if (IsEncrypted) *IsEncrypted = GF_TRUE;
4992 0 : if (key_info_size) *key_info_size = 8;
4993 : } else {
4994 288 : if (!senc->piff_type) {
4995 3 : senc->piff_type = 2;
4996 3 : senc->IV_size = 8;
4997 : }
4998 : assert(senc->IV_size);
4999 288 : if (IsEncrypted) *IsEncrypted = GF_TRUE;
5000 288 : if (key_info_size) *key_info_size = senc->IV_size;
5001 : }
5002 : }
5003 :
5004 : return GF_OK;
5005 : }
5006 :
5007 : GF_EXPORT
5008 38954 : GF_Err gf_isom_get_sample_cenc_info(GF_ISOFile *movie, u32 track, u32 sample_number, Bool *IsEncrypted, u8 *crypt_byte_block, u8 *skip_byte_block, const u8 **key_info, u32 *key_info_size)
5009 : {
5010 38954 : GF_TrackBox *trak = gf_isom_get_track_from_file(movie, track);
5011 38954 : GF_SampleEncryptionBox *senc = trak->sample_encryption;
5012 :
5013 38954 : return gf_isom_get_sample_cenc_info_internal(trak, NULL, senc, sample_number, IsEncrypted, crypt_byte_block, skip_byte_block, key_info, key_info_size);
5014 : }
5015 :
5016 :
5017 : GF_EXPORT
5018 269 : Bool gf_isom_get_last_producer_time_box(GF_ISOFile *file, GF_ISOTrackID *refTrackID, u64 *ntp, u64 *timestamp, Bool reset_info)
5019 : {
5020 269 : if (!file) return GF_FALSE;
5021 269 : if (refTrackID) *refTrackID = 0;
5022 269 : if (ntp) *ntp = 0;
5023 269 : if (timestamp) *timestamp = 0;
5024 :
5025 269 : if (file->last_producer_ref_time) {
5026 0 : if (refTrackID) *refTrackID = file->last_producer_ref_time->refTrackID;
5027 0 : if (ntp) *ntp = file->last_producer_ref_time->ntp;
5028 0 : if (timestamp) *timestamp = file->last_producer_ref_time->timestamp;
5029 :
5030 0 : if (reset_info) {
5031 0 : file->last_producer_ref_time = NULL;
5032 : }
5033 : return GF_TRUE;
5034 : }
5035 : return GF_FALSE;
5036 : }
5037 :
5038 : GF_EXPORT
5039 0 : u64 gf_isom_get_current_tfdt(GF_ISOFile *the_file, u32 trackNumber)
5040 : {
5041 : #ifdef GPAC_DISABLE_ISOM_FRAGMENTS
5042 : return 0;
5043 : #else
5044 : GF_TrackBox *trak;
5045 0 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
5046 0 : if (!trak) return 0;
5047 0 : return trak->dts_at_seg_start;
5048 : #endif
5049 : }
5050 :
5051 : GF_EXPORT
5052 52 : u64 gf_isom_get_smooth_next_tfdt(GF_ISOFile *the_file, u32 trackNumber)
5053 : {
5054 : #ifdef GPAC_DISABLE_ISOM_FRAGMENTS
5055 : return 0;
5056 : #else
5057 : GF_TrackBox *trak;
5058 52 : trak = gf_isom_get_track_from_file(the_file, trackNumber);
5059 52 : if (!trak) return 0;
5060 52 : return trak->dts_at_next_seg_start;
5061 : #endif
5062 : }
5063 :
5064 : GF_EXPORT
5065 52 : Bool gf_isom_is_smooth_streaming_moov(GF_ISOFile *the_file)
5066 : {
5067 52 : return the_file ? the_file->is_smooth : GF_FALSE;
5068 : }
5069 :
5070 :
5071 81 : void gf_isom_parse_trif_info(const u8 *data, u32 size, u32 *id, u32 *independent, Bool *full_picture, u32 *x, u32 *y, u32 *w, u32 *h)
5072 : {
5073 : GF_BitStream *bs;
5074 81 : bs = gf_bs_new(data, size, GF_BITSTREAM_READ);
5075 81 : *id = gf_bs_read_u16(bs);
5076 81 : if (! gf_bs_read_int(bs, 1)) {
5077 0 : *independent=0;
5078 0 : *full_picture=0;
5079 0 : *x = *y = *w = *h = 0;
5080 : } else {
5081 81 : *independent = gf_bs_read_int(bs, 2);
5082 81 : *full_picture = (Bool)gf_bs_read_int(bs, 1);
5083 81 : /*filter_disabled*/ gf_bs_read_int(bs, 1);
5084 81 : /*has_dependency_list*/ gf_bs_read_int(bs, 1);
5085 81 : gf_bs_read_int(bs, 2);
5086 81 : *x = *full_picture ? 0 : gf_bs_read_u16(bs);
5087 81 : *y = *full_picture ? 0 : gf_bs_read_u16(bs);
5088 81 : *w = gf_bs_read_u16(bs);
5089 81 : *h = gf_bs_read_u16(bs);
5090 : }
5091 81 : gf_bs_del(bs);
5092 81 : }
5093 :
5094 : GF_EXPORT
5095 105 : 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)
5096 : {
5097 : const u8 *data;
5098 : u32 size;
5099 :
5100 105 : if (!gf_isom_get_sample_group_info(file, trackNumber, sample_description_index, GF_ISOM_SAMPLE_GROUP_TRIF, default_sample_group_index, &data, &size))
5101 : return GF_FALSE;
5102 81 : gf_isom_parse_trif_info(data, size, id, independent, full_picture, x, y, w, h);
5103 81 : return GF_TRUE;
5104 : }
5105 :
5106 : GF_EXPORT
5107 24 : Bool gf_isom_get_oinf_info(GF_ISOFile *file, u32 trackNumber, GF_OperatingPointsInformation **ptr)
5108 : {
5109 24 : u32 oref_track, def_index=0;
5110 24 : GF_TrackBox *trak = gf_isom_get_track_from_file(file, trackNumber);
5111 :
5112 24 : if (!ptr) return GF_FALSE;
5113 :
5114 24 : oref_track=0;
5115 24 : gf_isom_get_reference(file, trackNumber, GF_ISOM_REF_OREF, 1, &oref_track);
5116 24 : if (oref_track) {
5117 3 : trak = gf_isom_get_track_from_file(file, oref_track);
5118 3 : if (!trak) return GF_FALSE;
5119 : }
5120 :
5121 24 : *ptr = (GF_OperatingPointsInformation *) gf_isom_get_sample_group_info_entry(file, trak, GF_ISOM_SAMPLE_GROUP_OINF, 1, &def_index, NULL);
5122 :
5123 24 : return *ptr ? GF_TRUE : GF_FALSE;
5124 : }
5125 :
5126 : GF_EXPORT
5127 0 : GF_Err gf_isom_set_byte_offset(GF_ISOFile *file, s64 byte_offset)
5128 : {
5129 0 : if (!file) return GF_BAD_PARAM;
5130 0 : file->read_byte_offset = byte_offset;
5131 0 : return GF_OK;
5132 : }
5133 :
5134 : GF_EXPORT
5135 174 : u32 gf_isom_get_nalu_length_field(GF_ISOFile *file, u32 track, u32 StreamDescriptionIndex)
5136 : {
5137 : GF_TrackBox *trak;
5138 : GF_SampleEntryBox *entry;
5139 : GF_MPEGVisualSampleEntryBox *ve;
5140 : GF_SampleDescriptionBox *stsd;
5141 :
5142 174 : trak = gf_isom_get_track_from_file(file, track);
5143 174 : if (!trak) {
5144 0 : file->LastError = GF_BAD_PARAM;
5145 0 : return 0;
5146 : }
5147 :
5148 174 : stsd = trak->Media->information->sampleTable->SampleDescription;
5149 174 : if (!stsd || !StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->child_boxes)) {
5150 0 : file->LastError = GF_BAD_PARAM;
5151 0 : return 0;
5152 : }
5153 :
5154 174 : entry = (GF_SampleEntryBox *)gf_list_get(stsd->child_boxes, StreamDescriptionIndex - 1);
5155 : //no support for generic sample entries (eg, no MPEG4 descriptor)
5156 174 : if (!entry || ! gf_isom_is_nalu_based_entry(trak->Media, entry)) {
5157 0 : file->LastError = GF_BAD_PARAM;
5158 0 : return 0;
5159 : }
5160 :
5161 : ve = (GF_MPEGVisualSampleEntryBox*)entry;
5162 174 : if (ve->avc_config) return ve->avc_config->config->nal_unit_size;
5163 0 : if (ve->svc_config) return ve->svc_config->config->nal_unit_size;
5164 0 : if (ve->hevc_config) return ve->hevc_config->config->nal_unit_size;
5165 0 : if (ve->lhvc_config) return ve->lhvc_config->config->nal_unit_size;
5166 : return 0;
5167 : }
5168 :
5169 : GF_EXPORT
5170 583091 : Bool gf_isom_is_video_handler_type(u32 mtype)
5171 : {
5172 583091 : switch (mtype) {
5173 : case GF_ISOM_MEDIA_VISUAL:
5174 : case GF_ISOM_MEDIA_AUXV:
5175 : case GF_ISOM_MEDIA_PICT:
5176 : return GF_TRUE;
5177 145453 : default:
5178 145453 : return GF_FALSE;
5179 : }
5180 : }
5181 :
5182 : GF_EXPORT
5183 1195 : GF_Err gf_isom_get_bitrate(GF_ISOFile *movie, u32 trackNumber, u32 sampleDescIndex, u32 *average_bitrate, u32 *max_bitrate, u32 *decode_buffer_size)
5184 : {
5185 : GF_BitRateBox *a;
5186 : u32 i, count, mrate, arate, dbsize, type;
5187 : GF_SampleEntryBox *ent;
5188 : GF_ProtectionSchemeInfoBox *sinf;
5189 : GF_TrackBox *trak;
5190 : GF_ESDBox *esd;
5191 :
5192 1195 : trak = gf_isom_get_track_from_file(movie, trackNumber);
5193 1195 : if (!trak || !trak->Media) return GF_BAD_PARAM;
5194 :
5195 : mrate = arate = dbsize = 0;
5196 1195 : count = gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes);
5197 2402 : for (i=0; i<count; i++) {
5198 1207 : if ((sampleDescIndex>0) && (i+1 != sampleDescIndex)) continue;
5199 :
5200 1195 : ent = (GF_SampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, i);
5201 1195 : if (!ent) return GF_BAD_PARAM;
5202 1195 : a = gf_isom_sample_entry_get_bitrate(ent, GF_FALSE);
5203 1195 : if (a) {
5204 772 : if (mrate<a->maxBitrate) mrate = a->maxBitrate;
5205 772 : if (arate<a->avgBitrate) arate = a->avgBitrate;
5206 772 : if (dbsize<a->bufferSizeDB) dbsize = a->bufferSizeDB;
5207 772 : continue;
5208 : }
5209 423 : type = ent->type;
5210 : switch (type) {
5211 42 : case GF_ISOM_BOX_TYPE_ENCV:
5212 : case GF_ISOM_BOX_TYPE_ENCA:
5213 : case GF_ISOM_BOX_TYPE_ENCS:
5214 42 : sinf = (GF_ProtectionSchemeInfoBox *) gf_isom_box_find_child(ent->child_boxes, GF_ISOM_BOX_TYPE_SINF);
5215 42 : if (sinf && sinf->original_format) type = sinf->original_format->data_format;
5216 : break;
5217 : }
5218 : esd = NULL;
5219 423 : switch (type) {
5220 40 : case GF_ISOM_BOX_TYPE_MP4V:
5221 40 : esd = ((GF_MPEGVisualSampleEntryBox *)ent)->esd;
5222 40 : break;
5223 201 : case GF_ISOM_BOX_TYPE_MP4A:
5224 201 : esd = ((GF_MPEGAudioSampleEntryBox *)ent)->esd;
5225 201 : break;
5226 29 : case GF_ISOM_BOX_TYPE_MP4S:
5227 29 : esd = ((GF_MPEGSampleEntryBox *)ent)->esd;
5228 29 : break;
5229 : }
5230 270 : if (esd && esd->desc && esd->desc->decoderConfig) {
5231 270 : if (mrate<esd->desc->decoderConfig->maxBitrate) mrate = esd->desc->decoderConfig->maxBitrate;
5232 270 : if (arate<esd->desc->decoderConfig->avgBitrate) arate = esd->desc->decoderConfig->avgBitrate;
5233 270 : if (dbsize<esd->desc->decoderConfig->bufferSizeDB) dbsize = esd->desc->decoderConfig->bufferSizeDB;
5234 : }
5235 : }
5236 1195 : if (average_bitrate) *average_bitrate = arate;
5237 1195 : if (max_bitrate) *max_bitrate = mrate;
5238 1195 : if (decode_buffer_size) *decode_buffer_size = dbsize;
5239 : return GF_OK;
5240 : }
5241 :
5242 3 : void gf_isom_enable_traf_map_templates(GF_ISOFile *movie)
5243 : {
5244 3 : if (movie)
5245 3 : movie->signal_frag_bounds=GF_TRUE;
5246 3 : }
5247 :
5248 : GF_EXPORT
5249 8188 : Bool gf_isom_sample_is_fragment_start(GF_ISOFile *movie, u32 trackNumber, u32 sampleNum, GF_ISOFragmentBoundaryInfo *frag_info)
5250 : {
5251 : u32 i;
5252 : GF_TrackBox *trak;
5253 : GF_TrafToSampleMap *tmap;
5254 :
5255 8188 : if (frag_info) memset(frag_info, 0, sizeof(GF_ISOFragmentBoundaryInfo));
5256 :
5257 8188 : trak = gf_isom_get_track_from_file(movie, trackNumber);
5258 8188 : if (!trak || !trak->Media) return GF_FALSE;
5259 8188 : if (!trak->Media->information->sampleTable->traf_map) return GF_FALSE;
5260 :
5261 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
5262 7323 : if (sampleNum<=trak->sample_count_at_seg_start)
5263 : return GF_FALSE;
5264 7323 : sampleNum -= trak->sample_count_at_seg_start;
5265 : #endif
5266 :
5267 : tmap = trak->Media->information->sampleTable->traf_map;
5268 : if (!tmap) return GF_FALSE;
5269 25284 : for (i=0; i<tmap->nb_entries; i++) {
5270 29463 : GF_TrafMapEntry *finfo = &tmap->frag_starts[i];
5271 29463 : if (finfo->sample_num == sampleNum) {
5272 195 : if (frag_info) {
5273 195 : frag_info->frag_start = finfo->moof_start;
5274 195 : frag_info->mdat_end = finfo->mdat_end;
5275 195 : frag_info->moof_template = finfo->moof_template;
5276 195 : frag_info->moof_template_size = finfo->moof_template_size;
5277 195 : frag_info->seg_start_plus_one = finfo->seg_start_plus_one;
5278 195 : frag_info->sidx_start = finfo->sidx_start;
5279 195 : frag_info->sidx_end = finfo->sidx_end;
5280 : }
5281 : return GF_TRUE;
5282 : }
5283 :
5284 29268 : if (tmap->frag_starts[i].sample_num > sampleNum) return GF_FALSE;
5285 : }
5286 : return GF_FALSE;
5287 : }
5288 :
5289 :
5290 :
5291 :
5292 : GF_EXPORT
5293 7 : GF_Err gf_isom_get_jp2_config(GF_ISOFile *movie, u32 trackNumber, u32 sampleDesc, u8 **out_dsi, u32 *out_size)
5294 : {
5295 : GF_TrackBox *trak;
5296 : GF_MPEGVisualSampleEntryBox *entry;
5297 : GF_BitStream *bs;
5298 :
5299 7 : trak = gf_isom_get_track_from_file(movie, trackNumber);
5300 7 : if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleDescription) return GF_ISOM_INVALID_FILE;
5301 7 : entry = (GF_MPEGVisualSampleEntryBox *) gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDesc-1);
5302 7 : if (!entry || !entry->jp2h) return GF_BAD_PARAM;
5303 7 : if (!entry->jp2h->ihdr) return GF_ISOM_INVALID_FILE;
5304 :
5305 7 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
5306 7 : gf_isom_box_array_write((GF_Box*)entry->jp2h, entry->jp2h->child_boxes, bs);
5307 7 : gf_bs_get_content(bs, out_dsi, out_size);
5308 7 : gf_bs_del(bs);
5309 7 : return GF_OK;
5310 : }
5311 :
5312 :
5313 21 : Bool gf_isom_is_identical_sgpd(void *ptr1, void *ptr2, u32 grouping_type)
5314 : {
5315 : Bool res = GF_FALSE;
5316 : #ifndef GPAC_DISABLE_ISOM_WRITE
5317 : GF_BitStream *bs1, *bs2;
5318 : u8 *buf1, *buf2;
5319 : u32 len1, len2;
5320 :
5321 21 : if (!ptr1 || !ptr2)
5322 : return GF_FALSE;
5323 :
5324 21 : bs1 = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
5325 21 : if (grouping_type) {
5326 21 : sgpd_write_entry(grouping_type, ptr1, bs1);
5327 : } else {
5328 0 : gf_isom_box_size((GF_Box *)ptr1);
5329 0 : gf_isom_box_write((GF_Box *)ptr1, bs1);
5330 : }
5331 21 : gf_bs_get_content(bs1, &buf1, &len1);
5332 21 : gf_bs_del(bs1);
5333 :
5334 21 : bs2 = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
5335 21 : if (grouping_type) {
5336 21 : sgpd_write_entry(grouping_type, ptr2, bs2);
5337 : } else {
5338 0 : gf_isom_box_write((GF_Box *)ptr2, bs2);
5339 : }
5340 21 : gf_bs_get_content(bs2, &buf2, &len2);
5341 21 : gf_bs_del(bs2);
5342 :
5343 :
5344 21 : if ((len1==len2) && !memcmp(buf1, buf2, len1))
5345 : res = GF_TRUE;
5346 :
5347 21 : gf_free(buf1);
5348 21 : gf_free(buf2);
5349 : #endif
5350 21 : return res;
5351 : }
5352 :
5353 : GF_EXPORT
5354 667 : u64 gf_isom_get_track_magic(GF_ISOFile *movie, u32 trackNumber)
5355 : {
5356 667 : GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
5357 667 : if (!trak) return 0;
5358 667 : return trak->magic;
5359 : }
5360 :
5361 : GF_EXPORT
5362 1 : GF_Err gf_isom_get_file_offset_for_time(GF_ISOFile *movie, Double start_time, u64 *max_offset)
5363 : {
5364 : u32 i;
5365 : u64 start_ts, cur_start_time;
5366 : u64 offset=0;
5367 1 : if (!movie || !movie->moov)
5368 : return GF_BAD_PARAM;
5369 :
5370 1 : if (!movie->main_sidx) return GF_NOT_SUPPORTED;
5371 1 : start_ts = (u64) (start_time * movie->main_sidx->timescale);
5372 : cur_start_time = 0;
5373 1 : offset = movie->main_sidx->first_offset + movie->main_sidx_end_pos;
5374 :
5375 1 : for (i=0; i<movie->main_sidx->nb_refs; i++) {
5376 1 : if (cur_start_time >= start_ts) {
5377 1 : *max_offset = offset;
5378 1 : return GF_OK;
5379 : }
5380 0 : cur_start_time += movie->main_sidx->refs[i].subsegment_duration;
5381 0 : offset += movie->main_sidx->refs[i].reference_size;
5382 : }
5383 :
5384 : return GF_EOS;
5385 : }
5386 :
5387 : GF_EXPORT
5388 2 : GF_Err gf_isom_get_sidx_duration(GF_ISOFile *movie, u64 *sidx_dur, u32 *sidx_timescale)
5389 : {
5390 : u64 dur=0;
5391 : u32 i;
5392 2 : if (!movie || !movie->moov || !sidx_timescale || !sidx_dur)
5393 : return GF_BAD_PARAM;
5394 :
5395 2 : if (!movie->main_sidx) return GF_NOT_SUPPORTED;
5396 1 : *sidx_timescale = movie->main_sidx->timescale;
5397 :
5398 61 : for (i=0; i<movie->main_sidx->nb_refs; i++) {
5399 60 : dur += movie->main_sidx->refs[i].subsegment_duration;
5400 : }
5401 1 : *sidx_dur = dur;
5402 1 : return GF_OK;
5403 : }
5404 :
5405 : GF_EXPORT
5406 2 : const u8 *gf_isom_get_mpegh_compatible_profiles(GF_ISOFile *movie, u32 trackNumber, u32 sampleDescIndex, u32 *nb_compat_profiles)
5407 : {
5408 : GF_SampleEntryBox *ent;
5409 : GF_MHACompatibleProfilesBox *mhap;
5410 : GF_TrackBox *trak;
5411 :
5412 2 : trak = gf_isom_get_track_from_file(movie, trackNumber);
5413 2 : if (!trak || !trak->Media || !nb_compat_profiles) return NULL;
5414 2 : *nb_compat_profiles = 0;
5415 2 : ent = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDescIndex-1);
5416 2 : if (!ent) return NULL;
5417 2 : mhap = (GF_MHACompatibleProfilesBox *) gf_isom_box_find_child(ent->child_boxes, GF_ISOM_BOX_TYPE_MHAP);
5418 2 : if (!mhap) return NULL;
5419 0 : *nb_compat_profiles = mhap->num_profiles;
5420 0 : return mhap->compat_profiles;
5421 : }
5422 :
5423 18669 : const void *gf_isom_get_tfrf(GF_ISOFile *movie, u32 trackNumber)
5424 : {
5425 : #ifdef GPAC_DISABLE_ISOM_FRAGMENTS
5426 : return NULL;
5427 : #else
5428 18669 : GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
5429 18669 : if (!trak) return NULL;
5430 :
5431 18623 : return trak->tfrf;
5432 : #endif
5433 : }
5434 :
5435 826 : GF_Err gf_isom_get_y3d_info(GF_ISOFile *movie, u32 trackNumber, u32 sampleDescriptionIndex, GF_ISOM_Y3D_Info *info)
5436 : {
5437 : GF_SampleEntryBox *ent;
5438 : GF_TrackBox *trak;
5439 : Bool found = GF_FALSE;
5440 826 : trak = gf_isom_get_track_from_file(movie, trackNumber);
5441 826 : if (!trak || !trak->Media || !info) return GF_BAD_PARAM;
5442 :
5443 826 : ent = gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, sampleDescriptionIndex-1);
5444 826 : if (!ent) return GF_BAD_PARAM;
5445 :
5446 : memset(info, 0, sizeof(GF_ISOM_Y3D_Info));
5447 :
5448 826 : GF_Stereo3DBox *st3d = (GF_Stereo3DBox *) gf_isom_box_find_child(ent->child_boxes, GF_ISOM_BOX_TYPE_ST3D);
5449 826 : if (st3d) {
5450 : found = GF_TRUE;
5451 0 : info->stereo_type = st3d->stereo_type;
5452 : }
5453 :
5454 826 : GF_Box *sv3d = gf_isom_box_find_child(ent->child_boxes, GF_ISOM_BOX_TYPE_SV3D);
5455 826 : if (!sv3d) {
5456 826 : return found ? GF_OK : GF_NOT_FOUND;
5457 : }
5458 0 : GF_SphericalVideoInfoBox *svhd = (GF_SphericalVideoInfoBox *) gf_isom_box_find_child(sv3d->child_boxes, GF_ISOM_BOX_TYPE_SVHD);
5459 0 : if (svhd && strlen(svhd->string)) info->meta_data = svhd->string;
5460 :
5461 0 : GF_Box *proj = gf_isom_box_find_child(sv3d->child_boxes, GF_ISOM_BOX_TYPE_PROJ);
5462 0 : if (!proj)
5463 0 : return found ? GF_OK : GF_NOT_FOUND;
5464 :
5465 0 : GF_ProjectionHeaderBox *projh = (GF_ProjectionHeaderBox *) gf_isom_box_find_child(proj->child_boxes, GF_ISOM_BOX_TYPE_PRHD);
5466 0 : if (projh) {
5467 0 : info->yaw = projh->yaw;
5468 0 : info->pitch = projh->pitch;
5469 0 : info->roll = projh->roll;
5470 0 : info->pose_present = GF_TRUE;
5471 : }
5472 :
5473 0 : GF_ProjectionTypeBox *projt = (GF_ProjectionTypeBox *) gf_isom_box_find_child(proj->child_boxes, GF_ISOM_BOX_TYPE_CBMP);
5474 0 : if (projt) {
5475 0 : info->layout = projt->layout;
5476 0 : info->padding = projt->padding;
5477 0 : info->projection_type = 1;
5478 : } else {
5479 0 : projt = (GF_ProjectionTypeBox *) gf_isom_box_find_child(proj->child_boxes, GF_ISOM_BOX_TYPE_EQUI);
5480 0 : if (projt) {
5481 0 : info->top = projt->bounds_top;
5482 0 : info->bottom = projt->bounds_bottom;
5483 0 : info->left = projt->bounds_left;
5484 0 : info->right = projt->bounds_right;
5485 0 : info->projection_type = 2;
5486 : } else {
5487 0 : projt = (GF_ProjectionTypeBox *) gf_isom_box_find_child(proj->child_boxes, GF_ISOM_BOX_TYPE_EQUI);
5488 0 : if (projt) {
5489 0 : info->projection_type = 3;
5490 : }
5491 : }
5492 : }
5493 : return GF_OK;
5494 : }
5495 :
5496 : #endif /*GPAC_DISABLE_ISOM*/
|