LCOV - code coverage report
Current view: top level - media_tools - isom_tools.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1547 2181 70.9 %
Date: 2021-04-29 23:48:07 Functions: 34 36 94.4 %

          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

Generated by: LCOV version 1.13