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 / Media Tools sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 :
27 :
28 : #include <gpac/internal/media_dev.h>
29 : #include <gpac/internal/isomedia_dev.h>
30 : #include <gpac/constants.h>
31 : #include <gpac/config_file.h>
32 :
33 : #ifndef GPAC_DISABLE_ISOM_WRITE
34 : GF_EXPORT
35 16 : GF_Err gf_media_change_par(GF_ISOFile *file, u32 track, s32 ar_num, s32 ar_den, Bool force_par, Bool rewrite_bs)
36 : {
37 : u32 tk_w, tk_h;
38 : GF_Err e;
39 : Bool get_par_info = GF_FALSE;
40 :
41 16 : e = gf_isom_get_visual_info(file, track, 1, &tk_w, &tk_h);
42 16 : if (e) return e;
43 :
44 16 : if ((ar_num < 0) || (ar_den < 0)) {
45 : get_par_info = GF_TRUE;
46 : rewrite_bs = GF_FALSE;
47 : }
48 9 : else if (!ar_num || !ar_den) {
49 : rewrite_bs = GF_FALSE;
50 : }
51 :
52 16 : if (get_par_info || rewrite_bs) {
53 10 : u32 stype = gf_isom_get_media_subtype(file, track, 1);
54 10 : if ((stype==GF_ISOM_SUBTYPE_AVC_H264)
55 : || (stype==GF_ISOM_SUBTYPE_AVC2_H264)
56 : || (stype==GF_ISOM_SUBTYPE_AVC3_H264)
57 10 : || (stype==GF_ISOM_SUBTYPE_AVC4_H264)
58 : ) {
59 : #ifndef GPAC_DISABLE_AV_PARSERS
60 4 : GF_AVCConfig *avcc = gf_isom_avc_config_get(file, track, 1);
61 4 : if (rewrite_bs) {
62 1 : gf_media_avc_change_par(avcc, ar_num, ar_den);
63 1 : e = gf_isom_avc_config_update(file, track, 1, avcc);
64 : } else {
65 3 : GF_NALUFFParam *sl = gf_list_get(avcc->sequenceParameterSets, 0);
66 3 : if (sl) {
67 2 : gf_avc_get_sps_info(sl->data, sl->size, NULL, NULL, NULL, &ar_num, &ar_den);
68 : } else {
69 1 : ar_num = ar_den = 0;
70 : }
71 : }
72 4 : gf_odf_avc_cfg_del(avcc);
73 4 : if (e) return e;
74 : #endif
75 : }
76 : #if !defined(GPAC_DISABLE_HEVC) && !defined(GPAC_DISABLE_AV_PARSERS)
77 12 : else if ((stype==GF_ISOM_SUBTYPE_HVC1) || (stype==GF_ISOM_SUBTYPE_HVC2)
78 8 : || (stype==GF_ISOM_SUBTYPE_HEV1) || (stype==GF_ISOM_SUBTYPE_HEV2)
79 : ) {
80 4 : GF_HEVCConfig *hvcc = gf_isom_hevc_config_get(file, track, 1);
81 4 : if (rewrite_bs) {
82 1 : gf_hevc_change_par(hvcc, ar_num, ar_den);
83 1 : e = gf_isom_hevc_config_update(file, track, 1, hvcc);
84 : } else {
85 3 : u32 i=0;
86 : GF_NALUFFParamArray *ar;
87 3 : ar_num = ar_den = 0;
88 8 : while ( (ar = gf_list_enum(hvcc->param_array, &i))) {
89 4 : if (ar->type==GF_HEVC_NALU_SEQ_PARAM) {
90 2 : GF_NALUFFParam *sl = gf_list_get(ar->nalus, 0);
91 2 : if (sl)
92 2 : gf_hevc_get_sps_info(sl->data, sl->size, NULL, NULL, NULL, &ar_num, &ar_den);
93 : break;
94 : }
95 : }
96 : }
97 4 : gf_odf_hevc_cfg_del(hvcc);
98 4 : if (e) return e;
99 : }
100 : #endif
101 : #if !defined(GPAC_DISABLE_AV1) && !defined(GPAC_DISABLE_AV_PARSERS)
102 2 : else if (stype == GF_ISOM_SUBTYPE_AV01) {
103 : //GF_AV1Config *av1c = gf_isom_av1_config_get(file, track, 1);
104 : //TODO: e = gf_isom_av1_config_update(file, track, 1, av1c);
105 : //gf_odf_av1_cfg_del(av1c);
106 : //if (e) return e;
107 : return GF_NOT_SUPPORTED;
108 : }
109 : #endif
110 2 : else if (stype==GF_ISOM_SUBTYPE_MPEG4) {
111 2 : GF_ESD *esd = gf_isom_get_esd(file, track, 1);
112 2 : if (!esd || !esd->decoderConfig || (esd->decoderConfig->streamType!=4) ) {
113 0 : if (esd) gf_odf_desc_del((GF_Descriptor *) esd);
114 : return GF_NOT_SUPPORTED;
115 : }
116 : #ifndef GPAC_DISABLE_AV_PARSERS
117 2 : if (esd->decoderConfig->objectTypeIndication==GF_CODECID_MPEG4_PART2) {
118 2 : if (rewrite_bs) {
119 1 : e = gf_m4v_rewrite_par(&esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength, ar_num, ar_den);
120 1 : if (!e) e = gf_isom_change_mpeg4_description(file, track, 1, esd);
121 : } else {
122 : GF_M4VDecSpecInfo dsi;
123 1 : e = gf_m4v_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi);
124 1 : ar_num = dsi.par_num;
125 1 : ar_den = dsi.par_den;
126 : }
127 2 : gf_odf_desc_del((GF_Descriptor *) esd);
128 2 : if (e) return e;
129 : }
130 : #endif
131 : } else {
132 0 : u32 mtype = gf_isom_get_media_type(file, track);
133 0 : if (gf_isom_is_video_handler_type(mtype)) {
134 0 : if (rewrite_bs) {
135 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER,
136 : ("[ISOBMF] Warning: changing pixel ratio of media subtype \"%s\" is not supported, changing only \"pasp\" signaling\n",
137 : gf_4cc_to_str(gf_isom_get_media_subtype(file, track, 1)) ));
138 : }
139 : } else {
140 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISOBMF] Error: changing pixel ratio on non-video track.\n"));
141 : return GF_BAD_PARAM;
142 : }
143 : }
144 : //auto mode
145 10 : if (get_par_info && ((ar_num<=0) || (ar_den<=0))) {
146 2 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[ISOBMF] No sample AR info present in sample description, ignoring SAR update\n"));
147 2 : if (force_par)
148 2 : return gf_isom_set_pixel_aspect_ratio(file, track, 1, 1, 1, force_par);
149 : return GF_OK;
150 : }
151 : }
152 14 : e = gf_isom_set_pixel_aspect_ratio(file, track, 1, ar_num, ar_den, force_par);
153 14 : if (e) return e;
154 :
155 14 : if ((ar_den>0) && (ar_num>0)) {
156 11 : tk_w = tk_w * ar_num / ar_den;
157 : }
158 : /*PASP has been removed or forced to 1:1, revert to full frame for track layout*/
159 : else {
160 3 : e = gf_isom_get_visual_info(file, track, 1, &tk_w, &tk_h);
161 3 : if (e) return e;
162 : }
163 14 : return gf_isom_set_track_layout_info(file, track, tk_w<<16, tk_h<<16, 0, 0, 0);
164 : }
165 :
166 : GF_EXPORT
167 2 : GF_Err gf_media_change_color(GF_ISOFile *file, u32 track, s32 fullrange, s32 vidformat, s32 colorprim, s32 transfer, s32 colmatrix)
168 : {
169 : #ifndef GPAC_DISABLE_AV_PARSERS
170 : GF_Err e;
171 2 : u32 stype = gf_isom_get_media_subtype(file, track, 1);
172 2 : if ((stype==GF_ISOM_SUBTYPE_AVC_H264)
173 : || (stype==GF_ISOM_SUBTYPE_AVC2_H264)
174 : || (stype==GF_ISOM_SUBTYPE_AVC3_H264)
175 2 : || (stype==GF_ISOM_SUBTYPE_AVC4_H264)
176 : ) {
177 2 : GF_AVCConfig *avcc = gf_isom_avc_config_get(file, track, 1);
178 2 : gf_media_avc_change_color(avcc, fullrange, vidformat, colorprim, transfer, colmatrix);
179 2 : e = gf_isom_avc_config_update(file, track, 1, avcc);
180 2 : gf_odf_avc_cfg_del(avcc);
181 2 : if (e) return e;
182 : //remove any colr box
183 2 : return gf_isom_set_visual_color_info(file, track, 1, 0, 0, 0, 0, 0, NULL, 0);
184 : }
185 0 : if ((stype==GF_ISOM_SUBTYPE_HEV1)
186 0 : || (stype==GF_ISOM_SUBTYPE_HEV2)
187 0 : || (stype==GF_ISOM_SUBTYPE_HVC1)
188 0 : || (stype==GF_ISOM_SUBTYPE_HVC2)
189 0 : || (stype==GF_ISOM_SUBTYPE_LHV1)
190 0 : || (stype==GF_ISOM_SUBTYPE_LHE1)
191 : ) {
192 0 : GF_HEVCConfig *hvcc = gf_isom_hevc_config_get(file, track, 1);
193 0 : gf_hevc_change_color(hvcc, fullrange, vidformat, colorprim, transfer, colmatrix);
194 0 : e = gf_isom_hevc_config_update(file, track, 1, hvcc);
195 0 : gf_odf_hevc_cfg_del(hvcc);
196 0 : if (e) return e;
197 : //remove any colr box
198 0 : return gf_isom_set_visual_color_info(file, track, 1, 0, 0, 0, 0, 0, NULL, 0);
199 : }
200 : #endif
201 : return GF_NOT_SUPPORTED;
202 : }
203 :
204 : GF_EXPORT
205 5 : GF_Err gf_media_remove_non_rap(GF_ISOFile *file, u32 track, Bool non_ref_only)
206 : {
207 : GF_Err e;
208 : u32 i, count, di;
209 : u64 offset, dur, last_dts;
210 5 : Bool all_raps = (gf_isom_has_sync_points(file, track)==0) ? 1 : 0;
211 5 : if (all_raps) return GF_OK;
212 :
213 : last_dts = 0;
214 5 : dur = gf_isom_get_media_duration(file, track);
215 :
216 5 : gf_isom_set_cts_packing(file, track, GF_TRUE);
217 :
218 5 : count = gf_isom_get_sample_count(file, track);
219 2024 : for (i=0; i<count; i++) {
220 : Bool remove = GF_TRUE;
221 2019 : GF_ISOSample *samp = gf_isom_get_sample_info(file, track, i+1, &di, &offset);
222 2019 : if (!samp) return gf_isom_last_error(file);
223 :
224 2019 : if (samp->IsRAP) remove = GF_FALSE;
225 1982 : else if (non_ref_only) {
226 : u32 isLeading, dependsOn, dependedOn, redundant;
227 1811 : gf_isom_get_sample_flags(file, track, i+1, &isLeading, &dependsOn, &dependedOn, &redundant);
228 1811 : if (dependedOn != 2) {
229 : remove = GF_FALSE;
230 : }
231 : }
232 :
233 : if (!remove) {
234 1533 : last_dts = samp->DTS;
235 1533 : gf_isom_sample_del(&samp);
236 1533 : continue;
237 : }
238 486 : gf_isom_sample_del(&samp);
239 486 : e = gf_isom_remove_sample(file, track, i+1);
240 486 : if (e) return e;
241 486 : i--;
242 486 : count--;
243 : }
244 5 : gf_isom_set_cts_packing(file, track, GF_FALSE);
245 5 : gf_isom_set_last_sample_duration(file, track, (u32) (dur - last_dts) );
246 5 : return GF_OK;
247 : }
248 :
249 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
250 :
251 : GF_EXPORT
252 2686 : GF_Err gf_media_get_file_hash(const char *file, u8 hash[20])
253 : {
254 : #ifdef GPAC_DISABLE_CORE_TOOLS
255 : return GF_NOT_SUPPORTED;
256 : #else
257 : u8 block[4096];
258 : u32 read;
259 : u64 size, tot;
260 : FILE *in;
261 : GF_SHA1Context *ctx;
262 : GF_Err e = GF_OK;
263 : #ifndef GPAC_DISABLE_ISOM
264 : GF_BitStream *bs = NULL;
265 2686 : Bool is_isom = gf_isom_probe_file(file);
266 : #endif
267 :
268 2686 : in = gf_fopen(file, "rb");
269 2686 : if (!in) return GF_URL_ERROR;
270 2676 : size = gf_fsize(in);
271 :
272 2676 : ctx = gf_sha1_starts();
273 : tot = 0;
274 : #ifndef GPAC_DISABLE_ISOM
275 2676 : if (is_isom) bs = gf_bs_from_file(in, GF_BITSTREAM_READ);
276 : #endif
277 :
278 94280 : while (tot<size) {
279 : #ifndef GPAC_DISABLE_ISOM
280 91604 : if (is_isom) {
281 6365 : u64 box_size = gf_bs_peek_bits(bs, 32, 0);
282 6365 : u32 box_type = gf_bs_peek_bits(bs, 32, 4);
283 :
284 : /*64-bit size*/
285 6365 : if (box_size==1) box_size = gf_bs_peek_bits(bs, 64, 8);
286 : /*till end of file*/
287 6365 : if (!box_size) box_size = size - tot;
288 :
289 : /*skip all MutableDRMInformation*/
290 6365 : if (box_type==GF_ISOM_BOX_TYPE_MDRI) {
291 0 : gf_bs_skip_bytes(bs, box_size);
292 0 : tot += box_size;
293 : } else {
294 : u64 bsize = 0;
295 158405 : while (bsize<box_size) {
296 152041 : u32 to_read = (u32) ((box_size-bsize<4096) ? (box_size-bsize) : 4096);
297 152041 : read = gf_bs_read_data(bs, (char *) block, to_read);
298 152041 : if (!read || (read != to_read) ) {
299 1 : GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("corrupted isobmf file, box read "LLU" but expected still "LLU" bytes\n", bsize, box_size));
300 : break;
301 : }
302 152040 : gf_sha1_update(ctx, block, to_read);
303 152040 : bsize += to_read;
304 : }
305 6365 : tot += box_size;
306 : }
307 : } else
308 : #endif
309 : {
310 85239 : read = (u32) gf_fread(block, 4096, in);
311 85239 : if ((s32) read <= 0) {
312 0 : if (ferror(in))
313 : e = GF_IO_ERR;
314 : break;
315 : }
316 85239 : gf_sha1_update(ctx, block, read);
317 85239 : tot += read;
318 : }
319 : }
320 2676 : gf_sha1_finish(ctx, hash);
321 : #ifndef GPAC_DISABLE_ISOM
322 2676 : if (bs) gf_bs_del(bs);
323 : #endif
324 2676 : gf_fclose(in);
325 2676 : return e;
326 : #endif
327 : }
328 :
329 : #ifndef GPAC_DISABLE_ISOM
330 :
331 : #ifndef GPAC_DISABLE_ISOM_WRITE
332 :
333 : static const u32 ISMA_VIDEO_OD_ID = 20;
334 : static const u32 ISMA_AUDIO_OD_ID = 10;
335 :
336 : static const u32 ISMA_VIDEO_ES_ID = 201;
337 : static const u32 ISMA_AUDIO_ES_ID = 101;
338 :
339 : /*ISMA audio*/
340 : static const u8 ISMA_BIFS_AUDIO[] =
341 : {
342 : 0xC0, 0x10, 0x12, 0x81, 0x30, 0x2A, 0x05, 0x7C
343 : };
344 : /*ISMA video*/
345 : static const u8 ISMA_GF_BIFS_VIDEO[] =
346 : {
347 : 0xC0, 0x10, 0x12, 0x60, 0x42, 0x82, 0x28, 0x29,
348 : 0xD0, 0x4F, 0x00
349 : };
350 : /*ISMA audio-video*/
351 : static const u8 ISMA_BIFS_AV[] =
352 : {
353 : 0xC0, 0x10, 0x12, 0x81, 0x30, 0x2A, 0x05, 0x72,
354 : 0x60, 0x42, 0x82, 0x28, 0x29, 0xD0, 0x4F, 0x00
355 : };
356 :
357 : /*image only - uses same visual OD ID as video*/
358 : static const u8 ISMA_BIFS_IMAGE[] =
359 : {
360 : 0xC0, 0x11, 0xA4, 0xCD, 0x53, 0x6A, 0x0A, 0x44,
361 : 0x13, 0x00
362 : };
363 :
364 : /*ISMA audio-image*/
365 : static const u8 ISMA_BIFS_AI[] =
366 : {
367 : 0xC0, 0x11, 0xA5, 0x02, 0x60, 0x54, 0x0A, 0xE4,
368 : 0xCD, 0x53, 0x6A, 0x0A, 0x44, 0x13, 0x00
369 : };
370 :
371 :
372 : GF_EXPORT
373 5 : GF_Err gf_media_make_isma(GF_ISOFile *mp4file, Bool keepESIDs, Bool keepImage, Bool no_ocr)
374 : {
375 : u32 AudioTrack, VideoTrack, Tracks, i, mType, bifsT, odT, descIndex, VID, AID, bifsID, odID;
376 : u32 bifs, w, h;
377 : Bool is_image, image_track;
378 : GF_ESD *a_esd, *v_esd, *_esd;
379 : GF_ObjectDescriptor *od;
380 : GF_ODUpdate *odU;
381 : GF_ODCodec *codec;
382 : GF_ISOSample *samp;
383 : GF_BitStream *bs;
384 : u8 audioPL, visualPL;
385 :
386 5 : switch (gf_isom_get_mode(mp4file)) {
387 : case GF_ISOM_OPEN_EDIT:
388 : case GF_ISOM_OPEN_WRITE:
389 : case GF_ISOM_WRITE_EDIT:
390 : break;
391 : default:
392 : return GF_BAD_PARAM;
393 : }
394 :
395 :
396 5 : Tracks = gf_isom_get_track_count(mp4file);
397 : AID = VID = 0;
398 : is_image = 0;
399 :
400 : //search for tracks
401 13 : for (i=0; i<Tracks; i++) {
402 8 : GF_ESD *esd = gf_isom_get_esd(mp4file, i+1, 1);
403 : //remove from IOD
404 8 : gf_isom_remove_track_from_root_od(mp4file, i+1);
405 :
406 8 : mType = gf_isom_get_media_type(mp4file, i+1);
407 8 : switch (mType) {
408 5 : case GF_ISOM_MEDIA_VISUAL:
409 : case GF_ISOM_MEDIA_AUXV:
410 : case GF_ISOM_MEDIA_PICT:
411 : image_track = 0;
412 5 : if (esd && ((esd->decoderConfig->objectTypeIndication==GF_CODECID_JPEG) || (esd->decoderConfig->objectTypeIndication==GF_CODECID_PNG)) )
413 : image_track = 1;
414 :
415 : /*remove image tracks if wanted*/
416 5 : if (keepImage || !image_track) {
417 : /*only ONE video stream possible with ISMA*/
418 5 : if (VID) {
419 0 : if (esd) gf_odf_desc_del((GF_Descriptor*)esd);
420 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[ISMA convert] More than one video track found, cannot convert file - remove extra track(s)\n"));
421 : return GF_NOT_SUPPORTED;
422 : }
423 5 : VID = gf_isom_get_track_id(mp4file, i+1);
424 : is_image = image_track;
425 : } else {
426 0 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[ISMA convert] Visual track ID %d: only one sample found, assuming image and removing track\n", gf_isom_get_track_id(mp4file, i+1) ) );
427 0 : gf_isom_remove_track(mp4file, i+1);
428 0 : i -= 1;
429 0 : Tracks = gf_isom_get_track_count(mp4file);
430 : }
431 : break;
432 3 : case GF_ISOM_MEDIA_AUDIO:
433 3 : if (AID) {
434 0 : if (esd) gf_odf_desc_del((GF_Descriptor*)esd);
435 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[ISMA convert] More than one audio track found, cannot convert file - remove extra track(s)\n") );
436 : return GF_NOT_SUPPORTED;
437 : }
438 3 : AID = gf_isom_get_track_id(mp4file, i+1);
439 3 : break;
440 : /*clean file*/
441 0 : default:
442 0 : if (mType==GF_ISOM_MEDIA_HINT) {
443 0 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[ISMA convert] Removing Hint track ID %d\n", gf_isom_get_track_id(mp4file, i+1) ));
444 : } else {
445 0 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[ISMA convert] Removing track ID %d\n", gf_isom_get_track_id(mp4file, i+1) ));
446 : }
447 0 : gf_isom_remove_track(mp4file, i+1);
448 0 : i -= 1;
449 0 : Tracks = gf_isom_get_track_count(mp4file);
450 0 : break;
451 : }
452 8 : if (esd) gf_odf_desc_del((GF_Descriptor*)esd);
453 : }
454 : //no audio no video
455 5 : if (!AID && !VID) return GF_OK;
456 :
457 : /*reset all PLs*/
458 : visualPL = 0xFE;
459 : audioPL = 0xFE;
460 :
461 5 : od = (GF_ObjectDescriptor *) gf_isom_get_root_od(mp4file);
462 5 : if (od && (od->tag==GF_ODF_IOD_TAG)) {
463 5 : audioPL = ((GF_InitialObjectDescriptor*)od)->audio_profileAndLevel;
464 5 : visualPL = ((GF_InitialObjectDescriptor*)od)->visual_profileAndLevel;
465 : }
466 5 : if (od) gf_odf_desc_del((GF_Descriptor *)od);
467 :
468 :
469 : //create the OD AU
470 : bifs = 0;
471 5 : odU = (GF_ODUpdate *) gf_odf_com_new(GF_ODF_OD_UPDATE_TAG);
472 :
473 : a_esd = v_esd = NULL;
474 :
475 5 : gf_isom_set_root_od_id(mp4file, 1);
476 :
477 : bifsID = 1;
478 : odID = 2;
479 5 : if (keepESIDs) {
480 : bifsID = 1;
481 0 : while ((bifsID==AID) || (bifsID==VID)) bifsID++;
482 : odID = 2;
483 0 : while ((odID==AID) || (odID==VID) || (odID==bifsID)) odID++;
484 :
485 : }
486 :
487 5 : VideoTrack = gf_isom_get_track_by_id(mp4file, VID);
488 5 : AudioTrack = gf_isom_get_track_by_id(mp4file, AID);
489 :
490 5 : w = h = 0;
491 5 : if (VideoTrack) {
492 : bifs = 1;
493 5 : od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG);
494 5 : od->objectDescriptorID = ISMA_VIDEO_OD_ID;
495 :
496 5 : if (!keepESIDs && (VID != ISMA_VIDEO_ES_ID)) {
497 5 : gf_isom_set_track_id(mp4file, VideoTrack, ISMA_VIDEO_ES_ID);
498 : }
499 :
500 5 : v_esd = gf_isom_get_esd(mp4file, VideoTrack, 1);
501 5 : if (v_esd) {
502 5 : v_esd->OCRESID = no_ocr ? 0 : bifsID;
503 :
504 5 : gf_odf_desc_add_desc((GF_Descriptor *)od, (GF_Descriptor *)v_esd);
505 5 : gf_list_add(odU->objectDescriptors, od);
506 :
507 5 : gf_isom_get_track_layout_info(mp4file, VideoTrack, &w, &h, NULL, NULL, NULL);
508 5 : if (!w || !h) {
509 0 : gf_isom_get_visual_info(mp4file, VideoTrack, 1, &w, &h);
510 : #ifndef GPAC_DISABLE_AV_PARSERS
511 0 : if ((v_esd->decoderConfig->objectTypeIndication==GF_CODECID_MPEG4_PART2) && (v_esd->decoderConfig->streamType==GF_STREAM_VISUAL)) {
512 : GF_M4VDecSpecInfo dsi;
513 0 : gf_m4v_get_config(v_esd->decoderConfig->decoderSpecificInfo->data, v_esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi);
514 0 : if (!is_image && (!w || !h)) {
515 0 : w = dsi.width;
516 0 : h = dsi.height;
517 0 : gf_isom_set_visual_info(mp4file, VideoTrack, 1, w, h);
518 0 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[ISMA convert] Adjusting visual track size to %d x %d\n", w, h));
519 : }
520 0 : if (dsi.par_num && (dsi.par_den!=dsi.par_num)) {
521 0 : w *= dsi.par_num;
522 0 : w /= dsi.par_den;
523 : }
524 0 : if (dsi.VideoPL) visualPL = dsi.VideoPL;
525 : }
526 : #endif
527 : }
528 : }
529 : }
530 :
531 5 : if (AudioTrack) {
532 3 : od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG);
533 3 : od->objectDescriptorID = ISMA_AUDIO_OD_ID;
534 :
535 3 : if (!keepESIDs && (AID != ISMA_AUDIO_ES_ID)) {
536 3 : gf_isom_set_track_id(mp4file, AudioTrack, ISMA_AUDIO_ES_ID);
537 : }
538 :
539 3 : a_esd = gf_isom_get_esd(mp4file, AudioTrack, 1);
540 3 : if (a_esd) {
541 3 : a_esd->OCRESID = no_ocr ? 0 : bifsID;
542 :
543 3 : if (!keepESIDs) a_esd->ESID = ISMA_AUDIO_ES_ID;
544 3 : gf_odf_desc_add_desc((GF_Descriptor *)od, (GF_Descriptor *)a_esd);
545 3 : gf_list_add(odU->objectDescriptors, od);
546 3 : if (!bifs) {
547 : bifs = 3;
548 : } else {
549 : bifs = 2;
550 : }
551 :
552 : #ifndef GPAC_DISABLE_AV_PARSERS
553 3 : if (a_esd->decoderConfig->objectTypeIndication == GF_CODECID_AAC_MPEG4) {
554 : GF_M4ADecSpecInfo cfg;
555 3 : gf_m4a_get_config(a_esd->decoderConfig->decoderSpecificInfo->data, a_esd->decoderConfig->decoderSpecificInfo->dataLength, &cfg);
556 3 : audioPL = cfg.audioPL;
557 : }
558 : #endif
559 : }
560 : }
561 :
562 : /*update video cfg if needed*/
563 5 : if (v_esd) gf_isom_change_mpeg4_description(mp4file, VideoTrack, 1, v_esd);
564 5 : if (a_esd) gf_isom_change_mpeg4_description(mp4file, AudioTrack, 1, a_esd);
565 :
566 : /*likely 3GP or other files...*/
567 5 : if ((!a_esd && AudioTrack) || (!v_esd && VideoTrack)) return GF_OK;
568 :
569 : //get the OD sample
570 5 : codec = gf_odf_codec_new();
571 5 : samp = gf_isom_sample_new();
572 5 : gf_odf_codec_add_com(codec, (GF_ODCom *)odU);
573 5 : gf_odf_codec_encode(codec, 1);
574 5 : gf_odf_codec_get_au(codec, &samp->data, &samp->dataLength);
575 5 : gf_odf_codec_del(codec);
576 5 : samp->CTS_Offset = 0;
577 5 : samp->DTS = 0;
578 5 : samp->IsRAP = RAP;
579 :
580 : /*create the OD track*/
581 5 : odT = gf_isom_new_track(mp4file, odID, GF_ISOM_MEDIA_OD, gf_isom_get_timescale(mp4file));
582 5 : if (!odT) return gf_isom_last_error(mp4file);
583 :
584 5 : _esd = gf_odf_desc_esd_new(SLPredef_MP4);
585 5 : _esd->decoderConfig->bufferSizeDB = samp->dataLength;
586 5 : _esd->decoderConfig->objectTypeIndication = GF_CODECID_OD_V1;
587 5 : _esd->decoderConfig->streamType = GF_STREAM_OD;
588 5 : _esd->ESID = odID;
589 5 : _esd->OCRESID = no_ocr ? 0 : bifsID;
590 5 : gf_isom_new_mpeg4_description(mp4file, odT, _esd, NULL, NULL, &descIndex);
591 5 : gf_odf_desc_del((GF_Descriptor *)_esd);
592 5 : gf_isom_add_sample(mp4file, odT, 1, samp);
593 5 : gf_isom_sample_del(&samp);
594 :
595 5 : gf_isom_set_track_interleaving_group(mp4file, odT, 1);
596 :
597 : /*create the BIFS track*/
598 5 : bifsT = gf_isom_new_track(mp4file, bifsID, GF_ISOM_MEDIA_SCENE, gf_isom_get_timescale(mp4file));
599 5 : if (!bifsT) return gf_isom_last_error(mp4file);
600 :
601 5 : _esd = gf_odf_desc_esd_new(SLPredef_MP4);
602 5 : _esd->decoderConfig->bufferSizeDB = 20;
603 5 : _esd->decoderConfig->objectTypeIndication = GF_CODECID_BIFS_V2;
604 5 : _esd->decoderConfig->streamType = GF_STREAM_SCENE;
605 5 : _esd->ESID = bifsID;
606 5 : _esd->OCRESID = 0;
607 :
608 : /*rewrite ISMA BIFS cfg*/
609 5 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
610 : /*empty bifs stuff*/
611 5 : gf_bs_write_int(bs, 0, 17);
612 : /*command stream*/
613 5 : gf_bs_write_int(bs, 1, 1);
614 : /*in pixel metrics*/
615 5 : gf_bs_write_int(bs, 1, 1);
616 : /*with size*/
617 5 : gf_bs_write_int(bs, 1, 1);
618 5 : gf_bs_write_int(bs, w, 16);
619 5 : gf_bs_write_int(bs, h, 16);
620 5 : gf_bs_align(bs);
621 5 : gf_bs_get_content(bs, &_esd->decoderConfig->decoderSpecificInfo->data, &_esd->decoderConfig->decoderSpecificInfo->dataLength);
622 5 : gf_isom_new_mpeg4_description(mp4file, bifsT, _esd, NULL, NULL, &descIndex);
623 5 : gf_odf_desc_del((GF_Descriptor *)_esd);
624 5 : gf_bs_del(bs);
625 5 : gf_isom_set_visual_info(mp4file, bifsT, descIndex, w, h);
626 :
627 5 : samp = gf_isom_sample_new();
628 5 : samp->CTS_Offset = 0;
629 5 : samp->DTS = 0;
630 5 : switch (bifs) {
631 2 : case 1:
632 2 : if (is_image) {
633 0 : samp->data = (char *) ISMA_BIFS_IMAGE;
634 0 : samp->dataLength = 10;
635 : } else {
636 2 : samp->data = (char *) ISMA_GF_BIFS_VIDEO;
637 2 : samp->dataLength = 11;
638 : }
639 : break;
640 3 : case 2:
641 3 : if (is_image) {
642 0 : samp->data = (char *) ISMA_BIFS_AI;
643 0 : samp->dataLength = 15;
644 : } else {
645 3 : samp->data = (char *) ISMA_BIFS_AV;
646 3 : samp->dataLength = 16;
647 : }
648 : break;
649 0 : case 3:
650 0 : samp->data = (char *) ISMA_BIFS_AUDIO;
651 0 : samp->dataLength = 8;
652 0 : break;
653 : }
654 :
655 5 : samp->IsRAP = RAP;
656 :
657 5 : gf_isom_add_sample(mp4file, bifsT, 1, samp);
658 5 : samp->data = NULL;
659 5 : gf_isom_sample_del(&samp);
660 5 : gf_isom_set_track_interleaving_group(mp4file, bifsT, 1);
661 :
662 5 : gf_isom_set_track_enabled(mp4file, bifsT, GF_TRUE);
663 5 : gf_isom_set_track_enabled(mp4file, odT, GF_TRUE);
664 5 : gf_isom_add_track_to_root_od(mp4file, bifsT);
665 5 : gf_isom_add_track_to_root_od(mp4file, odT);
666 :
667 5 : gf_isom_set_pl_indication(mp4file, GF_ISOM_PL_SCENE, 1);
668 5 : gf_isom_set_pl_indication(mp4file, GF_ISOM_PL_GRAPHICS, 1);
669 5 : gf_isom_set_pl_indication(mp4file, GF_ISOM_PL_OD, 1);
670 5 : gf_isom_set_pl_indication(mp4file, GF_ISOM_PL_AUDIO, audioPL);
671 5 : gf_isom_set_pl_indication(mp4file, GF_ISOM_PL_VISUAL, (u8) (is_image ? 0xFE : visualPL));
672 :
673 5 : gf_isom_set_brand_info(mp4file, GF_ISOM_BRAND_MP42, 1);
674 5 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_ISOM, GF_TRUE);
675 5 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_3GP5, GF_TRUE);
676 5 : return GF_OK;
677 : }
678 :
679 :
680 : GF_EXPORT
681 1 : GF_Err gf_media_make_3gpp(GF_ISOFile *mp4file)
682 : {
683 : u32 Tracks, i, mType, stype, nb_vid, nb_avc, nb_aud, nb_txt, nb_non_mp4, nb_dims;
684 : Bool is_3g2 = 0;
685 :
686 1 : switch (gf_isom_get_mode(mp4file)) {
687 : case GF_ISOM_OPEN_EDIT:
688 : case GF_ISOM_OPEN_WRITE:
689 : case GF_ISOM_WRITE_EDIT:
690 : break;
691 : default:
692 : return GF_BAD_PARAM;
693 : }
694 :
695 1 : Tracks = gf_isom_get_track_count(mp4file);
696 : nb_vid = nb_aud = nb_txt = nb_avc = nb_non_mp4 = nb_dims = 0;
697 :
698 3 : for (i=0; i<Tracks; i++) {
699 2 : gf_isom_remove_track_from_root_od(mp4file, i+1);
700 :
701 2 : mType = gf_isom_get_media_type(mp4file, i+1);
702 2 : stype = gf_isom_get_media_subtype(mp4file, i+1, 1);
703 2 : switch (mType) {
704 1 : case GF_ISOM_MEDIA_VISUAL:
705 : case GF_ISOM_MEDIA_AUXV:
706 : case GF_ISOM_MEDIA_PICT:
707 : /*remove image tracks if wanted*/
708 1 : if (gf_isom_get_sample_count(mp4file, i+1)<=1) {
709 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[3GPP convert] Visual track ID %d: only one sample found\n", gf_isom_get_track_id(mp4file, i+1) ));
710 : //goto remove_track;
711 : }
712 :
713 1 : if (stype == GF_ISOM_SUBTYPE_MPEG4_CRYP) gf_isom_get_ismacryp_info(mp4file, i+1, 1, &stype, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
714 :
715 1 : switch (stype) {
716 0 : case GF_ISOM_SUBTYPE_3GP_H263:
717 0 : nb_vid++;
718 0 : nb_non_mp4 ++;
719 0 : break;
720 1 : case GF_ISOM_SUBTYPE_AVC_H264:
721 : case GF_ISOM_SUBTYPE_AVC2_H264:
722 : case GF_ISOM_SUBTYPE_AVC3_H264:
723 : case GF_ISOM_SUBTYPE_AVC4_H264:
724 : case GF_ISOM_SUBTYPE_SVC_H264:
725 : case GF_ISOM_SUBTYPE_MVC_H264:
726 1 : nb_vid++;
727 1 : nb_avc++;
728 1 : break;
729 0 : case GF_ISOM_SUBTYPE_MPEG4:
730 : {
731 0 : GF_ESD *esd = gf_isom_get_esd(mp4file, i+1, 1);
732 : /*both MPEG4-Video and H264/AVC/SVC are supported*/
733 0 : if ((esd->decoderConfig->objectTypeIndication==GF_CODECID_MPEG4_PART2) || (esd->decoderConfig->objectTypeIndication==GF_CODECID_AVC) || (esd->decoderConfig->objectTypeIndication==GF_CODECID_SVC) || (esd->decoderConfig->objectTypeIndication==GF_CODECID_MVC)) {
734 0 : nb_vid++;
735 : } else {
736 0 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[3GPP convert] Video format not supported by 3GP - removing track ID %d\n", gf_isom_get_track_id(mp4file, i+1) ));
737 : goto remove_track;
738 : }
739 0 : gf_odf_desc_del((GF_Descriptor *)esd);
740 : }
741 0 : break;
742 0 : default:
743 0 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[3GPP convert] Video format not supported by 3GP - removing track ID %d\n", gf_isom_get_track_id(mp4file, i+1) ));
744 : goto remove_track;
745 : }
746 : break;
747 1 : case GF_ISOM_MEDIA_AUDIO:
748 1 : if (stype == GF_ISOM_SUBTYPE_MPEG4_CRYP) gf_isom_get_ismacryp_info(mp4file, i+1, 1, &stype, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
749 1 : switch (stype) {
750 0 : case GF_ISOM_SUBTYPE_3GP_EVRC:
751 : case GF_ISOM_SUBTYPE_3GP_QCELP:
752 : case GF_ISOM_SUBTYPE_3GP_SMV:
753 : is_3g2 = 1;
754 0 : nb_aud++;
755 0 : break;
756 0 : case GF_ISOM_SUBTYPE_3GP_AMR:
757 : case GF_ISOM_SUBTYPE_3GP_AMR_WB:
758 0 : nb_aud++;
759 0 : nb_non_mp4 ++;
760 0 : break;
761 1 : case GF_ISOM_SUBTYPE_MPEG4:
762 : {
763 1 : GF_ESD *esd = gf_isom_get_esd(mp4file, i+1, 1);
764 1 : switch (esd->decoderConfig->objectTypeIndication) {
765 0 : case GF_CODECID_QCELP:
766 : case GF_CODECID_EVRC:
767 : case GF_CODECID_SMV:
768 : is_3g2 = 1;
769 1 : case GF_CODECID_AAC_MPEG4:
770 1 : nb_aud++;
771 : break;
772 0 : default:
773 0 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[3GPP convert] Audio format not supported by 3GP - removing track ID %d\n", gf_isom_get_track_id(mp4file, i+1) ));
774 : goto remove_track;
775 : }
776 1 : gf_odf_desc_del((GF_Descriptor *)esd);
777 : }
778 1 : break;
779 0 : default:
780 0 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[3GPP convert] Audio format not supported by 3GP - removing track ID %d\n", gf_isom_get_track_id(mp4file, i+1) ));
781 : goto remove_track;
782 : }
783 : break;
784 :
785 0 : case GF_ISOM_MEDIA_SUBT:
786 0 : gf_isom_set_media_type(mp4file, i+1, GF_ISOM_MEDIA_TEXT);
787 0 : case GF_ISOM_MEDIA_TEXT:
788 0 : nb_txt++;
789 0 : break;
790 :
791 0 : case GF_ISOM_MEDIA_SCENE:
792 0 : if (stype == GF_ISOM_MEDIA_DIMS) {
793 : nb_dims++;
794 : break;
795 : }
796 : /*clean file*/
797 : default:
798 0 : if (mType==GF_ISOM_MEDIA_HINT) {
799 0 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[3GPP convert] Removing Hint track ID %d\n", gf_isom_get_track_id(mp4file, i+1) ));
800 : } else {
801 0 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[3GPP convert] Removing system track ID %d\n", gf_isom_get_track_id(mp4file, i+1) ));
802 : }
803 :
804 0 : remove_track:
805 0 : gf_isom_remove_track(mp4file, i+1);
806 0 : i -= 1;
807 0 : Tracks = gf_isom_get_track_count(mp4file);
808 0 : break;
809 : }
810 : }
811 :
812 : /*no more IOD*/
813 1 : gf_isom_remove_root_od(mp4file);
814 :
815 1 : if (is_3g2) {
816 0 : gf_isom_set_brand_info(mp4file, GF_ISOM_BRAND_3G2A, 65536);
817 0 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_3GP6, GF_FALSE);
818 0 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_3GP5, GF_FALSE);
819 0 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_3GG6, GF_FALSE);
820 0 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[3GPP convert] Setting major brand to 3GPP2\n"));
821 : } else {
822 : /*update FType*/
823 1 : if ((nb_vid>1) || (nb_aud>1) || (nb_txt>1)) {
824 : /*3GPP general purpose*/
825 0 : gf_isom_set_brand_info(mp4file, GF_ISOM_BRAND_3GG6, 1024);
826 0 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_3GP6, GF_FALSE);
827 0 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_3GP5, GF_FALSE);
828 0 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_3GP4, GF_FALSE);
829 0 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[3GPP convert] Setting major brand to 3GPP Generic file\n"));
830 1 : } else if (nb_txt) {
831 0 : gf_isom_set_brand_info(mp4file, GF_ISOM_BRAND_3GP6, 1024);
832 0 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_3GP5, GF_TRUE);
833 0 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_3GP4, GF_TRUE);
834 0 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_3GG6, GF_FALSE);
835 0 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[3GPP convert] Setting major brand to 3GPP V6 file\n"));
836 1 : } else if (nb_avc) {
837 1 : gf_isom_set_brand_info(mp4file, GF_ISOM_BRAND_3GP6, 0/*1024*/);
838 1 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_AVC1, GF_TRUE);
839 1 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_3GP5, GF_FALSE);
840 1 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_3GP4, GF_FALSE);
841 1 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[3GPP convert] Setting major brand to 3GPP V6 file + AVC compatible\n"));
842 : } else {
843 0 : gf_isom_set_brand_info(mp4file, GF_ISOM_BRAND_3GP5, 0/*1024*/);
844 0 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_3GP6, 0);
845 0 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_3GP4, GF_TRUE);
846 0 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_3GG6, GF_FALSE);
847 0 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[3GPP convert] Setting major brand to 3GPP V5 file\n"));
848 : }
849 : }
850 : /*add/remove MP4 brands and add isom*/
851 1 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_MP41, (u8) ((nb_avc||is_3g2||nb_non_mp4) ? GF_FALSE : GF_TRUE));
852 1 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_MP42, (u8) (nb_non_mp4 ? GF_FALSE : GF_TRUE));
853 1 : gf_isom_modify_alternate_brand(mp4file, GF_ISOM_BRAND_ISOM, GF_TRUE);
854 1 : return GF_OK;
855 : }
856 :
857 : GF_EXPORT
858 1 : GF_Err gf_media_make_psp(GF_ISOFile *mp4)
859 : {
860 : u32 i, count;
861 : u32 nb_a, nb_v;
862 : /*psp track UUID*/
863 1 : bin128 psp_track_uuid = {0x55, 0x53, 0x4D, 0x54, 0x21, 0xD2, 0x4F, 0xCE, 0xBB, 0x88, 0x69, 0x5C, 0xFA, 0xC9, 0xC7, 0x40};
864 1 : u8 psp_track_sig [] = {0x00, 0x00, 0x00, 0x1C, 0x4D, 0x54, 0x44, 0x54, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0A, 0x55, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00};
865 : /*psp mov UUID*/
866 : //bin128 psp_uuid = {0x50, 0x52, 0x4F, 0x46, 0x21, 0xD2, 0x4F, 0xCE, 0xBB, 0x88, 0x69, 0x5C, 0xFA, 0xC9, 0xC7, 0x40};
867 :
868 : nb_a = nb_v = 0;
869 1 : count = gf_isom_get_track_count(mp4);
870 4 : for (i=0; i<count; i++) {
871 2 : switch (gf_isom_get_media_type(mp4, i+1)) {
872 1 : case GF_ISOM_MEDIA_VISUAL:
873 1 : nb_v++;
874 1 : break;
875 1 : case GF_ISOM_MEDIA_AUDIO:
876 1 : nb_a++;
877 1 : break;
878 : }
879 : }
880 1 : if ((nb_v != 1) && (nb_a!=1)) {
881 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[PSP convert] Movies need one audio track and one video track\n" ));
882 : return GF_BAD_PARAM;
883 : }
884 2 : for (i=0; i<count; i++) {
885 2 : switch (gf_isom_get_media_type(mp4, i+1)) {
886 2 : case GF_ISOM_MEDIA_VISUAL:
887 : case GF_ISOM_MEDIA_AUDIO:
888 : /*if no edit list, add one*/
889 2 : if (!gf_isom_get_edits_count(mp4, i+1)) {
890 1 : GF_ISOSample *samp = gf_isom_get_sample_info(mp4, i+1, 1, NULL, NULL);
891 1 : if (samp) {
892 1 : gf_isom_append_edit(mp4, i+1, gf_isom_get_track_duration(mp4, i+1), samp->CTS_Offset, GF_ISOM_EDIT_NORMAL);
893 1 : gf_isom_sample_del(&samp);
894 : }
895 : }
896 : /*add PSP UUID*/
897 2 : gf_isom_remove_uuid(mp4, i+1, psp_track_uuid);
898 2 : gf_isom_add_uuid(mp4, i+1, psp_track_uuid, (char *) psp_track_sig, 28);
899 2 : break;
900 0 : default:
901 0 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[PSP convert] Removing track ID %d\n", gf_isom_get_track_id(mp4, i+1) ));
902 0 : gf_isom_remove_track(mp4, i+1);
903 0 : i -= 1;
904 0 : count -= 1;
905 0 : break;
906 : }
907 : }
908 1 : gf_isom_set_brand_info(mp4, GF_ISOM_BRAND_MSNV, 0);
909 1 : gf_isom_modify_alternate_brand(mp4, GF_ISOM_BRAND_MSNV, GF_TRUE);
910 1 : return GF_OK;
911 : }
912 :
913 1 : GF_Err gf_media_get_color_info(GF_ISOFile *file, u32 track, u32 sampleDescriptionIndex, u32 *colour_type, u16 *colour_primaries, u16 *transfer_characteristics, u16 *matrix_coefficients, Bool *full_range_flag)
914 : {
915 : #ifndef GPAC_DISABLE_AV_PARSERS
916 1 : u32 stype = gf_isom_get_media_subtype(file, track, sampleDescriptionIndex);
917 1 : if ((stype==GF_ISOM_SUBTYPE_AVC_H264)
918 : || (stype==GF_ISOM_SUBTYPE_AVC2_H264)
919 : || (stype==GF_ISOM_SUBTYPE_AVC3_H264)
920 1 : || (stype==GF_ISOM_SUBTYPE_AVC4_H264)
921 : ) {
922 : AVCState avc;
923 0 : GF_AVCConfig *avcc = gf_isom_avc_config_get(file, track, sampleDescriptionIndex);
924 : u32 i;
925 : s32 idx;
926 : GF_NALUFFParam *slc;
927 :
928 : memset(&avc, 0, sizeof(AVCState));
929 0 : avc.sps_active_idx = -1;
930 :
931 0 : i=0;
932 0 : while ((slc = (GF_NALUFFParam *)gf_list_enum(avcc->sequenceParameterSets, &i))) {
933 0 : idx = gf_avc_read_sps(slc->data, slc->size, &avc, 0, NULL);
934 :
935 0 : if (idx<0) continue;
936 0 : if (! avc.sps[idx].vui_parameters_present_flag )
937 0 : continue;
938 :
939 0 : *colour_type = avc.sps[idx].vui.video_format;
940 0 : *colour_primaries = avc.sps[idx].vui.colour_primaries;
941 0 : *transfer_characteristics = avc.sps[idx].vui.transfer_characteristics;
942 0 : *matrix_coefficients = avc.sps[idx].vui.matrix_coefficients;
943 0 : *full_range_flag = avc.sps[idx].vui.video_full_range_flag;
944 0 : gf_odf_avc_cfg_del(avcc);
945 0 : return GF_OK;
946 : }
947 0 : gf_odf_avc_cfg_del(avcc);
948 0 : return GF_NOT_FOUND;
949 : }
950 1 : if ((stype==GF_ISOM_SUBTYPE_HEV1)
951 1 : || (stype==GF_ISOM_SUBTYPE_HEV2)
952 1 : || (stype==GF_ISOM_SUBTYPE_HVC1)
953 1 : || (stype==GF_ISOM_SUBTYPE_HVC2)
954 1 : || (stype==GF_ISOM_SUBTYPE_LHV1)
955 1 : || (stype==GF_ISOM_SUBTYPE_LHE1)
956 : ) {
957 : HEVCState hvc;
958 0 : GF_HEVCConfig *hvcc = gf_isom_hevc_config_get(file, track, sampleDescriptionIndex);
959 : u32 i;
960 : GF_NALUFFParamArray *pa;
961 :
962 : memset(&hvc, 0, sizeof(HEVCState));
963 0 : hvc.sps_active_idx = -1;
964 :
965 0 : i=0;
966 0 : while ((pa = (GF_NALUFFParamArray *)gf_list_enum(hvcc->param_array, &i))) {
967 : GF_NALUFFParam *slc;
968 : u32 j;
969 : s32 idx;
970 0 : if (pa->type != GF_HEVC_NALU_SEQ_PARAM) continue;
971 :
972 0 : j=0;
973 0 : while ((slc = (GF_NALUFFParam *)gf_list_enum(pa->nalus, &j))) {
974 0 : idx = gf_hevc_read_sps(slc->data, slc->size, &hvc);
975 :
976 0 : if (idx<0) continue;
977 0 : if (! hvc.sps[idx].vui_parameters_present_flag)
978 0 : continue;
979 :
980 0 : *colour_type = hvc.sps[idx].video_format;
981 0 : *colour_primaries = hvc.sps[idx].colour_primaries;
982 0 : *transfer_characteristics = hvc.sps[idx].transfer_characteristic;
983 0 : *matrix_coefficients = hvc.sps[idx].matrix_coeffs;
984 0 : *full_range_flag = hvc.sps[idx].video_full_range_flag;
985 0 : gf_odf_hevc_cfg_del(hvcc);
986 0 : return GF_OK;
987 : }
988 : }
989 0 : gf_odf_hevc_cfg_del(hvcc);
990 0 : return GF_NOT_FOUND;
991 : }
992 1 : if (stype==GF_ISOM_SUBTYPE_AV01) {
993 : AV1State av1;
994 :
995 0 : gf_av1_init_state(&av1);
996 0 : av1.config = gf_isom_av1_config_get(file, track, sampleDescriptionIndex);
997 0 : if (av1.config) {
998 : u32 i;
999 0 : for (i=0; i<gf_list_count(av1.config->obu_array); i++) {
1000 : GF_BitStream *bs;
1001 : ObuType obu_type;
1002 : u32 hdr_size;
1003 : u64 obu_size;
1004 0 : GF_AV1_OBUArrayEntry *obu = gf_list_get(av1.config->obu_array, i);
1005 0 : bs = gf_bs_new(obu->obu, (u32) obu->obu_length, GF_BITSTREAM_READ);
1006 0 : gf_av1_parse_obu(bs, &obu_type, &obu_size, &hdr_size, &av1);
1007 0 : gf_bs_del(bs);
1008 :
1009 0 : if (av1.color_description_present_flag) {
1010 0 : *colour_type = 0;
1011 0 : *colour_primaries = av1.color_primaries;
1012 0 : *transfer_characteristics = av1.transfer_characteristics;
1013 0 : *matrix_coefficients = av1.matrix_coefficients;
1014 0 : *full_range_flag = av1.color_range;
1015 0 : if (av1.config) gf_odf_av1_cfg_del(av1.config);
1016 0 : gf_av1_reset_state(&av1, GF_TRUE);
1017 0 : return GF_OK;
1018 : }
1019 : }
1020 : }
1021 0 : if (av1.config) gf_odf_av1_cfg_del(av1.config);
1022 0 : gf_av1_reset_state(&av1, GF_TRUE);
1023 0 : return GF_NOT_FOUND;
1024 : }
1025 :
1026 : #endif
1027 : return GF_NOT_SUPPORTED;
1028 : }
1029 :
1030 :
1031 : GF_EXPORT
1032 2 : GF_Err gf_media_check_qt_prores(GF_ISOFile *mp4)
1033 : {
1034 : u32 i, count, timescale, def_dur=0, video_tk=0;
1035 : u32 prores_type = 0;
1036 : GF_Err e;
1037 2 : u32 colour_type=0;
1038 2 : u16 colour_primaries=0, transfer_characteristics=0, matrix_coefficients=0;
1039 2 : Bool full_range_flag=GF_FALSE;
1040 2 : u32 hspacing=0, vspacing=0;
1041 : u32 nb_video_tracks;
1042 2 : u32 target_ts = 0, w=0, h=0, chunk_size=0;
1043 :
1044 : nb_video_tracks = 0;
1045 :
1046 2 : count = gf_isom_get_track_count(mp4);
1047 16 : for (i=0; i<count; i++) {
1048 12 : u32 mtype = gf_isom_get_media_type(mp4, i+1);
1049 12 : if (mtype!=GF_ISOM_MEDIA_VISUAL) continue;
1050 2 : nb_video_tracks++;
1051 2 : if (!video_tk)
1052 : video_tk = i+1;
1053 : }
1054 :
1055 2 : if ((nb_video_tracks==1) && video_tk) {
1056 2 : u32 video_subtype = gf_isom_get_media_subtype(mp4, video_tk, 1);
1057 2 : switch (video_subtype) {
1058 2 : case GF_QT_SUBTYPE_APCH:
1059 : case GF_QT_SUBTYPE_APCO:
1060 : case GF_QT_SUBTYPE_APCN:
1061 : case GF_QT_SUBTYPE_APCS:
1062 : case GF_QT_SUBTYPE_AP4X:
1063 : case GF_QT_SUBTYPE_AP4H:
1064 : prores_type=video_subtype;
1065 2 : break;
1066 : }
1067 : }
1068 :
1069 2 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[QTFF/ProRes] Adjusting %s compliancy\n", prores_type ? "ProRes" : "QTFF"));
1070 :
1071 : //adjust audio tracks
1072 14 : for (i=0; i<count; i++) {
1073 12 : u32 mtype = gf_isom_get_media_type(mp4, i+1);
1074 :
1075 : //remove bitrate info (isobmff)
1076 12 : gf_isom_update_bitrate(mp4, i+1, 1, 0, 0, 0);
1077 :
1078 12 : if (mtype==GF_ISOM_MEDIA_AUDIO) {
1079 : u32 sr, nb_ch, bps;
1080 8 : gf_isom_get_audio_info(mp4, i+1, 1, &sr, &nb_ch, &bps);
1081 8 : gf_isom_set_audio_info(mp4, i+1, 1, sr, nb_ch, bps, GF_IMPORT_AUDIO_SAMPLE_ENTRY_v1_QTFF);
1082 :
1083 8 : gf_isom_hint_max_chunk_duration(mp4, i+1, gf_isom_get_media_timescale(mp4, i+1) / 2);
1084 8 : continue;
1085 : }
1086 : }
1087 : //make QT
1088 2 : gf_isom_remove_root_od(mp4);
1089 2 : if (gf_isom_get_mode(mp4) != GF_ISOM_OPEN_WRITE) {
1090 2 : gf_isom_set_brand_info(mp4, GF_ISOM_BRAND_QT, 512);
1091 2 : gf_isom_reset_alt_brands(mp4);
1092 : } else {
1093 : u32 brand, version;
1094 0 : gf_isom_get_brand_info(mp4, &brand, &version, NULL);
1095 0 : if (brand != GF_ISOM_BRAND_QT) {
1096 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[ProRes] Cannot change brand from \"%s\" to \"qt \", flat storage used. Try using different storage mode\n", gf_4cc_to_str(brand)));
1097 : }
1098 : }
1099 :
1100 2 : if (!video_tk) {
1101 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_AUTHOR, ("[QTFF] No visual track\n"));
1102 : return GF_OK;
1103 : }
1104 :
1105 2 : if (nb_video_tracks>1) {
1106 0 : if (prores_type) {
1107 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("QTFF] cannot adjust params to prores, %d video tracks present\n", nb_video_tracks));
1108 : return GF_BAD_PARAM;
1109 : }
1110 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_AUTHOR, ("[ProRes] no prores codec found but %d video tracks, not adjusting file\n", nb_video_tracks));
1111 : return GF_OK;
1112 : }
1113 :
1114 2 : if (prores_type) {
1115 : char *comp_name = NULL;
1116 2 : switch (prores_type) {
1117 2 : case GF_QT_SUBTYPE_APCH: comp_name = "\x0013""Apple ProRes 422 HQ"; break;
1118 0 : case GF_QT_SUBTYPE_APCO: comp_name = "\x0016""Apple ProRes 422 Proxy"; break;
1119 0 : case GF_QT_SUBTYPE_APCN: comp_name = "\x0010""Apple ProRes 422"; break;
1120 0 : case GF_QT_SUBTYPE_APCS: comp_name = "\x0013""Apple ProRes 422 LT"; break;
1121 0 : case GF_QT_SUBTYPE_AP4X: comp_name = "\x0014""Apple ProRes 4444 XQ"; break;
1122 0 : case GF_QT_SUBTYPE_AP4H: comp_name = "\x0011""Apple ProRes 4444"; break;
1123 : }
1124 2 : gf_isom_update_video_sample_entry_fields(mp4, video_tk, 1, 0, GF_4CC('a','p','p','l'), 0, 0x3FF, 72<<16, 72<<16, 1, comp_name, -1);
1125 : }
1126 :
1127 2 : timescale = gf_isom_get_media_timescale(mp4, video_tk);
1128 2 : def_dur = gf_isom_get_constant_sample_duration(mp4, video_tk);
1129 2 : if (!def_dur) {
1130 0 : def_dur = gf_isom_get_sample_duration(mp4, video_tk, 2);
1131 0 : if (!def_dur) {
1132 0 : def_dur = gf_isom_get_sample_duration(mp4, video_tk, 1);
1133 : }
1134 : }
1135 2 : if (!def_dur) {
1136 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[ProRes] cannot estimate default sample duration for video track\n"));
1137 : return GF_NON_COMPLIANT_BITSTREAM;
1138 : }
1139 :
1140 2 : gf_isom_get_pixel_aspect_ratio(mp4, video_tk, 1, &hspacing, &vspacing);
1141 : //force 1:1
1142 2 : if ((hspacing<=1) || (vspacing<=1)) {
1143 2 : hspacing = vspacing = 1;
1144 2 : gf_isom_set_pixel_aspect_ratio(mp4, video_tk, 1, 1, 1, GF_TRUE);
1145 : }
1146 :
1147 : //patch enof/prof/clef
1148 2 : if (prores_type) {
1149 2 : gf_isom_update_aperture_info(mp4, video_tk, GF_FALSE);
1150 : }
1151 :
1152 2 : e = gf_isom_get_color_info(mp4, video_tk, 1, &colour_type, &colour_primaries, &transfer_characteristics, &matrix_coefficients, &full_range_flag);
1153 2 : if (e==GF_NOT_FOUND) {
1154 0 : colour_primaries = transfer_characteristics = matrix_coefficients = 0;
1155 0 : if (prores_type) {
1156 : u32 di;
1157 0 : GF_ISOSample *s = gf_isom_get_sample(mp4, video_tk, 1, &di);
1158 0 : if (s && s->dataLength>24) {
1159 0 : GF_BitStream *bs = gf_bs_new(s->data, s->dataLength, GF_BITSTREAM_READ);
1160 0 : gf_bs_read_u32(bs); //frame size
1161 0 : gf_bs_read_u32(bs); //frame ID
1162 0 : gf_bs_read_u32(bs); //frame header size + reserved + bs version
1163 0 : gf_bs_read_u32(bs); //encoder id
1164 0 : gf_bs_read_u32(bs); //w and h
1165 0 : gf_bs_read_u16(bs); //bunch of flags
1166 0 : colour_primaries = gf_bs_read_u8(bs);
1167 0 : transfer_characteristics = gf_bs_read_u8(bs);
1168 0 : matrix_coefficients = gf_bs_read_u8(bs);
1169 0 : gf_bs_del(bs);
1170 : }
1171 0 : gf_isom_sample_del(&s);
1172 : } else {
1173 0 : e = gf_media_get_color_info(mp4, video_tk, 1, &colour_type, &colour_primaries, &transfer_characteristics, &matrix_coefficients, &full_range_flag);
1174 0 : if (e)
1175 0 : colour_primaries=0;
1176 : }
1177 0 : if (!colour_primaries) {
1178 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[ProRes] No color info present in visual track, defaulting to BT709\n"));
1179 0 : colour_primaries = 1;
1180 0 : transfer_characteristics = 1;
1181 0 : matrix_coefficients = 1;
1182 : } else {
1183 0 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[ProRes] No color info present in visual track, extracting from %s\n", prores_type ? "first ProRes frame" : "sample description"));
1184 : }
1185 0 : gf_isom_set_visual_color_info(mp4, video_tk, 1, GF_4CC('n','c','l','c'), colour_primaries, transfer_characteristics, matrix_coefficients, GF_FALSE, NULL, 0);
1186 2 : } else if (e) {
1187 : return e;
1188 : }
1189 2 : gf_isom_get_visual_info(mp4, video_tk, 1, &w, &h);
1190 :
1191 : u32 ifps;
1192 2 : Double FPS = timescale;
1193 2 : FPS /= def_dur;
1194 2 : FPS *= 100;
1195 2 : ifps = (u32) FPS;
1196 2 : if (ifps>= 2996 && ifps<=2998) target_ts = 30000; //29.97
1197 1 : else if (ifps>= 2999 && ifps<=3001) target_ts = 3000; //30
1198 1 : else if (ifps>= 2495 && ifps<=2505) target_ts = 2500; //25
1199 0 : else if (ifps >= 2396 && ifps<=2398) target_ts = 24000; //23.97
1200 0 : else if ((ifps>=2399) && (ifps<=2401)) target_ts = 2400; //24
1201 0 : else if (ifps>= 4990 && ifps<=5010) target_ts = 5000; //50
1202 0 : else if (ifps>= 5993 && ifps<=5995) target_ts = 60000; //59.94
1203 0 : else if (ifps>= 5996 && ifps<=6004) target_ts = 6000; //60
1204 :
1205 : if (!target_ts) {
1206 0 : if (prores_type) {
1207 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[ProRes] Unrecognized frame rate %g\n", ((Double)timescale)/def_dur ));
1208 : return GF_NON_COMPLIANT_BITSTREAM;
1209 : } else {
1210 : target_ts = timescale;
1211 : }
1212 : }
1213 :
1214 2 : if (target_ts != timescale) {
1215 1 : GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[ProRes] Adjusting timescale to %d\n", target_ts));
1216 1 : gf_isom_set_media_timescale(mp4, video_tk, target_ts, 0, 0);
1217 : }
1218 2 : gf_isom_set_timescale(mp4, target_ts);
1219 2 : if ((w<=720) && (h<=576)) chunk_size = 2000000;
1220 : else chunk_size = 4000000;
1221 :
1222 2 : gf_isom_set_interleave_time(mp4, 500);
1223 2 : gf_isom_hint_max_chunk_size(mp4, video_tk, chunk_size);
1224 :
1225 2 : return GF_OK;
1226 : }
1227 :
1228 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
1229 :
1230 : GF_EXPORT
1231 1256 : GF_ESD *gf_media_map_esd(GF_ISOFile *mp4, u32 track, u32 stsd_idx)
1232 : {
1233 : GF_ESD *esd;
1234 : u32 subtype;
1235 :
1236 1256 : if (!stsd_idx) stsd_idx = 1;
1237 1256 : subtype = gf_isom_get_media_subtype(mp4, track, stsd_idx);
1238 : /*all types with an official MPEG-4 mapping*/
1239 1256 : switch (subtype) {
1240 932 : case GF_ISOM_SUBTYPE_MPEG4:
1241 : case GF_ISOM_SUBTYPE_MPEG4_CRYP:
1242 : case GF_ISOM_SUBTYPE_AVC_H264:
1243 : case GF_ISOM_SUBTYPE_AVC2_H264:
1244 : case GF_ISOM_SUBTYPE_AVC3_H264:
1245 : case GF_ISOM_SUBTYPE_AVC4_H264:
1246 : case GF_ISOM_SUBTYPE_SVC_H264:
1247 : case GF_ISOM_SUBTYPE_MVC_H264:
1248 : case GF_ISOM_SUBTYPE_3GP_EVRC:
1249 : case GF_ISOM_SUBTYPE_3GP_QCELP:
1250 : case GF_ISOM_SUBTYPE_3GP_SMV:
1251 : case GF_ISOM_SUBTYPE_HVC1:
1252 : case GF_ISOM_SUBTYPE_HEV1:
1253 : case GF_ISOM_SUBTYPE_HVC2:
1254 : case GF_ISOM_SUBTYPE_HEV2:
1255 : case GF_ISOM_SUBTYPE_LHV1:
1256 : case GF_ISOM_SUBTYPE_LHE1:
1257 : case GF_ISOM_SUBTYPE_AV01:
1258 : case GF_ISOM_SUBTYPE_VP09:
1259 : case GF_ISOM_SUBTYPE_VP08:
1260 : case GF_ISOM_SUBTYPE_VVC1:
1261 : case GF_ISOM_SUBTYPE_VVI1:
1262 : case GF_ISOM_SUBTYPE_MH3D_MHA1:
1263 : case GF_ISOM_SUBTYPE_MH3D_MHA2:
1264 : case GF_ISOM_SUBTYPE_MH3D_MHM1:
1265 : case GF_ISOM_SUBTYPE_MH3D_MHM2:
1266 932 : return gf_isom_get_esd(mp4, track, stsd_idx);
1267 : }
1268 :
1269 324 : if (subtype == GF_ISOM_SUBTYPE_OPUS) {
1270 2 : esd = gf_isom_get_esd(mp4, track, 1);
1271 2 : if (!esd) return NULL;
1272 :
1273 2 : esd->decoderConfig->objectTypeIndication = GF_CODECID_OPUS;
1274 2 : return esd;
1275 : }
1276 :
1277 322 : if (subtype == GF_ISOM_SUBTYPE_3GP_DIMS) {
1278 : GF_BitStream *bs;
1279 : GF_DIMSDescription dims;
1280 3 : esd = gf_odf_desc_esd_new(0);
1281 3 : esd->slConfig->timestampResolution = gf_isom_get_media_timescale(mp4, track);
1282 3 : esd->ESID = gf_isom_get_track_id(mp4, track);
1283 3 : esd->OCRESID = esd->ESID;
1284 3 : esd->decoderConfig->streamType = GF_STREAM_SCENE;
1285 : /*use private DSI*/
1286 3 : esd->decoderConfig->objectTypeIndication = GF_CODECID_DIMS;
1287 3 : gf_isom_get_dims_description(mp4, track, 1, &dims);
1288 3 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
1289 : /*format ext*/
1290 3 : gf_bs_write_u8(bs, dims.profile);
1291 3 : gf_bs_write_u8(bs, dims.level);
1292 3 : gf_bs_write_int(bs, dims.pathComponents, 4);
1293 3 : gf_bs_write_int(bs, dims.fullRequestHost, 1);
1294 3 : gf_bs_write_int(bs, dims.streamType, 1);
1295 3 : gf_bs_write_int(bs, dims.containsRedundant, 2);
1296 3 : gf_bs_write_data(bs, (char*)dims.textEncoding, (u32) strlen(dims.textEncoding)+1);
1297 3 : gf_bs_write_data(bs, (char*)dims.contentEncoding, (u32) strlen(dims.contentEncoding)+1);
1298 3 : gf_bs_get_content(bs, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength);
1299 3 : gf_bs_del(bs);
1300 : return esd;
1301 : }
1302 319 : if (mp4->convert_streaming_text && ((subtype == GF_ISOM_SUBTYPE_TEXT) || (subtype == GF_ISOM_SUBTYPE_TX3G))
1303 : ) {
1304 1 : return gf_isom_get_esd(mp4, track, stsd_idx);
1305 : }
1306 : return NULL;
1307 : }
1308 :
1309 : GF_EXPORT
1310 72 : GF_ESD *gf_media_map_item_esd(GF_ISOFile *mp4, u32 item_id)
1311 : {
1312 : u32 item_type;
1313 : u32 prot_scheme, prot_scheme_version;
1314 : Bool is_self_ref;
1315 : const char *name;
1316 : const char *mime;
1317 : const char *encoding;
1318 : const char *url;
1319 : const char *urn;
1320 : GF_ESD *esd;
1321 : GF_Err e;
1322 :
1323 72 : u32 item_idx = gf_isom_get_meta_item_by_id(mp4, GF_TRUE, 0, item_id);
1324 72 : if (!item_idx) return NULL;
1325 :
1326 72 : e = gf_isom_get_meta_item_info(mp4, GF_TRUE, 0, item_idx, &item_id, &item_type, &prot_scheme, &prot_scheme_version, &is_self_ref, &name, &mime, &encoding, &url, &urn);
1327 72 : if (e != GF_OK) return NULL;
1328 :
1329 72 : if (item_type == GF_ISOM_SUBTYPE_HVC1) {
1330 : GF_ImageItemProperties props;
1331 52 : esd = gf_odf_desc_esd_new(0);
1332 52 : if (item_id > (1 << 16)) {
1333 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("Item ID greater than 16 bits, does not fit on ES ID\n"));
1334 : }
1335 52 : esd->ESID = (u16)item_id;
1336 52 : esd->OCRESID = esd->ESID;
1337 52 : esd->decoderConfig->streamType = GF_STREAM_VISUAL;
1338 52 : esd->decoderConfig->objectTypeIndication = GF_CODECID_HEVC;
1339 52 : e = gf_isom_get_meta_image_props(mp4, GF_TRUE, 0, item_id, &props);
1340 52 : if (e == GF_OK && props.config) {
1341 52 : gf_odf_hevc_cfg_write(((GF_HEVCConfigurationBox *)props.config)->config, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength);
1342 : }
1343 52 : esd->slConfig->hasRandomAccessUnitsOnlyFlag = 1;
1344 52 : esd->slConfig->useTimestampsFlag = 1;
1345 52 : esd->slConfig->timestampResolution = 1000;
1346 : return esd;
1347 20 : } else if (item_type == GF_ISOM_SUBTYPE_AVC_H264) {
1348 : GF_ImageItemProperties props;
1349 20 : esd = gf_odf_desc_esd_new(0);
1350 20 : if (item_id > (1 << 16)) {
1351 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("Item ID greater than 16 bits, does not fit on ES ID\n"));
1352 : }
1353 20 : esd->ESID = (u16)item_id;
1354 20 : esd->OCRESID = esd->ESID;
1355 20 : esd->decoderConfig->streamType = GF_STREAM_VISUAL;
1356 20 : esd->decoderConfig->objectTypeIndication = GF_CODECID_AVC;
1357 20 : e = gf_isom_get_meta_image_props(mp4, GF_TRUE, 0, item_id, &props);
1358 20 : if (e == GF_OK && props.config) {
1359 20 : gf_odf_avc_cfg_write(((GF_AVCConfigurationBox *)props.config)->config, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength);
1360 : }
1361 20 : esd->slConfig->hasRandomAccessUnitsOnlyFlag = 1;
1362 20 : esd->slConfig->useTimestampsFlag = 1;
1363 20 : esd->slConfig->timestampResolution = 1000;
1364 : return esd;
1365 0 : } else if (item_type == GF_ISOM_SUBTYPE_AV01) {
1366 : GF_ImageItemProperties props;
1367 0 : esd = gf_odf_desc_esd_new(0);
1368 0 : if (item_id > (1 << 16)) {
1369 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("Item ID greater than 16 bits, does not fit on ES ID\n"));
1370 : }
1371 0 : esd->ESID = (u16)item_id;
1372 0 : esd->OCRESID = esd->ESID;
1373 0 : esd->decoderConfig->streamType = GF_STREAM_VISUAL;
1374 0 : esd->decoderConfig->objectTypeIndication = GF_CODECID_AV1;
1375 0 : e = gf_isom_get_meta_image_props(mp4, GF_TRUE, 0, item_id, &props);
1376 0 : if (e == GF_OK && props.config) {
1377 0 : gf_odf_av1_cfg_write( ((GF_AV1ConfigurationBox *)props.config)->config, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength);
1378 : }
1379 0 : esd->slConfig->hasRandomAccessUnitsOnlyFlag = 1;
1380 0 : esd->slConfig->useTimestampsFlag = 1;
1381 0 : esd->slConfig->timestampResolution = 1000;
1382 : return esd;
1383 0 : } else if ((item_type == GF_ISOM_SUBTYPE_JPEG) || (mime && !strcmp(mime, "image/jpeg")) ){
1384 : GF_ImageItemProperties props;
1385 0 : esd = gf_odf_desc_esd_new(0);
1386 0 : if (item_id > (1 << 16)) {
1387 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("Item ID greater than 16 bits, does not fit on ES ID\n"));
1388 : }
1389 0 : esd->ESID = (u16)item_id;
1390 0 : esd->OCRESID = esd->ESID;
1391 0 : esd->decoderConfig->streamType = GF_STREAM_VISUAL;
1392 0 : esd->decoderConfig->objectTypeIndication = GF_CODECID_JPEG;
1393 0 : e = gf_isom_get_meta_image_props(mp4, GF_TRUE, 0, item_id, &props);
1394 0 : if (e == GF_OK && props.config) {
1395 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("JPEG image item decoder config not supported, patch welcome\n"));
1396 : }
1397 0 : esd->slConfig->hasRandomAccessUnitsOnlyFlag = 1;
1398 0 : esd->slConfig->useTimestampsFlag = 1;
1399 0 : esd->slConfig->timestampResolution = 1000;
1400 : return esd;
1401 0 : } else if ((item_type == GF_ISOM_SUBTYPE_PNG) || (mime && !strcmp(mime, "image/png")) ){
1402 : GF_ImageItemProperties props;
1403 0 : esd = gf_odf_desc_esd_new(0);
1404 0 : if (item_id > (1 << 16)) {
1405 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("Item ID greater than 16 bits, does not fit on ES ID\n"));
1406 : }
1407 0 : esd->ESID = (u16)item_id;
1408 0 : esd->OCRESID = esd->ESID;
1409 0 : esd->decoderConfig->streamType = GF_STREAM_VISUAL;
1410 0 : esd->decoderConfig->objectTypeIndication = GF_CODECID_PNG;
1411 0 : e = gf_isom_get_meta_image_props(mp4, GF_TRUE, 0, item_id, &props);
1412 0 : if (e) {
1413 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("Error fetching item properties %s\n", gf_error_to_string(e) ));
1414 : }
1415 0 : esd->slConfig->hasRandomAccessUnitsOnlyFlag = 1;
1416 0 : esd->slConfig->useTimestampsFlag = 1;
1417 0 : esd->slConfig->timestampResolution = 1000;
1418 : return esd;
1419 : } else {
1420 :
1421 : return NULL;
1422 : }
1423 : }
1424 :
1425 : #endif /*GPAC_DISABLE_ISOM*/
1426 :
1427 : #ifndef GPAC_DISABLE_MEDIA_IMPORT
1428 3 : static s32 gf_get_DQId(GF_ISOFile *file, u32 track)
1429 : {
1430 : GF_AVCConfig *svccfg;
1431 : GF_ISOSample *samp;
1432 3 : u32 di = 0, cur_extract_mode;
1433 : char *buffer;
1434 : GF_BitStream *bs;
1435 : u32 max_size = 4096;
1436 : u32 size, nalu_size_length;
1437 : u8 nal_type;
1438 : s32 DQId=0;
1439 :
1440 3 : samp = NULL;
1441 : bs = NULL;
1442 3 : cur_extract_mode = gf_isom_get_nalu_extract_mode(file, track);
1443 3 : gf_isom_set_nalu_extract_mode(file, track, GF_ISOM_NALU_EXTRACT_INSPECT);
1444 3 : buffer = (char*)gf_malloc(sizeof(char) * max_size);
1445 3 : svccfg = gf_isom_svc_config_get(file, track, 1);
1446 3 : if (!svccfg)
1447 : {
1448 : DQId = 0;
1449 : goto exit;
1450 : }
1451 2 : samp = gf_isom_get_sample(file, track, 1, &di);
1452 2 : if (!samp)
1453 : {
1454 : DQId = -1;
1455 : goto exit;
1456 : }
1457 2 : bs = gf_bs_new(samp->data, samp->dataLength, GF_BITSTREAM_READ);
1458 2 : nalu_size_length = 8 * svccfg->nal_unit_size;
1459 7 : while (gf_bs_available(bs))
1460 : {
1461 5 : size = gf_bs_read_int(bs, nalu_size_length);
1462 5 : if (size>max_size) {
1463 1 : buffer = (char*)gf_realloc(buffer, sizeof(char)*size);
1464 : max_size = size;
1465 : }
1466 5 : gf_bs_read_data(bs, buffer, size);
1467 5 : nal_type = buffer[0] & 0x1F;
1468 5 : if (nal_type == GF_AVC_NALU_SVC_SLICE)
1469 : {
1470 2 : DQId = buffer[2] & 0x7F;
1471 2 : goto exit;
1472 : }
1473 : }
1474 0 : exit:
1475 3 : if (svccfg) gf_odf_avc_cfg_del(svccfg);
1476 3 : if (samp) gf_isom_sample_del(&samp);
1477 3 : if (buffer) gf_free(buffer);
1478 3 : if (bs) gf_bs_del(bs);
1479 3 : gf_isom_set_nalu_extract_mode(file, track, cur_extract_mode);
1480 3 : return DQId;
1481 : }
1482 :
1483 : #ifndef GPAC_DISABLE_AV_PARSERS
1484 2 : static Bool gf_isom_has_svc_explicit(GF_ISOFile *file, u32 track)
1485 : {
1486 : GF_AVCConfig *svccfg;
1487 : GF_NALUFFParam *slc;
1488 : u32 i;
1489 : u8 type;
1490 : Bool ret = 0;
1491 :
1492 2 : svccfg = gf_isom_svc_config_get(file, track, 1);
1493 2 : if (!svccfg)
1494 : return 0;
1495 :
1496 4 : for (i = 0; i < gf_list_count(svccfg->sequenceParameterSets); i++)
1497 : {
1498 4 : slc = (GF_NALUFFParam *)gf_list_get(svccfg->sequenceParameterSets, i);
1499 4 : type = slc->data[0] & 0x1F;
1500 4 : if (type == GF_AVC_NALU_SEQ_PARAM)
1501 : {
1502 : ret = 1;
1503 : break;
1504 : }
1505 : }
1506 :
1507 2 : gf_odf_avc_cfg_del(svccfg);
1508 2 : return ret;
1509 : }
1510 :
1511 :
1512 1 : static u32 gf_isom_get_track_id_max(GF_ISOFile *file)
1513 : {
1514 : u32 num_track, i, trackID;
1515 : u32 max_id = 0;
1516 :
1517 1 : num_track = gf_isom_get_track_count(file);
1518 2 : for (i = 1; i <= num_track; i++)
1519 : {
1520 1 : trackID = gf_isom_get_track_id(file, i);
1521 1 : if (max_id < trackID)
1522 : max_id = trackID;
1523 : }
1524 :
1525 1 : return max_id;
1526 : }
1527 : #endif
1528 :
1529 : /* Split SVC layers */
1530 : GF_EXPORT
1531 1 : GF_Err gf_media_split_svc(GF_ISOFile *file, u32 track, Bool splitAll)
1532 : {
1533 : #ifndef GPAC_DISABLE_AV_PARSERS
1534 : GF_AVCConfig *svccfg, *cfg;
1535 : u32 num_svc_track, num_sample, svc_track, dst_track, ref_trackID, ref_trackNum, max_id, di, width, height, size, nalu_size_length, i, j, t, max_size, num_pps, num_sps, num_subseq, NALUnitHeader, data_offset, data_length, count, timescale, cur_extract_mode;
1536 : GF_Err e;
1537 : GF_NALUFFParam *slc, *sl;
1538 : AVCState avc;
1539 : s32 sps_id, pps_id;
1540 : GF_ISOSample *samp, *dst_samp;
1541 : GF_BitStream *bs, *dst_bs;
1542 : GF_BitStream ** sample_bs;
1543 : u8 nal_type, track_ref_index;
1544 : char *buffer;
1545 : s32 *sps_track, *sps, *pps;
1546 : u64 offset;
1547 : Bool is_splitted;
1548 : Bool *first_sample_track, *is_subseq_pps;
1549 : u64 *first_DTS_track;
1550 : s8 sample_offset;
1551 :
1552 : max_size = 4096;
1553 : e = GF_OK;
1554 1 : samp = dst_samp = NULL;
1555 : bs = NULL;
1556 : sample_bs = NULL;
1557 : sps_track = sps = pps = NULL;
1558 : first_DTS_track = NULL;
1559 : first_sample_track = is_subseq_pps = NULL;
1560 : buffer = NULL;
1561 : cfg = NULL;
1562 : num_svc_track=0;
1563 1 : cur_extract_mode = gf_isom_get_nalu_extract_mode(file, track);
1564 1 : gf_isom_set_nalu_extract_mode(file, track, GF_ISOM_NALU_EXTRACT_INSPECT);
1565 1 : svccfg = gf_isom_svc_config_get(file, track, 1);
1566 1 : if (!svccfg)
1567 : {
1568 : e = GF_OK;
1569 : goto exit;
1570 : }
1571 1 : num_sps = gf_list_count(svccfg->sequenceParameterSets);
1572 1 : if (!num_sps)
1573 : {
1574 : e = GF_OK;
1575 : goto exit;
1576 : }
1577 1 : num_pps = gf_list_count(svccfg->pictureParameterSets);
1578 1 : if ((gf_isom_get_avc_svc_type(file, track, 1) == GF_ISOM_AVCTYPE_SVC_ONLY) && !gf_isom_has_svc_explicit(file, track))
1579 : is_splitted = 1;
1580 : else
1581 : is_splitted = 0;
1582 1 : num_subseq = gf_isom_has_svc_explicit(file, track) ? num_sps - 1 : num_sps;
1583 :
1584 1 : if (is_splitted)
1585 : {
1586 : /*this track has only one SVC ...*/
1587 0 : if (num_sps == 1)
1588 : {
1589 : /*use 'all' mode -> stop*/
1590 0 : if (splitAll)
1591 : goto exit;
1592 : /*use 'base' mode -> merge SVC tracks*/
1593 : else
1594 : {
1595 0 : e = gf_media_merge_svc(file, track, 0);
1596 0 : goto exit;
1597 : }
1598 : }
1599 : /*this file has been in 'splitbase' mode*/
1600 0 : else if (!splitAll)
1601 : goto exit;
1602 :
1603 : }
1604 :
1605 1 : timescale = gf_isom_get_media_timescale(file, track);
1606 1 : num_svc_track = splitAll ? num_subseq : 1;
1607 1 : max_id = gf_isom_get_track_id_max(file);
1608 1 : di = 0;
1609 :
1610 : memset(&avc, 0, sizeof(AVCState));
1611 1 : avc.sps_active_idx = -1;
1612 1 : nalu_size_length = 8 * svccfg->nal_unit_size;
1613 : /*read all sps, but we need only the subset sequence parameter sets*/
1614 1 : sps = (s32 *) gf_malloc(num_subseq * sizeof(s32));
1615 1 : sps_track = (s32 *) gf_malloc(num_subseq * sizeof(s32));
1616 : count = 0;
1617 3 : for (i = 0; i < num_sps; i++)
1618 : {
1619 2 : slc = (GF_NALUFFParam *)gf_list_get(svccfg->sequenceParameterSets, i);
1620 2 : nal_type = slc->data[0] & 0x1F;
1621 2 : sps_id = gf_avc_read_sps(slc->data, slc->size, &avc, 0, NULL);
1622 2 : if (sps_id < 0) {
1623 : e = GF_NON_COMPLIANT_BITSTREAM;
1624 : goto exit;
1625 : }
1626 2 : if (nal_type == GF_AVC_NALU_SVC_SUBSEQ_PARAM)
1627 : {
1628 2 : sps[count] = sps_id;
1629 2 : sps_track[count] = i;
1630 2 : count++;
1631 : }
1632 : }
1633 : /*for testing*/
1634 : assert(count == num_subseq);
1635 : /*read all pps*/
1636 1 : pps = (s32 *) gf_malloc(num_pps * sizeof(s32));
1637 3 : for (j = 0; j < num_pps; j++)
1638 : {
1639 2 : slc = (GF_NALUFFParam *)gf_list_get(svccfg->pictureParameterSets, j);
1640 2 : pps_id = gf_avc_read_pps(slc->data, slc->size, &avc);
1641 2 : if (pps_id < 0) {
1642 : e = GF_NON_COMPLIANT_BITSTREAM;
1643 : goto exit;
1644 : }
1645 2 : pps[j] = pps_id;
1646 : }
1647 1 : if (!is_splitted)
1648 1 : ref_trackID = gf_isom_get_track_id(file, track);
1649 : else
1650 : {
1651 0 : gf_isom_get_reference(file, track, GF_ISOM_REF_BASE, 1, &ref_trackNum);
1652 0 : ref_trackID = gf_isom_get_track_id(file, ref_trackNum);
1653 : }
1654 :
1655 1 : buffer = (char*)gf_malloc(sizeof(char) * max_size);
1656 : /*read first sample for determinating the order of SVC tracks*/
1657 : count = 0;
1658 1 : samp = gf_isom_get_sample(file, track, 1, &di);
1659 1 : if (!samp)
1660 : {
1661 0 : e = gf_isom_last_error(file);
1662 0 : goto exit;
1663 : }
1664 1 : bs = gf_bs_new(samp->data, samp->dataLength, GF_BITSTREAM_READ);
1665 : offset = 0;
1666 1 : is_subseq_pps = (Bool *) gf_malloc(num_pps*sizeof(Bool));
1667 3 : for (i = 0; i < num_pps; i++)
1668 2 : is_subseq_pps[i] = 0;
1669 5 : while (gf_bs_available(bs))
1670 : {
1671 4 : gf_bs_enable_emulation_byte_removal(bs, GF_FALSE);
1672 4 : size = gf_bs_read_int(bs, nalu_size_length);
1673 4 : if (size>max_size) {
1674 1 : buffer = (char*)gf_realloc(buffer, sizeof(char)*size);
1675 : max_size = size;
1676 : }
1677 :
1678 4 : gf_avc_parse_nalu(bs, &avc);
1679 4 : nal_type = avc.last_nal_type_parsed;
1680 :
1681 4 : e = gf_bs_seek(bs, offset+nalu_size_length/8);
1682 4 : if (e)
1683 : goto exit;
1684 4 : gf_bs_read_data(bs, buffer, size);
1685 4 : offset += size + nalu_size_length/8;
1686 4 : if (nal_type == GF_AVC_NALU_SVC_SLICE)
1687 : {
1688 1 : for (i = 0; i < num_pps; i++)
1689 : {
1690 3 : if (avc.s_info.pps->id == pps[i])
1691 : {
1692 2 : is_subseq_pps[i] = 1;
1693 2 : break;
1694 : }
1695 : }
1696 2 : if ((count > 0) && (avc.s_info.pps->sps_id == sps[count-1]))
1697 0 : continue;
1698 : /*verify the order of SPS, reorder if necessary*/
1699 2 : if (avc.s_info.pps->sps_id != sps[count])
1700 : {
1701 0 : for (i = count+1; i < num_subseq; i++)
1702 : {
1703 : /*swap two SPS*/
1704 0 : if (avc.s_info.pps->sps_id == sps[i])
1705 : {
1706 0 : sps[i] = sps[count];
1707 0 : sps[count] = avc.s_info.pps->sps_id;
1708 0 : sps_track[count] = i;
1709 0 : break;
1710 : }
1711 : }
1712 : }
1713 2 : count++;
1714 : }
1715 : }
1716 1 : gf_bs_del(bs);
1717 : bs = NULL;
1718 :
1719 1 : gf_isom_sample_del(&samp);
1720 1 : samp = NULL;
1721 :
1722 3 : for (t = 0; t < num_svc_track; t++)
1723 : {
1724 2 : svc_track = gf_isom_new_track(file, t+1+max_id, GF_ISOM_MEDIA_VISUAL, timescale);
1725 2 : if (!svc_track)
1726 : {
1727 0 : e = gf_isom_last_error(file);
1728 0 : goto exit;
1729 : }
1730 2 : gf_isom_set_track_enabled(file, svc_track, GF_TRUE);
1731 2 : gf_isom_set_track_reference(file, svc_track, GF_ISOM_REF_BASE, ref_trackID);
1732 : //copy over edit list
1733 6 : for (i=0; i<gf_isom_get_edits_count(file, track); i++) {
1734 : GF_ISOEditType emode;
1735 : u64 etime, edur, mtime;
1736 2 : gf_isom_get_edit(file, track, i+1, &etime, &edur, &mtime, &emode);
1737 2 : gf_isom_set_edit(file, svc_track, etime, edur, mtime, emode);
1738 : }
1739 2 : cfg = gf_odf_avc_cfg_new();
1740 2 : cfg->complete_representation = 1; //SVC
1741 : /*this layer depends on the base layer and the lower layers*/
1742 2 : gf_isom_set_track_reference(file, svc_track, GF_ISOM_REF_SCAL, ref_trackID);
1743 3 : for (i = 0; i < t; i++)
1744 1 : gf_isom_set_track_reference(file, svc_track, GF_ISOM_REF_SCAL, i+1+max_id);
1745 :
1746 2 : e = gf_isom_svc_config_new(file, svc_track, cfg, NULL, NULL, &di);
1747 2 : if (e)
1748 : goto exit;
1749 2 : if (splitAll)
1750 : {
1751 2 : sps_id = sps[t];
1752 2 : width = avc.sps[sps_id].width;
1753 2 : height = avc.sps[sps_id].height;
1754 2 : gf_isom_set_visual_info(file, svc_track, di, width, height);
1755 2 : cfg->configurationVersion = 1;
1756 2 : cfg->chroma_bit_depth = 8 + avc.sps[sps_id].chroma_bit_depth_m8;
1757 2 : cfg->chroma_format = avc.sps[sps_id].chroma_format;
1758 2 : cfg->luma_bit_depth = 8 + avc.sps[sps_id].luma_bit_depth_m8;
1759 2 : cfg->profile_compatibility = avc.sps[sps_id].prof_compat;
1760 2 : cfg->AVCLevelIndication = avc.sps[sps_id].level_idc;
1761 2 : cfg->AVCProfileIndication = avc.sps[sps_id].profile_idc;
1762 2 : cfg->nal_unit_size = svccfg->nal_unit_size;
1763 2 : slc = (GF_NALUFFParam *)gf_list_get(svccfg->sequenceParameterSets, sps_track[t]);
1764 2 : sl = (GF_NALUFFParam*)gf_malloc(sizeof(GF_NALUFFParam));
1765 2 : sl->id = slc->id;
1766 2 : sl->size = slc->size;
1767 2 : sl->data = (char*)gf_malloc(sizeof(char)*sl->size);
1768 2 : memcpy(sl->data, slc->data, sizeof(char)*sl->size);
1769 2 : gf_list_add(cfg->sequenceParameterSets, sl);
1770 6 : for (j = 0; j < num_pps; j++)
1771 : {
1772 4 : pps_id = pps[j];
1773 4 : if (is_subseq_pps[j] && (avc.pps[pps_id].sps_id == sps_id))
1774 : {
1775 2 : slc = (GF_NALUFFParam *)gf_list_get(svccfg->pictureParameterSets, j);
1776 2 : sl = (GF_NALUFFParam*)gf_malloc(sizeof(GF_NALUFFParam));
1777 2 : sl->id = slc->id;
1778 2 : sl->size = slc->size;
1779 2 : sl->data = (char*)gf_malloc(sizeof(char)*sl->size);
1780 2 : memcpy(sl->data, slc->data, sizeof(char)*sl->size);
1781 2 : gf_list_add(cfg->pictureParameterSets, sl);
1782 : }
1783 : }
1784 : }
1785 : else
1786 : {
1787 0 : for (i = 0; i < num_subseq; i++)
1788 : {
1789 0 : sps_id = sps[i];
1790 0 : width = avc.sps[sps_id].width;
1791 0 : height = avc.sps[sps_id].height;
1792 0 : gf_isom_set_visual_info(file, svc_track, di, width, height);
1793 0 : cfg->configurationVersion = 1;
1794 0 : cfg->chroma_bit_depth = 8 + avc.sps[sps_id].chroma_bit_depth_m8;
1795 0 : cfg->chroma_format = avc.sps[sps_id].chroma_format;
1796 0 : cfg->luma_bit_depth = 8 + avc.sps[sps_id].luma_bit_depth_m8;
1797 0 : cfg->profile_compatibility = avc.sps[sps_id].prof_compat;
1798 0 : cfg->AVCLevelIndication = avc.sps[sps_id].level_idc;
1799 0 : cfg->AVCProfileIndication = avc.sps[sps_id].profile_idc;
1800 0 : cfg->nal_unit_size = svccfg->nal_unit_size;
1801 0 : slc = (GF_NALUFFParam *)gf_list_get(svccfg->sequenceParameterSets, sps_track[i]);
1802 0 : sl = (GF_NALUFFParam*)gf_malloc(sizeof(GF_NALUFFParam));
1803 0 : sl->id = slc->id;
1804 0 : sl->size = slc->size;
1805 0 : sl->data = (char*)gf_malloc(sizeof(char)*sl->size);
1806 0 : memcpy(sl->data, slc->data, sizeof(char)*sl->size);
1807 0 : gf_list_add(cfg->sequenceParameterSets, sl);
1808 0 : for (j = 0; j < num_pps; j++)
1809 : {
1810 0 : pps_id = pps[j];
1811 0 : if (avc.pps[pps_id].sps_id == sps_id)
1812 : {
1813 0 : slc = (GF_NALUFFParam *)gf_list_get(svccfg->pictureParameterSets, j);
1814 0 : sl = (GF_NALUFFParam*)gf_malloc(sizeof(GF_NALUFFParam));
1815 0 : sl->id = slc->id;
1816 0 : sl->size = slc->size;
1817 0 : sl->data = (char*)gf_malloc(sizeof(char)*sl->size);
1818 0 : memcpy(sl->data, slc->data, sizeof(char)*sl->size);
1819 0 : gf_list_add(cfg->pictureParameterSets, sl);
1820 : }
1821 : }
1822 : }
1823 : }
1824 2 : e = gf_isom_svc_config_update(file, svc_track, 1, cfg, 0);
1825 2 : if (e)
1826 : goto exit;
1827 2 : gf_odf_avc_cfg_del(cfg);
1828 : cfg = NULL;
1829 : }
1830 :
1831 1 : num_sample = gf_isom_get_sample_count(file, track);
1832 1 : first_sample_track = (Bool *) gf_malloc((num_svc_track+1) * sizeof(Bool));
1833 4 : for (t = 0; t <= num_svc_track; t++)
1834 3 : first_sample_track[t] = 1;
1835 1 : first_DTS_track = (u64 *) gf_malloc((num_svc_track+1) * sizeof(u64));
1836 4 : for (t = 0; t <= num_svc_track; t++)
1837 3 : first_DTS_track[t] = 0;
1838 250 : for (i = 1; i <= num_sample; i++)
1839 : {
1840 : /*reset*/
1841 250 : memset(buffer, 0, max_size);
1842 :
1843 250 : samp = gf_isom_get_sample(file, track, i, &di);
1844 250 : if (!samp)
1845 : {
1846 : e = GF_IO_ERR;
1847 : goto exit;
1848 : }
1849 :
1850 : /* Create (num_svc_track) SVC bitstreams + 1 AVC bitstream*/
1851 250 : sample_bs = (GF_BitStream **) gf_malloc(sizeof(GF_BitStream *) * (num_svc_track+1));
1852 1000 : for (j = 0; j <= num_svc_track; j++)
1853 750 : sample_bs[j] = (GF_BitStream *) gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
1854 :
1855 : /*write extractor*/
1856 750 : for (t = 0; t < num_svc_track; t++)
1857 : {
1858 : //reference to base layer
1859 500 : gf_bs_write_int(sample_bs[t+1], 14, nalu_size_length); // extractor 's size = 14
1860 : NALUnitHeader = 0; //reset
1861 : NALUnitHeader |= 0x1F000000; // NALU type = 31
1862 500 : gf_bs_write_u32(sample_bs[t+1], NALUnitHeader);
1863 500 : track_ref_index = (u8) gf_isom_has_track_reference(file, t+1+max_id, GF_ISOM_REF_SCAL, ref_trackID);
1864 500 : if (!track_ref_index)
1865 : {
1866 : e = GF_CORRUPTED_DATA;
1867 : goto exit;
1868 : }
1869 500 : gf_bs_write_u8(sample_bs[t+1], track_ref_index);
1870 : sample_offset = 0;
1871 500 : gf_bs_write_u8(sample_bs[t+1], sample_offset);
1872 : data_offset = 0;
1873 500 : gf_bs_write_u32(sample_bs[t+1], data_offset);
1874 : data_length = 0;
1875 500 : gf_bs_write_u32(sample_bs[t+1], data_length);
1876 : //reference to previous layer(s)
1877 1250 : for (j = 0; j < t; j++)
1878 : {
1879 250 : gf_bs_write_int(sample_bs[t+1], 14, nalu_size_length);
1880 : NALUnitHeader = 0;
1881 : NALUnitHeader |= 0x1F000000;
1882 250 : gf_bs_write_u32(sample_bs[t+1], NALUnitHeader);
1883 250 : track_ref_index = (u8) gf_isom_has_track_reference(file, t+1+max_id, GF_ISOM_REF_SCAL, j+1+max_id);
1884 250 : if (!track_ref_index)
1885 : {
1886 : e = GF_CORRUPTED_DATA;
1887 : goto exit;
1888 : }
1889 250 : gf_bs_write_u8(sample_bs[t+1], track_ref_index);
1890 : sample_offset = 0;
1891 250 : gf_bs_write_u8(sample_bs[t+1], sample_offset);
1892 250 : data_offset = (j+1) * (nalu_size_length/8 + 14); // (nalu_size_length/8) bytes of NALU length field + 14 bytes of extractor per layer
1893 250 : gf_bs_write_u32(sample_bs[t+1], data_offset);
1894 : data_length = 0;
1895 250 : gf_bs_write_u32(sample_bs[t+1], data_length);
1896 : }
1897 : }
1898 :
1899 250 : bs = gf_bs_new(samp->data, samp->dataLength, GF_BITSTREAM_READ);
1900 : offset = 0;
1901 1498 : while (gf_bs_available(bs))
1902 : {
1903 998 : gf_bs_enable_emulation_byte_removal(bs, GF_FALSE);
1904 998 : size = gf_bs_read_int(bs, nalu_size_length);
1905 998 : if (size>max_size) {
1906 5 : buffer = (char*)gf_realloc(buffer, sizeof(char)*size);
1907 : max_size = size;
1908 : }
1909 :
1910 998 : gf_avc_parse_nalu(bs, &avc);
1911 998 : nal_type = avc.last_nal_type_parsed;
1912 998 : e = gf_bs_seek(bs, offset+nalu_size_length/8);
1913 998 : if (e)
1914 : goto exit;
1915 998 : gf_bs_read_data(bs, buffer, size);
1916 998 : offset += size + nalu_size_length/8;
1917 :
1918 998 : switch (nal_type) {
1919 0 : case GF_AVC_NALU_PIC_PARAM:
1920 0 : pps_id = avc.last_ps_idx;
1921 : j = 0;
1922 : dst_track = 0;
1923 0 : while (j < num_pps)
1924 : {
1925 0 : if (pps_id == pps[j])
1926 : break;
1927 0 : j++;
1928 : }
1929 0 : if ((j < num_pps) && (is_subseq_pps[j]))
1930 : {
1931 0 : if (splitAll)
1932 : {
1933 0 : for (t = 0; t < num_svc_track; t++)
1934 : {
1935 0 : if (sps[t] == avc.pps[pps_id].sps_id)
1936 : {
1937 0 : dst_track = t + 1;
1938 0 : break;
1939 : }
1940 : }
1941 : }
1942 : else
1943 : dst_track = 1;
1944 : }
1945 0 : dst_bs = sample_bs[dst_track];
1946 0 : break;
1947 0 : case GF_AVC_NALU_SVC_SUBSEQ_PARAM:
1948 0 : sps_id = avc.last_ps_idx;
1949 : dst_track = 0;
1950 0 : if (splitAll)
1951 : {
1952 0 : for (t = 0; t < num_svc_track; t++)
1953 : {
1954 0 : if (sps[t] == sps_id)
1955 : {
1956 0 : dst_track = t + 1;
1957 0 : break;
1958 : }
1959 : }
1960 : }
1961 : else
1962 : dst_track = 1;
1963 0 : dst_bs = sample_bs[dst_track];
1964 0 : break;
1965 498 : case GF_AVC_NALU_SVC_SLICE:
1966 : dst_track = 0;
1967 498 : if (splitAll)
1968 : {
1969 250 : for (t = 0; t < num_svc_track; t++)
1970 : {
1971 748 : if (sps[t] == (avc.s_info.pps)->sps_id)
1972 : {
1973 498 : dst_track = t + 1;
1974 498 : break;
1975 : }
1976 : }
1977 : }
1978 : else
1979 : dst_track = 1;
1980 498 : dst_bs = sample_bs[dst_track];
1981 498 : break;
1982 500 : default:
1983 500 : dst_bs = sample_bs[0];
1984 : }
1985 :
1986 998 : gf_bs_write_int(dst_bs, size, nalu_size_length);
1987 998 : gf_bs_write_data(dst_bs, buffer, size);
1988 : }
1989 :
1990 750 : for (j = 0; j <= num_svc_track; j++)
1991 : {
1992 750 : if (gf_bs_get_position(sample_bs[j]))
1993 : {
1994 750 : if (first_sample_track[j])
1995 : {
1996 3 : first_sample_track[j] = 0;
1997 3 : first_DTS_track[j] = samp->DTS;
1998 : }
1999 750 : dst_samp = gf_isom_sample_new();
2000 750 : dst_samp->CTS_Offset = samp->CTS_Offset;
2001 750 : dst_samp->DTS = samp->DTS - first_DTS_track[j];
2002 750 : dst_samp->IsRAP = samp->IsRAP;
2003 750 : gf_bs_get_content(sample_bs[j], &dst_samp->data, &dst_samp->dataLength);
2004 750 : if (j) //SVC
2005 500 : e = gf_isom_add_sample(file, track+j, di, dst_samp);
2006 : else
2007 250 : e = gf_isom_update_sample(file, track, i, dst_samp, 1);
2008 750 : if (e)
2009 : goto exit;
2010 750 : gf_isom_sample_del(&dst_samp);
2011 750 : dst_samp = NULL;
2012 : }
2013 750 : gf_bs_del(sample_bs[j]);
2014 750 : sample_bs[j] = NULL;
2015 : }
2016 250 : gf_free(sample_bs);
2017 : sample_bs = NULL;
2018 250 : gf_bs_del(bs);
2019 : bs = NULL;
2020 250 : gf_isom_sample_del(&samp);
2021 250 : samp = NULL;
2022 : }
2023 :
2024 : /*add Editlist entry if DTS of the first sample is not zero*/
2025 3 : for (t = 0; t <= num_svc_track; t++)
2026 : {
2027 3 : if (first_DTS_track[t])
2028 : {
2029 : u32 media_ts, moov_ts, ts_offset;
2030 : u64 dur;
2031 0 : media_ts = gf_isom_get_media_timescale(file, t);
2032 0 : moov_ts = gf_isom_get_timescale(file);
2033 0 : ts_offset = (u32)(first_DTS_track[t]) * moov_ts / media_ts;
2034 0 : dur = gf_isom_get_media_duration(file, t) * moov_ts / media_ts;
2035 0 : gf_isom_set_edit(file, t, 0, ts_offset, 0, GF_ISOM_EDIT_EMPTY);
2036 0 : gf_isom_set_edit(file, t, ts_offset, dur, 0, GF_ISOM_EDIT_NORMAL);
2037 : }
2038 : }
2039 :
2040 : /*if this is a merged file*/
2041 1 : if (!is_splitted)
2042 : {
2043 : /*a normal stream: delete SVC config*/
2044 1 : if (!gf_isom_has_svc_explicit(file, track))
2045 : {
2046 1 : gf_isom_svc_config_del(file, track, 1);
2047 : }
2048 : else
2049 : {
2050 : s32 shift=0;
2051 :
2052 0 : for (i = 0; i < gf_list_count(svccfg->sequenceParameterSets); i++)
2053 : {
2054 0 : slc = (GF_NALUFFParam *)gf_list_get(svccfg->sequenceParameterSets, i);
2055 0 : sps_id = gf_avc_read_sps(slc->data, slc->size, &avc, 0, NULL);
2056 0 : if (sps_id < 0) {
2057 : e = GF_NON_COMPLIANT_BITSTREAM;
2058 : goto exit;
2059 : }
2060 0 : nal_type = slc->data[0] & 0x1F;
2061 0 : if (nal_type == GF_AVC_NALU_SVC_SUBSEQ_PARAM)
2062 : {
2063 0 : gf_list_rem(svccfg->sequenceParameterSets, i);
2064 0 : gf_free(slc->data);
2065 0 : gf_free(slc);
2066 0 : i--;
2067 : }
2068 : }
2069 :
2070 0 : for (j = 0; j < gf_list_count(svccfg->pictureParameterSets); j++)
2071 : {
2072 0 : slc = (GF_NALUFFParam *)gf_list_get(svccfg->pictureParameterSets, j);
2073 0 : pps_id = gf_avc_read_pps(slc->data, slc->size, &avc);
2074 0 : if (pps_id < 0) {
2075 : e = GF_NON_COMPLIANT_BITSTREAM;
2076 : goto exit;
2077 : }
2078 0 : if (is_subseq_pps[j+shift])
2079 : {
2080 0 : gf_list_rem(svccfg->pictureParameterSets, j);
2081 0 : gf_free(slc->data);
2082 0 : gf_free(slc);
2083 0 : j--;
2084 : }
2085 : }
2086 0 : e = gf_isom_svc_config_update(file, track, 1, svccfg, 0);
2087 : if (e)
2088 : goto exit;
2089 : }
2090 : }
2091 : /*if this is as splitted file: delete this track*/
2092 : else
2093 : {
2094 0 : gf_isom_remove_track(file, track);
2095 : }
2096 :
2097 1 : exit:
2098 1 : if (svccfg) gf_odf_avc_cfg_del(svccfg);
2099 1 : if (cfg) gf_odf_avc_cfg_del(cfg);
2100 1 : if (samp) gf_isom_sample_del(&samp);
2101 1 : if (dst_samp) gf_isom_sample_del(&dst_samp);
2102 1 : if (bs) gf_bs_del(bs);
2103 1 : if (sample_bs)
2104 : {
2105 0 : for (i = 0; i <= num_svc_track; i++)
2106 0 : gf_bs_del(sample_bs[i]);
2107 0 : gf_free(sample_bs);
2108 : }
2109 1 : if (sps_track) gf_free(sps_track);
2110 1 : if (sps) gf_free(sps);
2111 1 : if (pps) gf_free(pps);
2112 1 : if (first_sample_track) gf_free(first_sample_track);
2113 1 : if (first_DTS_track) gf_free(first_DTS_track);
2114 1 : if (buffer) gf_free(buffer);
2115 1 : if (is_subseq_pps) gf_free(is_subseq_pps);
2116 1 : gf_isom_set_nalu_extract_mode(file, track, cur_extract_mode);
2117 1 : return e;
2118 : #else
2119 : return GF_NOT_SUPPORTED;
2120 : #endif
2121 :
2122 : }
2123 :
2124 : /* Merge SVC layers*/
2125 : GF_EXPORT
2126 3 : GF_Err gf_media_merge_svc(GF_ISOFile *file, u32 track, Bool mergeAll)
2127 : {
2128 : GF_AVCConfig *svccfg, *cfg;
2129 : u32 merge_track, num_track, num_sample, size, i, t, di, max_size, nalu_size_length, ref_trackNum, ref_trackID, count, width, height, nb_EditList, media_ts, moov_ts;
2130 : GF_ISOSample *avc_samp, *samp, *dst_samp;
2131 : GF_BitStream *bs, *dst_bs;
2132 : GF_Err e;
2133 : char *buffer;
2134 : s32 *DQId;
2135 : u32 *list_track_sorted, *cur_sample, *max_sample;
2136 : u64 *DTS_offset;
2137 : u64 EditTime, SegmentDuration, MediaTime;
2138 : GF_ISOEditType EditMode;
2139 : u8 nal_type;
2140 : Bool first_sample;
2141 : u64 first_DTS, offset, dur;
2142 : GF_NALUFFParam *slc, *sl;
2143 :
2144 : e = GF_OK;
2145 3 : di = 1;
2146 : max_size = 4096;
2147 3 : width = height = 0;
2148 3 : avc_samp = samp = dst_samp = NULL;
2149 : svccfg = cfg = NULL;
2150 : buffer = NULL;
2151 : bs = dst_bs = NULL;
2152 : DQId = NULL;
2153 : list_track_sorted = cur_sample = max_sample = NULL;
2154 : DTS_offset = NULL;
2155 :
2156 3 : if (gf_isom_get_avc_svc_type(file, track, 1) == GF_ISOM_AVCTYPE_AVC_SVC)
2157 : goto exit;
2158 :
2159 1 : num_track = gf_isom_get_track_count(file);
2160 1 : if (num_track == 1)
2161 : goto exit;
2162 1 : gf_isom_get_reference(file, track, GF_ISOM_REF_BASE, 1, &ref_trackNum);
2163 1 : ref_trackID = gf_isom_get_track_id(file, ref_trackNum);
2164 1 : if (!ref_trackID)
2165 : {
2166 : e = GF_ISOM_INVALID_MEDIA;
2167 : goto exit;
2168 : }
2169 :
2170 1 : list_track_sorted = (u32 *) gf_malloc(num_track * sizeof(u32));
2171 : memset(list_track_sorted, 0, num_track * sizeof(u32));
2172 1 : DQId = (s32 *) gf_malloc(num_track * sizeof(s32));
2173 : memset(DQId, 0, num_track * sizeof(s32));
2174 : count = 0;
2175 4 : for (t = 1; t <= num_track; t++) {
2176 : u32 pos = 0;
2177 3 : s32 track_DQId = gf_get_DQId(file, t);
2178 3 : if (track_DQId < 0) {
2179 : e = GF_ISOM_INVALID_MEDIA;
2180 : goto exit;
2181 : }
2182 :
2183 3 : if (!gf_isom_has_track_reference(file, t, GF_ISOM_REF_BASE, ref_trackID))
2184 : {
2185 1 : if (t != ref_trackNum) continue;
2186 1 : else if (!mergeAll) continue;
2187 : }
2188 :
2189 6 : while ((pos < count ) && (DQId[pos] <= track_DQId))
2190 3 : pos++;
2191 3 : for (i = count; i > pos; i--)
2192 : {
2193 0 : list_track_sorted[i] = list_track_sorted[i-1];
2194 0 : DQId[i] = DQId[i-1];
2195 : }
2196 3 : list_track_sorted[pos] = t;
2197 3 : DQId[pos] = track_DQId;
2198 3 : count++;
2199 : }
2200 :
2201 1 : merge_track = list_track_sorted[0];
2202 1 : gf_isom_set_track_enabled(file, merge_track, GF_TRUE);
2203 : /*rewrite svccfg*/
2204 1 : svccfg = gf_odf_avc_cfg_new();
2205 1 : svccfg->complete_representation = 1;
2206 : /*rewrite visual info*/
2207 1 : if (!mergeAll)
2208 : {
2209 0 : for (t = 0; t < count; t++)
2210 0 : gf_isom_get_visual_info(file, list_track_sorted[t], 1, &width, &height);
2211 0 : gf_isom_set_visual_info(file, merge_track, 1, width, height);
2212 : }
2213 :
2214 3 : for (t = 0; t < count; t++)
2215 : {
2216 3 : cfg = gf_isom_svc_config_get(file, list_track_sorted[t], 1);
2217 3 : if (!cfg)
2218 1 : continue;
2219 2 : svccfg->configurationVersion = 1;
2220 2 : svccfg->chroma_bit_depth = cfg->chroma_bit_depth;
2221 2 : svccfg->chroma_format = cfg->chroma_format;
2222 2 : svccfg->luma_bit_depth = cfg->luma_bit_depth;
2223 2 : svccfg->profile_compatibility = cfg->profile_compatibility;
2224 2 : svccfg->AVCLevelIndication = cfg->AVCLevelIndication;
2225 2 : svccfg->AVCProfileIndication = cfg->AVCProfileIndication;
2226 2 : svccfg->nal_unit_size = cfg->nal_unit_size;
2227 4 : for (i = 0; i < gf_list_count(cfg->sequenceParameterSets); i++)
2228 : {
2229 2 : slc = (GF_NALUFFParam *)gf_list_get(cfg->sequenceParameterSets, i);
2230 2 : sl = (GF_NALUFFParam*)gf_malloc(sizeof(GF_NALUFFParam));
2231 2 : sl->id = slc->id;
2232 2 : sl->size = slc->size;
2233 2 : sl->data = (char*)gf_malloc(sizeof(char)*sl->size);
2234 2 : memcpy(sl->data, slc->data, sizeof(char)*sl->size);
2235 2 : gf_list_add(svccfg->sequenceParameterSets, sl);
2236 : }
2237 2 : for (i = 0; i < gf_list_count(cfg->pictureParameterSets); i++)
2238 : {
2239 2 : slc = (GF_NALUFFParam *)gf_list_get(cfg->pictureParameterSets, i);
2240 2 : sl = (GF_NALUFFParam*)gf_malloc(sizeof(GF_NALUFFParam));
2241 2 : sl->id = slc->id;
2242 2 : sl->size = slc->size;
2243 2 : sl->data = (char*)gf_malloc(sizeof(char)*sl->size);
2244 2 : memcpy(sl->data, slc->data, sizeof(char)*sl->size);
2245 2 : gf_list_add(svccfg->pictureParameterSets, sl);
2246 : }
2247 2 : if (mergeAll)
2248 : {
2249 2 : gf_isom_svc_config_update(file, merge_track, 1, svccfg, 1);
2250 : }
2251 : else
2252 0 : gf_isom_svc_config_update(file, merge_track, 1, svccfg, 0);
2253 2 : gf_odf_avc_cfg_del(cfg);
2254 : cfg = NULL;
2255 : }
2256 :
2257 1 : cur_sample = (u32 *) gf_malloc(count * sizeof(u32));
2258 1 : max_sample = (u32 *) gf_malloc(count * sizeof(u32));
2259 4 : for (t = 0; t < count; t++)
2260 : {
2261 3 : cur_sample[t] = 1;
2262 3 : max_sample[t] = gf_isom_get_sample_count(file, list_track_sorted[t]);
2263 : }
2264 :
2265 1 : DTS_offset = (u64 *) gf_malloc(count * sizeof(u64));
2266 4 : for (t = 0; t < count; t++) {
2267 3 : DTS_offset[t] = 0;
2268 3 : nb_EditList = gf_isom_get_edits_count(file, list_track_sorted[t]);
2269 3 : if (nb_EditList) {
2270 3 : media_ts = gf_isom_get_media_timescale(file, list_track_sorted[t]);
2271 3 : moov_ts = gf_isom_get_timescale(file);
2272 6 : for (i = 1; i <= nb_EditList; i++) {
2273 3 : e = gf_isom_get_edit(file, list_track_sorted[t], i, &EditTime, &SegmentDuration, &MediaTime, &EditMode);
2274 3 : if (e) goto exit;
2275 :
2276 3 : if (!EditMode) {
2277 0 : DTS_offset[t] = SegmentDuration * media_ts / moov_ts;
2278 : }
2279 : }
2280 : }
2281 : }
2282 :
2283 1 : num_sample = gf_isom_get_sample_count(file, ref_trackNum);
2284 1 : nalu_size_length = 8 * svccfg->nal_unit_size;
2285 : first_sample = 1;
2286 : first_DTS = 0;
2287 1 : buffer = (char*)gf_malloc(sizeof(char) * max_size);
2288 4 : for (t = 1; t <= num_track; t++)
2289 3 : gf_isom_set_nalu_extract_mode(file, t, GF_ISOM_NALU_EXTRACT_INSPECT);
2290 250 : for (i = 1; i <= num_sample; i++)
2291 : {
2292 250 : dst_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
2293 : /*add extractor if nessassary*/
2294 250 : if (!mergeAll)
2295 : {
2296 : u32 NALUnitHeader = 0;
2297 : u8 track_ref_index;
2298 : s8 sample_offset;
2299 : u32 data_offset;
2300 : u32 data_length;
2301 :
2302 0 : gf_bs_write_int(dst_bs, 14, nalu_size_length); // extractor 's size = 14
2303 : NALUnitHeader |= 0x1F000000; // NALU type = 31
2304 0 : gf_bs_write_u32(dst_bs, NALUnitHeader);
2305 0 : track_ref_index = (u8) gf_isom_has_track_reference(file, merge_track, GF_ISOM_REF_SCAL, ref_trackID);
2306 0 : if (!track_ref_index)
2307 : {
2308 : e = GF_CORRUPTED_DATA;
2309 : goto exit;
2310 : }
2311 0 : gf_bs_write_u8(dst_bs, track_ref_index);
2312 : sample_offset = 0;
2313 0 : gf_bs_write_u8(dst_bs, sample_offset);
2314 : data_offset = 0;
2315 0 : gf_bs_write_u32(dst_bs, data_offset);
2316 : data_length = 0;
2317 0 : gf_bs_write_u32(dst_bs, data_length);
2318 : }
2319 :
2320 250 : avc_samp = gf_isom_get_sample(file, ref_trackNum, i, &di);
2321 250 : if (!avc_samp) {
2322 0 : e = gf_isom_last_error(file);
2323 0 : goto exit;
2324 : }
2325 :
2326 750 : for (t = 0; t < count; t++)
2327 : {
2328 750 : if (cur_sample[t] > max_sample[t])
2329 0 : continue;
2330 750 : samp = gf_isom_get_sample(file, list_track_sorted[t], cur_sample[t], &di);
2331 750 : if (!samp) {
2332 0 : e = gf_isom_last_error(file);
2333 0 : goto exit;
2334 : }
2335 :
2336 750 : if ((samp->DTS + DTS_offset[t]) != avc_samp->DTS) {
2337 0 : gf_isom_sample_del(&samp);
2338 0 : samp = NULL;
2339 0 : continue;
2340 : }
2341 750 : bs = gf_bs_new(samp->data, samp->dataLength, GF_BITSTREAM_READ);
2342 : /*reset*/
2343 750 : memset(buffer, 0, sizeof(char) * max_size);
2344 2498 : while (gf_bs_available(bs))
2345 : {
2346 1748 : size = gf_bs_read_int(bs, nalu_size_length);
2347 1748 : if (size>max_size) {
2348 6 : buffer = (char*)gf_realloc(buffer, sizeof(char)*size);
2349 : max_size = size;
2350 : }
2351 1748 : gf_bs_read_data(bs, buffer, size);
2352 1748 : nal_type = buffer[0] & 0x1F;
2353 : /*skip extractor*/
2354 1748 : if (nal_type == 31)
2355 750 : continue;
2356 : /*copy to new bitstream*/
2357 998 : gf_bs_write_int(dst_bs, size, nalu_size_length);
2358 998 : gf_bs_write_data(dst_bs, buffer, size);
2359 : }
2360 750 : gf_bs_del(bs);
2361 : bs = NULL;
2362 750 : gf_isom_sample_del(&samp);
2363 750 : samp = NULL;
2364 750 : cur_sample[t]++;
2365 : }
2366 :
2367 : /*add sapmle to track*/
2368 250 : if (gf_bs_get_position(dst_bs))
2369 : {
2370 250 : if (first_sample)
2371 : {
2372 1 : first_DTS = avc_samp->DTS;
2373 : first_sample = 0;
2374 : }
2375 250 : dst_samp = gf_isom_sample_new();
2376 250 : dst_samp->CTS_Offset = avc_samp->CTS_Offset;
2377 250 : dst_samp->DTS = avc_samp->DTS - first_DTS;
2378 250 : dst_samp->IsRAP = avc_samp->IsRAP;
2379 250 : gf_bs_get_content(dst_bs, &dst_samp->data, &dst_samp->dataLength);
2380 250 : e = gf_isom_update_sample(file, merge_track, i, dst_samp, 1);
2381 250 : if (e)
2382 : goto exit;
2383 : }
2384 250 : gf_isom_sample_del(&avc_samp);
2385 250 : avc_samp = NULL;
2386 250 : gf_bs_del(dst_bs);
2387 : dst_bs = NULL;
2388 250 : gf_isom_sample_del(&dst_samp);
2389 250 : dst_samp = NULL;
2390 : }
2391 :
2392 : /*Add EditList if nessessary*/
2393 1 : if (!first_DTS)
2394 : {
2395 1 : media_ts = gf_isom_get_media_timescale(file, merge_track);
2396 1 : moov_ts = gf_isom_get_timescale(file);
2397 : offset = (u32)(first_DTS) * moov_ts / media_ts;
2398 1 : dur = gf_isom_get_media_duration(file, merge_track) * moov_ts / media_ts;
2399 1 : gf_isom_set_edit(file, merge_track, 0, offset, 0, GF_ISOM_EDIT_EMPTY);
2400 1 : gf_isom_set_edit(file, merge_track, offset, dur, 0, GF_ISOM_EDIT_NORMAL);
2401 : }
2402 :
2403 : /*Delete SVC track(s) that references to ref_track*/
2404 3 : for (t = 1; t <= num_track; t++)
2405 : {
2406 3 : if (gf_isom_has_track_reference(file, t, GF_ISOM_REF_BASE, ref_trackID) && (t != merge_track))
2407 : {
2408 2 : gf_isom_remove_track(file, t);
2409 2 : num_track--; //we removed one track from file
2410 2 : t--;
2411 : }
2412 : }
2413 :
2414 3 : exit:
2415 3 : if (avc_samp) gf_isom_sample_del(&avc_samp);
2416 3 : if (samp) gf_isom_sample_del(&samp);
2417 3 : if (dst_samp) gf_isom_sample_del(&dst_samp);
2418 3 : if (svccfg) gf_odf_avc_cfg_del(svccfg);
2419 3 : if (cfg) gf_odf_avc_cfg_del(cfg);
2420 : if (bs) gf_bs_del(bs);
2421 3 : if (dst_bs) gf_bs_del(dst_bs);
2422 3 : if (buffer) gf_free(buffer);
2423 3 : if (DQId) gf_free(DQId);
2424 3 : if (list_track_sorted) gf_free(list_track_sorted);
2425 3 : if (cur_sample) gf_free(cur_sample);
2426 3 : if (max_sample) gf_free(max_sample);
2427 3 : if (DTS_offset) gf_free(DTS_offset);
2428 3 : for (t = 1; t <= gf_isom_get_track_count(file); t++)
2429 3 : gf_isom_set_nalu_extract_mode(file, t, GF_ISOM_NALU_EXTRACT_DEFAULT);
2430 3 : return e;
2431 : }
2432 :
2433 : #ifndef GPAC_DISABLE_AV_PARSERS
2434 :
2435 : #if !defined(GPAC_DISABLE_HEVC)
2436 : /* Split LHVC layers */
2437 2 : static GF_NALUFFParamArray *alloc_hevc_param_array(GF_HEVCConfig *hevc_cfg, u8 type)
2438 : {
2439 : GF_NALUFFParamArray *ar;
2440 2 : u32 i, count = hevc_cfg->param_array ? gf_list_count(hevc_cfg->param_array) : 0;
2441 3 : for (i=0; i<count; i++) {
2442 1 : ar = gf_list_get(hevc_cfg->param_array, i);
2443 1 : if (ar->type==type) return ar;
2444 : }
2445 2 : GF_SAFEALLOC(ar, GF_NALUFFParamArray);
2446 2 : if (!ar) return NULL;
2447 2 : ar->nalus = gf_list_new();
2448 2 : ar->type = type;
2449 2 : if (ar->type == GF_HEVC_NALU_VID_PARAM)
2450 0 : gf_list_insert(hevc_cfg->param_array, ar, 0);
2451 : else
2452 2 : gf_list_add(hevc_cfg->param_array, ar);
2453 : return ar;
2454 : }
2455 : #endif
2456 :
2457 : typedef struct{
2458 : u8 layer_id_plus_one;
2459 : u8 min_temporal_id;
2460 : u8 max_temporal_id;
2461 : } LInfo;
2462 :
2463 : typedef struct
2464 : {
2465 : u32 track_num;
2466 : u32 layer_id;
2467 : GF_HEVCConfig *lhvccfg;
2468 : GF_BitStream *bs;
2469 : u32 data_offset, data_size;
2470 : u32 temporal_id_sample, max_temporal_id_sample;
2471 : LInfo layers[64];
2472 : u32 width, height;
2473 : Bool has_samples;
2474 : Bool non_tsa_vcl;
2475 : } LHVCTrackInfo;
2476 :
2477 :
2478 : GF_EXPORT
2479 1 : GF_Err gf_media_filter_hevc(GF_ISOFile *file, u32 track, u8 max_temporal_id_plus_one, u8 max_layer_id_plus_one)
2480 : {
2481 : GF_HEVCConfig *hevccfg, *lhvccfg;
2482 : u32 i, count, cur_extract_mode;
2483 : char *nal_data=NULL;
2484 : u32 nal_alloc_size, nalu_size;
2485 : GF_Err e = GF_OK;
2486 :
2487 1 : if (!max_temporal_id_plus_one && !max_layer_id_plus_one)
2488 : return GF_OK;
2489 :
2490 1 : hevccfg = gf_isom_hevc_config_get(file, track, 1);
2491 1 : lhvccfg = gf_isom_lhvc_config_get(file, track, 1);
2492 1 : if (!hevccfg && !lhvccfg)
2493 : nalu_size = 4;
2494 : else
2495 1 : nalu_size = hevccfg ? hevccfg->nal_unit_size : lhvccfg->nal_unit_size;
2496 :
2497 1 : cur_extract_mode = gf_isom_get_nalu_extract_mode(file, track);
2498 1 : gf_isom_set_nalu_extract_mode(file, track, GF_ISOM_NALU_EXTRACT_INSPECT);
2499 :
2500 : nal_alloc_size = 10000;
2501 1 : nal_data = gf_malloc(sizeof(char) * nal_alloc_size);
2502 :
2503 1 : if (hevccfg) {
2504 1 : count = gf_list_count(hevccfg->param_array);
2505 4 : for (i=0; i<count; i++) {
2506 : u32 j, count2;
2507 3 : GF_NALUFFParamArray *ar = (GF_NALUFFParamArray *)gf_list_get(hevccfg->param_array, i);
2508 3 : count2 = gf_list_count(ar->nalus);
2509 6 : for (j=0; j<count2; j++) {
2510 3 : GF_NALUFFParam *sl = (GF_NALUFFParam *)gf_list_get(ar->nalus, j);
2511 : //u8 nal_type = (sl->data[0] & 0x7E) >> 1;
2512 3 : u8 layer_id = ((sl->data[0] & 0x1) << 5) | (sl->data[1] >> 3);
2513 3 : u8 temporal_id_plus_one = sl->data[1] & 0x07;
2514 :
2515 3 : if ((max_temporal_id_plus_one && (temporal_id_plus_one > max_temporal_id_plus_one)) || (max_layer_id_plus_one && (layer_id+1 > max_layer_id_plus_one))) {
2516 0 : gf_list_rem(ar->nalus, j);
2517 0 : j--;
2518 0 : count2--;
2519 0 : gf_free(sl->data);
2520 0 : gf_free(sl);
2521 : }
2522 : }
2523 : }
2524 : }
2525 :
2526 1 : if (lhvccfg) {
2527 1 : count = gf_list_count(lhvccfg->param_array);
2528 3 : for (i=0; i<count; i++) {
2529 : u32 j, count2;
2530 2 : GF_NALUFFParamArray *ar = (GF_NALUFFParamArray *)gf_list_get(lhvccfg->param_array, i);
2531 2 : count2 = gf_list_count(ar->nalus);
2532 4 : for (j=0; j<count2; j++) {
2533 2 : GF_NALUFFParam *sl = (GF_NALUFFParam *)gf_list_get(ar->nalus, j);
2534 : //u8 nal_type = (sl->data[0] & 0x7E) >> 1;
2535 2 : u8 layer_id = ((sl->data[0] & 0x1) << 5) | (sl->data[1] >> 3);
2536 2 : u8 temporal_id_plus_one = sl->data[1] & 0x07;
2537 :
2538 2 : if ((max_temporal_id_plus_one && (temporal_id_plus_one > max_temporal_id_plus_one)) || (max_layer_id_plus_one && (layer_id+1 > max_layer_id_plus_one))) {
2539 2 : gf_list_rem(ar->nalus, j);
2540 2 : j--;
2541 2 : count2--;
2542 2 : gf_free(sl->data);
2543 2 : gf_free(sl);
2544 : }
2545 : }
2546 : }
2547 : }
2548 :
2549 : //parse all samples
2550 1 : count = gf_isom_get_sample_count(file, track);
2551 1 : for (i=0; i<count; i++) {
2552 : GF_BitStream *bs, *dst_bs;
2553 : u32 di;
2554 : GF_ISOSample *sample;
2555 :
2556 502 : sample = gf_isom_get_sample(file, track, i+1, &di);
2557 :
2558 502 : bs = gf_bs_new(sample->data, sample->dataLength, GF_BITSTREAM_READ);
2559 502 : dst_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
2560 3012 : while (gf_bs_available(bs)) {
2561 2008 : u32 size = gf_bs_read_int(bs, nalu_size*8);
2562 2008 : u8 fzero = gf_bs_read_int(bs, 1);
2563 2008 : u8 nal_type = gf_bs_read_int(bs, 6);
2564 2008 : u8 layer_id = gf_bs_read_int(bs, 6);
2565 2008 : u8 temporal_id_plus_one = gf_bs_read_int(bs, 3);
2566 2008 : size -= 2;
2567 :
2568 2008 : if ((max_temporal_id_plus_one && (temporal_id_plus_one > max_temporal_id_plus_one))
2569 2008 : || (max_layer_id_plus_one && (layer_id+1 > max_layer_id_plus_one))
2570 : ) {
2571 1004 : gf_bs_skip_bytes(bs, size);
2572 1004 : continue;
2573 : }
2574 :
2575 1004 : if (size>nal_alloc_size) {
2576 : nal_alloc_size = size;
2577 3 : nal_data = (char *)gf_realloc(nal_data, nal_alloc_size);
2578 : }
2579 1004 : gf_bs_read_data(bs, nal_data, size);
2580 :
2581 1004 : gf_bs_write_int(dst_bs, size+2, nalu_size*8);
2582 1004 : gf_bs_write_int(dst_bs, fzero, 1);
2583 1004 : gf_bs_write_int(dst_bs, nal_type, 6);
2584 1004 : gf_bs_write_int(dst_bs, layer_id, 6);
2585 1004 : gf_bs_write_int(dst_bs, temporal_id_plus_one, 3);
2586 1004 : gf_bs_write_data(dst_bs, nal_data, size);
2587 : }
2588 :
2589 502 : gf_bs_del(bs);
2590 502 : gf_free(sample->data);
2591 502 : sample->data = NULL;
2592 502 : sample->dataLength = 0;
2593 :
2594 502 : gf_bs_get_content(dst_bs, &sample->data, &sample->dataLength);
2595 502 : e = gf_isom_update_sample(file, track, i+1, sample, GF_TRUE);
2596 502 : gf_bs_del(dst_bs);
2597 502 : gf_isom_sample_del(&sample);
2598 :
2599 502 : if (e)
2600 : goto exit;
2601 : }
2602 :
2603 1 : exit:
2604 1 : if (lhvccfg) gf_odf_hevc_cfg_del(lhvccfg);
2605 1 : if (hevccfg) gf_odf_hevc_cfg_del(hevccfg);
2606 1 : gf_isom_set_nalu_extract_mode(file, track, cur_extract_mode);
2607 1 : if (nal_data) gf_free(nal_data);
2608 : return e;
2609 : }
2610 :
2611 : GF_EXPORT
2612 1 : GF_Err gf_media_split_lhvc(GF_ISOFile *file, u32 track, Bool for_temporal_sublayers, Bool splitAll, GF_LHVCExtractoreMode extractor_mode)
2613 : {
2614 : #if !defined(GPAC_DISABLE_HEVC) && !defined(GPAC_DISABLE_AV_PARSERS)
2615 : LHVCTrackInfo sti[64];
2616 : GF_HEVCConfig *hevccfg, *lhvccfg;
2617 : u32 sample_num, count, cur_extract_mode, j, k, max_layer_id;
2618 : char *nal_data=NULL;
2619 : u32 nal_alloc_size;
2620 : u32 nal_unit_size=0;
2621 : Bool single_layer_per_track=GF_TRUE;
2622 : GF_Err e = GF_OK;
2623 : HEVCState hevc_state;
2624 :
2625 : memset(&hevc_state, 0, sizeof(HEVCState));
2626 :
2627 1 : hevccfg = gf_isom_hevc_config_get(file, track, 1);
2628 1 : lhvccfg = gf_isom_lhvc_config_get(file, track, 1);
2629 1 : if (!lhvccfg && !for_temporal_sublayers) {
2630 0 : if (hevccfg) gf_odf_hevc_cfg_del(hevccfg);
2631 : return GF_OK;
2632 : }
2633 1 : else if (for_temporal_sublayers) {
2634 0 : if (lhvccfg) {
2635 0 : if (hevccfg) gf_odf_hevc_cfg_del(hevccfg);
2636 0 : gf_odf_hevc_cfg_del(lhvccfg);
2637 0 : return GF_NOT_SUPPORTED;
2638 : }
2639 0 : if (!hevccfg) return GF_NOT_SUPPORTED;
2640 :
2641 0 : if (hevccfg->numTemporalLayers<=1) {
2642 0 : gf_odf_hevc_cfg_del(hevccfg);
2643 0 : return GF_OK;
2644 : }
2645 : }
2646 :
2647 1 : cur_extract_mode = gf_isom_get_nalu_extract_mode(file, track);
2648 1 : gf_isom_set_nalu_extract_mode(file, track, GF_ISOM_NALU_EXTRACT_INSPECT);
2649 :
2650 : memset(sti, 0, sizeof(sti));
2651 1 : sti[0].track_num = track;
2652 1 : sti[0].has_samples=GF_TRUE;
2653 : max_layer_id = 0;
2654 :
2655 1 : nal_unit_size = lhvccfg ? lhvccfg->nal_unit_size : hevccfg->nal_unit_size;
2656 :
2657 1 : if (!for_temporal_sublayers) {
2658 : u32 i, pass, base_layer_pass = GF_TRUE;
2659 : GF_HEVCConfig *cur_cfg = hevccfg;
2660 :
2661 2 : reparse:
2662 : //split all SPS/PPS/VPS from lhvccfg
2663 8 : for (pass=0; pass<3; pass++) {
2664 6 : count = gf_list_count(cur_cfg->param_array);
2665 21 : for (i=0; i<count; i++) {
2666 : u32 count2;
2667 : GF_NALUFFParamArray *s_ar;
2668 15 : GF_NALUFFParamArray *ar = gf_list_get(cur_cfg->param_array, i);
2669 15 : if ((pass==0) && (ar->type!=GF_HEVC_NALU_VID_PARAM)) continue;
2670 11 : else if ((pass==1) && (ar->type!=GF_HEVC_NALU_SEQ_PARAM)) continue;
2671 8 : else if ((pass==2) && (ar->type!=GF_HEVC_NALU_PIC_PARAM)) continue;
2672 :
2673 5 : count2 = gf_list_count(ar->nalus);
2674 10 : for (j=0; j<count2; j++) {
2675 5 : GF_NALUFFParam *sl = gf_list_get(ar->nalus, j);
2676 : // u8 nal_type = (sl->data[0] & 0x7E) >> 1;
2677 5 : u8 layer_id = ((sl->data[0] & 0x1) << 5) | (sl->data[1] >> 3);
2678 :
2679 5 : if (ar->type==GF_HEVC_NALU_SEQ_PARAM) {
2680 : u32 lw, lh;
2681 2 : s32 idx = gf_hevc_get_sps_info_with_state(&hevc_state, sl->data, sl->size, NULL, &lw, &lh, NULL, NULL);
2682 2 : if (idx>=0) {
2683 2 : if (lw > sti[layer_id].width) sti[layer_id].width = lw;
2684 2 : if (lh > sti[layer_id].height) sti[layer_id].height = lh;
2685 : }
2686 3 : } else if (ar->type==GF_HEVC_NALU_PIC_PARAM) {
2687 2 : gf_hevc_read_pps(sl->data, sl->size, &hevc_state);
2688 1 : } else if (ar->type==GF_HEVC_NALU_VID_PARAM) {
2689 1 : gf_hevc_read_vps(sl->data, sl->size, &hevc_state);
2690 : }
2691 :
2692 : //don't touch base layer
2693 5 : if (!layer_id) {
2694 : assert(base_layer_pass);
2695 3 : continue;
2696 : }
2697 :
2698 2 : if (!splitAll) layer_id = 1;
2699 :
2700 2 : if (max_layer_id < layer_id)
2701 : max_layer_id = layer_id;
2702 :
2703 2 : if (!sti[layer_id].lhvccfg) {
2704 : GF_List *backup_list;
2705 1 : sti[layer_id].lhvccfg = gf_odf_hevc_cfg_new();
2706 1 : backup_list = sti[layer_id].lhvccfg->param_array;
2707 1 : memcpy(sti[layer_id].lhvccfg , lhvccfg ? lhvccfg : hevccfg, sizeof(GF_HEVCConfig));
2708 1 : sti[layer_id].lhvccfg->param_array = backup_list;
2709 :
2710 1 : sti[layer_id].lhvccfg->is_lhvc = 1;
2711 1 : sti[layer_id].lhvccfg->complete_representation = 1;
2712 : }
2713 :
2714 2 : s_ar = alloc_hevc_param_array(sti[layer_id].lhvccfg, ar->type);
2715 2 : gf_list_add(s_ar->nalus, sl);
2716 2 : gf_list_rem(ar->nalus, j);
2717 2 : j--;
2718 2 : count2--;
2719 : }
2720 : }
2721 : }
2722 2 : if (base_layer_pass) {
2723 : base_layer_pass = GF_FALSE;
2724 : cur_cfg = lhvccfg;
2725 : goto reparse;
2726 : }
2727 : } else {
2728 0 : gf_isom_set_cts_packing(file, track, GF_TRUE);
2729 : }
2730 :
2731 : //CLARIFY wether this is correct: we duplicate all VPS in the enhancement layer ...
2732 : //we do this because if we split the tracks some info for setting up the enhancement layer
2733 : //is in the VPS
2734 1 : if (extractor_mode != GF_LHVC_EXTRACTORS_ON) {
2735 : u32 i;
2736 0 : count = gf_list_count(hevccfg->param_array);
2737 0 : for (i=0; i<count; i++) {
2738 : u32 count2;
2739 : GF_NALUFFParamArray *s_ar;
2740 0 : GF_NALUFFParamArray *ar = gf_list_get(hevccfg->param_array, i);
2741 0 : if (ar->type != GF_HEVC_NALU_VID_PARAM) continue;
2742 0 : count2 = gf_list_count(ar->nalus);
2743 0 : for (j=0; j<count2; j++) {
2744 0 : GF_NALUFFParam *sl = gf_list_get(ar->nalus, j);
2745 0 : u8 layer_id = ((sl->data[0] & 0x1) << 5) | (sl->data[1] >> 3);
2746 0 : if (layer_id) continue;
2747 :
2748 0 : for (k=0; k <= max_layer_id; k++) {
2749 : GF_NALUFFParam *sl2;
2750 0 : if (!sti[k].lhvccfg) continue;
2751 :
2752 0 : s_ar = alloc_hevc_param_array(sti[k].lhvccfg, ar->type);
2753 0 : s_ar->array_completeness = ar->array_completeness;
2754 :
2755 0 : GF_SAFEALLOC(sl2, GF_NALUFFParam);
2756 0 : if (!sl2) break;
2757 0 : sl2->data = gf_malloc(sl->size);
2758 0 : if (!sl2->data) {
2759 0 : gf_free(sl2);
2760 0 : break;
2761 : }
2762 0 : memcpy(sl2->data, sl->data, sl->size);
2763 0 : sl2->id = sl->id;
2764 0 : sl2->size = sl->size;
2765 0 : gf_list_add(s_ar->nalus, sl2);
2766 : }
2767 : }
2768 : }
2769 : }
2770 :
2771 : //update lhvc config
2772 1 : if (for_temporal_sublayers) {
2773 0 : e = gf_isom_lhvc_config_update(file, track, 1, NULL, GF_ISOM_LEHVC_WITH_BASE_BACKWARD);
2774 : } else {
2775 1 : e = gf_isom_lhvc_config_update(file, track, 1, NULL, GF_ISOM_LEHVC_WITH_BASE_BACKWARD);
2776 : }
2777 1 : if (e) {
2778 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[HEVC] Failed to update HEVC/LHVC config\n"));
2779 : goto exit;
2780 : }
2781 :
2782 : //purge all linf sample groups
2783 1 : gf_isom_remove_sample_group(file, track, GF_ISOM_SAMPLE_GROUP_LINF);
2784 :
2785 : nal_alloc_size = 10000;
2786 1 : nal_data = gf_malloc(sizeof(char) * nal_alloc_size);
2787 : //parse all samples
2788 1 : count = gf_isom_get_sample_count(file, track);
2789 503 : for (sample_num=0; sample_num<count; sample_num++) {
2790 : GF_BitStream *bs;
2791 : u32 di;
2792 : GF_ISOSample *sample;
2793 : Bool is_irap;
2794 : GF_ISOSampleRollType roll_type;
2795 : s32 roll_distance;
2796 : u8 cur_max_layer_id = 0;
2797 :
2798 502 : sample = gf_isom_get_sample(file, track, sample_num+1, &di);
2799 502 : gf_isom_get_sample_rap_roll_info(file, track, sample_num+1, &is_irap, &roll_type, &roll_distance);
2800 :
2801 502 : bs = gf_bs_new(sample->data, sample->dataLength, GF_BITSTREAM_READ);
2802 3012 : while (gf_bs_available(bs)) {
2803 : u8 orig_layer_id, nal_size;
2804 2008 : u32 size = gf_bs_read_int(bs, nal_unit_size*8);
2805 2008 : u32 offset = (u32) gf_bs_get_position(bs);
2806 2008 : u8 fzero = gf_bs_read_int(bs, 1);
2807 2008 : u8 nal_type = gf_bs_read_int(bs, 6);
2808 2008 : u8 layer_id = orig_layer_id = gf_bs_read_int(bs, 6);
2809 2008 : u8 temporal_id = gf_bs_read_int(bs, 3);
2810 :
2811 2008 : if (for_temporal_sublayers) {
2812 0 : u32 tid = temporal_id-1;
2813 0 : if (tid && !sti[tid].layer_id) {
2814 0 : sti[tid].layer_id=tid;
2815 : }
2816 0 : layer_id = tid;
2817 :
2818 0 : if ((nal_type <= GF_HEVC_NALU_SLICE_CRA)
2819 0 : && (nal_type != GF_HEVC_NALU_SLICE_TSA_N)
2820 0 : && (nal_type != GF_HEVC_NALU_SLICE_TSA_R))
2821 0 : sti[layer_id].non_tsa_vcl = GF_TRUE;
2822 : } else {
2823 2008 : if (layer_id && !sti[layer_id].layer_id) {
2824 1 : sti[layer_id].layer_id=layer_id;
2825 : }
2826 : }
2827 2008 : if (!splitAll && layer_id) layer_id = 1;
2828 :
2829 2008 : if (cur_max_layer_id < layer_id) {
2830 : cur_max_layer_id = layer_id;
2831 : }
2832 :
2833 : nal_size = size;
2834 :
2835 2008 : if (!sti[layer_id].bs)
2836 1004 : sti[layer_id].bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
2837 :
2838 2008 : gf_bs_write_int(sti[layer_id].bs, size, nal_unit_size*8);
2839 2008 : gf_bs_write_int(sti[layer_id].bs, fzero, 1);
2840 2008 : gf_bs_write_int(sti[layer_id].bs, nal_type, 6);
2841 2008 : gf_bs_write_int(sti[layer_id].bs, orig_layer_id, 6);
2842 2008 : gf_bs_write_int(sti[layer_id].bs, temporal_id, 3);
2843 2008 : size -= 2;
2844 :
2845 2008 : sti[layer_id].layers[layer_id].layer_id_plus_one = layer_id+1;
2846 2008 : sti[layer_id].temporal_id_sample = temporal_id;
2847 :
2848 2008 : if (!sti[layer_id].layers[layer_id].min_temporal_id || (sti[layer_id].layers[layer_id].min_temporal_id > temporal_id)) {
2849 2 : sti[layer_id].layers[layer_id].min_temporal_id = temporal_id;
2850 : }
2851 2008 : if (!sti[layer_id].layers[layer_id].max_temporal_id || (sti[layer_id].layers[layer_id].max_temporal_id < temporal_id)) {
2852 8 : sti[layer_id].layers[layer_id].max_temporal_id = temporal_id;
2853 : }
2854 :
2855 2008 : if (!sti[layer_id].max_temporal_id_sample || (sti[layer_id].max_temporal_id_sample < temporal_id)) {
2856 1004 : sti[layer_id].max_temporal_id_sample = temporal_id;
2857 : }
2858 :
2859 2008 : if (! for_temporal_sublayers) {
2860 :
2861 2008 : if (nal_type==GF_HEVC_NALU_SEQ_PARAM) {
2862 : u32 lw, lh;
2863 0 : s32 idx = gf_hevc_get_sps_info_with_state(&hevc_state, sample->data + offset, nal_size, NULL, &lw, &lh, NULL, NULL);
2864 0 : if (idx>=0) {
2865 0 : if (lw > sti[layer_id].width) sti[layer_id].width = lw;
2866 0 : if (lh > sti[layer_id].height) sti[layer_id].height = lh;
2867 : }
2868 2008 : } else if (nal_type==GF_HEVC_NALU_PIC_PARAM) {
2869 0 : gf_hevc_read_pps(sample->data + offset, nal_size, &hevc_state);
2870 2008 : } else if (nal_type==GF_HEVC_NALU_VID_PARAM) {
2871 0 : gf_hevc_read_vps(sample->data + offset, nal_size, &hevc_state);
2872 : }
2873 : }
2874 :
2875 2008 : if (size>nal_alloc_size) {
2876 : nal_alloc_size = size;
2877 5 : nal_data = gf_realloc(nal_data, nal_alloc_size);
2878 : }
2879 :
2880 2008 : gf_bs_read_data(bs, nal_data, size);
2881 2008 : gf_bs_write_data(sti[layer_id].bs, nal_data, size);
2882 : }
2883 502 : gf_bs_del(bs);
2884 :
2885 502 : if (cur_max_layer_id>max_layer_id) {
2886 : max_layer_id = cur_max_layer_id;
2887 : }
2888 502 : if (for_temporal_sublayers && hevccfg->numTemporalLayers>max_layer_id+1) {
2889 0 : max_layer_id = hevccfg->numTemporalLayers-1;
2890 : }
2891 :
2892 502 : gf_free(sample->data);
2893 502 : sample->data = NULL;
2894 502 : sample->dataLength = 0;
2895 : //reset all samples on all layers found - we may have layers not present in this sample, we still need to process these layers when extractors are used
2896 1506 : for (j=0; j<=max_layer_id; j++) {
2897 1004 : if (!for_temporal_sublayers && ! sti[j].bs) {
2898 0 : if (!sti[j].track_num || (extractor_mode != GF_LHVC_EXTRACTORS_ON) ) {
2899 0 : sti[j].data_offset = sti[j].data_size = 0;
2900 0 : continue;
2901 : }
2902 : }
2903 :
2904 : //clone track
2905 1004 : if (! sti[j].track_num) {
2906 1 : u32 track_id = gf_isom_get_track_id(file, track);
2907 1 : e = gf_isom_clone_track(file, track, file, 0, &sti[j].track_num);
2908 1 : if (e) goto exit;
2909 :
2910 1 : if (! for_temporal_sublayers) {
2911 : //happens for inband param
2912 1 : if (!sti[j].lhvccfg) {
2913 : GF_List *backup_list;
2914 0 : sti[j].lhvccfg = gf_odf_hevc_cfg_new();
2915 0 : backup_list = sti[j].lhvccfg->param_array;
2916 0 : memcpy(sti[j].lhvccfg , lhvccfg ? lhvccfg : hevccfg, sizeof(GF_HEVCConfig));
2917 0 : sti[j].lhvccfg->param_array = backup_list;
2918 :
2919 0 : sti[j].lhvccfg->is_lhvc = 1;
2920 0 : sti[j].lhvccfg->complete_representation = 1;
2921 : }
2922 1 : e = gf_isom_lhvc_config_update(file, sti[j].track_num, 1, sti[j].lhvccfg, (extractor_mode == GF_LHVC_EXTRACTORS_ON) ? GF_ISOM_LEHVC_WITH_BASE : GF_ISOM_LEHVC_ONLY);
2923 1 : if (e) goto exit;
2924 :
2925 1 : if (extractor_mode == GF_LHVC_EXTRACTORS_OFF_FORCE_INBAND)
2926 0 : gf_isom_lhvc_force_inband_config(file, sti[j].track_num, 1);
2927 : } else {
2928 0 : e = gf_isom_lhvc_config_update(file, sti[j].track_num, 1, NULL, GF_ISOM_LEHVC_WITH_BASE);
2929 0 : if (e) goto exit;
2930 : }
2931 1 : if (e) {
2932 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[HEVC] Failed to update HEVC/LHVC config\n"));
2933 : goto exit;
2934 : }
2935 :
2936 1 : gf_isom_set_track_reference(file, sti[j].track_num, GF_ISOM_REF_BASE, track_id);
2937 :
2938 : //for an L-HEVC bitstream: only base track carries the 'oinf' sample group, other track have a track reference of type 'oref' to base track
2939 1 : e = gf_isom_remove_sample_group(file, sti[j].track_num, GF_ISOM_SAMPLE_GROUP_OINF);
2940 1 : if (e) goto exit;
2941 : //purge all linf sample groups
2942 1 : gf_isom_remove_sample_group(file, sti[j].track_num, GF_ISOM_SAMPLE_GROUP_LINF);
2943 1 : gf_isom_set_track_reference(file, sti[j].track_num, GF_ISOM_REF_OREF, track_id);
2944 :
2945 1 : gf_isom_set_nalu_extract_mode(file, sti[j].track_num, GF_ISOM_NALU_EXTRACT_INSPECT);
2946 :
2947 : //get lower layer
2948 1 : if (extractor_mode == GF_LHVC_EXTRACTORS_ON) {
2949 2 : for (k=j; k>0; k--) {
2950 1 : if (sti[k-1].track_num) {
2951 1 : u32 track_id_r = gf_isom_get_track_id(file, sti[k-1].track_num);
2952 1 : gf_isom_set_track_reference(file, sti[j].track_num, GF_ISOM_REF_SCAL, track_id_r);
2953 : }
2954 : }
2955 : }
2956 :
2957 1 : if (!for_temporal_sublayers)
2958 1 : gf_isom_set_visual_info(file, sti[j].track_num, 1, sti[j].width, sti[j].height);
2959 : } else {
2960 1003 : if (!for_temporal_sublayers)
2961 1003 : gf_isom_set_visual_info(file, sti[j].track_num, 1, sti[j].width, sti[j].height);
2962 : }
2963 :
2964 1004 : if (j && (extractor_mode == GF_LHVC_EXTRACTORS_ON)) {
2965 502 : GF_BitStream *xbs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
2966 : //get all lower layers
2967 1004 : for (k=0; k<j; k++) {
2968 : u8 trefidx, tid;
2969 502 : if (!sti[k].data_size)
2970 0 : continue;
2971 : //extractor size 5
2972 502 : gf_bs_write_int(xbs, 2*nal_unit_size + 5, 8*nal_unit_size);
2973 502 : gf_bs_write_int(xbs, 0, 1);
2974 502 : gf_bs_write_int(xbs, 49, 6); //extractor
2975 502 : gf_bs_write_int(xbs, k, 6);
2976 502 : gf_bs_write_int(xbs, sti[k].max_temporal_id_sample, 3);
2977 502 : gf_bs_write_u8(xbs, 0); //constructor type 0
2978 : //set ref track index
2979 502 : trefidx = (u8) gf_isom_has_track_reference(file, sti[j].track_num, GF_ISOM_REF_SCAL, gf_isom_get_track_id(file, sti[k].track_num) );
2980 502 : gf_bs_write_int(xbs, trefidx, 8);
2981 : // no sample offset
2982 502 : gf_bs_write_int(xbs, 0, 8);
2983 : // data offset: we start from beginning of the sample data, not the extractor
2984 502 : gf_bs_write_int(xbs, sti[k].data_offset, 8*nal_unit_size);
2985 502 : gf_bs_write_int(xbs, sti[k].data_size, 8*nal_unit_size);
2986 :
2987 502 : tid = sti[k].temporal_id_sample;
2988 502 : sti[j].layers[k].layer_id_plus_one = sti[k].layer_id+1;
2989 502 : if (!sti[j].layers[k].min_temporal_id || (sti[j].layers[k].min_temporal_id > tid)) {
2990 1 : sti[j].layers[k].min_temporal_id = tid;
2991 : }
2992 502 : if (!sti[j].layers[k].max_temporal_id || (sti[j].layers[k].max_temporal_id < tid)) {
2993 4 : sti[j].layers[k].max_temporal_id = tid;
2994 : }
2995 :
2996 : }
2997 :
2998 502 : gf_bs_get_content(xbs, &sample->data, &sample->dataLength);
2999 502 : gf_bs_del(xbs);
3000 :
3001 : //we wrote all our references, store offset for upper layers
3002 502 : sti[j].data_offset = sample->dataLength;
3003 502 : e = gf_isom_add_sample(file, sti[j].track_num, 1, sample);
3004 502 : if (e) {
3005 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[HEVC] Failed to add HEVC/LHVC sample to track %d\n", sti[j].track_num));
3006 : goto exit;
3007 : }
3008 502 : gf_free(sample->data);
3009 502 : sample->data = NULL;
3010 :
3011 : //get real content, remember its size and add it to the new bs
3012 502 : if (sti[j].bs) {
3013 502 : gf_bs_get_content(sti[j].bs, &sample->data, &sample->dataLength);
3014 502 : e = gf_isom_append_sample_data(file, sti[j].track_num, sample->data, sample->dataLength);
3015 502 : if (e) {
3016 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[HEVC] Failed to append HEVC/LHVC data to sample (track %d)\n", sti[j].track_num));
3017 : goto exit;
3018 : }
3019 : }
3020 :
3021 : }
3022 : //get sample content
3023 502 : else if (sti[j].bs) {
3024 : //add empty sample at DTS 0
3025 502 : if ( ! sti[j].has_samples) {
3026 0 : if (sample->DTS) {
3027 : GF_ISOSample s;
3028 : memset(&s, 0, sizeof(GF_ISOSample));
3029 0 : gf_isom_add_sample(file, sti[j].track_num, 1, &s);
3030 : }
3031 0 : sti[j].has_samples=GF_TRUE;
3032 : }
3033 502 : gf_bs_get_content(sti[j].bs, &sample->data, &sample->dataLength);
3034 502 : sti[j].data_offset = 0;
3035 502 : sti[j].data_size = sample->dataLength;
3036 :
3037 : //add sample
3038 502 : if (j) {
3039 0 : GF_ISOSAPType rap = sample->IsRAP;
3040 0 : if (for_temporal_sublayers && !sti[j].non_tsa_vcl)
3041 0 : sample->IsRAP = RAP;
3042 :
3043 0 : e = gf_isom_add_sample(file, sti[j].track_num, 1, sample);
3044 0 : sample->IsRAP = rap;
3045 : } else {
3046 502 : e = gf_isom_update_sample(file, sti[j].track_num, sample_num+1, sample, 1);
3047 : }
3048 502 : if (e) {
3049 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[HEVC] Failed to %s HEVC/LHVC sample (track %d, base sample num %d)\n", j ? "add" : "update", sti[j].track_num, sample_num+1));
3050 : goto exit;
3051 : }
3052 : }
3053 : //no data left in sample, update
3054 0 : else if (!j) {
3055 0 : e = gf_isom_remove_sample(file, sti[j].track_num, sample_num+1);
3056 0 : if (e) {
3057 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[HEVC] Failed to remove HEVC/LHVC sample (track %d)\n", sti[j].track_num));
3058 : goto exit;
3059 : }
3060 0 : sample_num--;
3061 0 : count--;
3062 : }
3063 :
3064 1004 : gf_bs_del(sti[j].bs);
3065 1004 : sti[j].bs = NULL;
3066 :
3067 1004 : if (sample->IsRAP>SAP_TYPE_1) {
3068 20 : u32 sample_idx = gf_isom_get_sample_count(file, sti[j].track_num);
3069 20 : if (is_irap) {
3070 20 : gf_isom_set_sample_rap_group(file, sti[j].track_num, sample_idx, GF_TRUE, 0);
3071 : }
3072 0 : else if (roll_type) {
3073 0 : gf_isom_set_sample_roll_group(file, sti[j].track_num, sample_idx, GF_ISOM_SAMPLE_ROLL, (s16) roll_distance);
3074 : }
3075 : }
3076 :
3077 1004 : if (sample->data) {
3078 1004 : gf_free(sample->data);
3079 1004 : sample->data = NULL;
3080 : }
3081 1004 : sample->dataLength = 0;
3082 : }
3083 502 : gf_isom_sample_del(&sample);
3084 :
3085 : //reset all scalable info
3086 1506 : for (j=0; j<=max_layer_id; j++) {
3087 1004 : sti[j].max_temporal_id_sample = 0;
3088 1004 : sti[j].temporal_id_sample = 0;
3089 1004 : sti[j].data_size = 0;
3090 1004 : sti[j].non_tsa_vcl = GF_FALSE;
3091 : }
3092 : }
3093 :
3094 1 : exit:
3095 : //reset all scalable info
3096 3 : for (j=0; j<=max_layer_id; j++) {
3097 : GF_BitStream *bs;
3098 : u32 data_size;
3099 2 : u8 *data=NULL;
3100 2 : if (sti[j].lhvccfg) gf_odf_hevc_cfg_del(sti[j].lhvccfg);
3101 : //set linf group
3102 2 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
3103 2 : gf_bs_write_int(bs, 0, 2);
3104 2 : count = 0;
3105 6 : for (k=0; k<=max_layer_id; k++) {
3106 4 : if (sti[j].layers[k].layer_id_plus_one) count++;
3107 : }
3108 2 : gf_bs_write_int(bs, count, 6);
3109 2 : if (count>1)
3110 : single_layer_per_track = GF_FALSE;
3111 :
3112 6 : for (k=0; k<=max_layer_id; k++) {
3113 4 : if (! sti[j].layers[k].layer_id_plus_one) continue;
3114 3 : gf_bs_write_int(bs, 0, 4);
3115 3 : gf_bs_write_int(bs, sti[j].layers[k].layer_id_plus_one - 1, 6);
3116 3 : gf_bs_write_int(bs, sti[j].layers[k].min_temporal_id, 3);
3117 3 : gf_bs_write_int(bs, sti[j].layers[k].max_temporal_id, 3);
3118 3 : gf_bs_write_int(bs, 0, 1);
3119 : //track carries the NALUs
3120 3 : if (k==j) {
3121 2 : gf_bs_write_int(bs, 0xFF, 7);
3122 : }
3123 : //otherwise referenced through extractors, not present natively
3124 : else {
3125 1 : gf_bs_write_int(bs, 0, 7);
3126 : }
3127 : }
3128 2 : gf_bs_get_content(bs, &data, &data_size);
3129 2 : gf_bs_del(bs);
3130 2 : gf_isom_add_sample_group_info(file, sti[j].track_num, GF_ISOM_SAMPLE_GROUP_LINF, data, data_size, GF_TRUE, &count);
3131 2 : gf_free(data);
3132 : }
3133 1 : gf_isom_set_nalu_extract_mode(file, track, cur_extract_mode);
3134 :
3135 1 : if (extractor_mode == GF_LHVC_EXTRACTORS_ON) {
3136 1 : gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_HVCE, GF_TRUE);
3137 1 : gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_HVCI, GF_FALSE);
3138 : }
3139 : //add hvci brand only if single layer per track
3140 0 : else if (single_layer_per_track) {
3141 0 : gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_HVCI, GF_TRUE);
3142 0 : gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_HVCE, GF_FALSE);
3143 : }
3144 1 : if (lhvccfg) gf_odf_hevc_cfg_del(lhvccfg);
3145 1 : if (hevccfg) gf_odf_hevc_cfg_del(hevccfg);
3146 1 : if (nal_data) gf_free(nal_data);
3147 : return e;
3148 : #else
3149 : return GF_NOT_SUPPORTED;
3150 : #endif
3151 :
3152 : }
3153 : #endif /*GPAC_DISABLE_HEVC*/
3154 :
3155 : GF_EXPORT
3156 3 : GF_Err gf_media_change_pl(GF_ISOFile *file, u32 track, u32 profile, u32 compat, u32 level)
3157 : {
3158 : u32 i, count, stype;
3159 : GF_Err e;
3160 : GF_AVCConfig *avcc;
3161 :
3162 3 : stype = gf_isom_get_media_subtype(file, track, 1);
3163 3 : switch (stype) {
3164 : case GF_ISOM_SUBTYPE_AVC_H264:
3165 : case GF_ISOM_SUBTYPE_AVC2_H264:
3166 : case GF_ISOM_SUBTYPE_AVC3_H264:
3167 : case GF_ISOM_SUBTYPE_AVC4_H264:
3168 : break;
3169 : default:
3170 : return GF_OK;
3171 : }
3172 :
3173 1 : avcc = gf_isom_avc_config_get(file, track, 1);
3174 1 : if (level) avcc->AVCLevelIndication = level;
3175 1 : if (compat) avcc->profile_compatibility = compat;
3176 1 : if (profile) avcc->AVCProfileIndication = profile;
3177 1 : count = gf_list_count(avcc->sequenceParameterSets);
3178 2 : for (i=0; i<count; i++) {
3179 1 : GF_NALUFFParam *slc = gf_list_get(avcc->sequenceParameterSets, i);
3180 1 : if (profile) slc->data[1] = profile;
3181 1 : if (level) slc->data[3] = level;
3182 : }
3183 1 : e = gf_isom_avc_config_update(file, track, 1, avcc);
3184 :
3185 1 : gf_odf_avc_cfg_del(avcc);
3186 1 : return e;
3187 : }
3188 :
3189 : #if !defined(GPAC_DISABLE_HEVC) && !defined(GPAC_DISABLE_AV_PARSERS)
3190 54000 : u32 hevc_get_tile_id(HEVCState *hevc, u32 *tile_x, u32 *tile_y, u32 *tile_width, u32 *tile_height)
3191 : {
3192 : HEVCSliceInfo *si = &hevc->s_info;
3193 : u32 i, tbX, tbY, PicWidthInCtbsY, PicHeightInCtbsY, tileX, tileY, oX, oY, val;
3194 :
3195 54000 : PicWidthInCtbsY = si->sps->width / si->sps->max_CU_width;
3196 54000 : if (PicWidthInCtbsY * si->sps->max_CU_width < si->sps->width) PicWidthInCtbsY++;
3197 54000 : PicHeightInCtbsY = si->sps->height / si->sps->max_CU_width;
3198 54000 : if (PicHeightInCtbsY * si->sps->max_CU_width < si->sps->height) PicHeightInCtbsY++;
3199 :
3200 54000 : tbX = si->slice_segment_address % PicWidthInCtbsY;
3201 54000 : tbY = si->slice_segment_address / PicWidthInCtbsY;
3202 :
3203 : tileX = tileY = 0;
3204 : oX = oY = 0;
3205 162000 : for (i=0; i < si->pps->num_tile_columns; i++) {
3206 108000 : if (si->pps->uniform_spacing_flag) {
3207 108000 : val = (i+1)*PicWidthInCtbsY / si->pps->num_tile_columns - (i)*PicWidthInCtbsY / si->pps->num_tile_columns;
3208 : } else {
3209 0 : if (i<si->pps->num_tile_columns-1) {
3210 0 : val = si->pps->column_width[i];
3211 : } else {
3212 0 : val = (PicWidthInCtbsY - si->pps->column_width[i-1]);
3213 : }
3214 : }
3215 108000 : *tile_x = oX;
3216 108000 : *tile_width = val;
3217 :
3218 108000 : if (oX >= tbX) break;
3219 54000 : oX += val;
3220 54000 : tileX++;
3221 : }
3222 162000 : for (i=0; i<si->pps->num_tile_rows; i++) {
3223 108000 : if (si->pps->uniform_spacing_flag) {
3224 108000 : val = (i+1)*PicHeightInCtbsY / si->pps->num_tile_rows - (i)*PicHeightInCtbsY / si->pps->num_tile_rows;
3225 : } else {
3226 0 : if (i<si->pps->num_tile_rows-1) {
3227 0 : val = si->pps->row_height[i];
3228 0 : } else if (i) {
3229 0 : val = (PicHeightInCtbsY - si->pps->row_height[i-1]);
3230 : } else {
3231 : val = PicHeightInCtbsY;
3232 : }
3233 : }
3234 108000 : *tile_y = oY;
3235 108000 : *tile_height = val;
3236 :
3237 108000 : if (oY >= tbY) break;
3238 54000 : oY += val;
3239 54000 : tileY++;
3240 : }
3241 54000 : *tile_x = *tile_x * si->sps->max_CU_width;
3242 54000 : *tile_y = *tile_y * si->sps->max_CU_width;
3243 54000 : *tile_width = *tile_width * si->sps->max_CU_width;
3244 54000 : *tile_height = *tile_height * si->sps->max_CU_width;
3245 :
3246 54000 : if (*tile_x + *tile_width > si->sps->width)
3247 0 : *tile_width = si->sps->width - *tile_x;
3248 54000 : if (*tile_y + *tile_height > si->sps->height)
3249 18000 : *tile_height = si->sps->height - *tile_y;
3250 :
3251 54000 : return tileX + tileY * si->pps->num_tile_columns;
3252 : }
3253 :
3254 : typedef struct
3255 : {
3256 : u32 track, track_id, sample_count;
3257 : u32 tx, ty, tw, th;
3258 : u32 data_offset;
3259 : GF_BitStream *sample_data;
3260 : u32 nb_nalus_in_sample;
3261 : Bool all_intra;
3262 : } HEVCTileImport;
3263 :
3264 45 : static void hevc_add_trif(GF_ISOFile *file, u32 track, u32 id, Bool full_picture, u32 independent, Bool filtering_disable, u32 tx, u32 ty, u32 tw, u32 th, Bool is_default)
3265 : {
3266 : char data[11];
3267 : u32 di, data_size=7;
3268 : GF_BitStream *bs;
3269 : //write TRIF sample group description
3270 45 : bs = gf_bs_new((const char*)data, 11, GF_BITSTREAM_WRITE);
3271 45 : gf_bs_write_u16(bs, id); //groupID
3272 45 : gf_bs_write_int(bs, 1, 1); //tile Region flag always true for us
3273 45 : gf_bs_write_int(bs, independent, 2); //independentIDC: set to 1 (motion-constrained tiles but not all tiles RAP)
3274 45 : gf_bs_write_int(bs, full_picture, 1);//full picture: false since we don't do L-HEVC tiles
3275 45 : gf_bs_write_int(bs, filtering_disable, 1); //filtering disabled: set to 1 (always true on our bitstreams for now) - Check xPS to be sure ...
3276 45 : gf_bs_write_int(bs, 0, 1);//has dependency list: false since we don't do L-HEVC tiles
3277 45 : gf_bs_write_int(bs, 0, 2); //reserved
3278 45 : if (!full_picture) {
3279 45 : gf_bs_write_u16(bs, tx);
3280 45 : gf_bs_write_u16(bs, ty);
3281 : data_size+=4;
3282 : }
3283 45 : gf_bs_write_u16(bs, tw);
3284 45 : gf_bs_write_u16(bs, th);
3285 45 : gf_bs_del(bs);
3286 :
3287 45 : gf_isom_add_sample_group_info(file, track, GF_ISOM_SAMPLE_GROUP_TRIF, data, data_size, is_default, &di);
3288 45 : }
3289 :
3290 : GF_EXPORT
3291 5 : GF_Err gf_media_split_hevc_tiles(GF_ISOFile *file, u32 signal_mode)
3292 : {
3293 : #if defined(GPAC_DISABLE_HEVC) || defined(GPAC_DISABLE_AV_PARSERS)
3294 : return GF_NOT_SUPPORTED;
3295 : #else
3296 : u32 i, j, cur_tile, count, stype, track, nb_tiles, di, nalu_size_length, tx, ty, tw, th;
3297 : s32 pps_idx=-1, sps_idx=-1, ret;
3298 : GF_Err e = GF_OK;
3299 : HEVCState hevc;
3300 : HEVCTileImport *tiles;
3301 : GF_HEVCConfig *hvcc;
3302 : Bool filter_disabled=GF_TRUE;
3303 :
3304 : track = 0;
3305 15 : for (i=0; i<gf_isom_get_track_count(file); i++) {
3306 5 : stype = gf_isom_get_media_subtype(file, i+1, 1);
3307 5 : switch (stype) {
3308 5 : case GF_ISOM_SUBTYPE_HVC1:
3309 : case GF_ISOM_SUBTYPE_HEV1:
3310 : case GF_ISOM_SUBTYPE_HVC2:
3311 : case GF_ISOM_SUBTYPE_HEV2:
3312 :
3313 5 : if (track) return GF_NOT_SUPPORTED;
3314 : track = i+1;
3315 : break;
3316 : default:
3317 : break;
3318 : }
3319 : }
3320 5 : if (!track) return GF_NOT_SUPPORTED;
3321 :
3322 5 : hvcc = gf_isom_hevc_config_get(file, track, 1);
3323 5 : nalu_size_length = hvcc->nal_unit_size;
3324 :
3325 : memset(&hevc, 0, sizeof(HEVCState));
3326 :
3327 5 : count = gf_list_count(hvcc->param_array);
3328 20 : for (i=0; i<count; i++) {
3329 15 : GF_NALUFFParamArray *ar = gf_list_get(hvcc->param_array, i);
3330 30 : for (j=0; j < gf_list_count(ar->nalus); j++) {
3331 15 : GF_NALUFFParam *sl = gf_list_get(ar->nalus, j);
3332 15 : if (!sl) continue;
3333 15 : switch (ar->type) {
3334 5 : case GF_HEVC_NALU_PIC_PARAM:
3335 5 : pps_idx = gf_hevc_read_pps(sl->data, sl->size, &hevc);
3336 5 : break;
3337 5 : case GF_HEVC_NALU_SEQ_PARAM:
3338 5 : sps_idx = gf_hevc_read_sps(sl->data, sl->size, &hevc);
3339 5 : break;
3340 5 : case GF_HEVC_NALU_VID_PARAM:
3341 5 : gf_hevc_read_vps(sl->data, sl->size, &hevc);
3342 5 : break;
3343 : }
3344 : }
3345 : }
3346 5 : gf_isom_hevc_set_tile_config(file, track, 1, hvcc, GF_TRUE);
3347 5 : gf_odf_hevc_cfg_del(hvcc);
3348 :
3349 : //if params sets are inband, get first sps/pps
3350 : i=0;
3351 10 : while ((pps_idx==-1) || (sps_idx==-1)) {
3352 0 : GF_ISOSample *sample = gf_isom_get_sample(file, track, i+1, &di);
3353 0 : char *data = sample->data;
3354 0 : u32 size = sample->dataLength;
3355 :
3356 0 : while (size) {
3357 : u8 temporal_id, layer_id;
3358 0 : u8 nal_type = 0;
3359 : u32 nalu_size = 0;
3360 :
3361 0 : for (j=0; j<nalu_size_length; j++) {
3362 0 : nalu_size = (nalu_size<<8) + data[j];
3363 : }
3364 0 : gf_hevc_parse_nalu(data + nalu_size_length, nalu_size, &hevc, &nal_type, &temporal_id, &layer_id);
3365 :
3366 0 : switch (nal_type) {
3367 0 : case GF_HEVC_NALU_PIC_PARAM:
3368 0 : pps_idx = gf_hevc_read_pps((char *) data+nalu_size_length, nalu_size, &hevc);
3369 0 : break;
3370 0 : case GF_HEVC_NALU_SEQ_PARAM:
3371 0 : sps_idx = gf_hevc_read_sps((char *) data+nalu_size_length, nalu_size, &hevc);
3372 0 : break;
3373 0 : case GF_HEVC_NALU_VID_PARAM:
3374 0 : gf_hevc_read_vps((char *) data+nalu_size_length, nalu_size, &hevc);
3375 0 : break;
3376 : }
3377 0 : data += nalu_size + nalu_size_length;
3378 0 : size -= nalu_size + nalu_size_length;
3379 : }
3380 0 : gf_isom_sample_del(&sample);
3381 : }
3382 :
3383 5 : if (pps_idx==-1) return GF_BAD_PARAM;
3384 5 : if (sps_idx==-1) return GF_BAD_PARAM;
3385 :
3386 5 : if (hevc.pps[pps_idx].loop_filter_across_tiles_enabled_flag)
3387 : filter_disabled=GF_FALSE;
3388 :
3389 5 : if (! hevc.pps[pps_idx].tiles_enabled_flag) {
3390 0 : hevc_add_trif(file, track, gf_isom_get_track_id(file, track), GF_TRUE, 1, filter_disabled, 0, 0, hevc.sps[pps_idx].width, hevc.sps[pps_idx].height, GF_TRUE);
3391 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[HEVC Tiles] Tiles not enabled, signal only single tile full picture\n"));
3392 : return GF_OK;
3393 : }
3394 :
3395 5 : nb_tiles = hevc.pps[pps_idx].num_tile_columns * hevc.pps[pps_idx].num_tile_rows;
3396 5 : tiles = gf_malloc(sizeof(HEVCTileImport) * nb_tiles);
3397 5 : if (!tiles) return GF_OUT_OF_MEM;
3398 : memset(tiles, 0, sizeof(HEVCTileImport) * nb_tiles);
3399 :
3400 50 : for (i=0; i<nb_tiles; i++) {
3401 45 : if (! signal_mode) {
3402 : //first clone tracks
3403 36 : e = gf_isom_clone_track(file, track, file, 0, &tiles[i].track );
3404 36 : if (e) goto err_exit;
3405 36 : tiles[i].track_id = gf_isom_get_track_id(file, tiles[i].track);
3406 36 : gf_isom_hevc_set_tile_config(file, tiles[i].track, 1, NULL, GF_FALSE);
3407 :
3408 : // setup track references from tile track to base
3409 36 : gf_isom_set_track_reference(file, tiles[i].track, GF_ISOM_REF_TBAS, gf_isom_get_track_id(file, track) );
3410 : } else {
3411 9 : tiles[i].track_id = gf_isom_get_track_id(file, track) + i+1;
3412 : }
3413 45 : tiles[i].all_intra = GF_TRUE;
3414 : }
3415 :
3416 5 : count = gf_isom_get_sample_count(file, track);
3417 5 : for (i=0; i<count; i++) {
3418 : u8 *data;
3419 : u32 size, nb_nalus=0, nb_nal_entries=0, last_tile_group=(u32) -1;
3420 : GF_BitStream *bs=NULL;
3421 3750 : GF_ISOSample *sample = gf_isom_get_sample(file, track, i+1, &di);
3422 :
3423 3750 : data = (u8 *) sample->data;
3424 3750 : size = sample->dataLength;
3425 3750 : if (!signal_mode) {
3426 3000 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
3427 3000 : sample->data = NULL;
3428 3000 : sample->dataLength = 0;
3429 :
3430 30000 : for (j=0; j<nb_tiles; j++) {
3431 27000 : tiles[j].data_offset = 0;
3432 27000 : tiles[j].sample_data = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
3433 : }
3434 : } else {
3435 6750 : for (j=0; j<nb_tiles; j++) {
3436 6750 : tiles[j].nb_nalus_in_sample = 0;
3437 : }
3438 750 : bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
3439 : //write start of nalm group
3440 750 : gf_bs_write_int(bs, 0, 6);//reserved
3441 750 : gf_bs_write_int(bs, 0, 1);//large_size
3442 750 : gf_bs_write_int(bs, (signal_mode==2) ? 1 : 0, 1);//rle
3443 750 : gf_bs_write_u8(bs, 0);//entry_count - will be set at the end
3444 : }
3445 :
3446 :
3447 3750 : sample->data = (char *) data;
3448 :
3449 45005 : while (size) {
3450 : u8 temporal_id, layer_id;
3451 37505 : u8 nal_type = 0;
3452 : u32 nalu_size = 0;
3453 187525 : for (j=0; j<nalu_size_length; j++) {
3454 150020 : nalu_size = (nalu_size<<8) + data[j];
3455 : }
3456 37505 : ret = gf_hevc_parse_nalu(data + nalu_size_length, nalu_size, &hevc, &nal_type, &temporal_id, &layer_id);
3457 :
3458 : //error parsing NAL, set nal to fallback to regular import
3459 37505 : if (ret<0) nal_type = GF_HEVC_NALU_VID_PARAM;
3460 :
3461 37505 : switch (nal_type) {
3462 33750 : case GF_HEVC_NALU_SLICE_TRAIL_N:
3463 : case GF_HEVC_NALU_SLICE_TRAIL_R:
3464 : case GF_HEVC_NALU_SLICE_TSA_N:
3465 : case GF_HEVC_NALU_SLICE_TSA_R:
3466 : case GF_HEVC_NALU_SLICE_STSA_N:
3467 : case GF_HEVC_NALU_SLICE_STSA_R:
3468 : case GF_HEVC_NALU_SLICE_BLA_W_LP:
3469 : case GF_HEVC_NALU_SLICE_BLA_W_DLP:
3470 : case GF_HEVC_NALU_SLICE_BLA_N_LP:
3471 : case GF_HEVC_NALU_SLICE_IDR_W_DLP:
3472 : case GF_HEVC_NALU_SLICE_IDR_N_LP:
3473 : case GF_HEVC_NALU_SLICE_CRA:
3474 : case GF_HEVC_NALU_SLICE_RADL_R:
3475 : case GF_HEVC_NALU_SLICE_RADL_N:
3476 : case GF_HEVC_NALU_SLICE_RASL_R:
3477 : case GF_HEVC_NALU_SLICE_RASL_N:
3478 33750 : tx = ty = tw = th = 0;
3479 33750 : cur_tile = hevc_get_tile_id(&hevc, &tx, &ty, &tw, &th);
3480 33750 : if (cur_tile>=nb_tiles) {
3481 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[HEVC Tiles] Tile index %d is greater than number of tiles %d in PPS\n", cur_tile, nb_tiles));
3482 : e = GF_NON_COMPLIANT_BITSTREAM;
3483 : }
3484 33750 : if (e)
3485 : goto err_exit;
3486 :
3487 33750 : tiles[cur_tile].tx = tx;
3488 33750 : tiles[cur_tile].ty = ty;
3489 33750 : tiles[cur_tile].tw = tw;
3490 33750 : tiles[cur_tile].th = th;
3491 33750 : if (hevc.s_info.slice_type != GF_HEVC_SLICE_TYPE_I) {
3492 32400 : tiles[cur_tile].all_intra = 0;
3493 : }
3494 :
3495 33750 : if (signal_mode) {
3496 6750 : nb_nalus++;
3497 6750 : tiles[cur_tile].nb_nalus_in_sample++;
3498 6750 : if (signal_mode==1) {
3499 6750 : gf_bs_write_u16(bs, tiles[cur_tile].track_id);
3500 6750 : nb_nal_entries++;
3501 0 : } else if (last_tile_group != tiles[cur_tile].track_id) {
3502 : last_tile_group = tiles[cur_tile].track_id;
3503 0 : gf_bs_write_u8(bs, nb_nalus);
3504 0 : gf_bs_write_u16(bs, tiles[cur_tile].track_id);
3505 0 : nb_nal_entries++;
3506 : }
3507 : } else {
3508 27000 : gf_bs_write_data(tiles[cur_tile].sample_data, (char *) data, nalu_size + nalu_size_length);
3509 :
3510 27000 : if (! gf_isom_has_track_reference(file, track, GF_ISOM_REF_SABT, tiles[cur_tile].track_id)) {
3511 36 : gf_isom_set_track_reference(file, track, GF_ISOM_REF_SABT, tiles[cur_tile].track_id);
3512 : }
3513 27000 : tiles[cur_tile].data_offset += nalu_size + nalu_size_length;
3514 : }
3515 : break;
3516 3755 : default:
3517 3755 : if (! signal_mode) {
3518 3004 : gf_bs_write_data(bs, (char *) data, nalu_size + nalu_size_length);
3519 : } else {
3520 751 : nb_nalus++;
3521 751 : if (signal_mode==1) {
3522 751 : gf_bs_write_u16(bs, 0);
3523 751 : nb_nal_entries++;
3524 0 : } else if (last_tile_group != 0) {
3525 : last_tile_group = 0;
3526 0 : gf_bs_write_u8(bs, nb_nalus);
3527 0 : gf_bs_write_u16(bs, 0);
3528 0 : nb_nal_entries++;
3529 : }
3530 : }
3531 : break;
3532 : }
3533 37505 : data += nalu_size + nalu_size_length;
3534 37505 : size -= nalu_size + nalu_size_length;
3535 : }
3536 :
3537 3750 : if (! signal_mode) {
3538 3000 : gf_free(sample->data);
3539 3000 : gf_bs_get_content(bs, &sample->data, &sample->dataLength);
3540 3000 : gf_bs_del(bs);
3541 :
3542 3000 : e = gf_isom_update_sample(file, track, i+1, sample, 1);
3543 3000 : if (e) goto err_exit;
3544 :
3545 3000 : gf_free(sample->data);
3546 3000 : sample->data = NULL;
3547 :
3548 30000 : for (j=0; j<nb_tiles; j++) {
3549 27000 : sample->dataLength = 0;
3550 27000 : gf_bs_get_content(tiles[j].sample_data, &sample->data, &sample->dataLength);
3551 27000 : if (!sample->data)
3552 0 : continue;
3553 :
3554 27000 : e = gf_isom_add_sample(file, tiles[j].track, 1, sample);
3555 27000 : if (e) goto err_exit;
3556 27000 : tiles[j].sample_count ++;
3557 :
3558 27000 : gf_bs_del(tiles[j].sample_data);
3559 27000 : tiles[j].sample_data = NULL;
3560 27000 : gf_free(sample->data);
3561 27000 : sample->data = NULL;
3562 :
3563 27000 : e = gf_isom_copy_sample_info(file, tiles[j].track, file, track, i+1);
3564 27000 : if (e) goto err_exit;
3565 : }
3566 : } else {
3567 : u32 sdesc;
3568 750 : data=NULL;
3569 750 : size=0;
3570 750 : gf_bs_get_content(bs, &data, &size);
3571 750 : gf_bs_del(bs);
3572 750 : data[1] = nb_nal_entries;
3573 :
3574 750 : e = gf_isom_add_sample_group_info(file, track, GF_ISOM_SAMPLE_GROUP_NALM, data, size, 0, &sdesc);
3575 750 : if (e) {
3576 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISOBMF] Error defining NALM group description entry\n" ));
3577 : } else {
3578 750 : e = gf_isom_add_sample_info(file, track, i+1, GF_ISOM_SAMPLE_GROUP_NALM, sdesc, GF_ISOM_SAMPLE_GROUP_TRIF);
3579 750 : if (e) {
3580 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISOBMF] Error associating NALM group description to sample\n" ));
3581 : }
3582 : }
3583 750 : gf_free(data);
3584 750 : if (e) goto err_exit;
3585 : }
3586 :
3587 3750 : gf_isom_sample_del(&sample);
3588 :
3589 : }
3590 :
3591 :
3592 45 : for (i=0; i<nb_tiles; i++) {
3593 : u32 width, height;
3594 : s32 translation_x, translation_y;
3595 : s16 layer;
3596 :
3597 45 : if (! signal_mode) {
3598 36 : tiles[i].track = gf_isom_get_track_by_id(file, tiles[i].track_id);
3599 36 : if (!tiles[i].sample_count) {
3600 0 : gf_isom_remove_track(file, tiles[i].track);
3601 0 : continue;
3602 : }
3603 :
3604 36 : hevc_add_trif(file, tiles[i].track, tiles[i].track_id, GF_FALSE, (tiles[i].all_intra) ? 2 : 1, filter_disabled, tiles[i].tx, tiles[i].ty, tiles[i].tw, tiles[i].th, GF_TRUE);
3605 36 : gf_isom_set_visual_info(file, tiles[i].track, 1, tiles[i].tw, tiles[i].th);
3606 :
3607 36 : gf_isom_get_track_layout_info(file, track, &width, &height, &translation_x, &translation_y, &layer);
3608 36 : gf_isom_set_track_layout_info(file, tiles[i].track, width<<16, height<<16, translation_x, translation_y, layer);
3609 : } else {
3610 9 : hevc_add_trif(file, track, tiles[i].track_id, GF_FALSE, (tiles[i].all_intra) ? 2 : 1, filter_disabled, tiles[i].tx, tiles[i].ty, tiles[i].tw, tiles[i].th, GF_FALSE);
3611 : }
3612 :
3613 : }
3614 :
3615 :
3616 5 : err_exit:
3617 5 : gf_free(tiles);
3618 5 : if (e) {
3619 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISOBMF] Could not split HEVC tiles into tracks: %s\n", gf_error_to_string(e) ));
3620 : }
3621 : return e;
3622 : #endif
3623 : }
3624 : #endif /*GPAC_DISABLE_HEVC*/
3625 :
3626 : #endif /*GPAC_DISABLE_MEDIA_IMPORT*/
3627 :
3628 : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
3629 :
3630 : #include <gpac/filters.h>
3631 :
3632 : typedef struct
3633 : {
3634 : u32 filter_idx_plus_one;
3635 : u32 last_prog;
3636 : GF_FilterSession *fsess;
3637 : } FragCallback;
3638 :
3639 : extern char gf_prog_lf;
3640 :
3641 0 : static Bool on_frag_event(void *_udta, GF_Event *evt)
3642 : {
3643 : u32 i, count;
3644 : GF_FilterStats stats;
3645 : FragCallback *fc = (FragCallback *)_udta;
3646 0 : if (!_udta)
3647 : return GF_FALSE;
3648 0 : if (evt && (evt->type != GF_EVENT_PROGRESS))
3649 : return GF_FALSE;
3650 :
3651 0 : stats.report_updated = GF_FALSE;
3652 0 : if (!fc->filter_idx_plus_one) {
3653 0 : count = gf_fs_get_filters_count(fc->fsess);
3654 0 : for (i=0; i<count; i++) {
3655 0 : if (gf_fs_get_filter_stats(fc->fsess, i, &stats) != GF_OK) continue;
3656 0 : if (strcmp(stats.reg_name, "mp4mx")) continue;
3657 0 : fc->filter_idx_plus_one = i+1;
3658 0 : break;
3659 : }
3660 0 : if (!fc->filter_idx_plus_one) return GF_FALSE;
3661 : } else {
3662 0 : if (gf_fs_get_filter_stats(fc->fsess, fc->filter_idx_plus_one-1, &stats) != GF_OK)
3663 : return GF_FALSE;
3664 : }
3665 0 : if (! stats.report_updated) return GF_FALSE;
3666 0 : if (stats.percent/100 == fc->last_prog) return GF_FALSE;
3667 0 : fc->last_prog = stats.percent / 100;
3668 :
3669 : #ifndef GPAC_DISABLE_LOG
3670 0 : GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("Fragmenting: % 2.2f %%%c", ((Double)stats.percent) / 100, gf_prog_lf));
3671 : #else
3672 : fprintf(stderr, "Fragmenting: % 2.2f %%%c", ((Double)stats.percent) / 100, gf_prog_lf);
3673 : #endif
3674 : return GF_FALSE;
3675 : }
3676 :
3677 : GF_EXPORT
3678 4 : GF_Err gf_media_fragment_file(GF_ISOFile *input, const char *output_file, Double max_duration_sec, Bool use_mfra)
3679 : {
3680 : char szArgs[1024];
3681 : FragCallback fc;
3682 4 : GF_Err e = GF_OK;
3683 : GF_Filter *f;
3684 4 : GF_FilterSession *fsess = gf_fs_new_defaults(0);
3685 :
3686 4 : if (!fsess) {
3687 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("Failed to create filter session\n"));
3688 : return GF_OUT_OF_MEM;
3689 : }
3690 :
3691 :
3692 : sprintf(szArgs, "mp4dmx:mov=%p", input);
3693 4 : f = gf_fs_load_filter(fsess, szArgs, &e);
3694 4 : if (!f) return e;
3695 :
3696 : strcpy(szArgs, "reframer:FID=1");
3697 4 : f = gf_fs_load_filter(fsess, szArgs, &e);
3698 4 : if (!f) return e;
3699 :
3700 : sprintf(szArgs, "%s:SID=1:frag:cdur=%g:abs_offset:fragdur", output_file, max_duration_sec);
3701 4 : if (use_mfra)
3702 : strcat(szArgs, ":mfra");
3703 :
3704 4 : f = gf_fs_load_destination(fsess, szArgs, NULL, NULL, &e);
3705 4 : if (!f) return e;
3706 :
3707 4 : if (!gf_sys_is_test_mode()
3708 : #ifndef GPAC_DISABLE_LOG
3709 0 : && (gf_log_get_tool_level(GF_LOG_APP)!=GF_LOG_QUIET)
3710 : #endif
3711 0 : && !gf_sys_is_quiet()
3712 : ) {
3713 0 : fc.last_prog=0;
3714 0 : fc.fsess=fsess;
3715 0 : fc.filter_idx_plus_one=0;
3716 0 : gf_fs_enable_reporting(fsess, GF_TRUE);
3717 0 : gf_fs_set_ui_callback(fsess, on_frag_event, &fc);
3718 : }
3719 :
3720 : #ifdef GPAC_ENABLE_COVERAGE
3721 4 : if (gf_sys_is_cov_mode())
3722 : on_frag_event(NULL, NULL);
3723 : #endif
3724 :
3725 4 : e = gf_fs_run(fsess);
3726 4 : gf_fs_del(fsess);
3727 4 : return (e<GF_OK) ? e : GF_OK;
3728 : }
3729 :
3730 : #endif /*GPAC_DISABLE_ISOM_FRAGMENTS*/
3731 :
3732 :
3733 179 : GF_Err rfc_6381_get_codec_aac(char *szCodec, u32 codec_id, u8 *dsi, u32 dsi_size, Bool force_sbr)
3734 : {
3735 179 : if (dsi && dsi_size) {
3736 : u8 audio_object_type;
3737 179 : if (dsi_size < 2) {
3738 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[RFC6381-AAC] invalid DSI size %u < 2\n", dsi_size));
3739 : return GF_NON_COMPLIANT_BITSTREAM;
3740 : }
3741 : /*5 first bits of AAC config*/
3742 179 : audio_object_type = (dsi[0] & 0xF8) >> 3;
3743 179 : if (audio_object_type == 31) { /*escape code*/
3744 1 : const u8 audio_object_type_ext = ((dsi[0] & 0x07) << 3) + ((dsi[1] & 0xE0) >> 5);
3745 1 : audio_object_type = 32 + audio_object_type_ext;
3746 : }
3747 : #ifndef GPAC_DISABLE_AV_PARSERS
3748 179 : if (force_sbr && (audio_object_type==2) ) {
3749 : GF_M4ADecSpecInfo a_cfg;
3750 116 : GF_Err e = gf_m4a_get_config(dsi, dsi_size, &a_cfg);
3751 116 : if (e==GF_OK) {
3752 116 : if (a_cfg.sbr_sr)
3753 2 : audio_object_type = a_cfg.sbr_object_type;
3754 116 : if (a_cfg.has_ps)
3755 : audio_object_type = 29;
3756 : }
3757 : }
3758 : #endif
3759 179 : snprintf(szCodec, RFC6381_CODEC_NAME_SIZE_MAX, "mp4a.%02X.%01d", gf_codecid_oti(codec_id), audio_object_type);
3760 179 : return GF_OK;
3761 : }
3762 :
3763 : snprintf(szCodec, RFC6381_CODEC_NAME_SIZE_MAX, "mp4a.%02X", codec_id);
3764 :
3765 0 : switch (codec_id) {
3766 0 : case GF_CODECID_AAC_MPEG4:
3767 : case GF_CODECID_AAC_MPEG2_MP:
3768 : case GF_CODECID_AAC_MPEG2_LCP:
3769 : case GF_CODECID_AAC_MPEG2_SSRP:
3770 : case GF_CODECID_USAC:
3771 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[RFC6381-AAC] Cannot find AAC config, using default %s\n", szCodec));
3772 : break;
3773 : }
3774 : return GF_OK;
3775 : }
3776 :
3777 10 : GF_Err rfc_6381_get_codec_m4v(char *szCodec, u32 codec_id, u8 *dsi, u32 dsi_size)
3778 : {
3779 : #ifndef GPAC_DISABLE_AV_PARSERS
3780 10 : if (dsi && dsi_size) {
3781 : GF_M4VDecSpecInfo m4vc;
3782 8 : gf_m4v_get_config(dsi, dsi_size, &m4vc);
3783 8 : snprintf(szCodec, RFC6381_CODEC_NAME_SIZE_MAX, "mp4v.%02X.%01x", codec_id, m4vc.VideoPL);
3784 : return GF_OK;
3785 : }
3786 : #endif
3787 : snprintf(szCodec, RFC6381_CODEC_NAME_SIZE_MAX, "mp4v.%02X", codec_id);
3788 2 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[RFC6381-M4V] Cannot find M4V config, using default %s\n", szCodec));
3789 : return GF_OK;
3790 : }
3791 :
3792 213 : GF_Err rfc_6381_get_codec_avc(char *szCodec, u32 subtype, GF_AVCConfig *avcc)
3793 : {
3794 : assert(avcc);
3795 213 : snprintf(szCodec, RFC6381_CODEC_NAME_SIZE_MAX, "%s.%02X%02X%02X", gf_4cc_to_str(subtype), avcc->AVCProfileIndication, avcc->profile_compatibility, avcc->AVCLevelIndication);
3796 213 : return GF_OK;
3797 : }
3798 :
3799 127 : GF_Err rfc_6381_get_codec_hevc(char *szCodec, u32 subtype, GF_HEVCConfig *hvcc)
3800 : {
3801 : u8 c;
3802 : char szTemp[RFC6381_CODEC_NAME_SIZE_MAX];
3803 : assert(hvcc);
3804 :
3805 127 : snprintf(szCodec, RFC6381_CODEC_NAME_SIZE_MAX, "%s.", gf_4cc_to_str(subtype));
3806 127 : if (hvcc->profile_space==1) strcat(szCodec, "A");
3807 127 : else if (hvcc->profile_space==2) strcat(szCodec, "B");
3808 127 : else if (hvcc->profile_space==3) strcat(szCodec, "C");
3809 : //profile idc encoded as a decimal number
3810 127 : sprintf(szTemp, "%d", hvcc->profile_idc);
3811 : strcat(szCodec, szTemp);
3812 : //general profile compatibility flags: hexa, bit-reversed
3813 : {
3814 127 : u32 val = hvcc->general_profile_compatibility_flags;
3815 : u32 i, res = 0;
3816 4064 : for (i=0; i<32; i++) {
3817 4064 : res |= val & 1;
3818 4064 : if (i==31) break;
3819 3937 : res <<= 1;
3820 3937 : val >>=1;
3821 : }
3822 : sprintf(szTemp, ".%X", res);
3823 : strcat(szCodec, szTemp);
3824 : }
3825 :
3826 127 : if (hvcc->tier_flag) strcat(szCodec, ".H");
3827 : else strcat(szCodec, ".L");
3828 127 : sprintf(szTemp, "%d", hvcc->level_idc);
3829 : strcat(szCodec, szTemp);
3830 :
3831 127 : c = hvcc->progressive_source_flag << 7;
3832 127 : c |= hvcc->interlaced_source_flag << 6;
3833 127 : c |= hvcc->non_packed_constraint_flag << 5;
3834 127 : c |= hvcc->frame_only_constraint_flag << 4;
3835 127 : c |= (hvcc->constraint_indicator_flags >> 40);
3836 127 : sprintf(szTemp, ".%X", c);
3837 : strcat(szCodec, szTemp);
3838 127 : if (hvcc->constraint_indicator_flags & 0xFFFFFFFF) {
3839 0 : c = (hvcc->constraint_indicator_flags >> 32) & 0xFF;
3840 0 : sprintf(szTemp, ".%X", c);
3841 : strcat(szCodec, szTemp);
3842 0 : if (hvcc->constraint_indicator_flags & 0x00FFFFFF) {
3843 0 : c = (hvcc->constraint_indicator_flags >> 24) & 0xFF;
3844 0 : sprintf(szTemp, ".%X", c);
3845 : strcat(szCodec, szTemp);
3846 0 : if (hvcc->constraint_indicator_flags & 0x0000FFFF) {
3847 0 : c = (hvcc->constraint_indicator_flags >> 16) & 0xFF;
3848 0 : sprintf(szTemp, ".%X", c);
3849 : strcat(szCodec, szTemp);
3850 0 : if (hvcc->constraint_indicator_flags & 0x000000FF) {
3851 0 : c = (hvcc->constraint_indicator_flags >> 8) & 0xFF;
3852 0 : sprintf(szTemp, ".%X", c);
3853 : strcat(szCodec, szTemp);
3854 0 : c = (hvcc->constraint_indicator_flags ) & 0xFF;
3855 0 : sprintf(szTemp, ".%X", c);
3856 : strcat(szCodec, szTemp);
3857 : }
3858 : }
3859 : }
3860 : }
3861 127 : return GF_OK;
3862 : }
3863 :
3864 92 : GF_Err rfc_6381_get_codec_av1(char *szCodec, u32 subtype, GF_AV1Config *av1c)
3865 : {
3866 : #ifndef GPAC_DISABLE_AV_PARSERS
3867 : GF_Err e;
3868 : u32 i = 0;
3869 : AV1State av1_state;
3870 : assert(av1c);
3871 :
3872 92 : gf_av1_init_state(&av1_state);
3873 92 : av1_state.config = av1c;
3874 :
3875 184 : for (i = 0; i < gf_list_count(av1c->obu_array); ++i) {
3876 : GF_BitStream *bs;
3877 92 : GF_AV1_OBUArrayEntry *a = gf_list_get(av1c->obu_array, i);
3878 92 : bs = gf_bs_new(a->obu, a->obu_length, GF_BITSTREAM_READ);
3879 92 : if (!av1_is_obu_header(a->obu_type))
3880 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[ISOM Tools] AV1: unexpected obu_type %d when computing RFC6381. PArsing anyway.\n", a->obu_type, gf_4cc_to_str(subtype)));
3881 :
3882 92 : e = aom_av1_parse_temporal_unit_from_section5(bs, &av1_state);
3883 92 : gf_bs_del(bs);
3884 : bs = NULL;
3885 92 : if (e) {
3886 : return e;
3887 : }
3888 : }
3889 :
3890 552 : snprintf(szCodec, RFC6381_CODEC_NAME_SIZE_MAX, "%s.%01u.%02u%c.%02u.%01u.%01u%01u%01u", gf_4cc_to_str(subtype),
3891 276 : av1_state.config->seq_profile, av1_state.config->seq_level_idx_0, av1_state.config->seq_tier_0 ? 'H' : 'M',
3892 92 : av1_state.bit_depth, av1_state.config->monochrome,
3893 92 : av1_state.config->chroma_subsampling_x, av1_state.config->chroma_subsampling_y,
3894 184 : av1_state.config->chroma_subsampling_x && av1_state.config->chroma_subsampling_y ? av1_state.config->chroma_sample_position : 0);
3895 :
3896 92 : if (av1_state.color_description_present_flag) {
3897 : char tmp[RFC6381_CODEC_NAME_SIZE_MAX];
3898 0 : snprintf(tmp, RFC6381_CODEC_NAME_SIZE_MAX, "%02u.%02u.%02u.%01u", av1_state.color_primaries, av1_state.transfer_characteristics, av1_state.matrix_coefficients, av1_state.color_range);
3899 : strcat(szCodec, tmp);
3900 : } else {
3901 92 : if ((av1_state.color_primaries == 2) && (av1_state.transfer_characteristics == 2) && (av1_state.matrix_coefficients == 2) && av1_state.color_range == GF_FALSE) {
3902 :
3903 : } else {
3904 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[AV1] incoherent color characteristics primaries %d transfer %d matrix %d color range %d\n", av1_state.color_primaries, av1_state.transfer_characteristics, av1_state.matrix_coefficients, av1_state.color_range));
3905 : }
3906 : }
3907 92 : gf_av1_reset_state(&av1_state, GF_TRUE);
3908 92 : return GF_OK;
3909 : #else
3910 : return GF_NOT_SUPPORTED;
3911 : #endif
3912 : }
3913 :
3914 54 : GF_Err rfc_6381_get_codec_vpx(char *szCodec, u32 subtype, GF_VPConfig *vpcc)
3915 : {
3916 : assert(vpcc);
3917 378 : snprintf(szCodec, RFC6381_CODEC_NAME_SIZE_MAX, "%s.%02u.%02x.%02u.%02u.%02u.%02u.%02u.%02u", gf_4cc_to_str(subtype),
3918 54 : vpcc->profile,
3919 54 : vpcc->level,
3920 54 : vpcc->bit_depth,
3921 54 : vpcc->chroma_subsampling,
3922 54 : vpcc->colour_primaries,
3923 54 : vpcc->transfer_characteristics,
3924 54 : vpcc->matrix_coefficients,
3925 54 : vpcc->video_fullRange_flag);
3926 54 : return GF_OK;
3927 : }
3928 :
3929 1 : GF_Err rfc_6381_get_codec_dolby_vision(char *szCodec, u32 subtype, GF_DOVIDecoderConfigurationRecord *dovi)
3930 : {
3931 : assert(dovi);
3932 1 : snprintf(szCodec, RFC6381_CODEC_NAME_SIZE_MAX, "%s.%02u.%02u", gf_4cc_to_str(subtype), dovi->dv_profile, dovi->dv_level);
3933 1 : return GF_OK;
3934 : }
3935 :
3936 0 : GF_Err rfc_6381_get_codec_vvc(char *szCodec, u32 subtype, GF_VVCConfig *vvcc)
3937 : {
3938 : assert(vvcc);
3939 :
3940 0 : snprintf(szCodec, RFC6381_CODEC_NAME_SIZE_MAX, "%s.%d.%s%d", gf_4cc_to_str(subtype), vvcc->general_profile_idc, vvcc->general_tier_flag ? "H" : "L", vvcc->general_level_idc);
3941 0 : return GF_OK;
3942 : }
3943 1 : GF_Err rfc_6381_get_codec_mpegha(char *szCodec, u32 subtype, u8 *dsi, u32 dsi_size, s32 pl)
3944 : {
3945 1 : if (dsi && (dsi_size>=2) ) {
3946 0 : pl = dsi[1];
3947 : }
3948 1 : if (pl<0) {
3949 1 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("Cannot find MPEG-H Audio Config or audio PL, defaulting to profile 0x01\n"));
3950 : }
3951 1 : snprintf(szCodec, RFC6381_CODEC_NAME_SIZE_MAX, "%s.0x%02X", gf_4cc_to_str(subtype), pl);
3952 1 : return GF_OK;
3953 : }
3954 :
3955 96 : GF_Err rfc6381_codec_name_default(char *szCodec, u32 subtype, u32 codec_id)
3956 : {
3957 96 : if (codec_id && (codec_id<GF_CODECID_LAST_MPEG4_MAPPING)) {
3958 13 : u32 stype = gf_codecid_type(codec_id);
3959 13 : if (stype==GF_STREAM_VISUAL)
3960 : snprintf(szCodec, RFC6381_CODEC_NAME_SIZE_MAX, "mp4v.%02X", codec_id);
3961 9 : else if (stype==GF_STREAM_AUDIO)
3962 : snprintf(szCodec, RFC6381_CODEC_NAME_SIZE_MAX, "mp4a.%02X", codec_id);
3963 : else
3964 : snprintf(szCodec, RFC6381_CODEC_NAME_SIZE_MAX, "mp4s.%02X", codec_id);
3965 : } else {
3966 83 : GF_LOG(GF_LOG_DEBUG, GF_LOG_AUTHOR, ("Codec parameters not known - using default value \"%s\"\n", gf_4cc_to_str(subtype) ));
3967 83 : snprintf(szCodec, RFC6381_CODEC_NAME_SIZE_MAX, "%s", gf_4cc_to_str(subtype));
3968 : }
3969 96 : return GF_OK;
3970 : }
3971 :
3972 : #ifndef GPAC_DISABLE_ISOM
3973 :
3974 : GF_EXPORT
3975 259 : GF_Err gf_media_get_rfc_6381_codec_name(GF_ISOFile *movie, u32 track, char *szCodec, Bool force_inband, Bool force_sbr)
3976 : {
3977 : GF_ESD *esd;
3978 : GF_Err e;
3979 : GF_AVCConfig *avcc;
3980 : #ifndef GPAC_DISABLE_HEVC
3981 : GF_HEVCConfig *hvcc;
3982 : #endif
3983 259 : u32 subtype = gf_isom_get_media_subtype(movie, track, 1);
3984 :
3985 259 : if (subtype == GF_ISOM_SUBTYPE_MPEG4_CRYP) {
3986 87 : u32 originalFormat=0;
3987 87 : if (gf_isom_is_ismacryp_media(movie, track, 1)) {
3988 5 : e = gf_isom_get_ismacryp_info(movie, track, 1, &originalFormat, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
3989 82 : } else if (gf_isom_is_omadrm_media(movie, track, 1)) {
3990 0 : e = gf_isom_get_omadrm_info(movie, track, 1, &originalFormat, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
3991 82 : } else if(gf_isom_is_cenc_media(movie, track, 1)) {
3992 77 : e = gf_isom_get_cenc_info(movie, track, 1, &originalFormat, NULL, NULL);
3993 : } else {
3994 5 : GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[ISOM Tools] Unkown protection scheme type %s\n", gf_4cc_to_str( gf_isom_is_media_encrypted(movie, track, 1)) ));
3995 5 : e = gf_isom_get_original_format_type(movie, track, 1, &originalFormat);
3996 : }
3997 87 : if (e) {
3998 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[ISOM Tools] Error fetching protection information\n"));
3999 0 : return e;
4000 : }
4001 :
4002 87 : if (originalFormat) subtype = originalFormat;
4003 : }
4004 :
4005 259 : switch (subtype) {
4006 66 : case GF_ISOM_SUBTYPE_MPEG4:
4007 66 : esd = gf_isom_get_esd(movie, track, 1);
4008 66 : if (esd && esd->decoderConfig) {
4009 66 : switch (esd->decoderConfig->streamType) {
4010 58 : case GF_STREAM_AUDIO:
4011 58 : if (esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) {
4012 58 : e = rfc_6381_get_codec_aac(szCodec, esd->decoderConfig->objectTypeIndication, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, force_sbr);
4013 : } else {
4014 0 : e = rfc_6381_get_codec_aac(szCodec, esd->decoderConfig->objectTypeIndication, NULL, 0, force_sbr);
4015 : }
4016 : break;
4017 8 : case GF_STREAM_VISUAL:
4018 8 : if (esd->decoderConfig->decoderSpecificInfo) {
4019 8 : e = rfc_6381_get_codec_m4v(szCodec, esd->decoderConfig->objectTypeIndication, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength);
4020 : } else {
4021 0 : e = rfc_6381_get_codec_m4v(szCodec, esd->decoderConfig->objectTypeIndication, NULL, 0);
4022 : }
4023 : break;
4024 0 : default:
4025 0 : snprintf(szCodec, RFC6381_CODEC_NAME_SIZE_MAX, "mp4s.%02X", esd->decoderConfig->objectTypeIndication);
4026 : e = GF_OK;
4027 0 : break;
4028 : }
4029 66 : gf_odf_desc_del((GF_Descriptor *)esd);
4030 66 : return e;
4031 : }
4032 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[RFC6381] Cannot find ESD. Aborting.\n"));
4033 0 : if (esd) gf_odf_desc_del((GF_Descriptor *)esd);
4034 : return GF_ISOM_INVALID_FILE;
4035 :
4036 39 : case GF_ISOM_SUBTYPE_AVC_H264:
4037 : case GF_ISOM_SUBTYPE_AVC2_H264:
4038 : case GF_ISOM_SUBTYPE_AVC3_H264:
4039 : case GF_ISOM_SUBTYPE_AVC4_H264:
4040 : //FIXME: in avc1 with multiple descriptor, we should take the right description index
4041 39 : avcc = gf_isom_avc_config_get(movie, track, 1);
4042 39 : if (force_inband) {
4043 0 : if (subtype==GF_ISOM_SUBTYPE_AVC_H264)
4044 : subtype = GF_ISOM_SUBTYPE_AVC3_H264;
4045 0 : else if (subtype==GF_ISOM_SUBTYPE_AVC2_H264)
4046 : subtype = GF_ISOM_SUBTYPE_AVC4_H264;
4047 : }
4048 39 : if (avcc) {
4049 39 : e = rfc_6381_get_codec_avc(szCodec, subtype, avcc);
4050 39 : gf_odf_avc_cfg_del(avcc);
4051 39 : return e;
4052 : }
4053 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Cannot find AVC configuration box"));
4054 : return GF_ISOM_INVALID_FILE;
4055 :
4056 0 : case GF_ISOM_SUBTYPE_SVC_H264:
4057 : case GF_ISOM_SUBTYPE_MVC_H264:
4058 0 : avcc = gf_isom_mvc_config_get(movie, track, 1);
4059 0 : if (!avcc) avcc = gf_isom_svc_config_get(movie, track, 1);
4060 0 : if (avcc) {
4061 0 : e = rfc_6381_get_codec_avc(szCodec, subtype, avcc);
4062 0 : gf_odf_avc_cfg_del(avcc);
4063 0 : return e;
4064 : }
4065 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Cannot find SVC/MVC configuration box\n"));
4066 : return GF_ISOM_INVALID_FILE;
4067 :
4068 : #ifndef GPAC_DISABLE_HEVC
4069 16 : case GF_ISOM_SUBTYPE_HVC1:
4070 : case GF_ISOM_SUBTYPE_HEV1:
4071 : case GF_ISOM_SUBTYPE_HVC2:
4072 : case GF_ISOM_SUBTYPE_HEV2:
4073 : case GF_ISOM_SUBTYPE_HVT1:
4074 : case GF_ISOM_SUBTYPE_LHV1:
4075 : case GF_ISOM_SUBTYPE_LHE1:
4076 :
4077 16 : if (force_inband) {
4078 0 : if (subtype==GF_ISOM_SUBTYPE_HVC1) subtype = GF_ISOM_SUBTYPE_HEV1;
4079 0 : else if (subtype==GF_ISOM_SUBTYPE_HVC2) subtype = GF_ISOM_SUBTYPE_HEV2;
4080 : }
4081 16 : hvcc = gf_isom_hevc_config_get(movie, track, 1);
4082 16 : if (!hvcc) {
4083 0 : hvcc = gf_isom_lhvc_config_get(movie, track, 1);
4084 : }
4085 16 : if (subtype==GF_ISOM_SUBTYPE_HVT1) {
4086 : u32 refTrack;
4087 0 : gf_isom_get_reference(movie, track, GF_ISOM_REF_TBAS, 1, &refTrack);
4088 0 : if (hvcc) gf_odf_hevc_cfg_del(hvcc);
4089 0 : hvcc = gf_isom_hevc_config_get(movie, refTrack, 1);
4090 : }
4091 16 : if (hvcc) {
4092 16 : e = rfc_6381_get_codec_hevc(szCodec, subtype, hvcc);
4093 16 : gf_odf_hevc_cfg_del(hvcc);
4094 16 : return e;
4095 : }
4096 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("HEVCConfig not compliant\n"));
4097 : return GF_ISOM_INVALID_FILE;
4098 : #else
4099 : return GF_NOT_SUPPORTED;
4100 : #endif
4101 :
4102 : #if !defined(GPAC_DISABLE_AV1) && !defined(GPAC_DISABLE_AV_PARSERS)
4103 38 : case GF_ISOM_SUBTYPE_AV01:
4104 : {
4105 38 : GF_AV1Config *av1c = gf_isom_av1_config_get(movie, track, 1);
4106 38 : if (!av1c) {
4107 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_AUTHOR, ("[ISOM Tools] No config found for AV1 file (\"%s\") when computing RFC6381.\n", gf_4cc_to_str(subtype)));
4108 : return GF_BAD_PARAM;
4109 : }
4110 38 : e = rfc_6381_get_codec_av1(szCodec, subtype, av1c);
4111 38 : gf_odf_av1_cfg_del(av1c);
4112 38 : return e;
4113 : }
4114 : #endif /*!defined(GPAC_DISABLE_AV1) && !defined(GPAC_DISABLE_AV_PARSERS)*/
4115 :
4116 11 : case GF_ISOM_SUBTYPE_VP08:
4117 : case GF_ISOM_SUBTYPE_VP09:
4118 : {
4119 11 : GF_VPConfig *vpcc = gf_isom_vp_config_get(movie, track, 1);
4120 11 : if (vpcc) {
4121 11 : e = rfc_6381_get_codec_vpx(szCodec, subtype, vpcc);
4122 11 : gf_odf_vp_cfg_del(vpcc);
4123 11 : return e;
4124 : }
4125 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_AUTHOR, ("[ISOM Tools] No config found for VP file (\"%s\") when computing RFC6381.\n", gf_4cc_to_str(subtype)));
4126 : return GF_BAD_PARAM;
4127 : }
4128 :
4129 0 : case GF_ISOM_SUBTYPE_DVHE:
4130 : {
4131 0 : GF_DOVIDecoderConfigurationRecord *dovi = gf_isom_dovi_config_get(movie, track, 1);
4132 0 : if (!dovi) {
4133 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[ISOM Tools] No config found for Dolby Vision file (\"%s\") when computing RFC6381.\n", gf_4cc_to_str(subtype)));
4134 : return GF_NON_COMPLIANT_BITSTREAM;
4135 : }
4136 :
4137 0 : e = rfc_6381_get_codec_dolby_vision(szCodec, subtype, dovi);
4138 0 : gf_odf_dovi_cfg_del(dovi);
4139 0 : return e;
4140 : }
4141 :
4142 0 : case GF_ISOM_SUBTYPE_VVC1:
4143 : case GF_ISOM_SUBTYPE_VVI1:
4144 : {
4145 0 : GF_VVCConfig *vvcc = gf_isom_vvc_config_get(movie, track, 1);
4146 0 : if (vvcc) {
4147 0 : if (force_inband) subtype = GF_ISOM_SUBTYPE_VVI1;
4148 :
4149 0 : e = rfc_6381_get_codec_vvc(szCodec, subtype, vvcc);
4150 0 : gf_odf_vvc_cfg_del(vvcc);
4151 0 : return e;
4152 : }
4153 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_AUTHOR, ("[ISOM Tools] No config found for VVC file (\"%s\") when computing RFC6381.\n", gf_4cc_to_str(subtype)));
4154 : return GF_BAD_PARAM;
4155 : }
4156 :
4157 1 : case GF_ISOM_SUBTYPE_MH3D_MHA1:
4158 : case GF_ISOM_SUBTYPE_MH3D_MHA2:
4159 : case GF_ISOM_SUBTYPE_MH3D_MHM1:
4160 : case GF_ISOM_SUBTYPE_MH3D_MHM2:
4161 : {
4162 1 : esd = gf_media_map_esd(movie, track, 1);
4163 1 : if (!esd || !esd->decoderConfig || !esd->decoderConfig->decoderSpecificInfo
4164 1 : || !esd->decoderConfig->decoderSpecificInfo->data
4165 : ) {
4166 1 : e = rfc_6381_get_codec_mpegha(szCodec, subtype, NULL, 0, -1);
4167 : } else {
4168 0 : e = rfc_6381_get_codec_mpegha(szCodec, subtype, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, -1);
4169 : }
4170 1 : if (esd) gf_odf_desc_del((GF_Descriptor *)esd);
4171 : return e;
4172 : }
4173 :
4174 88 : default:
4175 88 : return rfc6381_codec_name_default(szCodec, subtype, gf_codec_id_from_isobmf(subtype));
4176 :
4177 : }
4178 : return GF_OK;
4179 : }
4180 :
4181 : #endif //GPAC_DISABLE_ISOM
|