Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2019
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 : #include <gpac/internal/isomedia_dev.h>
27 : #include <gpac/constants.h>
28 : #include <gpac/avparse.h>
29 :
30 : #ifndef GPAC_DISABLE_ISOM
31 :
32 2852800 : GF_Err Media_GetSampleDesc(GF_MediaBox *mdia, u32 SampleDescIndex, GF_SampleEntryBox **out_entry, u32 *dataRefIndex)
33 : {
34 : GF_SampleDescriptionBox *stsd;
35 : GF_SampleEntryBox *entry = NULL;
36 :
37 2852800 : if (!mdia) return GF_ISOM_INVALID_FILE;
38 :
39 2852800 : stsd = mdia->information->sampleTable->SampleDescription;
40 2852800 : if (!stsd) return GF_ISOM_INVALID_FILE;
41 2852800 : if (!SampleDescIndex || (SampleDescIndex > gf_list_count(stsd->child_boxes)) ) return GF_BAD_PARAM;
42 :
43 2852795 : entry = (GF_SampleEntryBox*)gf_list_get(stsd->child_boxes, SampleDescIndex - 1);
44 2852795 : if (!entry) return GF_ISOM_INVALID_FILE;
45 :
46 2852795 : if (out_entry) *out_entry = entry;
47 2852795 : if (dataRefIndex) *dataRefIndex = entry->dataReferenceIndex;
48 : return GF_OK;
49 : }
50 :
51 187 : GF_Err Media_GetSampleDescIndex(GF_MediaBox *mdia, u64 DTS, u32 *sampleDescIndex)
52 : {
53 : GF_Err e;
54 : u32 sampleNumber, prevSampleNumber, num;
55 : u64 offset;
56 187 : if (sampleDescIndex == NULL) return GF_BAD_PARAM;
57 :
58 : //find the sample for this time
59 187 : e = stbl_findEntryForTime(mdia->information->sampleTable, (u32) DTS, 0, &sampleNumber, &prevSampleNumber);
60 187 : if (e) return e;
61 :
62 187 : if (!sampleNumber && !prevSampleNumber) {
63 : //we have to assume the track was created to be used... If we have a sampleDesc, OK
64 60 : if (gf_list_count(mdia->information->sampleTable->SampleDescription->child_boxes)) {
65 60 : (*sampleDescIndex) = 1;
66 60 : return GF_OK;
67 : }
68 : return GF_BAD_PARAM;
69 : }
70 127 : return stbl_GetSampleInfos(mdia->information->sampleTable, ( sampleNumber ? sampleNumber : prevSampleNumber), &offset, &num, sampleDescIndex, NULL);
71 : }
72 :
73 13 : static GF_Err gf_isom_get_3gpp_audio_esd(GF_SampleTableBox *stbl, u32 type, GF_GenericAudioSampleEntryBox *entry, GF_ESD **out_esd)
74 : {
75 13 : (*out_esd) = gf_odf_desc_esd_new(2);
76 13 : (*out_esd)->decoderConfig->streamType = GF_STREAM_AUDIO;
77 : /*official mapping to MPEG-4*/
78 13 : switch (type) {
79 3 : case GF_ISOM_SUBTYPE_3GP_EVRC:
80 3 : (*out_esd)->decoderConfig->objectTypeIndication = GF_CODECID_EVRC;
81 : return GF_OK;
82 6 : case GF_ISOM_SUBTYPE_3GP_QCELP:
83 : {
84 : u32 block_size, sample_rate, sample_size, i;
85 : GF_SttsEntry *ent;
86 : GF_BitStream *bs;
87 : char szName[80];
88 : /*only map CBR*/
89 6 : sample_size = stbl->SampleSize->sampleSize;
90 6 : (*out_esd)->decoderConfig->objectTypeIndication = GF_CODECID_QCELP;
91 6 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
92 6 : gf_bs_write_data(bs, "QLCMfmt ", 8);
93 6 : gf_bs_write_u32_le(bs, 150);/*fmt chunk size*/
94 6 : gf_bs_write_u8(bs, 1);
95 6 : gf_bs_write_u8(bs, 0);
96 : /*QCELP GUID*/
97 6 : gf_bs_write_data(bs, "\x41\x6D\x7F\x5E\x15\xB1\xD0\x11\xBA\x91\x00\x80\x5F\xB4\xB9\x7E", 16);
98 6 : gf_bs_write_u16_le(bs, 1);
99 : memset(szName, 0, 80);
100 : strcpy(szName, "QCELP-13K(GPAC-emulated)");
101 6 : gf_bs_write_data(bs, szName, 80);
102 6 : ent = &stbl->TimeToSample->entries[0];
103 6 : sample_rate = entry->samplerate_hi;
104 6 : block_size = ent ? ent->sampleDelta : 160;
105 6 : gf_bs_write_u16_le(bs, 8*sample_size*sample_rate/block_size);
106 6 : gf_bs_write_u16_le(bs, sample_size);
107 6 : gf_bs_write_u16_le(bs, block_size);
108 6 : gf_bs_write_u16_le(bs, sample_rate);
109 6 : gf_bs_write_u16_le(bs, entry->bitspersample);
110 6 : gf_bs_write_u32_le(bs, sample_size ? 0 : 7);
111 : /**/
112 42 : for (i=0; i<7; i++) {
113 : static const u32 qcelp_r2s [] = {0, 1, 1, 4, 2, 8, 3, 17, 4, 35, 5, 8, 14, 1};
114 42 : if (sample_size) {
115 0 : gf_bs_write_u16(bs, 0);
116 : } else {
117 42 : gf_bs_write_u8(bs, qcelp_r2s[2*i+1]);
118 42 : gf_bs_write_u8(bs, qcelp_r2s[2*i]);
119 : }
120 : }
121 6 : gf_bs_write_u16(bs, 0);
122 : memset(szName, 0, 80);
123 6 : gf_bs_write_data(bs, szName, 20);/*reserved*/
124 6 : gf_bs_get_content(bs, & (*out_esd)->decoderConfig->decoderSpecificInfo->data, & (*out_esd)->decoderConfig->decoderSpecificInfo->dataLength);
125 6 : gf_bs_del(bs);
126 : }
127 : return GF_OK;
128 0 : case GF_ISOM_SUBTYPE_3GP_SMV:
129 0 : (*out_esd)->decoderConfig->objectTypeIndication = GF_CODECID_SMV;
130 : return GF_OK;
131 2 : case GF_ISOM_SUBTYPE_3GP_AMR:
132 2 : (*out_esd)->decoderConfig->objectTypeIndication = GF_CODECID_AMR;
133 : return GF_OK;
134 2 : case GF_ISOM_SUBTYPE_3GP_AMR_WB:
135 2 : (*out_esd)->decoderConfig->objectTypeIndication = GF_CODECID_AMR_WB;
136 : return GF_OK;
137 0 : default:
138 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] unsupported sample description type %s\n", gf_4cc_to_str(entry->type)));
139 : break;
140 : }
141 : return GF_OK;
142 : }
143 :
144 5081 : GF_Err Media_GetESD(GF_MediaBox *mdia, u32 sampleDescIndex, GF_ESD **out_esd, Bool true_desc_only)
145 : {
146 : u32 type;
147 : GF_ESD *esd;
148 : GF_MPEGSampleEntryBox *entry = NULL;
149 : GF_ESDBox *ESDa;
150 : GF_ProtectionSchemeInfoBox *sinf;
151 5081 : GF_SampleDescriptionBox *stsd = mdia->information->sampleTable->SampleDescription;
152 :
153 5081 : *out_esd = NULL;
154 5081 : if (!stsd || !stsd->child_boxes || !sampleDescIndex || (sampleDescIndex > gf_list_count(stsd->child_boxes)) )
155 : return GF_BAD_PARAM;
156 :
157 : esd = NULL;
158 5079 : entry = (GF_MPEGSampleEntryBox*)gf_list_get(stsd->child_boxes, sampleDescIndex - 1);
159 5079 : if (! entry) return GF_ISOM_INVALID_MEDIA;
160 :
161 5079 : *out_esd = NULL;
162 : ESDa = NULL;
163 5079 : type = entry->type;
164 5079 : switch (type) {
165 505 : case GF_ISOM_BOX_TYPE_ENCV:
166 : case GF_ISOM_BOX_TYPE_ENCA:
167 : case GF_ISOM_BOX_TYPE_ENCS:
168 : case GF_ISOM_BOX_TYPE_ENCF:
169 : case GF_ISOM_BOX_TYPE_ENCM:
170 : case GF_ISOM_BOX_TYPE_ENCT:
171 505 : sinf = (GF_ProtectionSchemeInfoBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_SINF);
172 505 : if (sinf && sinf->original_format) {
173 505 : type = sinf->original_format->data_format;
174 : }
175 : break;
176 0 : case GF_ISOM_BOX_TYPE_RESV:
177 0 : sinf = (GF_ProtectionSchemeInfoBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_RINF);
178 0 : if (sinf && sinf->original_format) {
179 0 : type = sinf->original_format->data_format;
180 : }
181 : break;
182 : }
183 :
184 :
185 5079 : switch (type) {
186 394 : case GF_ISOM_BOX_TYPE_MP4V:
187 394 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO)
188 : return GF_ISOM_INVALID_MEDIA;
189 394 : ESDa = ((GF_MPEGVisualSampleEntryBox*)entry)->esd;
190 394 : if (ESDa) esd = (GF_ESD *) ESDa->desc;
191 : /*avc1 encrypted*/
192 0 : else esd = ((GF_MPEGVisualSampleEntryBox*) entry)->emul_esd;
193 : break;
194 3166 : case GF_ISOM_BOX_TYPE_AVC1:
195 : case GF_ISOM_BOX_TYPE_AVC2:
196 : case GF_ISOM_BOX_TYPE_AVC3:
197 : case GF_ISOM_BOX_TYPE_AVC4:
198 : case GF_ISOM_BOX_TYPE_HVC1:
199 : case GF_ISOM_BOX_TYPE_HEV1:
200 : case GF_ISOM_BOX_TYPE_HVC2:
201 : case GF_ISOM_BOX_TYPE_HEV2:
202 : case GF_ISOM_BOX_TYPE_HVT1:
203 : case GF_ISOM_BOX_TYPE_264B:
204 : case GF_ISOM_BOX_TYPE_265B:
205 : case GF_ISOM_BOX_TYPE_DVHE:
206 : case GF_ISOM_BOX_TYPE_VVC1:
207 : case GF_ISOM_BOX_TYPE_VVI1:
208 3166 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO)
209 : return GF_ISOM_INVALID_MEDIA;
210 3166 : esd = ((GF_MPEGVisualSampleEntryBox*) entry)->emul_esd;
211 3166 : break;
212 33 : case GF_ISOM_BOX_TYPE_SVC1:
213 : case GF_ISOM_BOX_TYPE_MVC1:
214 33 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO)
215 : return GF_ISOM_INVALID_MEDIA;
216 33 : if ((mdia->mediaTrack->extractor_mode & 0x0000FFFF) != GF_ISOM_NALU_EXTRACT_INSPECT)
217 33 : AVC_RewriteESDescriptorEx((GF_MPEGVisualSampleEntryBox*) entry, mdia);
218 : else
219 0 : AVC_RewriteESDescriptorEx((GF_MPEGVisualSampleEntryBox*) entry, NULL);
220 33 : esd = ((GF_MPEGVisualSampleEntryBox*) entry)->emul_esd;
221 33 : break;
222 0 : case GF_ISOM_BOX_TYPE_LHE1:
223 : case GF_ISOM_BOX_TYPE_LHV1:
224 0 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO)
225 : return GF_ISOM_INVALID_MEDIA;
226 0 : if ((mdia->mediaTrack->extractor_mode & 0x0000FFFF) != GF_ISOM_NALU_EXTRACT_INSPECT)
227 0 : HEVC_RewriteESDescriptorEx((GF_MPEGVisualSampleEntryBox*) entry, mdia);
228 : else
229 0 : HEVC_RewriteESDescriptorEx((GF_MPEGVisualSampleEntryBox*) entry, NULL);
230 0 : esd = ((GF_MPEGVisualSampleEntryBox*) entry)->emul_esd;
231 0 : break;
232 148 : case GF_ISOM_BOX_TYPE_AV01:
233 148 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO)
234 : return GF_ISOM_INVALID_MEDIA;
235 148 : AV1_RewriteESDescriptorEx((GF_MPEGVisualSampleEntryBox*)entry, mdia);
236 148 : esd = ((GF_MPEGVisualSampleEntryBox*)entry)->emul_esd;
237 148 : break;
238 38 : case GF_ISOM_BOX_TYPE_VP08:
239 : case GF_ISOM_BOX_TYPE_VP09:
240 38 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO)
241 : return GF_ISOM_INVALID_MEDIA;
242 38 : VP9_RewriteESDescriptorEx((GF_MPEGVisualSampleEntryBox*)entry, mdia);
243 38 : esd = ((GF_MPEGVisualSampleEntryBox*)entry)->emul_esd;
244 38 : break;
245 750 : case GF_ISOM_BOX_TYPE_MP4A:
246 750 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO)
247 : return GF_ISOM_INVALID_MEDIA;
248 : {
249 : GF_MPEGAudioSampleEntryBox *ase = (GF_MPEGAudioSampleEntryBox*)entry;
250 750 : ESDa = ase->esd;
251 750 : if (ESDa) {
252 750 : esd = (GF_ESD *) ESDa->desc;
253 0 : } else if (!true_desc_only) {
254 : Bool make_mp4a = GF_FALSE;
255 0 : sinf = (GF_ProtectionSchemeInfoBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_SINF);
256 :
257 0 : if (sinf && sinf->original_format) {
258 0 : if (sinf->original_format->data_format==GF_ISOM_BOX_TYPE_MP4A) {
259 : make_mp4a = GF_TRUE;
260 : }
261 : } else {
262 : // Assuming that if no ESD is provided the stream is Basic MPEG-4 AAC LC
263 : make_mp4a = GF_TRUE;
264 : }
265 : if (make_mp4a) {
266 : GF_M4ADecSpecInfo aacinfo;
267 : memset(&aacinfo, 0, sizeof(GF_M4ADecSpecInfo));
268 0 : aacinfo.nb_chan = ase->channel_count;
269 0 : aacinfo.base_object_type = GF_M4A_AAC_LC;
270 0 : aacinfo.base_sr = ase->samplerate_hi;
271 0 : *out_esd = gf_odf_desc_esd_new(0);
272 0 : (*out_esd)->decoderConfig->streamType = GF_STREAM_AUDIO;
273 0 : (*out_esd)->decoderConfig->objectTypeIndication = GF_CODECID_AAC_MPEG4;
274 0 : gf_m4a_write_config(&aacinfo, &(*out_esd)->decoderConfig->decoderSpecificInfo->data, &(*out_esd)->decoderConfig->decoderSpecificInfo->dataLength);
275 : }
276 : }
277 : }
278 : break;
279 326 : case GF_ISOM_BOX_TYPE_MP4S:
280 326 : if (entry->internal_type==GF_ISOM_SAMPLE_ENTRY_MP4S) {
281 326 : ESDa = entry->esd;
282 326 : if (ESDa) esd = (GF_ESD *) ESDa->desc;
283 : }
284 : break;
285 : #ifndef GPAC_DISABLE_TTXT
286 30 : case GF_ISOM_BOX_TYPE_TX3G:
287 : case GF_ISOM_BOX_TYPE_TEXT:
288 30 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_MP4S)
289 : return GF_ISOM_INVALID_MEDIA;
290 :
291 30 : if (!true_desc_only && mdia->mediaTrack->moov->mov->convert_streaming_text) {
292 3 : GF_Err e = gf_isom_get_ttxt_esd(mdia, out_esd);
293 3 : if (e) return e;
294 : break;
295 : }
296 : else
297 : return GF_ISOM_INVALID_MEDIA;
298 : #endif
299 : #ifndef GPAC_DISABLE_VTT
300 4 : case GF_ISOM_BOX_TYPE_WVTT:
301 4 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_MP4S)
302 : return GF_ISOM_INVALID_MEDIA;
303 : {
304 : GF_WebVTTSampleEntryBox*vtte = (GF_WebVTTSampleEntryBox*)entry;
305 4 : esd = gf_odf_desc_esd_new(2);
306 4 : *out_esd = esd;
307 4 : esd->decoderConfig->streamType = GF_STREAM_TEXT;
308 4 : esd->decoderConfig->objectTypeIndication = GF_CODECID_WEBVTT;
309 4 : if (vtte->config) {
310 4 : esd->decoderConfig->decoderSpecificInfo->dataLength = (u32) strlen(vtte->config->string);
311 4 : esd->decoderConfig->decoderSpecificInfo->data = gf_malloc(sizeof(char)*esd->decoderConfig->decoderSpecificInfo->dataLength);
312 4 : memcpy(esd->decoderConfig->decoderSpecificInfo->data, vtte->config->string, esd->decoderConfig->decoderSpecificInfo->dataLength);
313 : }
314 : }
315 : break;
316 : case GF_ISOM_BOX_TYPE_STPP:
317 : case GF_ISOM_BOX_TYPE_SBTT:
318 : case GF_ISOM_BOX_TYPE_STXT:
319 : break;
320 : #endif
321 :
322 14 : case GF_ISOM_SUBTYPE_3GP_AMR:
323 : case GF_ISOM_SUBTYPE_3GP_AMR_WB:
324 : case GF_ISOM_SUBTYPE_3GP_EVRC:
325 : case GF_ISOM_SUBTYPE_3GP_QCELP:
326 : case GF_ISOM_SUBTYPE_3GP_SMV:
327 14 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO)
328 : return GF_ISOM_INVALID_MEDIA;
329 14 : if (!true_desc_only) {
330 13 : GF_Err e = gf_isom_get_3gpp_audio_esd(mdia->information->sampleTable, type, (GF_GenericAudioSampleEntryBox*)entry, out_esd);
331 13 : if (e) return e;
332 : break;
333 : } else return GF_ISOM_INVALID_MEDIA;
334 :
335 3 : case GF_ISOM_SUBTYPE_OPUS:
336 3 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO)
337 : return GF_ISOM_INVALID_MEDIA;
338 : {
339 3 : GF_OpusSpecificBox *e = ((GF_MPEGAudioSampleEntryBox*)entry)->cfg_opus;
340 : GF_BitStream *bs_out;
341 3 : if (!e) {
342 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("ESD not found for Opus\n)"));
343 : break;
344 : }
345 :
346 3 : *out_esd = gf_odf_desc_esd_new(2);
347 3 : (*out_esd)->decoderConfig->streamType = GF_STREAM_AUDIO;
348 3 : (*out_esd)->decoderConfig->objectTypeIndication = GF_CODECID_OPUS;
349 :
350 : //serialize box with header - compatibility with ffmpeg
351 3 : bs_out = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
352 3 : gf_isom_box_size((GF_Box *) e);
353 3 : gf_isom_box_write((GF_Box *) e, bs_out);
354 3 : gf_bs_get_content(bs_out, & (*out_esd)->decoderConfig->decoderSpecificInfo->data, & (*out_esd)->decoderConfig->decoderSpecificInfo->dataLength);
355 3 : gf_bs_del(bs_out);
356 3 : break;
357 : }
358 3 : case GF_ISOM_SUBTYPE_3GP_H263:
359 3 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO)
360 : return GF_ISOM_INVALID_MEDIA;
361 3 : if (true_desc_only) {
362 : return GF_ISOM_INVALID_MEDIA;
363 : } else {
364 2 : esd = gf_odf_desc_esd_new(2);
365 2 : *out_esd = esd;
366 2 : esd->decoderConfig->streamType = GF_STREAM_VISUAL;
367 2 : esd->decoderConfig->objectTypeIndication = GF_CODECID_H263;
368 2 : break;
369 : }
370 :
371 14 : case GF_ISOM_SUBTYPE_MP3:
372 14 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO)
373 : return GF_ISOM_INVALID_MEDIA;
374 14 : if (true_desc_only) {
375 : return GF_ISOM_INVALID_MEDIA;
376 : } else {
377 14 : esd = gf_odf_desc_esd_new(2);
378 14 : *out_esd = esd;
379 14 : esd->decoderConfig->streamType = GF_STREAM_AUDIO;
380 14 : esd->decoderConfig->objectTypeIndication = GF_CODECID_MPEG_AUDIO;
381 14 : break;
382 : }
383 :
384 9 : case GF_ISOM_SUBTYPE_LSR1:
385 9 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_MP4S)
386 : return GF_ISOM_INVALID_MEDIA;
387 9 : if (true_desc_only) {
388 : return GF_ISOM_INVALID_MEDIA;
389 : } else {
390 : GF_LASeRSampleEntryBox*ptr = (GF_LASeRSampleEntryBox*)entry;
391 9 : esd = gf_odf_desc_esd_new(2);
392 9 : *out_esd = esd;
393 9 : esd->decoderConfig->streamType = GF_STREAM_SCENE;
394 9 : esd->decoderConfig->objectTypeIndication = GF_CODECID_LASER;
395 9 : esd->decoderConfig->decoderSpecificInfo->dataLength = ptr->lsr_config->hdr_size;
396 9 : esd->decoderConfig->decoderSpecificInfo->data = gf_malloc(sizeof(char)*ptr->lsr_config->hdr_size);
397 9 : if (!esd->decoderConfig->decoderSpecificInfo->data) return GF_OUT_OF_MEM;
398 9 : memcpy(esd->decoderConfig->decoderSpecificInfo->data, ptr->lsr_config->hdr, sizeof(char)*ptr->lsr_config->hdr_size);
399 : break;
400 : }
401 3 : case GF_ISOM_SUBTYPE_MH3D_MHA1:
402 : case GF_ISOM_SUBTYPE_MH3D_MHA2:
403 : case GF_ISOM_SUBTYPE_MH3D_MHM1:
404 : case GF_ISOM_SUBTYPE_MH3D_MHM2:
405 3 : if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO)
406 : return GF_ISOM_INVALID_MEDIA;
407 :
408 3 : if (true_desc_only) {
409 : return GF_ISOM_INVALID_MEDIA;
410 : } else {
411 : GF_MPEGAudioSampleEntryBox*ptr = (GF_MPEGAudioSampleEntryBox*)entry;
412 3 : esd = gf_odf_desc_esd_new(2);
413 3 : *out_esd = esd;
414 3 : esd->decoderConfig->streamType = GF_STREAM_AUDIO;
415 3 : if ((type==GF_ISOM_SUBTYPE_MH3D_MHA1) || (type==GF_ISOM_SUBTYPE_MH3D_MHA2))
416 0 : esd->decoderConfig->objectTypeIndication = GF_CODECID_MPHA;
417 : else
418 3 : esd->decoderConfig->objectTypeIndication = GF_CODECID_MHAS;
419 3 : if (ptr->cfg_mha) {
420 0 : GF_BitStream *bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
421 :
422 0 : gf_bs_write_u8(bs, ptr->cfg_mha->configuration_version);
423 0 : gf_bs_write_u8(bs, ptr->cfg_mha->mha_pl_indication);
424 0 : gf_bs_write_u8(bs, ptr->cfg_mha->reference_channel_layout);
425 0 : gf_bs_write_u16(bs, ptr->cfg_mha->mha_config ? ptr->cfg_mha->mha_config_size : 0);
426 0 : if (ptr->cfg_mha->mha_config && ptr->cfg_mha->mha_config_size)
427 0 : gf_bs_write_data(bs, ptr->cfg_mha->mha_config, ptr->cfg_mha->mha_config_size);
428 :
429 0 : gf_bs_get_content(bs, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength);
430 0 : gf_bs_del(bs);
431 : }
432 : }
433 : break;
434 :
435 : default:
436 : return GF_ISOM_INVALID_MEDIA;
437 : }
438 :
439 4912 : if (true_desc_only) {
440 3090 : if (!esd) return GF_ISOM_INVALID_MEDIA;
441 3090 : *out_esd = esd;
442 3090 : return GF_OK;
443 : } else {
444 1822 : if (!esd && !*out_esd) return GF_ISOM_INVALID_MEDIA;
445 1816 : if (*out_esd == NULL) return gf_odf_desc_copy((GF_Descriptor *)esd, (GF_Descriptor **)out_esd);
446 : }
447 : return GF_OK;
448 : }
449 :
450 1100156 : Bool Media_IsSampleSyncShadow(GF_ShadowSyncBox *stsh, u32 sampleNumber)
451 : {
452 : u32 i;
453 : GF_StshEntry *ent;
454 1100156 : if (!stsh) return 0;
455 6 : i=0;
456 21 : while ((ent = (GF_StshEntry*)gf_list_enum(stsh->entries, &i))) {
457 9 : if ((u32) ent->syncSampleNumber == sampleNumber) return 1;
458 9 : else if ((u32) ent->syncSampleNumber > sampleNumber) return 0;
459 : }
460 : return 0;
461 : }
462 :
463 1371048 : GF_Err Media_GetSample(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample **samp, u32 *sIDX, Bool no_data, u64 *out_offset)
464 : {
465 : GF_Err e;
466 : u32 bytesRead;
467 : u32 dataRefIndex, chunkNumber;
468 : u64 offset, new_size;
469 : u32 sdesc_idx;
470 : GF_SampleEntryBox *entry;
471 : GF_StscEntry *stsc_entry;
472 :
473 1371048 : if (!mdia || !mdia->information->sampleTable) return GF_BAD_PARAM;
474 1371048 : if (!mdia->information->sampleTable->SampleSize)
475 : return GF_ISOM_INVALID_FILE;
476 :
477 : //OK, here we go....
478 1371048 : if (sampleNumber > mdia->information->sampleTable->SampleSize->sampleCount) return GF_BAD_PARAM;
479 :
480 : //the data info
481 1100163 : if (!sIDX && !no_data) return GF_BAD_PARAM;
482 :
483 1100163 : e = stbl_GetSampleInfos(mdia->information->sampleTable, sampleNumber, &offset, &chunkNumber, &sdesc_idx, &stsc_entry);
484 1100163 : if (e) return e;
485 1100159 : if (sIDX) (*sIDX) = sdesc_idx;
486 :
487 1100159 : if (out_offset) *out_offset = offset;
488 1100159 : if (!samp ) return GF_OK;
489 :
490 1100156 : if (mdia->information->sampleTable->TimeToSample) {
491 : //get the DTS
492 1100156 : e = stbl_GetSampleDTS(mdia->information->sampleTable->TimeToSample, sampleNumber, &(*samp)->DTS);
493 1100156 : if (e) return e;
494 : } else {
495 0 : (*samp)->DTS=0;
496 : }
497 : //the CTS offset
498 1100156 : if (mdia->information->sampleTable->CompositionOffset) {
499 436672 : e = stbl_GetSampleCTS(mdia->information->sampleTable->CompositionOffset , sampleNumber, &(*samp)->CTS_Offset);
500 436672 : if (e) return e;
501 : } else {
502 663484 : (*samp)->CTS_Offset = 0;
503 : }
504 : //the size
505 1100156 : e = stbl_GetSampleSize(mdia->information->sampleTable->SampleSize, sampleNumber, &(*samp)->dataLength);
506 1100156 : if (e) return e;
507 : //the RAP
508 1100156 : if (mdia->information->sampleTable->SyncSample) {
509 743631 : e = stbl_GetSampleRAP(mdia->information->sampleTable->SyncSample, sampleNumber, &(*samp)->IsRAP, NULL, NULL);
510 743631 : if (e) return e;
511 : } else {
512 : //if no SyncSample, all samples are sync (cf spec)
513 356525 : (*samp)->IsRAP = RAP;
514 : }
515 :
516 1100156 : if (mdia->information->sampleTable->SampleDep) {
517 : u32 isLeading, dependsOn, dependedOn, redundant;
518 118653 : e = stbl_GetSampleDepType(mdia->information->sampleTable->SampleDep, sampleNumber, &isLeading, &dependsOn, &dependedOn, &redundant);
519 118653 : if (!e) {
520 118653 : if (dependsOn==1) (*samp)->IsRAP = RAP_NO;
521 : //commenting following code since it is wrong - an I frame is not always a SAP1, it can be a SAP2 or SAP3.
522 : //Keeping this code breaks AVC / HEVC openGOP import when writing sample dependencies
523 : //else if (dependsOn==2) (*samp)->IsRAP = RAP;
524 :
525 : /*if not depended upon and redundant, mark as carousel sample*/
526 118653 : if ((dependedOn==2) && (redundant==1)) (*samp)->IsRAP = RAP_REDUNDANT;
527 : /*TODO FIXME - we must enhance the IsRAP semantics to carry disposable info ... */
528 : }
529 : }
530 :
531 : /*get sync shadow*/
532 1100156 : if (Media_IsSampleSyncShadow(mdia->information->sampleTable->ShadowSync, sampleNumber)) (*samp)->IsRAP = RAP_REDUNDANT;
533 :
534 : //the data info
535 : if (!sIDX && !no_data) return GF_BAD_PARAM;
536 1100156 : if (!sIDX && !out_offset) return GF_OK;
537 1033917 : if (!sIDX) return GF_OK;
538 :
539 1033913 : (*sIDX) = sdesc_idx;
540 : // e = stbl_GetSampleInfos(mdia->information->sampleTable, sampleNumber, &offset, &chunkNumber, sIDX, &stsc_entry);
541 : // if (e) return e;
542 :
543 : //then get the DataRef
544 1033913 : e = Media_GetSampleDesc(mdia, sdesc_idx, &entry, &dataRefIndex);
545 1033913 : if (e) return e;
546 :
547 : //if moov is compressed, remove offset if sample is after moov in this file
548 1033913 : if (mdia->mediaTrack->moov->compressed_diff) {
549 250 : GF_DataEntryBox *ent = (GF_DataEntryBox*)gf_list_get(mdia->information->dataInformation->dref->child_boxes, dataRefIndex - 1);
550 250 : if (ent && (ent->flags&1) && (offset>=mdia->mediaTrack->moov->file_offset)) {
551 250 : offset -= mdia->mediaTrack->moov->compressed_diff;
552 : }
553 : }
554 :
555 :
556 1033913 : if (no_data) {
557 521746 : if ( ((*samp)->dataLength != 0) && mdia->mediaTrack->pack_num_samples) {
558 0 : u32 idx_in_chunk = sampleNumber - mdia->information->sampleTable->SampleToChunk->firstSampleInCurrentChunk;
559 0 : u32 left_in_chunk = stsc_entry->samplesPerChunk - idx_in_chunk;
560 0 : if (left_in_chunk > mdia->mediaTrack->pack_num_samples)
561 : left_in_chunk = mdia->mediaTrack->pack_num_samples;
562 0 : (*samp)->dataLength *= left_in_chunk;
563 0 : (*samp)->nb_pack = left_in_chunk;
564 : }
565 : return GF_OK;
566 : }
567 :
568 : // Open the data handler - check our mode, don't reopen in read only if this is
569 : //the same entry. In other modes we have no choice because the main data map is
570 : //divided into the original and the edition files
571 512167 : if (mdia->mediaTrack->moov->mov->openMode == GF_ISOM_OPEN_READ) {
572 : //same as last call in read mode
573 423592 : if (!mdia->information->dataHandler) {
574 965 : e = gf_isom_datamap_open(mdia, dataRefIndex, stsc_entry->isEdited);
575 965 : if (e) return e;
576 : }
577 423592 : mdia->information->dataEntryIndex = dataRefIndex;
578 : } else {
579 88575 : e = gf_isom_datamap_open(mdia, dataRefIndex, stsc_entry->isEdited);
580 88575 : if (e) return e;
581 : }
582 :
583 512167 : if ( mdia->mediaTrack->moov->mov->read_byte_offset || mdia->mediaTrack->moov->mov->bytes_removed) {
584 30231 : GF_DataEntryBox *ent = (GF_DataEntryBox*)gf_list_get(mdia->information->dataInformation->dref->child_boxes, dataRefIndex - 1);
585 30231 : if (ent && (ent->flags&1)) {
586 30231 : u64 real_offset = mdia->mediaTrack->moov->mov->read_byte_offset + mdia->mediaTrack->moov->mov->bytes_removed;
587 30231 : if (offset < real_offset)
588 : return GF_IO_ERR;
589 :
590 30231 : if (mdia->information->dataHandler->last_read_offset != mdia->mediaTrack->moov->mov->read_byte_offset) {
591 0 : mdia->information->dataHandler->last_read_offset = mdia->mediaTrack->moov->mov->read_byte_offset;
592 0 : gf_bs_get_refreshed_size(mdia->information->dataHandler->bs);
593 : }
594 :
595 30231 : offset -= real_offset;
596 : }
597 : }
598 512167 : if ((*samp)->dataLength != 0) {
599 512167 : if (mdia->mediaTrack->pack_num_samples) {
600 882 : u32 idx_in_chunk = sampleNumber - mdia->information->sampleTable->SampleToChunk->firstSampleInCurrentChunk;
601 882 : u32 left_in_chunk = stsc_entry->samplesPerChunk - idx_in_chunk;
602 882 : if (left_in_chunk > mdia->mediaTrack->pack_num_samples)
603 : left_in_chunk = mdia->mediaTrack->pack_num_samples;
604 882 : (*samp)->dataLength *= left_in_chunk;
605 882 : (*samp)->nb_pack = left_in_chunk;
606 : }
607 :
608 : /*and finally get the data, include padding if needed*/
609 512167 : if ((*samp)->alloc_size) {
610 397250 : if ((*samp)->alloc_size < (*samp)->dataLength + mdia->mediaTrack->padding_bytes) {
611 4258 : (*samp)->data = (char *) gf_realloc((*samp)->data, sizeof(char) * ( (*samp)->dataLength + mdia->mediaTrack->padding_bytes) );
612 4258 : if (! (*samp)->data) return GF_OUT_OF_MEM;
613 :
614 4258 : (*samp)->alloc_size = (*samp)->dataLength + mdia->mediaTrack->padding_bytes;
615 : }
616 : } else {
617 114917 : (*samp)->data = (char *) gf_malloc(sizeof(char) * ( (*samp)->dataLength + mdia->mediaTrack->padding_bytes) );
618 114917 : if (! (*samp)->data) return GF_OUT_OF_MEM;
619 : }
620 512167 : if (mdia->mediaTrack->padding_bytes)
621 0 : memset((*samp)->data + (*samp)->dataLength, 0, sizeof(char) * mdia->mediaTrack->padding_bytes);
622 :
623 : //check if we can get the sample (make sure we have enougth data...)
624 512167 : new_size = gf_bs_get_size(mdia->information->dataHandler->bs);
625 512167 : if (offset + (*samp)->dataLength > new_size) {
626 : //always refresh the size to avoid wrong info on http/ftp
627 1593 : new_size = gf_bs_get_refreshed_size(mdia->information->dataHandler->bs);
628 1593 : if (offset + (*samp)->dataLength > new_size) {
629 1527 : mdia->BytesMissing = offset + (*samp)->dataLength - new_size;
630 1527 : return GF_ISOM_INCOMPLETE_FILE;
631 : }
632 : }
633 :
634 510640 : bytesRead = gf_isom_datamap_get_data(mdia->information->dataHandler, (*samp)->data, (*samp)->dataLength, offset);
635 : //if bytesRead != sampleSize, we have an IO err
636 510640 : if (bytesRead < (*samp)->dataLength) {
637 : return GF_IO_ERR;
638 : }
639 510640 : mdia->BytesMissing = 0;
640 : }
641 :
642 : //finally rewrite the sample if this is an OD Access Unit or NAL-based one
643 : //we do this even if sample size is zero because of sample implicit reconstruction rules (especially tile tracks)
644 510640 : if (mdia->handler->handlerType == GF_ISOM_MEDIA_OD) {
645 98 : if (!mdia->mediaTrack->moov->mov->disable_odf_translate) {
646 97 : e = Media_RewriteODFrame(mdia, *samp);
647 97 : if (e) return e;
648 : }
649 : }
650 510542 : else if (gf_isom_is_nalu_based_entry(mdia, entry)
651 320123 : && !gf_isom_is_encrypted_entry(entry->type)
652 : ) {
653 299941 : e = gf_isom_nalu_sample_rewrite(mdia, *samp, sampleNumber, (GF_MPEGVisualSampleEntryBox *)entry);
654 299941 : if (e) return e;
655 : }
656 210601 : else if (mdia->mediaTrack->moov->mov->convert_streaming_text
657 202 : && ((mdia->handler->handlerType == GF_ISOM_MEDIA_TEXT) || (mdia->handler->handlerType == GF_ISOM_MEDIA_SCENE) || (mdia->handler->handlerType == GF_ISOM_MEDIA_SUBT))
658 202 : && (entry->type == GF_ISOM_BOX_TYPE_TX3G || entry->type == GF_ISOM_BOX_TYPE_TEXT)
659 : ) {
660 : u64 dur;
661 11 : if (sampleNumber == mdia->information->sampleTable->SampleSize->sampleCount) {
662 1 : dur = mdia->mediaHeader->duration - (*samp)->DTS;
663 : } else {
664 10 : stbl_GetSampleDTS(mdia->information->sampleTable->TimeToSample, sampleNumber+1, &dur);
665 10 : dur -= (*samp)->DTS;
666 : }
667 11 : e = gf_isom_rewrite_text_sample(*samp, sdesc_idx, (u32) dur);
668 11 : if (e) return e;
669 : }
670 : return GF_OK;
671 : }
672 :
673 :
674 :
675 219 : GF_Err Media_CheckDataEntry(GF_MediaBox *mdia, u32 dataEntryIndex)
676 : {
677 :
678 : GF_DataEntryURLBox *entry;
679 : GF_DataMap *map;
680 : GF_Err e;
681 219 : if (!mdia || !dataEntryIndex || dataEntryIndex > gf_list_count(mdia->information->dataInformation->dref->child_boxes)) return GF_BAD_PARAM;
682 :
683 219 : entry = (GF_DataEntryURLBox*)gf_list_get(mdia->information->dataInformation->dref->child_boxes, dataEntryIndex - 1);
684 219 : if (!entry) return GF_ISOM_INVALID_FILE;
685 219 : if (entry->flags == 1) return GF_OK;
686 :
687 : //ok, not self contained, let's go for it...
688 : //we don't know what's a URN yet
689 0 : if (entry->type == GF_ISOM_BOX_TYPE_URN) return GF_NOT_SUPPORTED;
690 0 : if (mdia->mediaTrack->moov->mov->openMode == GF_ISOM_OPEN_WRITE) {
691 0 : e = gf_isom_datamap_new(entry->location, NULL, GF_ISOM_DATA_MAP_READ, &map);
692 : } else {
693 0 : e = gf_isom_datamap_new(entry->location, mdia->mediaTrack->moov->mov->fileName, GF_ISOM_DATA_MAP_READ, &map);
694 : }
695 0 : if (e) return e;
696 0 : gf_isom_datamap_del(map);
697 0 : return GF_OK;
698 : }
699 :
700 :
701 580864 : Bool Media_IsSelfContained(GF_MediaBox *mdia, u32 StreamDescIndex)
702 : {
703 580864 : u32 drefIndex=0;
704 : GF_FullBox *a=NULL;
705 580864 : GF_SampleEntryBox *se = NULL;
706 :
707 580864 : Media_GetSampleDesc(mdia, StreamDescIndex, &se, &drefIndex);
708 580864 : if (!drefIndex) return 0;
709 580864 : if (mdia
710 580864 : && mdia->information
711 580864 : && mdia->information->dataInformation
712 580864 : && mdia->information->dataInformation->dref
713 : ) {
714 580864 : a = (GF_FullBox*)gf_list_get(mdia->information->dataInformation->dref->child_boxes, drefIndex - 1);
715 : }
716 580864 : if (!a) {
717 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] broken file: Data reference index set to %d but no data reference entry found\n", drefIndex));
718 : return 1;
719 : }
720 580864 : if (a->flags & 1) return 1;
721 : /*QT specific*/
722 1548 : if (a->type == GF_QT_BOX_TYPE_ALIS) return 1;
723 1548 : return 0;
724 : }
725 :
726 1817 : GF_ISOMDataRefAllType Media_SelfContainedType(GF_MediaBox *mdia)
727 : {
728 : u32 nb_ext, nb_self;
729 : u32 i, count;
730 :
731 : nb_ext = nb_self = 0;
732 1817 : count = mdia->information->sampleTable->SampleDescription ? gf_list_count(mdia->information->sampleTable->SampleDescription->child_boxes) : 0;
733 5461 : for (i=0; i<count; i++) {
734 1827 : if (Media_IsSelfContained(mdia, i+1)) nb_self++;
735 3 : else nb_ext++;
736 : }
737 1817 : if (nb_ext==count) return ISOM_DREF_EXT;
738 1814 : if (nb_self==count) return ISOM_DREF_SELF;
739 0 : return ISOM_DREF_MIXED;
740 : }
741 :
742 :
743 :
744 : //look for a sync sample from a given point in media time
745 99 : GF_Err Media_FindSyncSample(GF_SampleTableBox *stbl, u32 searchFromSample, u32 *sampleNumber, u8 mode)
746 : {
747 : GF_ISOSAPType isRAP;
748 : u32 next, prev, next_in_sap, prev_in_sap;
749 99 : if (!stbl || !stbl->SyncSample) return GF_BAD_PARAM;
750 :
751 : //set to current sample if we don't find a RAP
752 99 : *sampleNumber = searchFromSample;
753 :
754 : //this is not the exact sample, but the prev move to next sample if enough samples....
755 99 : if ( (mode == GF_ISOM_SEARCH_SYNC_FORWARD) && (searchFromSample == stbl->SampleSize->sampleCount) ) {
756 : return GF_OK;
757 : }
758 99 : if ( (mode == GF_ISOM_SEARCH_SYNC_BACKWARD) && !searchFromSample) {
759 0 : *sampleNumber = 1;
760 0 : return GF_OK;
761 : }
762 : //get the entry
763 99 : stbl_GetSampleRAP(stbl->SyncSample, searchFromSample, &isRAP, &prev, &next);
764 99 : if (isRAP) {
765 42 : (*sampleNumber) = searchFromSample;
766 42 : return GF_OK;
767 : }
768 :
769 : /*check sample groups - prev & next are overwritten if RAP group is found, but are not re-initialized otherwise*/
770 57 : stbl_SearchSAPs(stbl, searchFromSample, &isRAP, &prev_in_sap, &next_in_sap);
771 57 : if (isRAP) {
772 0 : (*sampleNumber) = searchFromSample;
773 0 : return GF_OK;
774 : }
775 :
776 57 : if (prev_in_sap > prev)
777 0 : prev = prev_in_sap;
778 57 : if (next_in_sap && next_in_sap < next)
779 0 : next = next_in_sap;
780 :
781 : //nothing yet, go for next time...
782 57 : if (mode == GF_ISOM_SEARCH_SYNC_FORWARD) {
783 31 : if (next) *sampleNumber = next;
784 : } else {
785 26 : if (prev) *sampleNumber = prev;
786 : }
787 :
788 : return GF_OK;
789 : }
790 :
791 : //create a DataReference if not existing (only for WRITE-edit mode)
792 1580 : GF_Err Media_FindDataRef(GF_DataReferenceBox *dref, char *URLname, char *URNname, u32 *dataRefIndex)
793 : {
794 : u32 i;
795 : GF_DataEntryURLBox *entry;
796 :
797 1580 : if (!dref) return GF_BAD_PARAM;
798 1580 : *dataRefIndex = 0;
799 1580 : i=0;
800 3160 : while ((entry = (GF_DataEntryURLBox*)gf_list_enum(dref->child_boxes, &i))) {
801 29 : if (entry->type == GF_ISOM_BOX_TYPE_URL) {
802 : //self-contained case
803 29 : if (entry->flags == 1) {
804 : //if nothing specified, get the dataRef
805 29 : if (!URLname && !URNname) {
806 29 : *dataRefIndex = i;
807 29 : return GF_OK;
808 : }
809 : } else {
810 : //OK, check if we have URL
811 0 : if (URLname && !strcmp(URLname, entry->location)) {
812 0 : *dataRefIndex = i;
813 0 : return GF_OK;
814 : }
815 : }
816 : } else {
817 : //this is a URN one, only check the URN name (URL optional)
818 0 : if (URNname && !strcmp(URNname, ((GF_DataEntryURNBox *)entry)->nameURN)) {
819 0 : *dataRefIndex = i;
820 0 : return GF_OK;
821 : }
822 : }
823 : }
824 : return GF_OK;
825 : }
826 :
827 : //Get the total media duration based on the TimeToSample table
828 599556 : GF_Err Media_SetDuration(GF_TrackBox *trak)
829 : {
830 : GF_Err e;
831 : GF_ESD *esd;
832 : u64 DTS;
833 : GF_SttsEntry *ent;
834 : u32 nbSamp;
835 :
836 599556 : if (!trak || !trak->Media || !trak->Media->information || !trak->Media->information->sampleTable)
837 : return GF_ISOM_INVALID_FILE;
838 :
839 599556 : if (!trak->Media->information->sampleTable->SampleSize || !trak->Media->information->sampleTable->TimeToSample)
840 : return GF_ISOM_INVALID_FILE;
841 :
842 599556 : nbSamp = trak->Media->information->sampleTable->SampleSize->sampleCount;
843 :
844 : //we need to check how many samples we have.
845 : // == 1 -> last sample duration == default duration
846 : // > 1 -> last sample duration == prev sample duration
847 599556 : switch (nbSamp) {
848 3180 : case 0:
849 3180 : trak->Media->mediaHeader->duration = 0;
850 3180 : if (Track_IsMPEG4Stream(trak->Media->handler->handlerType)) {
851 3141 : Media_GetESD(trak->Media, 1, &esd, 1);
852 3141 : if (esd && esd->URLString) trak->Media->mediaHeader->duration = (u64) -1;
853 :
854 : }
855 : return GF_OK;
856 :
857 : // case 1:
858 : // trak->Media->mediaHeader->duration = trak->Media->mediaHeader->timeScale;
859 : // return GF_OK;
860 :
861 596376 : default:
862 : //we assume a constant frame rate for the media and assume the last sample
863 : //will be hold the same time as the prev one
864 596376 : e = stbl_GetSampleDTS(trak->Media->information->sampleTable->TimeToSample, nbSamp, &DTS);
865 596376 : if (e < 0) {
866 : return e;
867 : }
868 596376 : if (trak->Media->information->sampleTable->TimeToSample->nb_entries > 0) {
869 596376 : ent = &trak->Media->information->sampleTable->TimeToSample->entries[trak->Media->information->sampleTable->TimeToSample->nb_entries-1];
870 : } else {
871 : ent = NULL;
872 : }
873 596376 : trak->Media->mediaHeader->duration = DTS;
874 :
875 :
876 : #if 1
877 596376 : if (ent) trak->Media->mediaHeader->duration += ent->sampleDelta;
878 : #else
879 : if (!ent) {
880 : u64 DTSprev;
881 : stbl_GetSampleDTS(trak->Media->information->sampleTable->TimeToSample, nbSamp-1, &DTSprev);
882 : trak->Media->mediaHeader->duration += (DTS - DTSprev);
883 : } else {
884 : #ifndef GPAC_DISABLE_ISOM_WRITE
885 : if (trak->moov->mov->editFileMap && trak->Media->information->sampleTable->CompositionOffset) {
886 : u32 count, i;
887 : u64 max_ts;
888 : GF_DttsEntry *cts_ent;
889 : GF_CompositionOffsetBox *ctts = trak->Media->information->sampleTable->CompositionOffset;
890 : if (ctts->w_LastSampleNumber==nbSamp) {
891 : count = gf_list_count(ctts->entryList);
892 : max_ts = trak->Media->mediaHeader->duration;
893 : while (count) {
894 : count -= 1;
895 : cts_ent = gf_list_get(ctts->entryList, count);
896 : if (nbSamp<cts_ent->sampleCount) break;
897 :
898 : for (i=0; i<cts_ent->sampleCount; i++) {
899 : stbl_GetSampleDTS(trak->Media->information->sampleTable->TimeToSample, nbSamp-i, &DTS);
900 : if ((s32) cts_ent->decodingOffset < 0) max_ts = DTS;
901 : else max_ts = DTS + cts_ent->decodingOffset;
902 : if (max_ts>=trak->Media->mediaHeader->duration) {
903 : trak->Media->mediaHeader->duration = max_ts;
904 : } else {
905 : break;
906 : }
907 : }
908 : if (max_ts<trak->Media->mediaHeader->duration) {
909 : break;
910 : }
911 : nbSamp-=cts_ent->sampleCount;
912 : }
913 : }
914 : }
915 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
916 : trak->Media->mediaHeader->duration += ent->sampleDelta;
917 : }
918 : #endif
919 : return GF_OK;
920 : }
921 : }
922 :
923 :
924 :
925 :
926 : #ifndef GPAC_DISABLE_ISOM_WRITE
927 :
928 3 : GF_Err Media_SetDrefURL(GF_DataEntryURLBox *dref_entry, const char *origName, const char *finalName)
929 : {
930 : //for now we only support dref created in same folder for relative URLs
931 3 : if (strstr(origName, "://") || ((origName[1]==':') && (origName[2]=='\\'))
932 3 : || (origName[0]=='/') || (origName[0]=='\\')
933 : ) {
934 0 : dref_entry->location = gf_strdup(origName);
935 : } else {
936 3 : char *fname = strrchr(origName, '/');
937 3 : if (!fname) fname = strrchr(origName, '\\');
938 3 : if (fname) fname++;
939 :
940 3 : if (!fname) {
941 0 : dref_entry->location = gf_strdup(origName);
942 : } else {
943 3 : u32 len = (u32) (fname - origName);
944 3 : if (!finalName || strncmp(origName, finalName, len)) {
945 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Concatenation of relative path %s with relative path %s not supported, use absolute URLs\n", origName, finalName));
946 : return GF_NOT_SUPPORTED;
947 : } else {
948 3 : dref_entry->location = gf_strdup(fname);
949 : }
950 : }
951 : }
952 : return GF_OK;
953 : }
954 :
955 :
956 1726 : GF_Err Media_CreateDataRef(GF_ISOFile *movie, GF_DataReferenceBox *dref, char *URLname, char *URNname, u32 *dataRefIndex)
957 : {
958 : GF_Err e;
959 : Bool use_alis=GF_FALSE;
960 : GF_DataEntryURLBox *entry;
961 :
962 1726 : if (URLname && !strcmp(URLname, "alis")) {
963 : URLname = NULL;
964 : use_alis=GF_TRUE;
965 : }
966 :
967 1726 : if (!URLname && !URNname) {
968 : //THIS IS SELF CONTAIN, create a regular entry if needed
969 1726 : entry = (GF_DataEntryURLBox *) gf_isom_box_new_parent(&dref->child_boxes, use_alis ? GF_QT_BOX_TYPE_ALIS : GF_ISOM_BOX_TYPE_URL);
970 1726 : if (!entry) return GF_OUT_OF_MEM;
971 1726 : entry->flags = 1;
972 1726 : *dataRefIndex = gf_list_count(dref->child_boxes);
973 1726 : return GF_OK;
974 0 : } else if (!URNname && URLname) {
975 : //THIS IS URL
976 0 : entry = (GF_DataEntryURLBox *) gf_isom_box_new_parent(&dref->child_boxes, GF_ISOM_BOX_TYPE_URL);
977 0 : if (!entry) return GF_OUT_OF_MEM;
978 0 : entry->flags = 0;
979 :
980 0 : e = Media_SetDrefURL(entry, URLname, movie->fileName ? movie->fileName : movie->finalName);
981 0 : if (! entry->location) {
982 0 : gf_isom_box_del_parent(&dref->child_boxes, (GF_Box *)entry);
983 0 : return e ? e : GF_OUT_OF_MEM;
984 : }
985 0 : *dataRefIndex = gf_list_count(dref->child_boxes);
986 0 : return GF_OK;
987 : } else {
988 : //THIS IS URN
989 0 : entry = (GF_DataEntryURLBox *) gf_isom_box_new_parent(&dref->child_boxes, GF_ISOM_BOX_TYPE_URN);
990 0 : if (!entry) return GF_OUT_OF_MEM;
991 0 : ((GF_DataEntryURNBox *)entry)->flags = 0;
992 0 : ((GF_DataEntryURNBox *)entry)->nameURN = (char*)gf_malloc(strlen(URNname)+1);
993 0 : if (! ((GF_DataEntryURNBox *)entry)->nameURN) {
994 0 : gf_isom_box_del_parent(&dref->child_boxes, (GF_Box *)entry);
995 0 : return GF_OUT_OF_MEM;
996 : }
997 : strcpy(((GF_DataEntryURNBox *)entry)->nameURN, URNname);
998 : //check for URL
999 0 : if (URLname) {
1000 0 : ((GF_DataEntryURNBox *)entry)->location = (char*)gf_malloc(strlen(URLname)+1);
1001 0 : if (! ((GF_DataEntryURNBox *)entry)->location) {
1002 0 : gf_isom_box_del_parent(&dref->child_boxes, (GF_Box *)entry);
1003 0 : return GF_OUT_OF_MEM;
1004 : }
1005 : strcpy(((GF_DataEntryURNBox *)entry)->location, URLname);
1006 : }
1007 0 : *dataRefIndex = gf_list_count(dref->child_boxes);
1008 0 : return GF_OK;
1009 : }
1010 : return GF_OK;
1011 : }
1012 :
1013 :
1014 556713 : GF_Err Media_AddSample(GF_MediaBox *mdia, u64 data_offset, const GF_ISOSample *sample, u32 StreamDescIndex, u32 syncShadowNumber)
1015 : {
1016 : GF_Err e;
1017 : GF_SampleTableBox *stbl;
1018 : u32 sampleNumber, i;
1019 556713 : if (!mdia || !sample) return GF_BAD_PARAM;
1020 :
1021 556713 : stbl = mdia->information->sampleTable;
1022 :
1023 : //get a valid sampleNumber for this new guy
1024 556713 : e = stbl_AddDTS(stbl, sample->DTS, &sampleNumber, mdia->mediaHeader->timeScale, sample->nb_pack);
1025 556713 : if (e) return e;
1026 :
1027 : //add size
1028 556713 : e = stbl_AddSize(stbl->SampleSize, sampleNumber, sample->dataLength, sample->nb_pack);
1029 556713 : if (e) return e;
1030 :
1031 : //adds CTS offset
1032 556713 : if (sample->CTS_Offset) {
1033 : //if we don't have a CTS table, add it...
1034 116782 : if (!stbl->CompositionOffset) {
1035 296 : stbl->CompositionOffset = (GF_CompositionOffsetBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_CTTS);
1036 296 : if (!stbl->CompositionOffset) return GF_OUT_OF_MEM;
1037 : }
1038 : //then add our CTS (the prev samples with no CTS offset will be automatically added...
1039 116782 : e = stbl_AddCTS(stbl, sampleNumber, sample->CTS_Offset);
1040 116782 : if (e) return e;
1041 439931 : } else if (stbl->CompositionOffset) {
1042 35220 : e = stbl_AddCTS(stbl, sampleNumber, sample->CTS_Offset);
1043 35220 : if (e) return e;
1044 : }
1045 :
1046 : //The first non sync sample we see must create a syncTable
1047 556713 : if (sample->IsRAP) {
1048 : //insert it only if we have a sync table and if we have an IDR slice
1049 218642 : if (stbl->SyncSample && (sample->IsRAP == RAP)) {
1050 11409 : e = stbl_AddRAP(stbl->SyncSample, sampleNumber);
1051 11409 : if (e) return e;
1052 : }
1053 : } else {
1054 : //non-sync sample. Create a SyncSample table if needed
1055 338071 : if (!stbl->SyncSample) {
1056 708 : stbl->SyncSample = (GF_SyncSampleBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSS);
1057 708 : if (!stbl->SyncSample) return GF_OUT_OF_MEM;
1058 : //all the prev samples are sync
1059 2108 : for (i=0; i<stbl->SampleSize->sampleCount; i++) {
1060 1400 : if (i+1 != sampleNumber) {
1061 692 : e = stbl_AddRAP(stbl->SyncSample, i+1);
1062 692 : if (e) return e;
1063 : }
1064 : }
1065 : }
1066 : }
1067 556713 : if (sample->IsRAP==RAP_REDUNDANT) {
1068 0 : e = stbl_AddRedundant(stbl, sampleNumber);
1069 0 : if (e) return e;
1070 : }
1071 :
1072 556713 : if (!mdia->mediaTrack->chunk_cache) {
1073 : //and update the chunks
1074 555707 : e = stbl_AddChunkOffset(mdia, sampleNumber, StreamDescIndex, data_offset, sample->nb_pack);
1075 555707 : if (e) return e;
1076 : }
1077 :
1078 556713 : if (!syncShadowNumber) return GF_OK;
1079 12 : if (!stbl->ShadowSync) {
1080 6 : stbl->ShadowSync = (GF_ShadowSyncBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSH);
1081 6 : if (!stbl->ShadowSync) return GF_OUT_OF_MEM;
1082 : }
1083 12 : return stbl_AddShadow(mdia->information->sampleTable->ShadowSync, sampleNumber, syncShadowNumber);
1084 : }
1085 :
1086 :
1087 0 : static GF_Err UpdateSample(GF_MediaBox *mdia, u32 sampleNumber, u32 size, s32 CTS, u64 offset, u8 isRap)
1088 : {
1089 : u32 i;
1090 0 : GF_SampleTableBox *stbl = mdia->information->sampleTable;
1091 :
1092 : //set size, offset, RAP, CTS ...
1093 0 : stbl_SetSampleSize(stbl->SampleSize, sampleNumber, size);
1094 0 : stbl_SetChunkOffset(mdia, sampleNumber, offset);
1095 :
1096 : //do we have a CTS?
1097 0 : if (stbl->CompositionOffset) {
1098 0 : stbl_SetSampleCTS(stbl, sampleNumber, CTS);
1099 : } else {
1100 : //do we need one ??
1101 0 : if (CTS) {
1102 0 : stbl->CompositionOffset = (GF_CompositionOffsetBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_CTTS);
1103 0 : if (!stbl->CompositionOffset) return GF_OUT_OF_MEM;
1104 0 : stbl_AddCTS(stbl, sampleNumber, CTS);
1105 : }
1106 : }
1107 : //do we have a sync ???
1108 0 : if (stbl->SyncSample) {
1109 0 : stbl_SetSampleRAP(stbl->SyncSample, sampleNumber, isRap);
1110 : } else {
1111 : //do we need one
1112 0 : if (! isRap) {
1113 0 : stbl->SyncSample = (GF_SyncSampleBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSS);
1114 0 : if (!stbl->SyncSample) return GF_OUT_OF_MEM;
1115 : //what a pain: all the sample we had have to be sync ...
1116 0 : for (i=0; i<stbl->SampleSize->sampleCount; i++) {
1117 0 : if (i+1 != sampleNumber) stbl_AddRAP(stbl->SyncSample, i+1);
1118 : }
1119 : }
1120 : }
1121 0 : if (isRap==2) {
1122 0 : stbl_SetRedundant(stbl, sampleNumber);
1123 : }
1124 : return GF_OK;
1125 : }
1126 :
1127 4677 : GF_Err Media_UpdateSample(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample *sample, Bool data_only)
1128 : {
1129 : GF_Err e;
1130 : u32 drefIndex, chunkNum, descIndex;
1131 : u64 newOffset, DTS;
1132 : GF_DataEntryURLBox *Dentry;
1133 : GF_SampleTableBox *stbl;
1134 :
1135 4677 : if (!mdia || !sample || !sampleNumber || !mdia->mediaTrack->moov->mov->editFileMap)
1136 : return GF_BAD_PARAM;
1137 :
1138 4677 : stbl = mdia->information->sampleTable;
1139 :
1140 4677 : if (!data_only) {
1141 : //check we have the sampe dts
1142 0 : e = stbl_GetSampleDTS(stbl->TimeToSample, sampleNumber, &DTS);
1143 0 : if (e) return e;
1144 0 : if (DTS != sample->DTS) return GF_BAD_PARAM;
1145 : }
1146 :
1147 : //get our infos
1148 4677 : stbl_GetSampleInfos(stbl, sampleNumber, &newOffset, &chunkNum, &descIndex, NULL);
1149 :
1150 : //then check the data ref
1151 4677 : e = Media_GetSampleDesc(mdia, descIndex, NULL, &drefIndex);
1152 4677 : if (e) return e;
1153 4677 : Dentry = (GF_DataEntryURLBox*)gf_list_get(mdia->information->dataInformation->dref->child_boxes, drefIndex - 1);
1154 4677 : if (!Dentry) return GF_ISOM_INVALID_FILE;
1155 :
1156 4677 : if (Dentry->flags != 1) return GF_BAD_PARAM;
1157 :
1158 : //MEDIA DATA EDIT: write this new sample to the edit temp file
1159 4677 : newOffset = gf_isom_datamap_get_offset(mdia->mediaTrack->moov->mov->editFileMap);
1160 4677 : if (sample->dataLength) {
1161 4677 : e = gf_isom_datamap_add_data(mdia->mediaTrack->moov->mov->editFileMap, sample->data, sample->dataLength);
1162 4677 : if (e) return e;
1163 : }
1164 :
1165 4677 : if (data_only) {
1166 4677 : stbl_SetSampleSize(stbl->SampleSize, sampleNumber, sample->dataLength);
1167 4677 : return stbl_SetChunkOffset(mdia, sampleNumber, newOffset);
1168 : }
1169 0 : return UpdateSample(mdia, sampleNumber, sample->dataLength, sample->CTS_Offset, newOffset, sample->IsRAP);
1170 : }
1171 :
1172 0 : GF_Err Media_UpdateSampleReference(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample *sample, u64 data_offset)
1173 : {
1174 : GF_Err e;
1175 : u32 drefIndex, chunkNum, descIndex;
1176 : u64 off, DTS;
1177 : GF_DataEntryURLBox *Dentry;
1178 : GF_SampleTableBox *stbl;
1179 :
1180 0 : if (!mdia) return GF_BAD_PARAM;
1181 0 : stbl = mdia->information->sampleTable;
1182 :
1183 : //check we have the sampe dts
1184 0 : e = stbl_GetSampleDTS(stbl->TimeToSample, sampleNumber, &DTS);
1185 0 : if (e) return e;
1186 0 : if (DTS != sample->DTS) return GF_BAD_PARAM;
1187 :
1188 : //get our infos
1189 0 : stbl_GetSampleInfos(stbl, sampleNumber, &off, &chunkNum, &descIndex, NULL);
1190 :
1191 : //then check the data ref
1192 0 : e = Media_GetSampleDesc(mdia, descIndex, NULL, &drefIndex);
1193 0 : if (e) return e;
1194 0 : Dentry = (GF_DataEntryURLBox*)gf_list_get(mdia->information->dataInformation->dref->child_boxes, drefIndex - 1);
1195 0 : if (!Dentry) return GF_ISOM_INVALID_FILE;
1196 :
1197 : //we only modify self-contained data
1198 0 : if (Dentry->flags == 1) return GF_ISOM_INVALID_MODE;
1199 :
1200 : //and we don't modify the media data
1201 0 : return UpdateSample(mdia, sampleNumber, sample->dataLength, sample->CTS_Offset, data_offset, sample->IsRAP);
1202 : }
1203 :
1204 :
1205 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
1206 :
1207 : #endif /*GPAC_DISABLE_ISOM*/
|