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