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