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