Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2020
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 :
29 : #ifndef GPAC_DISABLE_ISOM
30 :
31 56 : GF_TrackBox *GetTrackbyID(GF_MovieBox *moov, GF_ISOTrackID TrackID)
32 : {
33 : GF_TrackBox *trak;
34 : u32 i;
35 56 : if (!moov) return NULL;
36 56 : i=0;
37 139 : while ((trak = (GF_TrackBox *)gf_list_enum(moov->trackList, &i))) {
38 81 : if (trak->Header->trackID == TrackID) return trak;
39 : }
40 : return NULL;
41 : }
42 :
43 6158961 : GF_TrackBox *gf_isom_get_track(GF_MovieBox *moov, u32 trackNumber)
44 : {
45 : GF_TrackBox *trak;
46 6158961 : if (!moov || !trackNumber || (trackNumber > gf_list_count(moov->trackList))) return NULL;
47 6157736 : trak = (GF_TrackBox*)gf_list_get(moov->trackList, trackNumber - 1);
48 6157736 : return trak;
49 :
50 : }
51 :
52 : //get the number of a track given its ID
53 : //return 0 if not found error
54 101153 : u32 gf_isom_get_tracknum_from_id(GF_MovieBox *moov, GF_ISOTrackID trackID)
55 : {
56 : u32 i;
57 : GF_TrackBox *trak;
58 101153 : i=0;
59 346954 : while ((trak = (GF_TrackBox *)gf_list_enum(moov->trackList, &i))) {
60 245801 : if (trak->Header->trackID == trackID) return i;
61 : }
62 : return 0;
63 : }
64 :
65 : //extraction of the ESD from the track
66 1902 : GF_Err GetESD(GF_MovieBox *moov, GF_ISOTrackID trackID, u32 StreamDescIndex, GF_ESD **outESD)
67 : {
68 : GF_Err e;
69 : GF_ESD *esd;
70 : u32 track_num = 0;
71 : u32 k;
72 : GF_SampleTableBox *stbl;
73 : GF_TrackBox *trak, *OCRTrack;
74 : GF_TrackReferenceTypeBox *dpnd;
75 : GF_SLConfig *slc;
76 : GF_MPEGSampleEntryBox *entry;
77 :
78 1902 : if (!moov) return GF_ISOM_INVALID_FILE;
79 :
80 1902 : track_num = gf_isom_get_tracknum_from_id(moov, trackID);
81 1902 : dpnd = NULL;
82 1902 : *outESD = NULL;
83 :
84 1902 : trak = gf_isom_get_track(moov, track_num);
85 1902 : if (!trak) return GF_ISOM_INVALID_FILE;
86 :
87 1902 : e = Media_GetESD(trak->Media, StreamDescIndex, &esd, 0);
88 1902 : if (e) return e;
89 1781 : if (!esd) return GF_NON_COMPLIANT_BITSTREAM;
90 :
91 1781 : e = Media_GetSampleDesc(trak->Media, StreamDescIndex, (GF_SampleEntryBox **) &entry, NULL);
92 1781 : if (e) return e;
93 : //set the ID
94 1781 : esd->ESID = trackID;
95 :
96 : //find stream dependencies: dpnd, sbas and scal
97 7085 : for (k=0; k<3; k++) {
98 : u32 ref = GF_ISOM_BOX_TYPE_DPND;
99 5325 : if (k==1) ref = GF_ISOM_REF_BASE;
100 3544 : else if (k==2) ref = GF_ISOM_REF_SCAL;
101 :
102 5325 : e = Track_FindRef(trak, ref , &dpnd);
103 5325 : if (e) return e;
104 5325 : if (dpnd) {
105 : //ONLY ONE STREAM DEPENDENCY IS ALLOWED
106 21 : if (!k && (dpnd->trackIDCount != 1)) return GF_ISOM_INVALID_MEDIA;
107 : //fix the spec: where is the index located ??
108 21 : esd->dependsOnESID = dpnd->trackIDs[0];
109 21 : break;
110 : } else {
111 5304 : esd->dependsOnESID = 0;
112 : }
113 : }
114 :
115 1781 : if (trak->udta) {
116 : GF_UserDataMap *map;
117 9 : u32 i = 0;
118 25 : while ((map = (GF_UserDataMap*)gf_list_enum(trak->udta->recordList, &i))) {
119 9 : if (map->boxType == GF_ISOM_BOX_TYPE_AUXV) {
120 2 : GF_Descriptor *d = gf_odf_desc_new(GF_ODF_AUX_VIDEO_DATA);
121 2 : gf_list_add(esd->extensionDescriptors, d);
122 2 : break;
123 : }
124 : }
125 : }
126 :
127 : //OK, get the OCR (in a REAL MP4File, OCR is 0 in ESD and is specified through track reference
128 1781 : dpnd = NULL;
129 : OCRTrack = NULL;
130 : //find OCR dependencies
131 1781 : e = Track_FindRef(trak, GF_ISOM_BOX_TYPE_SYNC, &dpnd);
132 1781 : if (e) return e;
133 1781 : if (dpnd) {
134 58 : if (dpnd->trackIDCount != 1) return GF_ISOM_INVALID_MEDIA;
135 58 : esd->OCRESID = dpnd->trackIDs[0];
136 58 : OCRTrack = gf_isom_get_track_from_id(trak->moov, dpnd->trackIDs[0]);
137 :
138 116 : while (OCRTrack) {
139 : /*if we have a dependency on a track that doesn't have OCR dep, remove that dependency*/
140 58 : e = Track_FindRef(OCRTrack, GF_ISOM_BOX_TYPE_SYNC, &dpnd);
141 58 : if (e || !dpnd || !dpnd->trackIDCount) {
142 : OCRTrack = NULL;
143 : goto default_sync;
144 : }
145 : /*this is explicit desync*/
146 46 : if ((dpnd->trackIDs[0]==0) || (dpnd->trackIDs[0]==OCRTrack->Header->trackID))
147 : break;
148 : /*loop in OCRs, break it*/
149 0 : if (esd->ESID == (u16) OCRTrack->Header->trackID) {
150 : OCRTrack = NULL;
151 : goto default_sync;
152 : }
153 : /*check next*/
154 0 : OCRTrack = gf_isom_get_track_from_id(trak->moov, dpnd->trackIDs[0]);
155 : }
156 46 : if (!OCRTrack) goto default_sync;
157 : } else {
158 1723 : default_sync:
159 : /*all tracks are sync'ed by default*/
160 1735 : if (trak->moov->mov->es_id_default_sync<0) {
161 1118 : if (esd->OCRESID)
162 0 : trak->moov->mov->es_id_default_sync = esd->OCRESID;
163 : else
164 1118 : trak->moov->mov->es_id_default_sync = esd->ESID;
165 : }
166 1735 : if (trak->moov->mov->es_id_default_sync) esd->OCRESID = (u16) trak->moov->mov->es_id_default_sync;
167 : /*cf ESD writer*/
168 1735 : if (esd->OCRESID == esd->ESID) esd->OCRESID = 0;
169 : }
170 :
171 :
172 :
173 : //update the IPI stuff if needed
174 1781 : if (esd->ipiPtr != NULL) {
175 0 : dpnd = NULL;
176 0 : e = Track_FindRef(trak, GF_ISOM_BOX_TYPE_IPIR, &dpnd);
177 0 : if (e) return e;
178 0 : if (dpnd) {
179 0 : if (esd->ipiPtr->tag != GF_ODF_ISOM_IPI_PTR_TAG) return GF_ISOM_INVALID_FILE;
180 : //OK, retrieve the ID: the IPI_ES_Id is currently the ref track
181 0 : esd->ipiPtr->IPI_ES_Id = dpnd->trackIDs[esd->ipiPtr->IPI_ES_Id - 1];
182 : //and change the tag
183 0 : esd->ipiPtr->tag = GF_ODF_IPI_PTR_TAG;
184 : } else {
185 : return GF_ISOM_INVALID_FILE;
186 : }
187 : }
188 :
189 3562 : if ((trak->Media->mediaHeader->packedLanguage[0] != 'u')
190 1781 : || (trak->Media->mediaHeader->packedLanguage[1] != 'n')
191 1757 : || (trak->Media->mediaHeader->packedLanguage[2] != 'd') ) {
192 24 : if (!esd->langDesc) esd->langDesc = (GF_Language *) gf_odf_desc_new(GF_ODF_LANG_TAG);
193 :
194 24 : esd->langDesc->langCode = trak->Media->mediaHeader->packedLanguage[0];
195 24 : esd->langDesc->langCode <<= 8;
196 24 : esd->langDesc->langCode |= trak->Media->mediaHeader->packedLanguage[1];
197 24 : esd->langDesc->langCode <<= 8;
198 24 : esd->langDesc->langCode |= trak->Media->mediaHeader->packedLanguage[2];
199 : }
200 :
201 :
202 : {
203 : u16 rvc_predefined;
204 : u8 *rvc_cfg_data;
205 : const char *mime_type;
206 : u32 rvc_cfg_size;
207 1781 : e = gf_isom_get_rvc_config(moov->mov, track_num, 1, &rvc_predefined, &rvc_cfg_data, &rvc_cfg_size, &mime_type);
208 1781 : if (e==GF_OK) {
209 0 : if (rvc_predefined) {
210 0 : esd->decoderConfig->predefined_rvc_config = rvc_predefined;
211 : } else {
212 0 : esd->decoderConfig->rvc_config = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG);
213 0 : if (mime_type && !strcmp(mime_type, "application/rvc-config+xml+gz") ) {
214 : #if !defined(GPAC_DISABLE_CORE_TOOLS) && !defined(GPAC_DISABLE_ZLIB)
215 0 : gf_gz_decompress_payload(rvc_cfg_data, rvc_cfg_size, &esd->decoderConfig->rvc_config->data, &esd->decoderConfig->rvc_config->dataLength);
216 0 : gf_free(rvc_cfg_data);
217 : #endif
218 : } else {
219 0 : esd->decoderConfig->rvc_config->data = rvc_cfg_data;
220 0 : esd->decoderConfig->rvc_config->dataLength = rvc_cfg_size;
221 : }
222 : }
223 : }
224 : }
225 :
226 :
227 : /*normally all files shall be stored with predefined=SLPredef_MP4, but of course some are broken (philips)
228 : so we just check the ESD_URL. If set, use the given cfg, otherwise always rewrite it*/
229 1781 : if (esd->URLString != NULL) {
230 0 : *outESD = esd;
231 0 : return GF_OK;
232 : }
233 :
234 : //if we are in publishing mode and we have an SLConfig specified, use it as is
235 1781 : switch (entry->type) {
236 218 : case GF_ISOM_BOX_TYPE_MP4V:
237 218 : slc = ((GF_MPEGVisualSampleEntryBox *)entry)->slc;
238 218 : break;
239 322 : case GF_ISOM_BOX_TYPE_MP4A:
240 322 : slc = ((GF_MPEGAudioSampleEntryBox *)entry)->slc;
241 322 : break;
242 273 : case GF_ISOM_BOX_TYPE_MP4S:
243 273 : slc = entry->slc;
244 273 : break;
245 : default:
246 : slc = NULL;
247 : break;
248 : }
249 813 : if (slc) {
250 103 : gf_odf_desc_del((GF_Descriptor *)esd->slConfig);
251 103 : gf_odf_desc_copy((GF_Descriptor *)slc, (GF_Descriptor **)&esd->slConfig);
252 103 : *outESD = esd;
253 103 : return GF_OK;
254 : }
255 : //otherwise use the regular mapping
256 :
257 1678 : if (!esd->slConfig)
258 0 : esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG);
259 :
260 : //this is a desc for a media in the file, let's rewrite some param
261 1678 : esd->slConfig->timestampLength = 32;
262 1678 : esd->slConfig->timestampResolution = trak->Media->mediaHeader->timeScale;
263 : //NO OCR from MP4File streams (eg, constant OC Res one)
264 1678 : esd->slConfig->OCRLength = 0;
265 1678 : esd->slConfig->OCRResolution = 0;
266 : // if (OCRTrack) esd->slConfig->OCRResolution = OCRTrack->Media->mediaHeader->timeScale;
267 :
268 1678 : stbl = trak->Media->information->sampleTable;
269 : // a little optimization here: if all our samples are sync,
270 : //set the RAPOnly to true... for external users...
271 1678 : if (! stbl->SyncSample) {
272 781 : if (
273 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
274 1003 : moov->mvex &&
275 : #endif
276 444 : esd->decoderConfig && esd->decoderConfig->streamType &&
277 : (esd->decoderConfig->streamType==GF_STREAM_VISUAL)
278 : ) {
279 160 : esd->slConfig->hasRandomAccessUnitsOnlyFlag = 0;
280 160 : esd->slConfig->useRandomAccessPointFlag = 1;
281 160 : if (trak->moov->mov->openMode!=GF_ISOM_OPEN_READ) {
282 0 : stbl->SyncSample = (GF_SyncSampleBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSS);
283 0 : if (!stbl->SyncSample) return GF_OUT_OF_MEM;
284 : }
285 : } else {
286 621 : esd->slConfig->hasRandomAccessUnitsOnlyFlag = 1;
287 621 : esd->slConfig->useRandomAccessPointFlag = 0;
288 : }
289 : } else {
290 897 : esd->slConfig->hasRandomAccessUnitsOnlyFlag = 0;
291 : //signal we are NOT using sync points if no info is present in the table
292 897 : esd->slConfig->useRandomAccessPointFlag = stbl->SyncSample->nb_entries ? 1 : 0;
293 : }
294 : //change to support reflecting OD streams
295 1678 : esd->slConfig->useAccessUnitEndFlag = 1;
296 1678 : esd->slConfig->useAccessUnitStartFlag = 1;
297 :
298 : //signal we do have padding flag (since we only use logical SL packet
299 : //the user can decide whether to use the info or not
300 1678 : esd->slConfig->usePaddingFlag = stbl->PaddingBits ? 1 : 0;
301 :
302 : //same with degradation priority
303 1678 : esd->slConfig->degradationPriorityLength = stbl->DegradationPriority ? 32 : 0;
304 :
305 : //this new SL will be OUT OF THE FILE. Let's set its predefined to 0
306 1678 : esd->slConfig->predefined = 0;
307 :
308 :
309 1678 : *outESD = esd;
310 1678 : return GF_OK;
311 : }
312 :
313 :
314 : //extraction of the ESD from the track for the given time
315 187 : GF_Err GetESDForTime(GF_MovieBox *moov, GF_ISOTrackID trackID, u64 CTS, GF_ESD **outESD)
316 : {
317 : GF_Err e;
318 : u32 sampleDescIndex;
319 : GF_TrackBox *trak;
320 :
321 187 : trak = gf_isom_get_track(moov, gf_isom_get_tracknum_from_id(moov, trackID));
322 187 : if (!trak) return GF_ISOM_INVALID_FILE;
323 :
324 187 : e = Media_GetSampleDescIndex(trak->Media, CTS, &sampleDescIndex );
325 187 : if (e) return e;
326 187 : return GetESD(moov, trackID, sampleDescIndex, outESD);
327 : }
328 :
329 :
330 619935 : GF_Err Track_FindRef(GF_TrackBox *trak, u32 ReferenceType, GF_TrackReferenceTypeBox **dpnd)
331 : {
332 : GF_TrackReferenceBox *ref;
333 : GF_TrackReferenceTypeBox *a;
334 : u32 i;
335 619935 : if (! trak) return GF_BAD_PARAM;
336 619935 : if (! trak->References) {
337 223779 : *dpnd = NULL;
338 223779 : return GF_OK;
339 : }
340 : ref = trak->References;
341 396156 : i=0;
342 924034 : while ((a = (GF_TrackReferenceTypeBox *)gf_list_enum(ref->child_boxes, &i))) {
343 407498 : if (a->reference_type == ReferenceType) {
344 275776 : *dpnd = a;
345 275776 : return GF_OK;
346 : }
347 : }
348 120380 : *dpnd = NULL;
349 120380 : return GF_OK;
350 : }
351 :
352 3792 : Bool Track_IsMPEG4Stream(u32 HandlerType)
353 : {
354 3792 : switch (HandlerType) {
355 : case GF_ISOM_MEDIA_VISUAL:
356 : case GF_ISOM_MEDIA_AUXV:
357 : case GF_ISOM_MEDIA_PICT:
358 : case GF_ISOM_MEDIA_AUDIO:
359 : case GF_ISOM_MEDIA_SUBPIC:
360 : case GF_ISOM_MEDIA_OD:
361 : case GF_ISOM_MEDIA_OCR:
362 : case GF_ISOM_MEDIA_SCENE:
363 : case GF_ISOM_MEDIA_MPEG7:
364 : case GF_ISOM_MEDIA_OCI:
365 : case GF_ISOM_MEDIA_IPMP:
366 : case GF_ISOM_MEDIA_MPEGJ:
367 : case GF_ISOM_MEDIA_ESM:
368 : return 1;
369 : /*Timedtext is NOT an MPEG-4 stream*/
370 40 : default:
371 : /*consider xxsm as MPEG-4 handlers*/
372 40 : if ( (((HandlerType>>8) & 0xFF)== 's') && ((HandlerType& 0xFF)== 'm'))
373 : return 1;
374 40 : return 0;
375 : }
376 : }
377 :
378 :
379 586785 : GF_Err SetTrackDuration(GF_TrackBox *trak)
380 : {
381 : u64 trackDuration;
382 : u32 i;
383 : GF_Err e;
384 :
385 : //the total duration is the media duration: adjust it in case...
386 586785 : e = Media_SetDuration(trak);
387 586785 : if (e) return e;
388 :
389 : //assert the timeScales are non-NULL
390 586785 : if (!trak->moov->mvhd || !trak->moov->mvhd->timeScale || !trak->Media->mediaHeader->timeScale) return GF_ISOM_INVALID_FILE;
391 586785 : trackDuration = (trak->Media->mediaHeader->duration * trak->moov->mvhd->timeScale) / trak->Media->mediaHeader->timeScale;
392 :
393 : //if we have an edit list, the duration is the sum of all the editList
394 : //entries' duration (always expressed in MovieTimeScale)
395 586785 : if (trak->editBox && trak->editBox->editList) {
396 : GF_EdtsEntry *ent;
397 : GF_EditListBox *elst = trak->editBox->editList;
398 : trackDuration = 0;
399 30863 : i=0;
400 104135 : while ((ent = (GF_EdtsEntry*)gf_list_enum(elst->entryList, &i))) {
401 42409 : trackDuration += ent->segmentDuration;
402 : }
403 : }
404 586785 : if (!trackDuration) {
405 12889 : trackDuration = (trak->Media->mediaHeader->duration * trak->moov->mvhd->timeScale) / trak->Media->mediaHeader->timeScale;
406 : }
407 586785 : if (!trak->Header) {
408 : return GF_OK;
409 : }
410 586785 : trak->Header->duration = trackDuration;
411 586785 : if (!trak->moov->mov->keep_utc && !gf_sys_is_test_mode() )
412 746 : trak->Header->modificationTime = gf_isom_get_mp4time();
413 : return GF_OK;
414 : }
415 :
416 :
417 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
418 :
419 : #ifdef GF_ENABLE_CTRN
420 : GF_TrunEntry *traf_get_sample_entry(GF_TrackFragmentBox *traf, u32 sample_index)
421 : {
422 : u32 i, idx;
423 : GF_TrackFragmentRunBox *trun;
424 : idx=0;
425 : i=0;
426 : while ((trun = (GF_TrackFragmentRunBox *)gf_list_enum(traf->TrackRuns, &i))) {
427 : u32 j;
428 : for (j=0; j<trun->sample_count; j++) {
429 : GF_TrunEntry *ent = gf_list_get(trun->entries, j);
430 : if (idx==sample_index) return ent;
431 : if (ent->nb_pack>1) {
432 : if (idx < sample_index + ent->nb_pack)
433 : return ent;
434 : idx += ent->nb_pack;
435 : } else {
436 : idx++;
437 : }
438 : }
439 : }
440 : return NULL;
441 : }
442 : #endif
443 :
444 :
445 4079 : GF_Err MergeTrack(GF_TrackBox *trak, GF_TrackFragmentBox *traf, GF_MovieFragmentBox *moof_box, u64 moof_offset, s32 compressed_diff, u64 *cumulated_offset, Bool is_first_merge)
446 : {
447 : u32 i, j, chunk_size, track_num;
448 : u64 base_offset, data_offset, traf_duration;
449 : u32 def_duration, DescIndex, def_size, def_flags;
450 : u32 duration, size, flags, prev_trun_data_offset, sample_index;
451 : u8 pad, sync;
452 : u16 degr;
453 : Bool first_samp_in_traf=GF_TRUE;
454 : Bool store_traf_map=GF_FALSE;
455 4079 : u8 *moof_template=NULL;
456 4079 : u32 moof_template_size=0;
457 : Bool is_seg_start = GF_FALSE;
458 : u64 seg_start=0, sidx_start=0, sidx_end=0, frag_start=0, last_dts=0;
459 : GF_TrackFragmentRunBox *trun;
460 : GF_TrunEntry *ent;
461 : #ifdef GF_ENABLE_CTRN
462 : GF_TrackFragmentBox *traf_ref = NULL;
463 : #endif
464 :
465 : GF_Err stbl_AppendTime(GF_SampleTableBox *stbl, u32 duration, u32 nb_pack);
466 : GF_Err stbl_AppendSize(GF_SampleTableBox *stbl, u32 size, u32 nb_pack);
467 : GF_Err stbl_AppendChunk(GF_SampleTableBox *stbl, u64 offset);
468 : GF_Err stbl_AppendSampleToChunk(GF_SampleTableBox *stbl, u32 DescIndex, u32 samplesInChunk);
469 : GF_Err stbl_AppendCTSOffset(GF_SampleTableBox *stbl, s32 CTSOffset);
470 : GF_Err stbl_AppendRAP(GF_SampleTableBox *stbl, u8 isRap);
471 : GF_Err stbl_AppendPadding(GF_SampleTableBox *stbl, u8 padding);
472 : GF_Err stbl_AppendDegradation(GF_SampleTableBox *stbl, u16 DegradationPriority);
473 :
474 4079 : if (trak->Header->trackID != traf->tfhd->trackID) return GF_OK;
475 4079 : if (!trak->Media->information->sampleTable
476 4079 : || !trak->Media->information->sampleTable->SampleSize
477 4079 : || !trak->Media->information->sampleTable->TimeToSample
478 4079 : || !trak->Media->information->sampleTable->SampleToChunk
479 4079 : || !trak->Media->information->sampleTable->ChunkOffset
480 : ) {
481 : return GF_ISOM_INVALID_FILE;
482 : }
483 :
484 4079 : if (!traf->trex->track)
485 316 : traf->trex->track = trak;
486 :
487 : //setup all our defaults
488 4079 : DescIndex = (traf->tfhd->flags & GF_ISOM_TRAF_SAMPLE_DESC) ? traf->tfhd->sample_desc_index : traf->trex->def_sample_desc_index;
489 4079 : if (!DescIndex) {
490 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] default sample description set to 0, likely broken ! Fixing to 1\n" ));
491 : DescIndex = 1;
492 4079 : } else if (DescIndex > gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes)) {
493 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] default sample description set to %d but only %d sample description(s), likely broken ! Fixing to 1\n", DescIndex, gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes)));
494 : DescIndex = 1;
495 : }
496 : #ifdef GF_ENABLE_CTRN
497 : if (traf->trex->inherit_from_traf_id) {
498 : u32 traf_count = gf_list_count(moof_box->TrackList);
499 : for (i=0; i<traf_count; i++) {
500 : GF_TrackFragmentBox *atraf = gf_list_get(moof_box->TrackList, i);
501 : if (atraf->tfhd && atraf->tfhd->trackID==traf->trex->inherit_from_traf_id) {
502 : traf_ref = atraf;
503 : break;
504 : }
505 : }
506 : }
507 : #endif
508 :
509 4079 : def_duration = (traf->tfhd->flags & GF_ISOM_TRAF_SAMPLE_DUR) ? traf->tfhd->def_sample_duration : traf->trex->def_sample_duration;
510 4079 : def_size = (traf->tfhd->flags & GF_ISOM_TRAF_SAMPLE_SIZE) ? traf->tfhd->def_sample_size : traf->trex->def_sample_size;
511 4079 : def_flags = (traf->tfhd->flags & GF_ISOM_TRAF_SAMPLE_FLAGS) ? traf->tfhd->def_sample_flags : traf->trex->def_sample_flags;
512 :
513 : //locate base offset, by default use moof (dash-like)
514 : base_offset = moof_offset;
515 : //explicit base offset, use it
516 4079 : if (traf->tfhd->flags & GF_ISOM_TRAF_BASE_OFFSET)
517 51 : base_offset = traf->tfhd->base_data_offset;
518 : //no moof offset and no explicit offset, the offset is the end of the last written chunk of
519 : //the previous traf. For the first traf, *cumulated_offset is actually moof offset
520 4028 : else if (!(traf->tfhd->flags & GF_ISOM_MOOF_BASE_OFFSET))
521 32 : base_offset = *cumulated_offset;
522 :
523 : chunk_size = 0;
524 : prev_trun_data_offset = 0;
525 : data_offset = 0;
526 : traf_duration = 0;
527 :
528 : /*in playback mode*/
529 4079 : if (traf->tfdt && is_first_merge) {
530 : #ifndef GPAC_DISABLE_LOG
531 3071 : if (trak->moov->mov->NextMoofNumber && trak->present_in_scalable_segment && trak->sample_count_at_seg_start && (trak->dts_at_seg_start != traf->tfdt->baseMediaDecodeTime)) {
532 0 : s32 drift = (s32) ((s64) traf->tfdt->baseMediaDecodeTime - (s64)trak->dts_at_seg_start);
533 0 : if (drift<0) {
534 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Warning: TFDT timing "LLD" less than cumulated timing "LLD" - using tfdt\n", traf->tfdt->baseMediaDecodeTime, trak->dts_at_seg_start ));
535 : } else {
536 0 : GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[iso file] TFDT timing "LLD" higher than cumulated timing "LLD" (last sample got extended in duration)\n", traf->tfdt->baseMediaDecodeTime, trak->dts_at_seg_start ));
537 : }
538 : }
539 : #endif
540 3071 : trak->dts_at_seg_start = traf->tfdt->baseMediaDecodeTime;
541 : }
542 1008 : else if (traf->tfxd) {
543 3 : trak->dts_at_seg_start = traf->tfxd->absolute_time_in_track_timescale;
544 : }
545 :
546 4079 : if (traf->tfxd) {
547 3 : trak->last_tfxd_value = traf->tfxd->absolute_time_in_track_timescale;
548 3 : trak->last_tfxd_value += traf->tfxd->fragment_duration_in_track_timescale;
549 : }
550 4079 : if (traf->tfrf) {
551 0 : if (trak->tfrf) gf_isom_box_del_parent(&trak->child_boxes, (GF_Box *)trak->tfrf);
552 0 : trak->tfrf = traf->tfrf;
553 0 : gf_list_del_item(traf->child_boxes, traf->tfrf);
554 0 : gf_list_add(trak->child_boxes, trak->tfrf);
555 : }
556 :
557 4079 : if (trak->moov->mov->signal_frag_bounds) {
558 : store_traf_map = GF_TRUE;
559 195 : if (is_first_merge) {
560 87 : GF_MovieFragmentBox *moof_clone = NULL;
561 87 : gf_isom_box_freeze_order((GF_Box *)moof_box);
562 87 : gf_isom_clone_box((GF_Box *)moof_box, (GF_Box **)&moof_clone);
563 :
564 87 : if (moof_clone) {
565 : GF_BitStream *bs;
566 174 : for (i=0; i<gf_list_count(moof_clone->TrackList); i++) {
567 87 : GF_TrackFragmentBox *traf_clone = gf_list_get(moof_clone->TrackList, i);
568 87 : gf_isom_box_array_reset_parent(&traf_clone->child_boxes, traf_clone->TrackRuns);
569 87 : gf_isom_box_array_reset_parent(&traf_clone->child_boxes, traf_clone->sampleGroups);
570 87 : gf_isom_box_array_reset_parent(&traf_clone->child_boxes, traf_clone->sampleGroupsDescription);
571 87 : gf_isom_box_array_reset_parent(&traf_clone->child_boxes, traf_clone->sub_samples);
572 87 : gf_isom_box_array_reset_parent(&traf_clone->child_boxes, traf_clone->sai_offsets);
573 87 : gf_isom_box_array_reset_parent(&traf_clone->child_boxes, traf_clone->sai_sizes);
574 87 : if (traf_clone->sample_encryption) {
575 0 : gf_isom_box_del_parent(&traf_clone->child_boxes, (GF_Box *) traf_clone->sample_encryption);
576 0 : traf_clone->sample_encryption = NULL;
577 : }
578 87 : if (traf_clone->sdtp) {
579 0 : gf_isom_box_del_parent(&traf_clone->child_boxes, (GF_Box *) traf_clone->sdtp);
580 0 : traf_clone->sdtp = NULL;
581 : }
582 : }
583 87 : gf_isom_box_size((GF_Box *)moof_clone);
584 87 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
585 :
586 87 : if (trak->moov->mov->seg_styp) {
587 84 : gf_isom_box_size(trak->moov->mov->seg_styp);
588 84 : gf_isom_box_write(trak->moov->mov->seg_styp, bs);
589 : }
590 87 : if (trak->moov->mov->root_sidx) {
591 87 : gf_isom_box_size((GF_Box *)trak->moov->mov->root_sidx);
592 87 : gf_isom_box_write((GF_Box *)trak->moov->mov->root_sidx, bs);
593 : }
594 87 : if (trak->moov->mov->seg_ssix) {
595 0 : gf_isom_box_size(trak->moov->mov->seg_ssix);
596 0 : gf_isom_box_write(trak->moov->mov->seg_ssix, bs);
597 : }
598 87 : gf_isom_box_write((GF_Box *)moof_clone, bs);
599 87 : gf_isom_box_del((GF_Box*)moof_clone);
600 :
601 87 : gf_bs_get_content(bs, &moof_template, &moof_template_size);
602 87 : gf_bs_del(bs);
603 : }
604 : }
605 195 : if (trak->moov->mov->seg_styp) {
606 : is_seg_start = GF_TRUE;
607 84 : seg_start = trak->moov->mov->styp_start_offset;
608 : }
609 195 : if (trak->moov->mov->root_sidx) {
610 : is_seg_start = GF_TRUE;
611 87 : sidx_start = trak->moov->mov->sidx_start_offset;
612 87 : sidx_end = trak->moov->mov->sidx_end_offset;
613 87 : if (! seg_start || (sidx_start<seg_start))
614 : seg_start = sidx_start;
615 : }
616 195 : frag_start = trak->moov->mov->current_top_box_start;
617 : }
618 3884 : else if (trak->moov->mov->store_traf_map) {
619 : store_traf_map = GF_TRUE;
620 : }
621 :
622 :
623 : sample_index = 0;
624 4079 : i=0;
625 12282 : while ((trun = (GF_TrackFragmentRunBox *)gf_list_enum(traf->TrackRuns, &i))) {
626 : //merge the run
627 109375 : for (j=0; j<trun->sample_count; j++) {
628 : GF_Err e;
629 : s32 cts_offset=0;
630 109375 : if (j<trun->nb_samples) {
631 109375 : ent = &trun->samples[j];
632 : } else {
633 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Track %d doesn't have enough trun entries (%d) compared to sample count (%d) in run\n", traf->trex->trackID, trun->nb_samples, trun->sample_count ));
634 : break;
635 : }
636 : size = def_size;
637 : duration = def_duration;
638 : flags = def_flags;
639 :
640 : //CTS - if flag not set (trun or ctrn) defaults to 0 which is the base value after alloc
641 : //we just need to overrite its value if inherited
642 109375 : cts_offset = ent->CTS_Offset;
643 :
644 : #ifdef GF_ENABLE_CTRN
645 : if (trun->use_ctrn) {
646 : if (!j && (trun->ctrn_flags & GF_ISOM_CTRN_FIRST_SAMPLE) ) {
647 : if (trun->ctrn_first_dur) duration = ent->Duration;
648 : if (trun->ctrn_first_size) size = ent->size;
649 : if (trun->ctrn_first_ctts) flags = ent->flags;
650 : } else {
651 : if (trun->ctrn_dur) duration = ent->Duration;
652 : if (trun->ctrn_size) size = ent->size;
653 : if (trun->ctrn_sample_flags) flags = ent->flags;
654 : }
655 : /*re-override*/
656 : if (trun->ctrn_flags & 0xF0) {
657 : GF_TrunEntry *ref_entry;
658 : if (!traf_ref) {
659 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Track %d use traf inheritance to track ID %d but reference traf not found\n", traf->trex->trackID, traf->trex->inherit_from_traf_id ));
660 : break;
661 : }
662 : ref_entry = traf_get_sample_entry(traf_ref, sample_index);
663 : if (!ref_entry) {
664 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Track %d use traf inheritance but sample %d not found in reference traf\n", traf->trex->trackID, sample_index+1 ));
665 : break;
666 : }
667 : if (trun->ctrn_flags & GF_ISOM_CTRN_INHERIT_DUR)
668 : duration = ref_entry->Duration;
669 : if (trun->ctrn_flags & GF_ISOM_CTRN_INHERIT_SIZE)
670 : size = ref_entry->size;
671 : if (trun->ctrn_flags & GF_ISOM_CTRN_INHERIT_FLAGS)
672 : flags = ref_entry->flags;
673 : if (trun->ctrn_flags & GF_ISOM_CTRN_INHERIT_CTSO)
674 : cts_offset = ref_entry->CTS_Offset;
675 : }
676 :
677 : } else
678 : #endif
679 : {
680 114634 : if (trun->flags & GF_ISOM_TRUN_DURATION) duration = ent->Duration;
681 109375 : if (trun->flags & GF_ISOM_TRUN_SIZE) size = ent->size;
682 109375 : if (trun->flags & GF_ISOM_TRUN_FLAGS) {
683 6868 : flags = ent->flags;
684 102507 : } else if (!j && (trun->flags & GF_ISOM_TRUN_FIRST_FLAG)) {
685 3147 : flags = trun->first_sample_flags;
686 : }
687 : }
688 : sample_index++;
689 : /*store the resolved value in case we have inheritance*/
690 109375 : ent->size = size;
691 109375 : ent->Duration = duration;
692 109375 : ent->flags = flags;
693 : ent->CTS_Offset = cts_offset;
694 :
695 109375 : last_dts += duration;
696 :
697 : //add size first
698 109375 : if (!trak->Media->information->sampleTable->SampleSize) {
699 0 : trak->Media->information->sampleTable->SampleSize = (GF_SampleSizeBox *) gf_isom_box_new_parent(&trak->Media->information->sampleTable->child_boxes, GF_ISOM_BOX_TYPE_STSZ);
700 0 : if (!trak->Media->information->sampleTable->SampleSize)
701 : return GF_OUT_OF_MEM;
702 : }
703 109375 : e = stbl_AppendSize(trak->Media->information->sampleTable, size, ent->nb_pack);
704 109375 : if (e) return e;
705 :
706 : //then TS
707 109375 : if (!trak->Media->information->sampleTable->TimeToSample) {
708 0 : trak->Media->information->sampleTable->TimeToSample = (GF_TimeToSampleBox *) gf_isom_box_new_parent(&trak->Media->information->sampleTable->child_boxes, GF_ISOM_BOX_TYPE_STTS);
709 0 : if (!trak->Media->information->sampleTable->TimeToSample)
710 : return GF_OUT_OF_MEM;
711 : }
712 109375 : e = stbl_AppendTime(trak->Media->information->sampleTable, duration, ent->nb_pack);
713 109375 : if (e) return e;
714 :
715 : //add chunk on first sample
716 109375 : if (!j) {
717 : u64 final_offset;
718 : data_offset = base_offset;
719 : //we have an explicit data offset for this trun
720 4124 : if (trun->flags & GF_ISOM_TRUN_DATA_OFFSET) {
721 4083 : data_offset += trun->data_offset;
722 : /*reset chunk size since data is now relative to this trun*/
723 : chunk_size = 0;
724 : /*remember this data offset for following trun*/
725 4083 : prev_trun_data_offset = trun->data_offset;
726 : /*if mdat is located after the moof, and the moof was compressed, adjust offset
727 : otherwise the offset does not need adjustment*/
728 4083 : if (trun->data_offset>=0) {
729 4083 : data_offset -= compressed_diff;
730 4083 : prev_trun_data_offset -= compressed_diff;
731 : }
732 : }
733 : //we had an explicit data offset for the previous trun, use it + chunk size
734 41 : else if (prev_trun_data_offset) {
735 : /*data offset is previous chunk size plus previous offset of the trun*/
736 0 : data_offset += prev_trun_data_offset + chunk_size;
737 : }
738 : //no explicit data offset, continuous data after last data in previous chunk
739 : else {
740 41 : data_offset += chunk_size;
741 : //data offset of first trun in first traf, adjust if compressed moof
742 41 : if ((i==1) && (trun->data_offset>=0)) {
743 41 : data_offset -= compressed_diff;
744 : }
745 : }
746 :
747 : final_offset = data_offset;
748 : //adjust offset if moov was also compressed and we are still in the same file
749 : //so that later call to gf_isom_get_sample properly adjust back the offset
750 4124 : if (trak->moov->compressed_diff) {
751 10 : final_offset += trak->moov->compressed_diff;
752 : }
753 :
754 4124 : if (!trak->Media->information->sampleTable->ChunkOffset) {
755 0 : trak->Media->information->sampleTable->ChunkOffset = gf_isom_box_new_parent(&trak->Media->information->sampleTable->child_boxes, GF_ISOM_BOX_TYPE_STCO);
756 0 : if (!trak->Media->information->sampleTable->ChunkOffset)
757 : return GF_OUT_OF_MEM;
758 : }
759 4124 : e = stbl_AppendChunk(trak->Media->information->sampleTable, final_offset);
760 4124 : if (e) return e;
761 : //then sampleToChunk
762 4124 : if (!trak->Media->information->sampleTable->SampleToChunk) {
763 0 : trak->Media->information->sampleTable->SampleToChunk = (GF_SampleToChunkBox *) gf_isom_box_new_parent(&trak->Media->information->sampleTable->child_boxes, GF_ISOM_BOX_TYPE_STSC);
764 0 : if (!trak->Media->information->sampleTable->SampleToChunk)
765 : return GF_OUT_OF_MEM;
766 : }
767 4124 : e = stbl_AppendSampleToChunk(trak->Media->information->sampleTable,
768 : DescIndex, trun->sample_count);
769 4124 : if (e) return e;
770 : }
771 109375 : chunk_size += size;
772 :
773 109375 : if (store_traf_map && first_samp_in_traf) {
774 : first_samp_in_traf = GF_FALSE;
775 195 : e = stbl_AppendTrafMap(trak->Media->information->sampleTable, is_seg_start, seg_start, frag_start, moof_template, moof_template_size, sidx_start, sidx_end);
776 195 : if (e) return e;
777 : //do not deallocate, the memory is now owned by traf map
778 195 : moof_template = NULL;
779 195 : moof_template_size = 0;
780 : }
781 109375 : if (ent->nb_pack>1) {
782 185 : j+= ent->nb_pack-1;
783 185 : traf_duration += ent->nb_pack*duration;
784 185 : continue;
785 : }
786 :
787 109190 : traf_duration += duration;
788 :
789 109190 : e = stbl_AppendCTSOffset(trak->Media->information->sampleTable, cts_offset);
790 109190 : if (e) return e;
791 : //flags
792 109190 : sync = GF_ISOM_GET_FRAG_SYNC(flags);
793 109190 : if (trak->Media->information->sampleTable->no_sync_found && sync) {
794 291 : trak->Media->information->sampleTable->no_sync_found = 0;
795 : }
796 109190 : e = stbl_AppendRAP(trak->Media->information->sampleTable, sync);
797 109190 : if (e) return e;
798 109190 : pad = GF_ISOM_GET_FRAG_PAD(flags);
799 109190 : if (pad) {
800 0 : e = stbl_AppendPadding(trak->Media->information->sampleTable, pad);
801 0 : if (e) return e;
802 : }
803 109190 : degr = GF_ISOM_GET_FRAG_DEG(flags);
804 109190 : if (degr) {
805 3 : e = stbl_AppendDegradation(trak->Media->information->sampleTable, degr);
806 3 : if (e) return e;
807 : }
808 109190 : e = stbl_AppendDependencyType(trak->Media->information->sampleTable, GF_ISOM_GET_FRAG_LEAD(flags), GF_ISOM_GET_FRAG_DEPENDS(flags), GF_ISOM_GET_FRAG_DEPENDED(flags), GF_ISOM_GET_FRAG_REDUNDANT(flags));
809 109190 : if (e) return e;
810 : }
811 : }
812 :
813 4079 : if (trak->moov->mov->is_smooth && !traf->tfdt && !traf->tfxd) {
814 25 : if (is_first_merge)
815 25 : trak->dts_at_seg_start = trak->dts_at_next_seg_start;
816 25 : trak->dts_at_next_seg_start += last_dts;
817 : }
818 4079 : if (traf_duration && trak->editBox && trak->editBox->editList) {
819 264 : for (i=0; i<gf_list_count(trak->editBox->editList->entryList); i++) {
820 132 : GF_EdtsEntry *edts_e = gf_list_get(trak->editBox->editList->entryList, i);
821 132 : if (edts_e->was_empty_dur) {
822 : u64 extend_dur = traf_duration;
823 105 : extend_dur *= trak->moov->mvhd->timeScale;
824 105 : extend_dur /= trak->Media->mediaHeader->timeScale;
825 105 : edts_e->segmentDuration += extend_dur;
826 : }
827 27 : else if (!edts_e->segmentDuration) {
828 27 : edts_e->was_empty_dur = GF_TRUE;
829 27 : if ((s64) traf_duration > edts_e->mediaTime)
830 27 : traf_duration -= edts_e->mediaTime;
831 : else
832 : traf_duration = 0;
833 :
834 27 : edts_e->segmentDuration = traf_duration;
835 27 : edts_e->segmentDuration *= trak->moov->mvhd->timeScale;
836 27 : edts_e->segmentDuration /= trak->Media->mediaHeader->timeScale;
837 : }
838 :
839 : }
840 : }
841 :
842 : //in any case, update the cumulated offset
843 : //this will handle hypothetical files mixing MOOF offset and implicit non-moof offset
844 4079 : *cumulated_offset = data_offset + chunk_size;
845 :
846 : /*merge sample groups*/
847 4079 : if (traf->sampleGroups) {
848 : GF_List *groups;
849 : GF_List *groupDescs;
850 : Bool is_identical_sgpd = GF_TRUE;
851 : u32 *new_idx = NULL, new_idx_count=0;
852 :
853 98 : if (!trak->Media->information->sampleTable->sampleGroups)
854 98 : trak->Media->information->sampleTable->sampleGroups = gf_list_new();
855 :
856 98 : if (!trak->Media->information->sampleTable->sampleGroupsDescription)
857 10 : trak->Media->information->sampleTable->sampleGroupsDescription = gf_list_new();
858 :
859 98 : groupDescs = trak->Media->information->sampleTable->sampleGroupsDescription;
860 126 : for (i=0; i<gf_list_count(traf->sampleGroupsDescription); i++) {
861 : GF_SampleGroupDescriptionBox *new_sgdesc = NULL;
862 28 : GF_SampleGroupDescriptionBox *sgdesc = gf_list_get(traf->sampleGroupsDescription, i);
863 28 : for (j=0; j<gf_list_count(groupDescs); j++) {
864 0 : new_sgdesc = gf_list_get(groupDescs, j);
865 0 : if (new_sgdesc->grouping_type==sgdesc->grouping_type) break;
866 : new_sgdesc = NULL;
867 : }
868 : /*new description, move it to our sample table*/
869 28 : if (!new_sgdesc) {
870 28 : gf_list_add(groupDescs, sgdesc);
871 28 : gf_list_add(trak->Media->information->sampleTable->child_boxes, sgdesc);
872 28 : gf_list_rem(traf->sampleGroupsDescription, i);
873 28 : gf_list_del_item(traf->child_boxes, sgdesc);
874 28 : i--;
875 : }
876 : /*merge descriptions*/
877 : else {
878 : u32 count;
879 :
880 0 : is_identical_sgpd = gf_isom_is_identical_sgpd(new_sgdesc, sgdesc, 0);
881 0 : if (is_identical_sgpd)
882 0 : continue;
883 :
884 0 : new_idx_count = gf_list_count(sgdesc->group_descriptions);
885 0 : new_idx = (u32 *)gf_malloc(new_idx_count * sizeof(u32));
886 0 : if (!new_idx) return GF_OUT_OF_MEM;
887 :
888 : count = 0;
889 0 : while (gf_list_count(sgdesc->group_descriptions)) {
890 0 : void *sgpd_entry = gf_list_get(sgdesc->group_descriptions, 0);
891 : Bool new_entry = GF_TRUE;
892 :
893 0 : for (j = 0; j < gf_list_count(new_sgdesc->group_descriptions); j++) {
894 0 : void *ptr = gf_list_get(new_sgdesc->group_descriptions, j);
895 0 : if (gf_isom_is_identical_sgpd(sgpd_entry, ptr, new_sgdesc->grouping_type)) {
896 0 : new_idx[count] = j + 1;
897 0 : count ++;
898 : new_entry = GF_FALSE;
899 0 : gf_free(sgpd_entry);
900 : break;
901 : }
902 : }
903 :
904 : if (new_entry) {
905 0 : gf_list_add(new_sgdesc->group_descriptions, sgpd_entry);
906 0 : new_idx[count] = gf_list_count(new_sgdesc->group_descriptions);
907 0 : count ++;
908 : }
909 :
910 0 : gf_list_rem(sgdesc->group_descriptions, 0);
911 : }
912 : }
913 : }
914 :
915 98 : groups = trak->Media->information->sampleTable->sampleGroups;
916 196 : for (i=0; i<gf_list_count(traf->sampleGroups); i++) {
917 : GF_SampleGroupBox *stbl_group = NULL;
918 98 : GF_SampleGroupBox *frag_group = gf_list_get(traf->sampleGroups, i);
919 :
920 :
921 98 : for (j=0; j<gf_list_count(groups); j++) {
922 0 : stbl_group = gf_list_get(groups, j);
923 0 : if ((frag_group->grouping_type==stbl_group->grouping_type) && (frag_group->grouping_type_parameter==stbl_group->grouping_type_parameter))
924 : break;
925 : stbl_group = NULL;
926 : }
927 98 : if (!stbl_group) {
928 98 : stbl_group = (GF_SampleGroupBox *) gf_isom_box_new_parent(&trak->Media->information->sampleTable->child_boxes, GF_ISOM_BOX_TYPE_SBGP);
929 98 : if (!stbl_group) return GF_OUT_OF_MEM;
930 98 : stbl_group->grouping_type = frag_group->grouping_type;
931 98 : stbl_group->grouping_type_parameter = frag_group->grouping_type_parameter;
932 98 : stbl_group->version = frag_group->version;
933 98 : gf_list_add(groups, stbl_group);
934 : }
935 :
936 98 : if (is_identical_sgpd) {
937 : //adjust sgpd index: in traf index start at 0x1001
938 181 : for (j = 0; j < frag_group->entry_count; j++)
939 181 : frag_group->sample_entries[j].group_description_index &= 0x0FFFF;
940 98 : if (frag_group->entry_count && stbl_group->entry_count &&
941 0 : (frag_group->sample_entries[0].group_description_index==stbl_group->sample_entries[stbl_group->entry_count-1].group_description_index)
942 : ) {
943 0 : stbl_group->sample_entries[stbl_group->entry_count - 1].sample_count += frag_group->sample_entries[0].sample_count;
944 0 : if (frag_group->entry_count>1) {
945 0 : stbl_group->sample_entries = gf_realloc(stbl_group->sample_entries, sizeof(GF_SampleGroupEntry) * (stbl_group->entry_count + frag_group->entry_count - 1));
946 0 : memcpy(&stbl_group->sample_entries[stbl_group->entry_count], &frag_group->sample_entries[1], sizeof(GF_SampleGroupEntry) * (frag_group->entry_count - 1));
947 0 : stbl_group->entry_count += frag_group->entry_count - 1;
948 : }
949 : } else {
950 98 : stbl_group->sample_entries = gf_realloc(stbl_group->sample_entries, sizeof(GF_SampleGroupEntry) * (stbl_group->entry_count + frag_group->entry_count));
951 98 : memcpy(&stbl_group->sample_entries[stbl_group->entry_count], &frag_group->sample_entries[0], sizeof(GF_SampleGroupEntry) * frag_group->entry_count);
952 98 : stbl_group->entry_count += frag_group->entry_count;
953 : }
954 : } else {
955 0 : stbl_group->sample_entries = gf_realloc(stbl_group->sample_entries, sizeof(GF_SampleGroupEntry) * (stbl_group->entry_count + frag_group->entry_count));
956 : //adjust sgpd index
957 0 : for (j = 0; j < frag_group->entry_count; j++) {
958 0 : u32 sgidx = frag_group->sample_entries[j].group_description_index;
959 0 : if (sgidx > 0x10000) {
960 0 : sgidx -= 0x10001;
961 0 : if (sgidx>=new_idx_count) {
962 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[isobmf] corrupted sample group index in fragment %d but only %d group descriptions in fragment\n", sgidx, new_idx_count));
963 : } else {
964 0 : frag_group->sample_entries[j].group_description_index = new_idx[sgidx];
965 : }
966 : }
967 : }
968 0 : memcpy(&stbl_group->sample_entries[stbl_group->entry_count], &frag_group->sample_entries[0], sizeof(GF_SampleGroupEntry) * frag_group->entry_count);
969 0 : stbl_group->entry_count += frag_group->entry_count;
970 : }
971 : }
972 :
973 98 : if (new_idx) gf_free(new_idx);
974 : }
975 :
976 : /*content is encrypted*/
977 4079 : track_num = gf_isom_get_tracknum_from_id(trak->moov, trak->Header->trackID);
978 4079 : if (gf_isom_is_cenc_media(trak->moov->mov, track_num, DescIndex)
979 3942 : || traf->sample_encryption) {
980 : /*Merge sample auxiliary encryption information*/
981 : GF_SampleEncryptionBox *senc = NULL;
982 : u32 scheme_type;
983 141 : gf_isom_get_cenc_info(trak->moov->mov, track_num, DescIndex, NULL, &scheme_type, NULL);
984 :
985 141 : if (traf->sample_encryption) {
986 1431 : for (i = 0; i < gf_list_count(trak->Media->information->sampleTable->child_boxes); i++) {
987 1290 : GF_Box *a = (GF_Box *)gf_list_get(trak->Media->information->sampleTable->child_boxes, i);
988 1290 : if (a->type != traf->sample_encryption->type) continue;
989 :
990 0 : if ((a->type ==GF_ISOM_BOX_TYPE_UUID) && (((GF_UUIDBox *)a)->internal_4cc == GF_ISOM_BOX_UUID_PSEC)) {
991 : senc = (GF_SampleEncryptionBox *)a;
992 : break;
993 : }
994 0 : else if (a->type ==GF_ISOM_BOX_TYPE_SENC) {
995 : senc = (GF_SampleEncryptionBox *)a;
996 : break;
997 : }
998 : }
999 141 : if (!senc && trak->sample_encryption)
1000 : senc = trak->sample_encryption;
1001 :
1002 141 : if (!senc) {
1003 72 : if (traf->sample_encryption->piff_type==1) {
1004 2 : senc = (GF_SampleEncryptionBox *)gf_isom_create_piff_psec_box(1, 0x2, 0, 0, NULL);
1005 : } else {
1006 70 : senc = gf_isom_create_samp_enc_box(1, 0x2);
1007 : }
1008 :
1009 72 : if (!trak->Media->information->sampleTable->child_boxes) trak->Media->information->sampleTable->child_boxes = gf_list_new();
1010 :
1011 72 : trak->sample_encryption = senc;
1012 72 : if (!trak->child_boxes) trak->child_boxes = gf_list_new();
1013 72 : gf_list_add(trak->child_boxes, senc);
1014 : }
1015 : }
1016 :
1017 : /*get sample auxiliary information by saiz/saio rather than by parsing senc box*/
1018 141 : if (gf_isom_cenc_has_saiz_saio_traf(traf, scheme_type)) {
1019 : u32 nb_saio;
1020 : u32 aux_info_type;
1021 : u64 offset;
1022 : GF_Err e;
1023 : Bool is_encrypted;
1024 : GF_SampleAuxiliaryInfoOffsetBox *saio = NULL;
1025 : GF_SampleAuxiliaryInfoSizeBox *saiz = NULL;
1026 :
1027 : offset = nb_saio = 0;
1028 :
1029 139 : for (i = 0; i < gf_list_count(traf->sai_offsets); i++) {
1030 139 : saio = (GF_SampleAuxiliaryInfoOffsetBox *)gf_list_get(traf->sai_offsets, i);
1031 139 : aux_info_type = saio->aux_info_type;
1032 139 : if (!aux_info_type) aux_info_type = scheme_type;
1033 :
1034 : /*if we have only 1 sai_offsets, assume that its type is cenc*/
1035 139 : if ((aux_info_type == GF_ISOM_CENC_SCHEME) || (aux_info_type == GF_ISOM_CBC_SCHEME) ||
1036 30 : (aux_info_type == GF_ISOM_CENS_SCHEME) || (aux_info_type == GF_ISOM_CBCS_SCHEME) ||
1037 0 : (gf_list_count(traf->sai_offsets) == 1)) {
1038 139 : if (saio->offsets && saio->entry_count) {
1039 139 : offset = saio->offsets[0] + moof_offset;
1040 : nb_saio = saio->entry_count;
1041 139 : break;
1042 : }
1043 : }
1044 : saio = NULL;
1045 : }
1046 139 : for (i = 0; i < gf_list_count(traf->sai_sizes); i++) {
1047 139 : saiz = (GF_SampleAuxiliaryInfoSizeBox *)gf_list_get(traf->sai_sizes, i);
1048 139 : aux_info_type = saiz->aux_info_type;
1049 139 : if (!aux_info_type) aux_info_type = scheme_type;
1050 : /*if we have only 1 sai_sizes, assume that its type is cenc*/
1051 139 : if ((aux_info_type == GF_ISOM_CENC_SCHEME) || (aux_info_type == GF_ISOM_CBC_SCHEME) ||
1052 30 : (aux_info_type == GF_ISOM_CENS_SCHEME) || (aux_info_type == GF_ISOM_CBCS_SCHEME) ||
1053 0 : (gf_list_count(traf->sai_sizes) == 1)) {
1054 : break;
1055 : }
1056 : saiz = NULL;
1057 : }
1058 139 : if (saiz && saio && senc) {
1059 8616 : for (i = 0; i < saiz->sample_count; i++) {
1060 : GF_CENCSampleAuxInfo *sai;
1061 4169 : const u8 *key_info=NULL;
1062 : u32 key_info_size;
1063 : u64 cur_position;
1064 4169 : if (nb_saio != 1)
1065 0 : offset = saio->offsets[i] + moof_offset;
1066 4169 : size = saiz->default_sample_info_size ? saiz->default_sample_info_size : saiz->sample_info_size[i];
1067 :
1068 4169 : cur_position = gf_bs_get_position(trak->moov->mov->movieFileMap->bs);
1069 4169 : gf_bs_seek(trak->moov->mov->movieFileMap->bs, offset);
1070 :
1071 4169 : GF_SAFEALLOC(sai, GF_CENCSampleAuxInfo);
1072 4169 : if (!sai) return GF_OUT_OF_MEM;
1073 :
1074 4169 : e = gf_isom_get_sample_cenc_info_internal(trak, traf, senc, i+1, &is_encrypted, NULL, NULL, &key_info, &key_info_size);
1075 4169 : if (e) {
1076 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[isobmf] could not get cenc info for sample %d: %s\n", i+1, gf_error_to_string(e) ));
1077 : return e;
1078 : }
1079 :
1080 4169 : if (is_encrypted) {
1081 4144 : sai->cenc_data_size = size;
1082 4144 : sai->cenc_data = gf_malloc(sizeof(u8)*size);
1083 4144 : if (!sai->cenc_data) return GF_OUT_OF_MEM;
1084 4144 : gf_bs_read_data(trak->moov->mov->movieFileMap->bs, sai->cenc_data, sai->cenc_data_size);
1085 : } else {
1086 25 : sai->isNotProtected=1;
1087 : }
1088 :
1089 4169 : if (key_info) {
1090 : //not multikey
1091 4072 : if (!key_info[0]) {
1092 : //size greater than IV
1093 4072 : if (size > key_info[3])
1094 1805 : senc->flags = 0x00000002;
1095 : }
1096 : //multikey, always use subsamples
1097 : else {
1098 0 : senc->flags = 0x00000002;
1099 : }
1100 : }
1101 :
1102 :
1103 4169 : gf_bs_seek(trak->moov->mov->movieFileMap->bs, cur_position);
1104 :
1105 4169 : gf_list_add(senc->samp_aux_info, sai);
1106 :
1107 4169 : e = gf_isom_cenc_merge_saiz_saio(senc, trak->Media->information->sampleTable, offset, size);
1108 4169 : if (e) return e;
1109 4169 : if (nb_saio == 1)
1110 4169 : offset += size;
1111 : }
1112 : }
1113 2 : } else if (traf->sample_encryption) {
1114 2 : senc_Parse(trak->moov->mov->movieFileMap->bs, trak, traf, traf->sample_encryption);
1115 2 : trak->sample_encryption->AlgorithmID = traf->sample_encryption->AlgorithmID;
1116 2 : if (!trak->sample_encryption->IV_size)
1117 2 : trak->sample_encryption->IV_size = traf->sample_encryption->IV_size;
1118 2 : if (!trak->sample_encryption->samp_aux_info) trak->sample_encryption->samp_aux_info = gf_list_new();
1119 2 : gf_list_transfer(trak->sample_encryption->samp_aux_info, traf->sample_encryption->samp_aux_info);
1120 2 : if (traf->sample_encryption->flags & 0x00000002)
1121 2 : trak->sample_encryption->flags |= 0x00000002;
1122 : }
1123 : }
1124 : return GF_OK;
1125 : }
1126 :
1127 : #endif
1128 :
1129 :
1130 : #ifndef GPAC_DISABLE_ISOM_WRITE
1131 :
1132 : //used to check if a TrackID is available
1133 1857 : u8 RequestTrack(GF_MovieBox *moov, GF_ISOTrackID TrackID)
1134 : {
1135 : u32 i;
1136 : GF_TrackBox *trak;
1137 :
1138 1857 : i=0;
1139 5351 : while ((trak = (GF_TrackBox *)gf_list_enum(moov->trackList, &i))) {
1140 1831 : if (trak->Header->trackID == TrackID) {
1141 194 : gf_isom_set_last_error(moov->mov, GF_BAD_PARAM);
1142 194 : return 0;
1143 : }
1144 : }
1145 : return 1;
1146 : }
1147 :
1148 1 : GF_Err Track_RemoveRef(GF_TrackBox *trak, u32 ReferenceType)
1149 : {
1150 : GF_TrackReferenceBox *ref;
1151 : GF_Box *a;
1152 : u32 i;
1153 1 : if (! trak) return GF_BAD_PARAM;
1154 1 : if (! trak->References) return GF_OK;
1155 : ref = trak->References;
1156 1 : i=0;
1157 4 : while ((a = (GF_Box *)gf_list_enum(ref->child_boxes, &i))) {
1158 2 : if (a->type == ReferenceType) {
1159 0 : gf_isom_box_del_parent(&ref->child_boxes, a);
1160 0 : return GF_OK;
1161 : }
1162 : }
1163 : return GF_OK;
1164 : }
1165 :
1166 1626 : GF_Err NewMedia(GF_MediaBox **mdia, u32 MediaType, u32 TimeScale)
1167 : {
1168 : GF_MediaHeaderBox *mdhd;
1169 : GF_Box *mediaInfo;
1170 : GF_HandlerBox *hdlr;
1171 : GF_MediaInformationBox *minf;
1172 : GF_DataInformationBox *dinf;
1173 : GF_SampleTableBox *stbl;
1174 : GF_DataReferenceBox *dref;
1175 : char *str="";
1176 :
1177 : GF_Err e;
1178 :
1179 1626 : if (!mdia) return GF_BAD_PARAM;
1180 :
1181 1626 : minf = *mdia ? (*mdia)->information : NULL;
1182 1626 : mdhd = *mdia ? (*mdia)->mediaHeader : NULL;
1183 1626 : hdlr = *mdia ? (*mdia)->handler : NULL;
1184 1626 : dinf = minf ? minf->dataInformation : NULL;
1185 1626 : stbl = minf ? minf->sampleTable : NULL;
1186 1626 : dref = dinf ? dinf->dref : NULL;
1187 1626 : mediaInfo = minf ? minf->InfoHeader : NULL;
1188 :
1189 : //first create the media
1190 1626 : if (!*mdia) {
1191 1011 : *mdia = (GF_MediaBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MDIA);
1192 1011 : if (! *mdia) { e = GF_OUT_OF_MEM; goto err_exit; }
1193 : }
1194 1626 : if (!mdhd) {
1195 1011 : mdhd = (GF_MediaHeaderBox *) gf_isom_box_new_parent( & ((*mdia)->child_boxes), GF_ISOM_BOX_TYPE_MDHD);
1196 1011 : if (! mdhd) { e = GF_OUT_OF_MEM; goto err_exit; }
1197 1011 : e = mdia_on_child_box((GF_Box*)*mdia, (GF_Box *) mdhd, GF_FALSE);
1198 1011 : if (e) goto err_exit;
1199 : }
1200 1626 : if (!hdlr) {
1201 1011 : hdlr = (GF_HandlerBox *) gf_isom_box_new_parent(& ((*mdia)->child_boxes), GF_ISOM_BOX_TYPE_HDLR);
1202 1011 : if (! hdlr) { e = GF_OUT_OF_MEM; goto err_exit; }
1203 1011 : e = mdia_on_child_box((GF_Box*)*mdia, (GF_Box *) hdlr, GF_FALSE);
1204 1011 : if (e) goto err_exit;
1205 : }
1206 1626 : if (!minf) {
1207 1011 : minf = (GF_MediaInformationBox *) gf_isom_box_new_parent(& ((*mdia)->child_boxes), GF_ISOM_BOX_TYPE_MINF);
1208 1011 : if (! minf) { e = GF_OUT_OF_MEM; goto err_exit; }
1209 1011 : e = mdia_on_child_box((GF_Box*)*mdia, (GF_Box *) minf, GF_FALSE);
1210 1011 : if (e) goto err_exit;
1211 : }
1212 1626 : if (!dinf) {
1213 1011 : dinf = (GF_DataInformationBox *) gf_isom_box_new_parent(&minf->child_boxes, GF_ISOM_BOX_TYPE_DINF);
1214 1011 : if (! dinf) { e = GF_OUT_OF_MEM; goto err_exit; }
1215 1011 : e = minf_on_child_box((GF_Box*)minf, (GF_Box *) dinf, GF_FALSE);
1216 1011 : if (e) goto err_exit;
1217 : }
1218 :
1219 1626 : if (!mediaInfo) {
1220 : //"handler name" is for debugging purposes. Let's stick our name here ;)
1221 1011 : switch (MediaType) {
1222 537 : case GF_ISOM_MEDIA_VISUAL:
1223 537 : mediaInfo = gf_isom_box_new(GF_ISOM_BOX_TYPE_VMHD);
1224 : str = "GPAC ISO Video Handler";
1225 537 : break;
1226 0 : case GF_ISOM_MEDIA_AUXV:
1227 0 : mediaInfo = gf_isom_box_new(GF_ISOM_BOX_TYPE_VMHD);
1228 : str = "GPAC ISO Auxiliary Video Handler";
1229 0 : break;
1230 0 : case GF_ISOM_MEDIA_PICT:
1231 0 : mediaInfo = gf_isom_box_new(GF_ISOM_BOX_TYPE_VMHD);
1232 : str = "GPAC ISO Picture Sequence Handler";
1233 0 : break;
1234 179 : case GF_ISOM_MEDIA_AUDIO:
1235 179 : mediaInfo = gf_isom_box_new(GF_ISOM_BOX_TYPE_SMHD);
1236 : str = "GPAC ISO Audio Handler";
1237 179 : break;
1238 73 : case GF_ISOM_MEDIA_HINT:
1239 73 : mediaInfo = gf_isom_box_new(GF_ISOM_BOX_TYPE_HMHD);
1240 : str = "GPAC ISO Hint Handler";
1241 73 : break;
1242 11 : case GF_ISOM_MEDIA_META:
1243 11 : mediaInfo = gf_isom_box_new(GF_ISOM_BOX_TYPE_NMHD);
1244 : str = "GPAC Timed MetaData Handler";
1245 11 : break;
1246 30 : case GF_ISOM_MEDIA_OD:
1247 30 : mediaInfo = gf_isom_box_new(GF_ISOM_BOX_TYPE_NMHD);
1248 : str = "GPAC MPEG-4 OD Handler";
1249 30 : break;
1250 0 : case GF_ISOM_MEDIA_OCR:
1251 0 : mediaInfo = gf_isom_box_new(GF_ISOM_BOX_TYPE_NMHD);
1252 : str = "GPAC MPEG-4 OCR Handler";
1253 0 : break;
1254 69 : case GF_ISOM_MEDIA_SCENE:
1255 69 : mediaInfo = gf_isom_box_new(GF_ISOM_BOX_TYPE_NMHD);
1256 : str = "GPAC MPEG-4 Scene Description Handler";
1257 69 : break;
1258 0 : case GF_ISOM_MEDIA_MPEG7:
1259 0 : mediaInfo = gf_isom_box_new(GF_ISOM_BOX_TYPE_NMHD);
1260 : str = "GPAC MPEG-4 MPEG-7 Handler";
1261 0 : break;
1262 0 : case GF_ISOM_MEDIA_OCI:
1263 0 : mediaInfo = gf_isom_box_new(GF_ISOM_BOX_TYPE_NMHD);
1264 : str = "GPAC MPEG-4 OCI Handler";
1265 0 : break;
1266 0 : case GF_ISOM_MEDIA_IPMP:
1267 0 : mediaInfo = gf_isom_box_new(GF_ISOM_BOX_TYPE_NMHD);
1268 : str = "GPAC MPEG-4 IPMP Handler";
1269 0 : break;
1270 0 : case GF_ISOM_MEDIA_MPEGJ:
1271 0 : mediaInfo = gf_isom_box_new(GF_ISOM_BOX_TYPE_NMHD);
1272 : str = "GPAC MPEG-4 MPEG-J Handler";
1273 0 : break;
1274 83 : case GF_ISOM_MEDIA_TEXT:
1275 : case GF_ISOM_MEDIA_SUBT:
1276 83 : mediaInfo = gf_isom_box_new(GF_ISOM_BOX_TYPE_NMHD);
1277 : str = "GPAC Streaming Text Handler";
1278 83 : break;
1279 25 : case GF_ISOM_MEDIA_MPEG_SUBT:
1280 25 : mediaInfo = gf_isom_box_new(GF_ISOM_BOX_TYPE_STHD);
1281 : str = "GPAC MPEG Subtitle Handler";
1282 25 : break;
1283 0 : case GF_ISOM_MEDIA_DIMS:
1284 0 : mediaInfo = gf_isom_box_new(GF_ISOM_BOX_TYPE_VMHD);
1285 : MediaType = GF_ISOM_MEDIA_SCENE;
1286 : str = "GPAC DIMS Handler";
1287 0 : break;
1288 3 : case GF_ISOM_MEDIA_TIMECODE:
1289 3 : mediaInfo = gf_isom_box_new(GF_ISOM_BOX_TYPE_GMHD);
1290 : str = "GPAC TMCD Handler";
1291 3 : break;
1292 1 : default:
1293 1 : mediaInfo = gf_isom_box_new(GF_ISOM_BOX_TYPE_NMHD);
1294 : str = "GPAC IsoMedia Handler";
1295 1 : break;
1296 : }
1297 1011 : if (! mediaInfo) { e = GF_OUT_OF_MEM; goto err_exit; }
1298 1011 : if (!minf->child_boxes) minf->child_boxes = gf_list_new();
1299 1011 : gf_list_add(minf->child_boxes, mediaInfo);
1300 :
1301 1011 : e = minf_on_child_box((GF_Box*)minf, (GF_Box *) mediaInfo, GF_FALSE);
1302 1011 : if (e) goto err_exit;
1303 : }
1304 :
1305 1626 : mdhd->timeScale = TimeScale;
1306 1626 : hdlr->handlerType = MediaType;
1307 1626 : if (!hdlr->nameUTF8)
1308 1011 : hdlr->nameUTF8 = gf_strdup(str);
1309 :
1310 1626 : if (!dref) {
1311 : //Create a data reference WITHOUT DATA ENTRY (we don't know anything yet about the media Data)
1312 1011 : dref = (GF_DataReferenceBox *) gf_isom_box_new_parent(&dinf->child_boxes, GF_ISOM_BOX_TYPE_DREF);
1313 1011 : if (! dref) { e = GF_OUT_OF_MEM; goto err_exit; }
1314 1011 : e = dinf_on_child_box((GF_Box*)dinf, (GF_Box *)dref, GF_FALSE);
1315 1011 : if (e) goto err_exit;
1316 : }
1317 :
1318 1626 : if (!stbl) {
1319 : //first set-up the sample table...
1320 1011 : stbl = (GF_SampleTableBox *) gf_isom_box_new_parent(&minf->child_boxes, GF_ISOM_BOX_TYPE_STBL);
1321 1011 : if (! stbl) { e = GF_OUT_OF_MEM; goto err_exit; }
1322 :
1323 1011 : e = minf_on_child_box((GF_Box*)minf, (GF_Box *) stbl, GF_FALSE);
1324 1011 : if (e) goto err_exit;
1325 : }
1326 1626 : if (!stbl->SampleDescription) {
1327 1011 : stbl->SampleDescription = (GF_SampleDescriptionBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSD);
1328 1011 : if (! stbl->SampleDescription) { e = GF_OUT_OF_MEM; goto err_exit; }
1329 : }
1330 :
1331 : //by default create a regular table, 32 but offset and normal sample size
1332 1626 : if (!stbl->ChunkOffset) {
1333 1626 : stbl->ChunkOffset = gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STCO);
1334 1626 : if (! stbl->ChunkOffset) { e = GF_OUT_OF_MEM; goto err_exit; }
1335 : }
1336 1626 : if (!stbl->SampleSize) {
1337 1626 : stbl->SampleSize = (GF_SampleSizeBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSZ);
1338 1626 : if (! stbl->SampleSize) { e = GF_OUT_OF_MEM; goto err_exit; }
1339 : }
1340 1626 : if (!stbl->SampleToChunk) {
1341 1626 : stbl->SampleToChunk = (GF_SampleToChunkBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSC);
1342 1626 : if (! stbl->SampleToChunk) { e = GF_OUT_OF_MEM; goto err_exit; }
1343 : }
1344 1626 : if (!stbl->TimeToSample) {
1345 1626 : stbl->TimeToSample = (GF_TimeToSampleBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STTS);
1346 1626 : if (! stbl->TimeToSample) { e = GF_OUT_OF_MEM; goto err_exit; }
1347 : }
1348 1626 : if (!stbl->SampleDescription) {
1349 0 : stbl->SampleDescription = (GF_SampleDescriptionBox *) gf_isom_box_new_parent(&stbl->child_boxes, GF_ISOM_BOX_TYPE_STSD);
1350 0 : if (! stbl->SampleDescription) { e = GF_OUT_OF_MEM; goto err_exit; }
1351 : }
1352 : return GF_OK;
1353 :
1354 0 : err_exit:
1355 0 : if (mdhd) gf_isom_box_del_parent(& ((*mdia)->child_boxes), (GF_Box *)mdhd);
1356 0 : if (minf) gf_isom_box_del_parent(& ((*mdia)->child_boxes), (GF_Box *)minf);
1357 0 : if (hdlr) {
1358 0 : gf_isom_box_del_parent(& ((*mdia)->child_boxes) , (GF_Box *)hdlr);
1359 : }
1360 : return e;
1361 :
1362 : }
1363 :
1364 612 : GF_Err Track_SetStreamDescriptor(GF_TrackBox *trak, u32 StreamDescriptionIndex, u32 DataReferenceIndex, GF_ESD *esd, u32 *outStreamIndex)
1365 : {
1366 : GF_Err e;
1367 : GF_MPEGSampleEntryBox *entry;
1368 : GF_MPEGVisualSampleEntryBox *entry_v;
1369 : GF_MPEGAudioSampleEntryBox *entry_a;
1370 : GF_TrackReferenceBox *tref;
1371 : GF_TrackReferenceTypeBox *dpnd;
1372 : u16 tmpRef;
1373 :
1374 : entry = NULL;
1375 : tref = NULL;
1376 :
1377 612 : if (!trak || !esd || (!outStreamIndex && !DataReferenceIndex) ) return GF_BAD_PARAM;
1378 612 : if (!Track_IsMPEG4Stream(trak->Media->handler->handlerType)) return GF_ISOM_INVALID_MEDIA;
1379 :
1380 :
1381 611 : esd->ESID = 0;
1382 : //set SL to predefined if no url
1383 611 : if (esd->URLString == NULL) {
1384 611 : if (!esd->slConfig) esd->slConfig = (GF_SLConfig*) gf_odf_desc_new(GF_ODF_SLC_TAG);
1385 611 : esd->slConfig->predefined = SLPredef_MP4;
1386 611 : esd->slConfig->durationFlag = 0;
1387 611 : esd->slConfig->useTimestampsFlag = 1;
1388 : }
1389 :
1390 : //get the REF box if needed
1391 611 : if (esd->dependsOnESID || (esd->OCRESID && (esd->OCRESID != trak->moov->mov->es_id_default_sync)) ) {
1392 53 : if (!trak->References) {
1393 27 : tref = (GF_TrackReferenceBox *) gf_isom_box_new_parent(&trak->child_boxes, GF_ISOM_BOX_TYPE_TREF);
1394 27 : if (!tref) return GF_OUT_OF_MEM;
1395 27 : e = trak_on_child_box((GF_Box*)trak, (GF_Box *)tref, GF_FALSE);
1396 27 : if (e) return e;
1397 : }
1398 53 : tref = trak->References;
1399 : }
1400 :
1401 : //Update Stream dependencies
1402 611 : e = Track_FindRef(trak, GF_ISOM_REF_DECODE, &dpnd);
1403 611 : if (e) return e;
1404 :
1405 611 : if (!dpnd && esd->dependsOnESID) {
1406 17 : e = Track_FindRef(trak, GF_ISOM_REF_BASE, &dpnd);
1407 17 : if (e) return e;
1408 : }
1409 :
1410 611 : if (!dpnd && esd->dependsOnESID) {
1411 14 : dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new_parent(&tref->child_boxes, GF_ISOM_BOX_TYPE_REFT);
1412 14 : dpnd->reference_type = GF_ISOM_BOX_TYPE_DPND;
1413 14 : e = reftype_AddRefTrack(dpnd, esd->dependsOnESID, NULL);
1414 14 : if (e) return e;
1415 597 : } else if (dpnd && !esd->dependsOnESID) {
1416 0 : Track_RemoveRef(trak, GF_ISOM_BOX_TYPE_DPND);
1417 : }
1418 611 : esd->dependsOnESID = 0;
1419 :
1420 : //Update GF_Clock dependencies
1421 611 : e = Track_FindRef(trak, GF_ISOM_REF_OCR, &dpnd);
1422 611 : if (e) return e;
1423 611 : if (!dpnd && esd->OCRESID && (esd->OCRESID != trak->moov->mov->es_id_default_sync)) {
1424 29 : dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new_parent(&tref->child_boxes, GF_ISOM_BOX_TYPE_REFT);
1425 29 : if (!dpnd) return GF_OUT_OF_MEM;
1426 29 : dpnd->reference_type = GF_ISOM_BOX_TYPE_SYNC;
1427 29 : e = reftype_AddRefTrack(dpnd, esd->OCRESID, NULL);
1428 29 : if (e) return e;
1429 582 : } else if (dpnd && !esd->OCRESID) {
1430 1 : Track_RemoveRef(trak, GF_ISOM_BOX_TYPE_SYNC);
1431 581 : } else if (dpnd && esd->OCRESID) {
1432 21 : if (dpnd->trackIDCount != 1) return GF_ISOM_INVALID_MEDIA;
1433 21 : dpnd->trackIDs[0] = esd->OCRESID;
1434 : }
1435 611 : esd->OCRESID = 0;
1436 :
1437 : //brand new case: we have to change the IPI desc
1438 611 : if (esd->ipiPtr) {
1439 0 : e = Track_FindRef(trak, GF_ISOM_REF_IPI, &dpnd);
1440 0 : if (e) return e;
1441 0 : if (!dpnd) {
1442 0 : tmpRef = 0;
1443 0 : dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new_parent(&tref->child_boxes, GF_ISOM_BOX_TYPE_REFT);
1444 0 : if (!dpnd) return GF_OUT_OF_MEM;
1445 0 : dpnd->reference_type = GF_ISOM_BOX_TYPE_IPIR;
1446 0 : e = reftype_AddRefTrack(dpnd, esd->ipiPtr->IPI_ES_Id, &tmpRef);
1447 0 : if (e) return e;
1448 : //and replace the tag and value...
1449 0 : esd->ipiPtr->IPI_ES_Id = tmpRef;
1450 0 : esd->ipiPtr->tag = GF_ODF_ISOM_IPI_PTR_TAG;
1451 : } else {
1452 : //Watch out! ONLY ONE IPI dependency is allowed per stream
1453 0 : if (dpnd->trackIDCount != 1) return GF_ISOM_INVALID_MEDIA;
1454 : //if an existing one is there, what shall we do ???
1455 : //donno, erase it
1456 0 : dpnd->trackIDs[0] = esd->ipiPtr->IPI_ES_Id;
1457 : //and replace the tag and value...
1458 0 : esd->ipiPtr->IPI_ES_Id = 1;
1459 0 : esd->ipiPtr->tag = GF_ODF_ISOM_IPI_PTR_TAG;
1460 : }
1461 : }
1462 :
1463 : /*don't store the lang desc in ESD, use the media header language info*/
1464 611 : if (esd->langDesc) {
1465 2 : trak->Media->mediaHeader->packedLanguage[0] = (esd->langDesc->langCode>>16)&0xFF;
1466 2 : trak->Media->mediaHeader->packedLanguage[1] = (esd->langDesc->langCode>>8)&0xFF;
1467 2 : trak->Media->mediaHeader->packedLanguage[2] = (esd->langDesc->langCode)&0xFF;
1468 2 : gf_odf_desc_del((GF_Descriptor *)esd->langDesc);
1469 2 : esd->langDesc = NULL;
1470 : }
1471 :
1472 : //we have a streamDescriptionIndex, use it
1473 611 : if (StreamDescriptionIndex) {
1474 : u32 entry_type;
1475 116 : entry = (GF_MPEGSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, StreamDescriptionIndex - 1);
1476 116 : if (!entry) return GF_ISOM_INVALID_FILE;
1477 :
1478 116 : entry_type = entry->type;
1479 116 : GF_ProtectionSchemeInfoBox *sinf = (GF_ProtectionSchemeInfoBox *) gf_isom_box_find_child(entry->child_boxes, GF_ISOM_BOX_TYPE_SINF);
1480 116 : if (sinf && sinf->original_format) entry_type = sinf->original_format->data_format;
1481 :
1482 116 : switch (entry_type) {
1483 73 : case GF_ISOM_BOX_TYPE_MP4S:
1484 : //OK, delete the previous ESD
1485 73 : gf_odf_desc_del((GF_Descriptor *) entry->esd->desc);
1486 73 : entry->esd->desc = esd;
1487 73 : break;
1488 5 : case GF_ISOM_BOX_TYPE_MP4V:
1489 : entry_v = (GF_MPEGVisualSampleEntryBox*) entry;
1490 : //OK, delete the previous ESD
1491 5 : gf_odf_desc_del((GF_Descriptor *) entry_v->esd->desc);
1492 5 : entry_v->esd->desc = esd;
1493 5 : break;
1494 10 : case GF_ISOM_BOX_TYPE_MP4A:
1495 : entry_a = (GF_MPEGAudioSampleEntryBox*) entry;
1496 10 : if (entry_a->esd) { // some non-conformant files may not have an ESD ...
1497 : //OK, delete the previous ESD
1498 10 : gf_odf_desc_del((GF_Descriptor *) entry_a->esd->desc);
1499 10 : entry_a->esd->desc = esd;
1500 : } else {
1501 : // can't return OK here otherwise we can't know if esd hasn't been used
1502 : // and need to be freed
1503 : return GF_ISOM_INVALID_MEDIA;
1504 : }
1505 10 : break;
1506 26 : case GF_ISOM_BOX_TYPE_AVC1:
1507 : case GF_ISOM_BOX_TYPE_AVC2:
1508 : case GF_ISOM_BOX_TYPE_AVC3:
1509 : case GF_ISOM_BOX_TYPE_AVC4:
1510 : case GF_ISOM_BOX_TYPE_SVC1:
1511 : case GF_ISOM_BOX_TYPE_MVC1:
1512 : case GF_ISOM_BOX_TYPE_HVC1:
1513 : case GF_ISOM_BOX_TYPE_HEV1:
1514 : case GF_ISOM_BOX_TYPE_HVC2:
1515 : case GF_ISOM_BOX_TYPE_HEV2:
1516 : case GF_ISOM_BOX_TYPE_LHE1:
1517 : case GF_ISOM_BOX_TYPE_LHV1:
1518 : case GF_ISOM_BOX_TYPE_HVT1:
1519 : case GF_ISOM_BOX_TYPE_VVC1:
1520 : case GF_ISOM_BOX_TYPE_VVI1:
1521 26 : e = AVC_HEVC_UpdateESD((GF_MPEGVisualSampleEntryBox*)entry, esd);
1522 26 : if (e) return e;
1523 : break;
1524 2 : case GF_ISOM_BOX_TYPE_LSR1:
1525 2 : e = LSR_UpdateESD((GF_LASeRSampleEntryBox*)entry, esd);
1526 2 : if (e) return e;
1527 : break;
1528 : case GF_ISOM_BOX_TYPE_AV01:
1529 : case GF_ISOM_BOX_TYPE_AV1C:
1530 : case GF_ISOM_BOX_TYPE_OPUS:
1531 : case GF_ISOM_BOX_TYPE_DOPS:
1532 : case GF_ISOM_BOX_TYPE_STXT:
1533 : case GF_ISOM_BOX_TYPE_WVTT:
1534 : case GF_ISOM_BOX_TYPE_STPP:
1535 0 : if (esd) gf_odf_desc_del((GF_Descriptor *) esd);
1536 : break;
1537 :
1538 0 : default:
1539 : //silently fail, not an MPEG-4 esd
1540 0 : gf_odf_desc_del((GF_Descriptor *) esd);
1541 0 : return GF_OK;
1542 : }
1543 : } else {
1544 : //need to check we're not in URL mode where only ONE description is allowed...
1545 495 : StreamDescriptionIndex = gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes);
1546 495 : if (StreamDescriptionIndex) {
1547 0 : GF_ESD *old_esd=NULL;
1548 0 : entry = (GF_MPEGSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->child_boxes, StreamDescriptionIndex - 1);
1549 0 : if (!entry) return GF_ISOM_INVALID_FILE;
1550 : //get ESD (only if present, do not emulate)
1551 0 : Media_GetESD(trak->Media, StreamDescriptionIndex, &old_esd, GF_TRUE);
1552 0 : if (old_esd && old_esd->URLString) return GF_BAD_PARAM;
1553 : }
1554 :
1555 : //OK, check the handler and create the entry
1556 495 : switch (trak->Media->handler->handlerType) {
1557 154 : case GF_ISOM_MEDIA_AUXV:
1558 : case GF_ISOM_MEDIA_PICT:
1559 : case GF_ISOM_MEDIA_VISUAL:
1560 154 : if ((esd->decoderConfig->objectTypeIndication==GF_CODECID_AVC) || (esd->decoderConfig->objectTypeIndication==GF_CODECID_SVC) || (esd->decoderConfig->objectTypeIndication==GF_CODECID_MVC)) {
1561 4 : entry_v = (GF_MPEGVisualSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_AVC1);
1562 4 : if (!entry_v) return GF_OUT_OF_MEM;
1563 4 : e = AVC_HEVC_UpdateESD((GF_MPEGVisualSampleEntryBox*)entry_v, esd);
1564 4 : if (e) return e;
1565 150 : } else if (esd->decoderConfig->objectTypeIndication==GF_CODECID_HEVC) {
1566 0 : entry_v = (GF_MPEGVisualSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_HVC1);
1567 0 : if (!entry_v) return GF_OUT_OF_MEM;
1568 0 : e = AVC_HEVC_UpdateESD((GF_MPEGVisualSampleEntryBox*)entry_v, esd);
1569 0 : if (e) return e;
1570 150 : } else if (esd->decoderConfig->objectTypeIndication==GF_CODECID_VVC) {
1571 0 : entry_v = (GF_MPEGVisualSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_VVC1);
1572 0 : if (!entry_v) return GF_OUT_OF_MEM;
1573 0 : e = AVC_HEVC_UpdateESD((GF_MPEGVisualSampleEntryBox*)entry_v, esd);
1574 0 : if (e) return e;
1575 : } else {
1576 150 : entry_v = (GF_MPEGVisualSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MP4V);
1577 150 : if (!entry_v) return GF_OUT_OF_MEM;
1578 150 : entry_v->esd = (GF_ESDBox *) gf_isom_box_new_parent(&entry_v->child_boxes, GF_ISOM_BOX_TYPE_ESDS);
1579 150 : if (!entry_v->esd) return GF_OUT_OF_MEM;
1580 150 : entry_v->esd->desc = esd;
1581 : }
1582 :
1583 : //type cast possible now
1584 : entry = (GF_MPEGSampleEntryBox*) entry_v;
1585 : break;
1586 218 : case GF_ISOM_MEDIA_AUDIO:
1587 218 : if (esd->decoderConfig->objectTypeIndication == GF_CODECID_OPUS) {
1588 0 : GF_MPEGAudioSampleEntryBox *opus = (GF_MPEGAudioSampleEntryBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_OPUS);
1589 0 : if (!opus) return GF_OUT_OF_MEM;
1590 0 : opus->cfg_opus = (GF_OpusSpecificBox *)gf_isom_box_new_parent(&opus->child_boxes, GF_ISOM_BOX_TYPE_DOPS);
1591 0 : if (!opus->cfg_opus) return GF_OUT_OF_MEM;
1592 : entry = (GF_MPEGSampleEntryBox*)opus;
1593 0 : gf_odf_desc_del((GF_Descriptor *) esd);
1594 218 : } else if (esd->decoderConfig->objectTypeIndication == GF_CODECID_AC3) {
1595 0 : GF_MPEGAudioSampleEntryBox *ac3 = (GF_MPEGAudioSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_AC3);
1596 0 : if (!ac3) return GF_OUT_OF_MEM;
1597 0 : ac3->cfg_ac3 = (GF_AC3ConfigBox *) gf_isom_box_new_parent(&ac3->child_boxes, GF_ISOM_BOX_TYPE_DAC3);
1598 0 : if (!ac3->cfg_ac3) return GF_OUT_OF_MEM;
1599 : entry = (GF_MPEGSampleEntryBox*) ac3;
1600 0 : gf_odf_desc_del((GF_Descriptor *) esd);
1601 218 : } else if (esd->decoderConfig->objectTypeIndication==GF_CODECID_EAC3) {
1602 0 : GF_MPEGAudioSampleEntryBox *eac3 = (GF_MPEGAudioSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_EC3);
1603 0 : if (!eac3) return GF_OUT_OF_MEM;
1604 0 : eac3->cfg_ac3 = (GF_AC3ConfigBox *) gf_isom_box_new_parent(&eac3->child_boxes, GF_ISOM_BOX_TYPE_DEC3);
1605 0 : if (!eac3->cfg_ac3) return GF_OUT_OF_MEM;
1606 : entry = (GF_MPEGSampleEntryBox*) eac3;
1607 0 : gf_odf_desc_del((GF_Descriptor *) esd);
1608 : } else {
1609 218 : entry_a = (GF_MPEGAudioSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MP4A);
1610 218 : if (!entry_a) return GF_OUT_OF_MEM;
1611 218 : entry_a->samplerate_hi = trak->Media->mediaHeader->timeScale;
1612 218 : entry_a->esd = (GF_ESDBox *) gf_isom_box_new_parent(&entry_a->child_boxes, GF_ISOM_BOX_TYPE_ESDS);
1613 218 : if (!entry_a->esd) return GF_OUT_OF_MEM;
1614 218 : entry_a->esd->desc = esd;
1615 : //type cast possible now
1616 : entry = (GF_MPEGSampleEntryBox*) entry_a;
1617 : }
1618 : break;
1619 123 : default:
1620 123 : if ((esd->decoderConfig->streamType==0x03) && (esd->decoderConfig->objectTypeIndication==0x09)) {
1621 3 : entry = (GF_MPEGSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_LSR1);
1622 3 : if (!entry) return GF_OUT_OF_MEM;
1623 3 : e = LSR_UpdateESD((GF_LASeRSampleEntryBox*)entry, esd);
1624 3 : if (e) return e;
1625 : } else {
1626 120 : entry = (GF_MPEGSampleEntryBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MP4S);
1627 120 : entry->esd = (GF_ESDBox *) gf_isom_box_new_parent(&entry->child_boxes, GF_ISOM_BOX_TYPE_ESDS);
1628 120 : if (!entry->esd) return GF_OUT_OF_MEM;
1629 120 : entry->esd->desc = esd;
1630 : }
1631 : break;
1632 : }
1633 495 : entry->dataReferenceIndex = DataReferenceIndex;
1634 :
1635 495 : if (!trak->Media->information->sampleTable->SampleDescription->child_boxes)
1636 0 : trak->Media->information->sampleTable->SampleDescription->child_boxes = gf_list_new();
1637 495 : gf_list_add(trak->Media->information->sampleTable->SampleDescription->child_boxes, entry);
1638 :
1639 495 : e = stsd_on_child_box((GF_Box*)trak->Media->information->sampleTable->SampleDescription, (GF_Box *) entry, GF_FALSE);
1640 495 : if (e) return e;
1641 495 : if(outStreamIndex) *outStreamIndex = gf_list_count(trak->Media->information->sampleTable->SampleDescription->child_boxes);
1642 : }
1643 : return GF_OK;
1644 : }
1645 :
1646 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
1647 :
1648 : #endif /*GPAC_DISABLE_ISOM*/
|