LCOV - code coverage report
Current view: top level - filters - mux_isom.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 2467 3223 76.5 %
Date: 2021-04-29 23:48:07 Functions: 38 40 95.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2017-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / ISOBMF mux filter
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : #include <gpac/filters.h>
      27             : #include <gpac/constants.h>
      28             : #include <gpac/internal/isomedia_dev.h>
      29             : #include <gpac/internal/media_dev.h>
      30             : 
      31             : #ifndef GPAC_DISABLE_ISOM_WRITE
      32             : 
      33             : #define TEXT_DEFAULT_WIDTH      400
      34             : #define TEXT_DEFAULT_HEIGHT     60
      35             : #define TEXT_DEFAULT_FONT_SIZE  18
      36             : 
      37             : #define GF_VENDOR_GPAC          GF_4CC('G','P','A','C')
      38             : 
      39             : 
      40             : #define ISOM_FILE_EXT "mp4|mpg4|m4a|m4i|3gp|3gpp|3g2|3gp2|iso|ismv|m4s|heif|heic|iff|avci|avif|mj2|mov|qt"
      41             : #define ISOM_FILE_MIME "application/x-isomedia|application/mp4|video/mp4|audio/mp4|video/3gpp|audio/3gpp|video/3gp2|audio/3gp2|video/iso.segment|audio/iso.segment|image/heif|image/heic|image/avci|video/quicktime"
      42             : 
      43             : enum{
      44             :         NALU_NONE,
      45             :         NALU_AVC,
      46             :         NALU_HEVC,
      47             :         NALU_VVC
      48             : };
      49             : 
      50             : 
      51             : enum
      52             : {
      53             :         CENC_NONE=0,
      54             :         CENC_NEED_SETUP,
      55             :         CENC_SETUP_DONE,
      56             :         CENC_SETUP_ERROR
      57             : };
      58             : 
      59             : enum{
      60             :         TAG_NONE,
      61             :         TAG_STRICT,
      62             :         TAG_ALL
      63             : };
      64             : 
      65             : 
      66             : typedef struct
      67             : {
      68             :         GF_FilterPid *ipid;
      69             :         u32 track_num, track_id;
      70             :         GF_ISOSample sample;
      71             : 
      72             :         u32 src_timescale;
      73             :         u32 tk_timescale;
      74             :         u32 stream_type;
      75             :         u32 codecid;
      76             :         Bool is_encrypted;
      77             : 
      78             :         u32 cfg_crc, enh_cfg_crc;
      79             :         u32 dep_id;
      80             :         u32 stsd_idx;
      81             :         u32 clear_stsd_idx;
      82             : 
      83             :         Bool use_dref;
      84             :         Bool aborted;
      85             :         Bool suspended;
      86             :         Bool has_append;
      87             :         Bool has_ctts;
      88             :         s64 min_neg_ctts;
      89             :         u32 nb_samples, samples_in_stsd;
      90             :         u32 nb_frames_per_sample;
      91             :         u64 ts_shift;
      92             :         Bool has_subs;
      93             : 
      94             :         Bool skip_bitrate_update;
      95             :         Bool has_open_gop;
      96             :         GF_FilterSAPType gdr_type;
      97             : 
      98             :         Bool next_is_first_sample;
      99             : 
     100             :         u32 media_profile_level;
     101             : 
     102             :         Bool import_msg_header_done;
     103             : 
     104             :         u32 nal_unit_size;
     105             : 
     106             :         GF_AVCConfig *avcc, *svcc;
     107             :         GF_HEVCConfig *hvcc, *lvcc;
     108             :         GF_VVCConfig *vvcc;
     109             : 
     110             :         u8 *inband_hdr, *inband_hdr_non_rap;
     111             :         u32 inband_hdr_size, inband_hdr_non_rap_size;
     112             :         u32 is_nalu;
     113             :         Bool is_av1, is_vpx;
     114             :         Bool fragment_done;
     115             :         s32 ts_delay, negctts_shift;
     116             :         Bool insert_tfdt, probe_min_ctts;
     117             :         u64 first_dts_in_seg, next_seg_cts, cts_next;
     118             :         u64 offset_dts;
     119             :         u32 samples_in_frag;
     120             :         Bool patch_tfdt;
     121             : 
     122             :         //0: not cenc, 1: needs setup of stsd entry, 2: setup done
     123             :         u32 cenc_state;
     124             :         Bool cenc_subsamples;
     125             :         u32 scheme_type;
     126             :         u32 def_skip_byte_block, def_crypt_byte_block;
     127             :         u32 def_cenc_key_info_crc;
     128             :         const GF_PropertyValue *cenc_ki;
     129             :         u32 cenc_key_info_crc;
     130             :         u32 constant_IV_size;
     131             :         Bool cenc_multikey;
     132             :         Bool cenc_frag_protected;
     133             : 
     134             :         Bool fake_track;
     135             : 
     136             :         Bool has_brands;
     137             :         Bool force_inband_inject;
     138             : 
     139             :         u64 dur_in_frag;
     140             : 
     141             :         u32 amr_mode_set;
     142             :         Bool has_seig;
     143             :         u64 empty_init_dur;
     144             :         u32 raw_audio_bytes_per_sample, raw_samplerate;
     145             :         u64 dts_patch;
     146             : 
     147             :         Bool is_item;
     148             :         u32 item_id;
     149             :         char status_type;
     150             :         u32 last_import_pc;
     151             : 
     152             :         u32 nb_frames;
     153             :         u64 down_bytes, down_size;
     154             :         GF_Fraction64 pid_dur;
     155             :         //for import message
     156             :         u64 prog_done, prog_total;
     157             : 
     158             :         u32 prev_tid_group;
     159             : 
     160             :         Bool box_patched;
     161             : 
     162             :         u64 imported_edit_sdur, imported_edit_offset;
     163             : 
     164             :         Bool force_ctts;
     165             : 
     166             :         Bool is_hevc_tile_base;
     167             :         Bool insert_pssh;
     168             : 
     169             :         Bool wait_sap;
     170             :         u64 min_ts_seek_plus_one;
     171             :         u64 clamp_ts_plus_one;
     172             :         Bool check_seek_ts;
     173             : 
     174             :         u64 max_cts, min_cts;
     175             :         u32 max_cts_samp_dur;
     176             : 
     177             : } TrackWriter;
     178             : 
     179             : enum
     180             : {
     181             :         MP4MX_MODE_INTER=0,
     182             :         MP4MX_MODE_FLAT,
     183             :         MP4MX_MODE_FASTSTART,
     184             :         MP4MX_MODE_TIGHT,
     185             :         MP4MX_MODE_FRAG,
     186             :         MP4MX_MODE_SFRAG,
     187             : };
     188             : 
     189             : 
     190             : enum
     191             : {
     192             :         MP4MX_DASH_OFF=0,
     193             :         MP4MX_DASH_ON,
     194             :         MP4MX_DASH_VOD,
     195             : };
     196             : 
     197             : enum
     198             : {
     199             :         MP4MX_PSSH_MOOV=0,
     200             :         MP4MX_PSSH_MOOF,
     201             :         MP4MX_PSSH_SKIP,
     202             : };
     203             : 
     204             : enum
     205             : {
     206             :         MP4MX_CT_EDIT=0,
     207             :         MP4MX_CT_NOEDIT,
     208             :         MP4MX_CT_NEGCTTS,
     209             : };
     210             : 
     211             : enum
     212             : {
     213             :         MP4MX_VODCACHE_ON=0,
     214             :         MP4MX_VODCACHE_INSERT,
     215             :         MP4MX_VODCACHE_REPLACE,
     216             : };
     217             : 
     218             : enum
     219             : {
     220             :         MP4MX_CMAF_NO=0,
     221             :         MP4MX_CMAF_CMFC,
     222             :         MP4MX_CMAF_CMF2,
     223             : };
     224             : 
     225             : typedef struct
     226             : {
     227             :         //filter args
     228             :         GF_ISOFile *file;
     229             :         Bool m4sys, dref;
     230             :         GF_Fraction idur;
     231             :         u32 pack3gp, ctmode;
     232             :         Bool importer, pack_nal, moof_first, abs_offset, fsap, tfdt_traf, keep_utc, pps_inband;
     233             :         u32 xps_inband, moovpad;
     234             :         u32 block_size;
     235             :         u32 store, tktpl, mudta;
     236             :         s32 subs_sidx;
     237             :         GF_Fraction cdur;
     238             :         s32 moovts;
     239             :         char *m4cc;
     240             :         Bool chain_sidx;
     241             :         u32 msn, msninc;
     242             :         GF_Fraction64 tfdt;
     243             :         Bool nofragdef, straf, strun, sgpd_traf, noinit;
     244             :         u32 vodcache;
     245             :         u32 psshs;
     246             :         u32 trackid;
     247             :         Bool fragdur;
     248             :         Bool btrt;
     249             :         Bool ssix;
     250             :         Bool ccst;
     251             :         s32 mediats;
     252             :         GF_AudioSampleEntryImportMode ase;
     253             :         char *styp;
     254             :         Bool sseg;
     255             :         Bool noroll;
     256             :         Bool saio32, tfdt64;
     257             :         u32 compress;
     258             :         Bool trun_inter;
     259             :         Bool truns_first;
     260             :         char *boxpatch;
     261             :         Bool fcomp, otyp;
     262             :         Bool deps;
     263             :         Bool mvex;
     264             :         u32 sdtp_traf;
     265             :         u32 cmaf;
     266             : #ifdef GF_ENABLE_CTRN
     267             :         Bool ctrn;
     268             :         Bool ctrni;
     269             : #endif
     270             :         Bool mfra;
     271             :         Bool forcesync, refrag;
     272             :         u32 itags;
     273             :         Double start;
     274             : 
     275             :         //internal
     276             :         Bool owns_mov;
     277             :         GF_FilterPid *opid;
     278             :         Bool first_pck_sent;
     279             : 
     280             :         GF_List *tracks;
     281             : 
     282             :         GF_BitStream *bs_r;
     283             :         //fragmentation state
     284             :         Bool init_movie_done, fragment_started, segment_started, insert_tfdt, insert_pssh, cdur_set;
     285             : 
     286             :         u64 next_frag_start, adjusted_next_frag_start;
     287             : 
     288             :         u64 current_offset;
     289             :         u64 current_size;
     290             : 
     291             :         u32 nb_segs, nb_frags, nb_frags_in_seg;
     292             : 
     293             :         GF_FilterPacket *dst_pck;
     294             :         char *seg_name;
     295             :         u32 dash_seg_num_plus_one;
     296             :         Bool flush_seg;
     297             :         u32 eos_marker;
     298             :         TrackWriter *ref_tkw;
     299             :         Bool single_file;
     300             :         Bool store_output;
     301             :         FILE *tmp_store;
     302             :         u64 flush_size, flush_done;
     303             : 
     304             :         u32 dash_mode, llhls_mode;
     305             :         GF_Fraction dash_dur;
     306             :         Double media_dur;
     307             :         u32 sidx_max_size, sidx_chunk_offset;
     308             :         Bool final_sidx_flush;
     309             :         Bool sidx_size_exact;
     310             : 
     311             :         u32 *seg_sizes;
     312             :         u32 nb_seg_sizes, alloc_seg_sizes;
     313             :         Bool config_timing;
     314             : 
     315             :         u32 major_brand_set;
     316             :         Bool def_brand_patched;
     317             : 
     318             :         Bool force_play;
     319             : 
     320             :         Bool moov_inserted;
     321             :         Bool update_report;
     322             :         u64 total_bytes_in, total_bytes_out;
     323             :         u32 total_samples, last_mux_pc;
     324             : 
     325             :         u32 maxchunk;
     326             :         u32 make_qt;
     327             :         TrackWriter *prores_track;
     328             : 
     329             :         GF_SegmentIndexBox *cloned_sidx;
     330             :         u32 cloned_sidx_index;
     331             :         GF_Fraction faststart_ts_regulate;
     332             : 
     333             :         Bool is_rewind;
     334             :         Bool box_patched;
     335             :         u32 cur_file_idx_plus_one;
     336             :         char *cur_file_suffix;
     337             :         Bool notify_filename;
     338             : 
     339             :         u32 next_file_idx;
     340             :         const char *next_file_suffix;
     341             : 
     342             :         //for route scheduling
     343             :         u64 min_cts_plus_one, next_seg_start;
     344             :         u64 min_cts_next_frag;
     345             : 
     346             :         u64 frag_size, frag_offset;
     347             :         u32 frag_num;
     348             :         u64 frag_duration;
     349             :         u32 frag_timescale;
     350             :         Bool frag_has_intra;
     351             : 
     352             :         u64 wait_dts_plus_one;
     353             :         u32 wait_dts_timescale;
     354             : } GF_MP4MuxCtx;
     355             : 
     356             : static void mp4_mux_set_hevc_groups(GF_MP4MuxCtx *ctx, TrackWriter *tkw);
     357             : 
     358          18 : static GF_Err mp4mx_setup_dash_vod(GF_MP4MuxCtx *ctx, TrackWriter *tkw)
     359             : {
     360          18 :         if (tkw) {
     361             :                 const GF_PropertyValue *p;
     362          18 :                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_DASH_DUR);
     363          18 :                 if (p) {
     364          18 :                         ctx->dash_dur = p->value.frac;
     365             :                 }
     366          18 :                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_DURATION);
     367          18 :                 if (p && p->value.lfrac.den) {
     368          18 :                         Double mdur = (Double) p->value.lfrac.num;
     369          18 :                         mdur /= p->value.lfrac.den;
     370          18 :                         if (ctx->media_dur < mdur) ctx->media_dur = mdur;
     371             :                 }
     372             :         }
     373          18 :         ctx->dash_mode = MP4MX_DASH_VOD;
     374          18 :         ctx->llhls_mode = 0;
     375          18 :         if ((ctx->vodcache==MP4MX_VODCACHE_ON) && !ctx->tmp_store) {
     376          17 :                 ctx->tmp_store = gf_file_temp(NULL);
     377          17 :                 if (!ctx->tmp_store) {
     378           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Cannot allocate temp file for VOD sidx generation\n"));
     379             :                         return GF_IO_ERR;
     380             :                 }
     381          17 :                 if (!ctx->block_size) ctx->block_size = 10000;
     382             :         }
     383             : 
     384             :         return GF_OK;
     385             : }
     386             : 
     387             : 
     388        1453 : static u32 gf_isom_stream_type_to_media_type(u32 stream_type, u32 codecid)
     389             : {
     390        1453 :         switch (stream_type) {
     391             :         case GF_STREAM_SCENE: return GF_ISOM_MEDIA_SCENE;
     392          13 :         case GF_STREAM_OD: return GF_ISOM_MEDIA_OD;
     393           0 :         case GF_STREAM_OCR: return GF_ISOM_MEDIA_OCR;
     394           0 :         case GF_STREAM_OCI: return GF_ISOM_MEDIA_OCI;
     395           0 :         case GF_STREAM_MPEG7: return GF_ISOM_MEDIA_MPEG7;
     396           0 :         case GF_STREAM_METADATA: return GF_ISOM_MEDIA_META;
     397         974 :         case GF_STREAM_VISUAL: return GF_ISOM_MEDIA_VISUAL;
     398         313 :         case GF_STREAM_AUDIO: return GF_ISOM_MEDIA_AUDIO;
     399         111 :         case GF_STREAM_TEXT:
     400         111 :                 if (codecid==GF_ISOM_SUBTYPE_STPP)
     401             :                         return GF_ISOM_MEDIA_MPEG_SUBT;
     402          94 :                 if (codecid == GF_CODECID_SUBPIC)
     403             :                         return GF_ISOM_MEDIA_SUBPIC;
     404          93 :                 return GF_ISOM_MEDIA_TEXT;
     405             :         case GF_STREAM_INTERACT: return GF_ISOM_MEDIA_SCENE;
     406           0 :         case GF_STREAM_IPMP: return GF_ISOM_MEDIA_IPMP;
     407           0 :         case GF_STREAM_MPEGJ: return GF_ISOM_MEDIA_MPEGJ;
     408           0 :         case GF_STREAM_IPMP_TOOL: return GF_ISOM_MEDIA_IPMP;
     409           0 :         case GF_STREAM_FONT: return GF_ISOM_MEDIA_MPEGJ;//TOCHECK !!
     410             : 
     411           0 :         case GF_STREAM_PRIVATE_SCENE:
     412             :         case GF_STREAM_ENCRYPTED:
     413             :         case GF_STREAM_FILE:
     414           0 :                 return 0;
     415          26 :         default:
     416          26 :                 return stream_type;
     417             :         }
     418             :         return 0;
     419             : }
     420             : 
     421          94 : static void mp4_mux_write_ps_list(GF_BitStream *bs, GF_List *list, u32 nalu_size_length)
     422             : {
     423          94 :         u32 i, count = list ? gf_list_count(list) : 0;
     424         194 :         for (i=0; i<count; i++) {
     425         100 :                 GF_NALUFFParam *sl = gf_list_get(list, i);
     426         100 :                 gf_bs_write_int(bs, sl->size, 8*nalu_size_length);
     427         100 :                 gf_bs_write_data(bs, sl->data, sl->size);
     428             :         }
     429          94 : }
     430             : 
     431          48 : static GF_List *mp4_mux_get_nalus_ps(GF_List *list, u8 type)
     432             : {
     433          48 :         u32 i, count = gf_list_count(list);
     434          96 :         for (i=0; i<count; i++) {
     435          96 :                 GF_NALUFFParamArray *pa = gf_list_get(list, i);
     436          96 :                 if (pa->type == type) return pa->nalus;
     437             :         }
     438             :         return NULL;
     439             : }
     440             : 
     441          39 : static void mp4_mux_make_inband_header(GF_MP4MuxCtx *ctx, TrackWriter *tkw, Bool for_non_rap)
     442             : {
     443             :         GF_BitStream *bs;
     444          39 :         if (for_non_rap) {
     445           0 :                 if (tkw->inband_hdr_non_rap) gf_free(tkw->inband_hdr_non_rap);
     446           0 :                 tkw->inband_hdr_non_rap = NULL;
     447             :         } else {
     448          39 :                 if (tkw->inband_hdr) gf_free(tkw->inband_hdr);
     449          39 :                 tkw->inband_hdr = NULL;
     450             :         }
     451             : 
     452          39 :         tkw->nal_unit_size = 0;
     453          39 :         bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
     454          39 :         if (tkw->avcc || tkw->svcc) {
     455          23 :                 if (tkw->avcc) {
     456          23 :                         if (!for_non_rap)
     457          23 :                                 mp4_mux_write_ps_list(bs, tkw->avcc->sequenceParameterSets, tkw->avcc->nal_unit_size);
     458          23 :                         /*if (!tkw->nal_unit_size) */tkw->nal_unit_size = tkw->avcc->nal_unit_size;
     459             :                 }
     460             : 
     461          23 :                 if (tkw->svcc) {
     462           0 :                         if (!for_non_rap)
     463           0 :                                 mp4_mux_write_ps_list(bs, tkw->svcc->sequenceParameterSets, tkw->svcc->nal_unit_size);
     464           0 :                         if (!tkw->nal_unit_size) tkw->nal_unit_size = tkw->svcc->nal_unit_size;
     465             :                 }
     466             : 
     467          23 :                 if (tkw->avcc && tkw->avcc->sequenceParameterSetExtensions && !for_non_rap)
     468           0 :                         mp4_mux_write_ps_list(bs, tkw->avcc->sequenceParameterSetExtensions, tkw->avcc->nal_unit_size);
     469             : 
     470          23 :                 if (tkw->svcc && tkw->svcc->sequenceParameterSetExtensions && !for_non_rap)
     471           0 :                         mp4_mux_write_ps_list(bs, tkw->svcc->sequenceParameterSetExtensions, tkw->svcc->nal_unit_size);
     472             : 
     473          23 :                 if (tkw->avcc)
     474          23 :                         mp4_mux_write_ps_list(bs, tkw->avcc->pictureParameterSets, tkw->avcc->nal_unit_size);
     475             : 
     476          23 :                 if (tkw->svcc)
     477           0 :                         mp4_mux_write_ps_list(bs, tkw->svcc->pictureParameterSets, tkw->svcc->nal_unit_size);
     478             :         }
     479          39 :         if (tkw->hvcc || tkw->lvcc) {
     480          16 :                 if (tkw->hvcc) {
     481          16 :                         if (!for_non_rap)
     482          16 :                                 mp4_mux_write_ps_list(bs, mp4_mux_get_nalus_ps(tkw->hvcc->param_array, GF_HEVC_NALU_VID_PARAM), tkw->hvcc->nal_unit_size);
     483          16 :                         if (!tkw->nal_unit_size) tkw->nal_unit_size = tkw->hvcc->nal_unit_size;
     484             :                 }
     485          16 :                 if (tkw->lvcc) {
     486           0 :                         if (!for_non_rap)
     487           0 :                                 mp4_mux_write_ps_list(bs, mp4_mux_get_nalus_ps(tkw->lvcc->param_array, GF_HEVC_NALU_VID_PARAM), tkw->lvcc->nal_unit_size);
     488           0 :                         if (!tkw->nal_unit_size) tkw->nal_unit_size = tkw->lvcc->nal_unit_size;
     489             :                 }
     490          16 :                 if (tkw->hvcc && !for_non_rap)
     491          16 :                         mp4_mux_write_ps_list(bs, mp4_mux_get_nalus_ps(tkw->hvcc->param_array, GF_HEVC_NALU_SEQ_PARAM), tkw->hvcc->nal_unit_size);
     492          16 :                 if (tkw->lvcc && !for_non_rap)
     493           0 :                         mp4_mux_write_ps_list(bs, mp4_mux_get_nalus_ps(tkw->lvcc->param_array, GF_HEVC_NALU_SEQ_PARAM), tkw->lvcc->nal_unit_size);
     494          16 :                 if (tkw->hvcc)
     495          16 :                         mp4_mux_write_ps_list(bs, mp4_mux_get_nalus_ps(tkw->hvcc->param_array, GF_HEVC_NALU_PIC_PARAM), tkw->hvcc->nal_unit_size);
     496          16 :                 if (tkw->lvcc)
     497           0 :                         mp4_mux_write_ps_list(bs, mp4_mux_get_nalus_ps(tkw->lvcc->param_array, GF_HEVC_NALU_PIC_PARAM), tkw->lvcc->nal_unit_size);
     498             :         }
     499             : 
     500          39 :         if (tkw->vvcc) {
     501           0 :                 if (!for_non_rap)
     502           0 :                         mp4_mux_write_ps_list(bs, mp4_mux_get_nalus_ps(tkw->vvcc->param_array, GF_VVC_NALU_VID_PARAM), tkw->vvcc->nal_unit_size);
     503           0 :                 if (!tkw->nal_unit_size) tkw->nal_unit_size = tkw->vvcc->nal_unit_size;
     504             : 
     505           0 :                 if (!for_non_rap)
     506           0 :                         mp4_mux_write_ps_list(bs, mp4_mux_get_nalus_ps(tkw->vvcc->param_array, GF_VVC_NALU_SEQ_PARAM), tkw->vvcc->nal_unit_size);
     507             : 
     508           0 :                 mp4_mux_write_ps_list(bs, mp4_mux_get_nalus_ps(tkw->vvcc->param_array, GF_VVC_NALU_PIC_PARAM), tkw->vvcc->nal_unit_size);
     509           0 :                 mp4_mux_write_ps_list(bs, mp4_mux_get_nalus_ps(tkw->vvcc->param_array, GF_VVC_NALU_APS_PREFIX), tkw->vvcc->nal_unit_size);
     510             :         }
     511             : 
     512          39 :         if (for_non_rap) {
     513           0 :                 gf_bs_get_content(bs, &tkw->inband_hdr_non_rap, &tkw->inband_hdr_non_rap_size);
     514             :         } else {
     515          39 :                 gf_bs_get_content(bs, &tkw->inband_hdr, &tkw->inband_hdr_size);
     516             :         }
     517          39 :         gf_bs_del(bs);
     518             :         //we may have cases where the param sets are updated before a non-IDR/SAP3 picture, we must inject asap at least once
     519          39 :         tkw->force_inband_inject = GF_TRUE;
     520          39 : }
     521             : 
     522          66 : void mp4_mux_get_video_size(GF_MP4MuxCtx *ctx, u32 *width, u32 *height)
     523             : {
     524             :         u32 w, h, f_w, f_h, i;
     525             : 
     526             :         f_w = f_h = 0;
     527         206 :         for (i=0; i<gf_isom_get_track_count(ctx->file); i++) {
     528          74 :                 switch (gf_isom_get_media_type(ctx->file, i+1)) {
     529           5 :                 case GF_ISOM_MEDIA_SCENE:
     530             :                 case GF_ISOM_MEDIA_VISUAL:
     531           5 :                         gf_isom_get_visual_info(ctx->file, i+1, 1, &w, &h);
     532           5 :                         if (w > f_w) f_w = w;
     533           5 :                         if (h > f_h) f_h = h;
     534             :                         //fallthrough
     535             :                 case GF_ISOM_MEDIA_TEXT:
     536          71 :                         gf_isom_get_track_layout_info(ctx->file, i+1, &w, &h, NULL, NULL, NULL);
     537          71 :                         if (w > f_w) f_w = w;
     538          71 :                         if (h > f_h) f_h = h;
     539             :                         break;
     540             :                 }
     541             :         }
     542          66 :         (*width) = f_w ? f_w : TEXT_DEFAULT_WIDTH;
     543          66 :         (*height) = f_h ? f_h : TEXT_DEFAULT_HEIGHT;
     544          66 : }
     545             : 
     546        1376 : static void mp4_mux_track_writer_del(TrackWriter *tkw)
     547             : {
     548        1376 :         if (tkw->avcc) gf_odf_avc_cfg_del(tkw->avcc);
     549        1376 :         if (tkw->svcc) gf_odf_avc_cfg_del(tkw->svcc);
     550        1376 :         if (tkw->hvcc) gf_odf_hevc_cfg_del(tkw->hvcc);
     551        1376 :         if (tkw->lvcc) gf_odf_hevc_cfg_del(tkw->lvcc);
     552        1376 :         if (tkw->vvcc) gf_odf_vvc_cfg_del(tkw->vvcc);
     553        1376 :         if (tkw->inband_hdr) gf_free(tkw->inband_hdr);
     554        1376 :         if (tkw->inband_hdr_non_rap) gf_free(tkw->inband_hdr_non_rap);
     555        1376 :         gf_free(tkw);
     556        1376 : }
     557             : 
     558        4404 : static void mp4_mux_write_track_refs(GF_MP4MuxCtx *ctx, TrackWriter *tkw, const char *rname, u32 rtype)
     559             : {
     560             :         u32 i;
     561        4404 :         const GF_PropertyValue *p = gf_filter_pid_get_property_str(tkw->ipid, rname);
     562        4404 :         if (!p) return;
     563         241 :         for (i=0; i<p->value.uint_list.nb_items; i++) {
     564         241 :                 gf_isom_set_track_reference(ctx->file, tkw->track_num, rtype, p->value.uint_list.vals[i]);
     565             :         }
     566             : }
     567             : 
     568           0 : static void mp4mux_track_reorder(void *udta, u32 old_track_num, u32 new_track_num)
     569             : {
     570             :         GF_MP4MuxCtx *ctx = (GF_MP4MuxCtx *) udta;
     571             :         u32 i, count;
     572           0 :         count = gf_list_count(ctx->tracks);
     573           0 :         for (i=0; i<count; i++) {
     574           0 :                 TrackWriter *tkw = gf_list_get(ctx->tracks, i);
     575           0 :                 if (tkw->track_num==old_track_num) {
     576           0 :                         tkw->track_num = new_track_num;
     577           0 :                         return;
     578             :                 }
     579             :         }
     580             : }
     581             : 
     582         461 : static void mp4mux_reorder_tracks(GF_MP4MuxCtx *ctx)
     583             : {
     584             :         u32 i, count, prev_num, prev_pos;
     585         461 :         GF_List *new_tracks = gf_list_new();
     586             :         prev_num = prev_pos = 0;
     587         461 :         count = gf_list_count(ctx->tracks);
     588         469 :         for (i=0; i<count; i++) {
     589         469 :                 TrackWriter *tkw = gf_list_get(ctx->tracks, i);
     590         469 :                 if (tkw->track_num<prev_num) {
     591           1 :                         gf_list_insert(new_tracks, tkw, prev_pos);
     592             :                 } else {
     593         468 :                         gf_list_add(new_tracks, tkw);
     594             :                 }
     595         469 :                 prev_pos = gf_list_count(new_tracks) - 1;
     596         469 :                 prev_num = tkw->track_num;
     597             :         }
     598         461 :         if (gf_list_count(new_tracks)!=count) {
     599           0 :                 gf_list_del(new_tracks);
     600             :                 return;
     601             :         }
     602         461 :         gf_list_del(ctx->tracks);
     603         461 :         ctx->tracks = new_tracks;
     604             : }
     605             : 
     606        1461 : static void mp4_mux_set_tags(GF_MP4MuxCtx *ctx, TrackWriter *tkw)
     607             : {
     608        1461 :         u32 idx=0;
     609        1461 :         if (ctx->itags==TAG_NONE) return;
     610             : 
     611             :         while (1) {
     612             :                 GF_Err e;
     613             :                 u32 len;
     614       42054 :                 u32 prop_4cc=0;
     615             :                 u32 itag;
     616             :                 s32 tag_idx;
     617       42054 :                 const char *tag_name=NULL;
     618       42054 :                 const GF_PropertyValue *tag = gf_filter_pid_enum_properties(tkw->ipid, &idx, &prop_4cc, &tag_name);
     619       42054 :                 if (!tag) break;
     620             : 
     621       40593 :                 if (prop_4cc==GF_PROP_PID_COVER_ART) {
     622           0 :                         e = gf_isom_apple_set_tag(ctx->file, GF_ISOM_ITUNE_COVER_ART, tag->value.data.ptr, tag->value.data.size, 0, 0);
     623           0 :                         if (e) {
     624           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Failed to set cover art: %s\n", gf_error_to_string(e)));
     625             :                         }
     626             :                 }
     627       40593 :                 if (!tag_name)
     628       80898 :                         continue;
     629             : 
     630         288 :                 tag_idx = gf_itags_find_by_name(tag_name);
     631         288 :                 if (tag_idx>=0) {
     632           0 :                         itag = gf_itags_get_itag(tag_idx);
     633             :                 } else {
     634         288 :                         if (ctx->itags==TAG_STRICT)
     635         288 :                                 continue;
     636             : 
     637           0 :                         if (strnicmp(tag_name, "tag_", 4))
     638           0 :                                 continue;
     639             : 
     640           0 :                         tag_name += 4;
     641             : 
     642           0 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MP4Mux] Unrecognized tag %s: %s\n", tag_name, tag->value.string));
     643             : 
     644           0 :                         if (strlen(tag_name)==4) {
     645           0 :                                 itag = GF_4CC(tag_name[0], tag_name[1], tag_name[2], tag_name[3]);
     646           0 :                         } else if (strlen(tag_name)==3) {
     647           0 :                                 itag = GF_4CC(0xA9, tag_name[0], tag_name[1], tag_name[2]);
     648             :                         } else {
     649           0 :                                 itag = gf_crc_32(tag_name, (u32) strlen(tag_name));
     650           0 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MP4Mux] Tag name %s is not a 4CC, using CRC32 %08X as value\n", tag_name, itag));
     651             :                         }
     652             :                 }
     653             : 
     654           0 :                 switch (tag->type) {
     655           0 :                 case GF_PROP_STRING:
     656             :                 case GF_PROP_NAME:
     657           0 :                         len = tag->value.string ? (u32) strlen(tag->value.string) : 0;
     658           0 :                         e = gf_isom_apple_set_tag(ctx->file, GF_ISOM_ITUNE_COVER_ART, tag->value.string, len, 0, 0);
     659             :                         break;
     660           0 :                 case GF_PROP_BOOL:
     661           0 :                         e = gf_isom_apple_set_tag(ctx->file, itag, NULL, 0, tag->value.boolean, 0);
     662             :                         break;
     663           0 :                 case GF_PROP_UINT:
     664             :                 case GF_PROP_4CC:
     665           0 :                         e = gf_isom_apple_set_tag(ctx->file, itag, NULL, 0, tag->value.uint, 0);
     666             :                         break;
     667           0 :                 case GF_PROP_LUINT:
     668           0 :                         e = gf_isom_apple_set_tag(ctx->file, itag, NULL, 0, tag->value.longuint, 0);
     669             :                         break;
     670           0 :                 case GF_PROP_FRACTION:
     671           0 :                         e = gf_isom_apple_set_tag(ctx->file, itag, NULL, 0, tag->value.frac.num, tag->value.frac.den);
     672             :                         break;
     673           0 :                 case GF_PROP_DATA:
     674             :                 case GF_PROP_CONST_DATA:
     675           0 :                         e = gf_isom_apple_set_tag(ctx->file, itag, tag->value.data.ptr, tag->value.data.size, 0, 0);
     676             :                         break;
     677           0 :                 default:
     678           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Failed to set tag %s: invalid data format\n", gf_itags_get_name(tag_idx) ));
     679             :                         e = GF_OK;
     680             :                         break;
     681             :                 }
     682             : 
     683           0 :                 if (e) {
     684           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Failed to set tag %s: %s\n", tag_name, gf_error_to_string(e)));
     685             :                 }
     686             :         }
     687             : }
     688             : 
     689             : 
     690        2794 : static GF_Err mp4_mux_setup_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_true_pid)
     691             : {
     692             :         void mux_assign_mime_file_ext(GF_FilterPid *ipid, GF_FilterPid *opid, const char *file_exts, const char *mime_types, const char *def_ext);
     693             :         Bool use_m4sys = GF_FALSE;
     694             :         Bool use_tx3g = GF_FALSE;
     695             :         Bool use_webvtt = GF_FALSE;
     696             :         Bool needs_track = GF_FALSE;
     697             :         u32 needs_sample_entry = 0; //1: change of codecID, 2 change of decoder config
     698             :         Bool use_gen_sample_entry = GF_FALSE;
     699             :         Bool use_3gpp_config = GF_FALSE;
     700             :         Bool use_ac3_entry = GF_FALSE;
     701             :         Bool use_flac_entry = GF_FALSE;
     702             :         Bool use_avc = GF_FALSE;
     703             :         Bool use_hevc = GF_FALSE;
     704             :         Bool use_vvc = GF_FALSE;
     705             :         Bool use_hvt1 = GF_FALSE;
     706             :         Bool use_av1 = GF_FALSE;
     707             :         Bool use_vpX = GF_FALSE;
     708             :         Bool use_mj2 = GF_FALSE;
     709             :         Bool use_opus = GF_FALSE;
     710             :         Bool use_dref = GF_FALSE;
     711             :         Bool skip_dsi = GF_FALSE;
     712             :         Bool is_text_subs = GF_FALSE;
     713             :         Bool force_colr = GF_FALSE;
     714             :         u32 m_subtype=0;
     715             :         u32 m_subtype_src=0;
     716             :         u32 m_subtype_alt_raw=0;
     717             :         u32 raw_bitdepth=0;
     718             :         u32 override_stype=0;
     719             :         u32 width, height, sr, nb_chan, nb_bps, z_order, txt_fsize;
     720             :         u64 ch_layout;
     721             :         GF_Fraction fps, sar;
     722             :         GF_List *multi_pid_stsd = NULL;
     723             :         u32 multi_pid_idx = 0;
     724             :         GF_FilterPid *orig_pid = NULL;
     725             :         u32 codec_id;
     726             :         u32 frames_per_sample_backup=0;
     727             :         u32 is_nalu_backup = NALU_NONE;
     728             :         Bool is_tile_base = GF_FALSE;
     729             :         Bool unknown_generic = GF_FALSE;
     730             :         u32 multi_pid_final_stsd_idx = 0;
     731             :         u32 audio_pli=0;
     732             :         Bool force_tk_layout = GF_FALSE;
     733             :         Bool force_mix_xps = GF_FALSE;
     734             :         Bool make_inband_headers = GF_FALSE;
     735             :         Bool is_prores = GF_FALSE;
     736             : 
     737             :         const char *lang_name = NULL;
     738             :         const char *comp_name = NULL;
     739             :         const char *imp_name = NULL;
     740             :         const char *src_url = NULL;
     741             :         const char *meta_mime = NULL;
     742             :         const char *meta_encoding = NULL;
     743             :         const char *meta_config = NULL;
     744             :         const char *meta_xmlns = NULL;
     745             :         const char *meta_schemaloc = NULL;
     746             :         const char *meta_auxmimes = NULL;
     747             :         const char *meta_content_encoding = NULL;
     748             :         char *txt_font = NULL;
     749             : 
     750             :         u32 i, count, reuse_stsd = 0;
     751             :         GF_Err e;
     752             :         const GF_PropertyValue *dsi=NULL;
     753             :         const GF_PropertyValue *enh_dsi=NULL;
     754             :         const GF_PropertyValue *p;
     755        2794 :         GF_MP4MuxCtx *ctx = gf_filter_get_udta(filter);
     756        2794 :         GF_AudioSampleEntryImportMode ase_mode = ctx->ase;
     757             :         TrackWriter *tkw;
     758             : 
     759        2794 :         if (ctx->owns_mov && !ctx->opid) {
     760             :                 char *dst;
     761         664 :                 ctx->opid = gf_filter_pid_new(filter);
     762             : 
     763         664 :                 dst = gf_filter_get_dst_name(filter);
     764         664 :                 if (dst) {
     765         664 :                         char *ext = gf_file_ext_start(dst);
     766         664 :                         if (ext && (!stricmp(ext, ".mov") || !stricmp(ext, ".qt")) ) {
     767           1 :                                 ctx->make_qt = 1;
     768             :                         }
     769         664 :                         gf_free(dst);
     770             :                 }
     771             :         }
     772             :         //copy properties at init or reconfig
     773        2794 :         if (ctx->opid && is_true_pid) {
     774        1439 :                 gf_filter_pid_copy_properties(ctx->opid, pid);
     775        1439 :                 if (gf_list_count(ctx->tracks)>1)
     776         145 :                         gf_filter_pid_set_name(ctx->opid, "isobmf_mux");
     777             : 
     778        1439 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, NULL);
     779        1439 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG_ENHANCEMENT, NULL);
     780        1439 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, NULL);
     781        1439 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, NULL);
     782        1439 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_FILE) );
     783             : 
     784        1439 :                 mux_assign_mime_file_ext(pid, ctx->opid, ISOM_FILE_EXT, ISOM_FILE_MIME, NULL);
     785             :                 
     786        1439 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DASH_MODE, NULL);
     787             :                 //we dispatch timing in milliseconds
     788        1439 :                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, &PROP_UINT(1000));
     789        1439 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_STREAM_TYPE);
     790        1439 :                 if (p)
     791        1439 :                         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_ORIG_STREAM_TYPE, &PROP_UINT(p->value.uint));
     792             : 
     793        1439 :                 switch (ctx->store) {
     794           2 :                 case MP4MX_MODE_FLAT:
     795             :                 case MP4MX_MODE_FASTSTART:
     796           2 :                         gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DISABLE_PROGRESSIVE, &PROP_UINT(GF_PID_FILE_PATCH_INSERT) );
     797           2 :                         break;
     798         894 :                 case MP4MX_MODE_INTER:
     799             :                 case MP4MX_MODE_TIGHT:
     800         894 :                         gf_filter_pid_allow_direct_dispatch(ctx->opid);
     801         894 :                         break;
     802             :                 }
     803             :         }
     804             : 
     805        2794 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_TILE_BASE);
     806        2794 :         if (p && p->value.boolean)
     807             :                 is_tile_base = GF_TRUE;
     808             : 
     809        2794 :         if (is_true_pid && !is_tile_base) {
     810        2762 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_DASH_MULTI_TRACK);
     811        2762 :                 if (p) {
     812             :                         u32 j, count2;
     813           3 :                         GF_List *multi_tracks = p->value.ptr;
     814           3 :                         count = gf_list_count(multi_tracks);
     815           6 :                         for (i=0; i<count; i++) {
     816           3 :                                 GF_FilterPid *a_ipid = gf_list_get(multi_tracks, i);
     817           3 :                                 const GF_PropertyValue *a_pidid = gf_filter_pid_get_property(a_ipid, GF_PROP_PID_ID);
     818           3 :                                 count2 = gf_list_count(ctx->tracks);
     819           3 :                                 for (j=0; j<count2; j++) {
     820           3 :                                         TrackWriter *atkw = gf_list_get(ctx->tracks, j);
     821           3 :                                         const GF_PropertyValue *c_pidid = gf_filter_pid_get_property(atkw->ipid, GF_PROP_PID_ID);
     822           3 :                                         if (gf_props_equal(a_pidid, c_pidid)) {
     823             :                                                 a_ipid = NULL;
     824             :                                                 break;
     825             :                                         }
     826             :                                 }
     827           3 :                                 if (a_ipid)
     828           0 :                                         mp4_mux_setup_pid(filter, a_ipid, GF_FALSE);
     829             :                         }
     830             :                 }
     831             :         }
     832             : 
     833        2794 :         audio_pli = gf_isom_get_pl_indication(ctx->file, GF_ISOM_PL_AUDIO);
     834             : 
     835             :         //new pid ?
     836        2794 :         tkw = gf_filter_pid_get_udta(pid);
     837        2794 :         if (!tkw) {
     838             :                 GF_FilterEvent evt;
     839        1387 :                 GF_SAFEALLOC(tkw, TrackWriter);
     840        1387 :                 if (!tkw) return GF_OUT_OF_MEM;
     841             :                 
     842        1387 :                 gf_list_add(ctx->tracks, tkw);
     843        1387 :                 tkw->ipid = pid;
     844        1387 :                 tkw->fake_track = !is_true_pid;
     845        1387 :                 tkw->min_cts = (u64) -1;
     846             : 
     847        1387 :                 if (is_true_pid) {
     848        1360 :                         gf_filter_pid_set_udta(pid, tkw);
     849             : 
     850        1360 :                         tkw->is_hevc_tile_base = is_tile_base;
     851             : #ifdef GPAC_ENABLE_COVERAGE
     852        1360 :                         if (gf_sys_is_cov_mode()) {
     853        1359 :                                 gf_filter_pid_get_min_pck_duration(pid);
     854             :                         }
     855             : #endif
     856        1360 :                         if (!ctx->owns_mov || ctx->force_play) {
     857         624 :                                 if (!ctx->owns_mov) {
     858         615 :                                         if (ctx->start != 0)
     859           0 :                                                 tkw->wait_sap = GF_TRUE;
     860         615 :                                         gf_filter_pid_init_play_event(pid, &evt, ctx->start, 0, "MP4Mux");
     861             :                                 } else {
     862           9 :                                         GF_FEVT_INIT(evt, GF_FEVT_PLAY, pid);
     863             :                                 }
     864         624 :                                 gf_filter_pid_send_event(pid, &evt);
     865             :                         }
     866        1360 :                         gf_filter_pid_set_framing_mode(pid, GF_TRUE);
     867             : 
     868        1360 :                         p = gf_filter_pid_get_property(pid, GF_PROP_PID_ITEM_ID);
     869        1360 :                         if (p) {
     870          32 :                                 tkw->is_item = GF_TRUE;
     871             :                         } else {
     872        1328 :                                 ctx->config_timing = GF_TRUE;
     873        1328 :                                 ctx->update_report = GF_TRUE;
     874             :                         }
     875             :                 }
     876             :         }
     877             : 
     878             :         //check change of pid config
     879        2794 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_DEPENDENCY_ID);
     880        2794 :         if (p) {
     881          83 :                 if (p->value.uint!=tkw->dep_id) needs_track = GF_TRUE;
     882          83 :                 tkw->dep_id = p->value.uint;
     883             :         }
     884             : 
     885             :         //check change of pid config
     886        2794 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
     887        2794 :         if (p) {
     888        2794 :                 if (p->value.uint!=tkw->codecid) needs_sample_entry = 1;
     889        2794 :                 tkw->codecid = p->value.uint;
     890             :         }
     891             : 
     892        2794 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_STREAM_TYPE);
     893        2794 :         if (p) {
     894        2794 :                 u32 stype = p->value.uint;
     895        2794 :                 if (tkw->is_encrypted && (p->value.uint==GF_STREAM_ENCRYPTED) ) {
     896         336 :                         stype = gf_codecid_type(tkw->codecid);
     897             :                 }
     898        2794 :                 if (stype != tkw->stream_type) {
     899             :                         needs_track = GF_TRUE;
     900        1387 :                         tkw->stream_type = stype;
     901        1387 :                         const char *name = gf_stream_type_name(stype);
     902        1387 :                         tkw->status_type = name ? name[0] : 'U';
     903             :                 }
     904             :         }
     905             : 
     906        2794 :         dsi = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
     907        2794 :         if (dsi) {
     908        2499 :                 u32 cfg_crc = gf_crc_32(dsi->value.data.ptr, dsi->value.data.size);
     909        2499 :                 if (cfg_crc!=tkw->cfg_crc) needs_sample_entry = 2;
     910        2499 :                 tkw->cfg_crc = cfg_crc;
     911         295 :         } else if (tkw->cfg_crc) {
     912           0 :                 tkw->cfg_crc = 0;
     913             :                 needs_sample_entry = 2;
     914             :         }
     915             : 
     916        2794 :         enh_dsi = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG_ENHANCEMENT);
     917        2810 :         if (enh_dsi && (enh_dsi->type==GF_PROP_DATA) ) {
     918          16 :                 u32 cfg_crc = gf_crc_32(enh_dsi->value.data.ptr, enh_dsi->value.data.size);
     919          16 :                 if (cfg_crc!=tkw->enh_cfg_crc) needs_sample_entry = 2;
     920          16 :                 tkw->enh_cfg_crc = cfg_crc;
     921        2778 :         } else if (tkw->enh_cfg_crc) {
     922           0 :                 tkw->enh_cfg_crc = 0;
     923             :                 needs_sample_entry = 2;
     924             :         }
     925             : 
     926             :         //TODO: try to merge PPS/SPS for AVC and HEVC rather than creating a new sample description
     927             : 
     928        2794 :         switch (tkw->codecid) {
     929        1245 :         case GF_CODECID_AAC_MPEG4:
     930             :         case GF_CODECID_AAC_MPEG2_MP:
     931             :         case GF_CODECID_AAC_MPEG2_LCP:
     932             :         case GF_CODECID_AAC_MPEG2_SSRP:
     933             :         case GF_CODECID_USAC:
     934             :         case GF_CODECID_MPEG4_PART2:
     935             :         case GF_CODECID_AVC:
     936             :         case GF_CODECID_SVC:
     937             :         case GF_CODECID_HEVC:
     938             :         case GF_CODECID_LHVC:
     939        1245 :                 if (!dsi && !enh_dsi) return GF_OK;
     940             :                 break;
     941           4 :         case GF_CODECID_APCH:
     942             :         case GF_CODECID_APCO:
     943             :         case GF_CODECID_APCN:
     944             :         case GF_CODECID_APCS:
     945             :         case GF_CODECID_AP4X:
     946             :         case GF_CODECID_AP4H:
     947           4 :                 if (!ctx->make_qt) {
     948           2 :                         GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MP4Mux] ProRes track detected, muxing to QTFF even though ISOBMFF was asked\n"));
     949           2 :                         ctx->make_qt = 2;
     950             :                 }
     951           4 :                 if (ctx->prores_track && (ctx->prores_track != tkw)) {
     952           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] More than one ProRes track detected, result might be non compliant\n"));
     953             :                 }
     954             :                 is_prores = GF_TRUE;
     955             :                 break;
     956             :         default:
     957             :                 break;
     958             :         }
     959        2786 :         if (!tkw->track_num) {
     960             :                 needs_sample_entry = 1;
     961             :                 needs_track = GF_TRUE;
     962             :         }
     963             : 
     964        2786 :         if (ctx->make_qt) {
     965           4 :                 gf_isom_remove_root_od(ctx->file);
     966           4 :                 gf_isom_set_brand_info(ctx->file, GF_ISOM_BRAND_QT, 512);
     967           4 :                 gf_isom_reset_alt_brands(ctx->file);
     968           4 :                 tkw->has_brands = GF_TRUE;
     969           4 :                 ctx->major_brand_set = GF_ISOM_BRAND_QT;
     970           4 :                 ctx->btrt = GF_FALSE;
     971             : 
     972           4 :                 if (is_prores && !ctx->prores_track) {
     973           3 :                         ctx->prores_track = tkw;
     974             :                 }
     975             :         }
     976             : 
     977        2786 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_URL);
     978        2786 :         if (p) src_url = p->value.string;
     979             : 
     980             : 
     981        2786 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_DASH_MODE);
     982        2786 :         if (p) {
     983         360 :                 ctx->dash_mode = MP4MX_DASH_ON;
     984         360 :                 if (p->value.uint==2) {
     985          18 :                         e = mp4mx_setup_dash_vod(ctx, tkw);
     986          18 :                         if (e) return e;
     987             :                 }
     988             :         }
     989             :         //we consider that when muxing single segments, we are always in DASH, not VoD mode
     990        2426 :         else if (ctx->noinit) {
     991           3 :                 ctx->dash_mode = MP4MX_DASH_ON;
     992             :         }
     993             : 
     994        2786 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_LLHLS);
     995        2786 :         ctx->llhls_mode = p ? p->value.uint : 0;
     996             :         //insert tfdt in each traf for LL-HLS so that correct timing can be found when doing in-segment tune-in
     997        2786 :         if (ctx->llhls_mode) {
     998          12 :                 ctx->tfdt_traf = GF_TRUE;
     999          12 :                 ctx->store = MP4MX_MODE_SFRAG;
    1000             :         }
    1001             : 
    1002        2786 :         if (!ctx->cdur_set) {
    1003        1272 :                 ctx->cdur_set = GF_TRUE;
    1004        1272 :                 if (ctx->cdur.num<0) {
    1005        1022 :                         if (ctx->make_qt) {
    1006           3 :                                 ctx->cdur.num = 1000;
    1007           3 :                                 ctx->cdur.den = 2000;
    1008             :                         } else {
    1009        1019 :                                 ctx->cdur.num = 1000;
    1010        1019 :                                 ctx->cdur.den = 1000;
    1011        1019 :                                 if (ctx->dash_mode)
    1012         301 :                                         ctx->fragdur = GF_FALSE;
    1013             :                         }
    1014         250 :                 } else if (ctx->dash_mode)
    1015          26 :                         ctx->fragdur = GF_TRUE;
    1016             :         }
    1017             : 
    1018        2786 :         if (needs_track) {
    1019        1501 :                 if (ctx->init_movie_done) {
    1020           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] Cannot add track to already finalized movie in fragmented file, will request a new muxer for that track\n"));
    1021             :                         return GF_REQUIRES_NEW_INSTANCE;
    1022             :                 }
    1023        1501 :                 if (tkw->is_item) {
    1024             :                         needs_track = GF_FALSE;
    1025             : 
    1026          48 :                         if (tkw->stream_type == GF_STREAM_ENCRYPTED) {
    1027          10 :                                 tkw->is_encrypted = GF_TRUE;
    1028          10 :                                 tkw->stream_type = gf_codecid_type(tkw->codecid);
    1029          10 :                                 tkw->insert_pssh = GF_TRUE;
    1030             :                         }
    1031             :                 }
    1032             :         }
    1033             : 
    1034        2738 :         if (needs_track) {
    1035             :                 u32 tkid=0;
    1036             :                 u32 tk_idx=0;
    1037             :                 u32 mtype=0;
    1038             :                 u32 target_timescale = 0;
    1039             : 
    1040        1453 :                 if (ctx->make_qt && (tkw->stream_type==GF_STREAM_VISUAL)) {
    1041           3 :                         p = gf_filter_pid_get_property(pid, GF_PROP_PID_FPS);
    1042           3 :                         if (p) {
    1043           3 :                                 u32 ts=p->value.frac.num, inc=p->value.frac.den;
    1044           3 :                                 if (inc * 24000 == ts * 1001) target_timescale = 24000;
    1045           3 :                                 else if (inc * 2400 == ts * 100) target_timescale = 2400;
    1046           3 :                                 else if (inc * 2500 == ts * 100) target_timescale = 2500;
    1047           1 :                                 else if (inc * 30000 == ts * 1001) target_timescale = 30000;
    1048           1 :                                 else if (inc * 2997 == ts * 100) target_timescale = 30000;
    1049           0 :                                 else if (inc * 3000 == ts * 100) target_timescale = 3000;
    1050           0 :                                 else if (inc * 5000 == ts * 100) target_timescale = 5000;
    1051           0 :                                 else if (inc * 60000 == ts * 1001) target_timescale = 60000;
    1052           0 :                                 else if (inc * 5994 == ts * 100) target_timescale = 60000;
    1053           0 :                                 else if (is_prores) {
    1054           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[ProRes] Unrecognized frame rate %g\n", ((Double)ts)/inc ));
    1055             :                                         return GF_NON_COMPLIANT_BITSTREAM;
    1056             :                                 }
    1057             :                         }
    1058           3 :                         if (!ctx->prores_track)
    1059           0 :                                 ctx->prores_track = tkw;
    1060             :                 }
    1061             : 
    1062        1453 :                 if (!ctx->moov_inserted) {
    1063        1453 :                         if (target_timescale) {
    1064           3 :                                 ctx->moovts = target_timescale;
    1065           3 :                                 gf_isom_set_timescale(ctx->file, target_timescale);
    1066        1450 :                         } else if (ctx->moovts>=0) {
    1067        1446 :                                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_ISOM_MOVIE_TIME);
    1068        1446 :                                 if (p && p->value.lfrac.den) {
    1069         612 :                                         gf_isom_set_timescale(ctx->file, (u32) p->value.lfrac.den);
    1070         612 :                                         ctx->moovts = (u32) p->value.lfrac.den;
    1071             :                                 } else {
    1072         834 :                                         gf_isom_set_timescale(ctx->file, ctx->moovts);
    1073             :                                 }
    1074             :                         }
    1075        1453 :                         if (ctx->store==MP4MX_MODE_FASTSTART) {
    1076           4 :                                 gf_isom_make_interleave_ex(ctx->file, &ctx->cdur);
    1077             :                         }
    1078             :                 }
    1079             : 
    1080             :                 //assign some defaults
    1081        1453 :                 tkw->src_timescale = 0;
    1082        1453 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
    1083        1453 :                 if (p) tkw->src_timescale = p->value.uint;
    1084             : 
    1085             :                 u32 mtimescale = 1000;
    1086        1453 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_SAMPLE_RATE);
    1087        1453 :                 if (p) mtimescale = p->value.uint;
    1088             :                 else {
    1089        1161 :                         p = gf_filter_pid_get_property(pid, GF_PROP_PID_FPS);
    1090        1161 :                         if (p && p->value.frac.den) mtimescale = p->value.frac.den;
    1091             :                 }
    1092        1453 :                 if (!tkw->src_timescale) {
    1093           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] No timescale specified, guessing from media: %d\n", mtimescale));
    1094           0 :                         tkw->src_timescale = mtimescale;
    1095             :                 }
    1096        1453 :                 if (target_timescale) tkw->tk_timescale = target_timescale;
    1097        1450 :                 else if (ctx->mediats>0) tkw->tk_timescale = ctx->mediats;
    1098        1450 :                 else if (ctx->mediats<0) tkw->tk_timescale = mtimescale;
    1099        1450 :                 else tkw->tk_timescale = tkw->src_timescale;
    1100             : 
    1101        1453 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_ESID);
    1102        1453 :                 if (!p) p = gf_filter_pid_get_property(pid, GF_PROP_PID_ID);
    1103        1453 :                 if (p) tkid = p->value.uint;
    1104             : 
    1105        1453 :                 if (ctx->trackid) tkid = ctx->trackid;
    1106             : 
    1107        1453 :                 if (tkw->stream_type == GF_STREAM_ENCRYPTED) {
    1108         229 :                         tkw->is_encrypted = GF_TRUE;
    1109         229 :                         tkw->stream_type = gf_codecid_type(tkw->codecid);
    1110             :                 }
    1111        1453 :                 mtype = gf_isom_stream_type_to_media_type(tkw->stream_type, tkw->codecid);
    1112             : 
    1113        1453 :                 if (ctx->moovts<0) {
    1114           4 :                         ctx->moovts = tkw->tk_timescale;
    1115           4 :                         gf_isom_set_timescale(ctx->file, (u32) ctx->moovts);
    1116             :                 }
    1117             : 
    1118        1453 :                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_MUX_INDEX);
    1119        1453 :                 if (p) {
    1120         461 :                         tk_idx = p->value.uint;
    1121         461 :                         if (!ctx->owns_mov) {
    1122         461 :                                 u32 nb_dst_tk = gf_isom_get_track_count(ctx->file);
    1123         461 :                                 if (tk_idx < nb_dst_tk) {
    1124             :                                         tk_idx = nb_dst_tk;
    1125             :                                 }
    1126             :                         }
    1127             :                 }
    1128             : 
    1129        1453 :                 if (ctx->keep_utc) {
    1130           0 :                         if (!gf_isom_get_track_count(ctx->file)) {
    1131             :                                 u64 create_date=0, modif_date=0;
    1132           0 :                                 p = gf_filter_pid_get_property_str(tkw->ipid, "isom:creation_date");
    1133           0 :                                 if (p && (p->type==GF_PROP_LUINT)) create_date = p->value.longuint;
    1134           0 :                                 p = gf_filter_pid_get_property_str(tkw->ipid, "isom:modification_date");
    1135           0 :                                 if (p && (p->type==GF_PROP_LUINT)) modif_date = p->value.longuint;
    1136             : 
    1137           0 :                                 if (create_date && modif_date)
    1138           0 :                                         gf_isom_set_creation_time(ctx->file, create_date, modif_date);
    1139             :                         }
    1140           0 :                         gf_isom_keep_utc_times(ctx->file, GF_TRUE);
    1141             :                 }
    1142             : 
    1143        1453 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_ISOM_TRACK_TEMPLATE);
    1144        1453 :                 if (ctx->tktpl && p && p->value.data.ptr) {
    1145         615 :                         Bool udta_only = (ctx->tktpl==2) ? GF_TRUE : GF_FALSE;
    1146             : 
    1147             : 
    1148         615 :                         tkw->track_num = gf_isom_new_track_from_template(ctx->file, tkid, mtype, tkw->tk_timescale, p->value.data.ptr, p->value.data.size, udta_only);
    1149         615 :                         if (!tkw->track_num) {
    1150           0 :                                 tkw->track_num = gf_isom_new_track_from_template(ctx->file, 0, mtype, tkw->tk_timescale, p->value.data.ptr, p->value.data.size, udta_only);
    1151             :                         }
    1152             :                         //purge all track references we inject internally
    1153         615 :                         if (tkw->track_num) {
    1154         615 :                                 gf_isom_remove_track_reference(ctx->file, tkw->track_num, GF_ISOM_REF_SCAL);
    1155         615 :                                 gf_isom_remove_track_reference(ctx->file, tkw->track_num, GF_ISOM_REF_SABT);
    1156         615 :                                 gf_isom_remove_track_reference(ctx->file, tkw->track_num, GF_ISOM_REF_TBAS);
    1157         615 :                                 gf_isom_remove_track_reference(ctx->file, tkw->track_num, GF_ISOM_REF_OREF);
    1158         615 :                                 gf_isom_remove_track_reference(ctx->file, tkw->track_num, GF_ISOM_REF_BASE);
    1159             :                         }
    1160             : 
    1161         615 :                         if (!ctx->btrt) {
    1162           1 :                                 gf_isom_update_bitrate(ctx->file, tkw->track_num, 0, 0, 0, 0);
    1163             :                         }
    1164             :                 } else {
    1165         838 :                         if (!mtype) {
    1166             :                                 mtype = GF_4CC('u','n','k','n');
    1167           0 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] Unable to find ISOM media type for stream type %s codec %s\n", gf_stream_type_name(tkw->stream_type), gf_codecid_name(tkw->codecid) ));
    1168             :                         }
    1169         838 :                         if (!tkid) tkid = tk_idx;
    1170             : 
    1171         838 :                         tkw->track_num = gf_isom_new_track(ctx->file, tkid, mtype, tkw->tk_timescale);
    1172         838 :                         if (!tkw->track_num) {
    1173          13 :                                 tkw->track_num = gf_isom_new_track(ctx->file, 0, mtype, tkw->tk_timescale);
    1174             :                         }
    1175             :                         //FIXME once we finally merge to filters, there is an old bug in isobmff initializing the width and height to 320x240 which breaks text import
    1176             :                         //this should be removed and hashes regenerated
    1177         838 :                         gf_isom_set_track_layout_info(ctx->file, tkw->track_num, 0, 0, 0, 0, 0);
    1178             : 
    1179         838 :                         if (!gf_sys_is_test_mode()) {
    1180           1 :                                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_URL);
    1181           1 :                                 if (tkw->track_num && p && p->value.string) {
    1182             :                                         char szHName[1025];
    1183           1 :                                         char *f = gf_file_basename(p->value.string);
    1184           1 :                                         szHName[1024]=0;
    1185           1 :                                         snprintf(szHName, 1024, "*%s@GPAC%s", f ? f : "", gf_gpac_version() );
    1186           1 :                                         gf_isom_set_handler_name(ctx->file, tkw->track_num, szHName);
    1187             :                                 }
    1188             :                         }
    1189             :                 }
    1190             : 
    1191        1453 :                 if (!tkw->track_num) {
    1192           0 :                         e = gf_isom_last_error(ctx->file);
    1193           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Failed to create new track: %s\n", gf_error_to_string(e) ));
    1194             :                         return e;
    1195             :                 }
    1196        1453 :                 tkw->track_id = gf_isom_get_track_id(ctx->file, tkw->track_num);
    1197        1453 :                 tkw->next_is_first_sample = GF_TRUE;
    1198             : 
    1199             :                 //TODO: this should be the case for any new file since the redefinition of  track_in_movie and track_in_preview in ISOBMFF
    1200             :                 //This will require modifying ALL our isobmf hashes
    1201        1453 :                 if (ctx->cmaf) {
    1202           0 :                         gf_isom_set_track_flags(ctx->file, tkw->track_num, 0x7, GF_ISOM_TKFLAGS_SET);
    1203             :                 }
    1204             : 
    1205        1453 :                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_ISOM_TRACK_FLAGS);
    1206        1453 :                 if (p) {
    1207           0 :                         gf_isom_set_track_flags(ctx->file, tkw->track_num, p->value.uint, GF_ISOM_TKFLAGS_SET);
    1208             :                 } else {
    1209        1453 :                         gf_isom_set_track_enabled(ctx->file, tkw->track_num, GF_TRUE);
    1210             :                 }
    1211             : 
    1212             :                 //if we have a subtype set for the pid, use it
    1213        1453 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_SUBTYPE);
    1214        1453 :                 if (p) gf_isom_set_media_type(ctx->file, tkw->track_num, p->value.uint);
    1215             : 
    1216        1453 :                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_ISOM_HANDLER);
    1217        1453 :                 if (p && p->value.string) {
    1218           0 :                         gf_isom_set_handler_name(ctx->file, tkw->track_num, p->value.string);
    1219             :                 }
    1220             : 
    1221        1453 :                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_ISOM_TRACK_MATRIX);
    1222        1453 :                 if (p && (p->value.uint_list.nb_items==9)) {
    1223           0 :                         gf_isom_set_track_matrix(ctx->file, tkw->track_num, (s32 *) p->value.uint_list.vals);
    1224             :                 }
    1225             : 
    1226        1453 :                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_SRC_MAGIC);
    1227        1453 :                 if (p) {
    1228         561 :                         gf_isom_set_track_magic(ctx->file, tkw->track_num, p->value.longuint);
    1229             :                 }
    1230        1453 :                 if (tk_idx) {
    1231         461 :                         gf_isom_set_track_index(ctx->file, tkw->track_num, tk_idx, mp4mux_track_reorder, ctx);
    1232         461 :                         mp4mux_reorder_tracks(ctx);
    1233             :                 }
    1234             : 
    1235             :                 //by default use cttsv1 (negative ctts)
    1236        1453 :                 gf_isom_set_composition_offset_mode(ctx->file, tkw->track_num, GF_TRUE);
    1237             : 
    1238        1453 :                 p = ctx->make_qt ? NULL : gf_filter_pid_get_property(pid, GF_PROP_PID_PROFILE_LEVEL);
    1239        1450 :                 if (p) {
    1240         512 :                         tkw->media_profile_level = p->value.uint;
    1241         512 :                         if (tkw->stream_type == GF_STREAM_AUDIO) {
    1242             :                                 //patch to align old arch (IOD not written in dash) with new
    1243         203 :                                 if (!ctx->dash_mode) {
    1244         142 :                                         gf_isom_set_pl_indication(ctx->file, GF_ISOM_PL_AUDIO, p->value.uint);
    1245             :                                 }
    1246         309 :                         } else if (tkw->stream_type == GF_STREAM_VISUAL) {
    1247             :                                 //patch to align old arch (IOD not written in dash) with new
    1248         309 :                                 if (!ctx->dash_mode) {
    1249         167 :                                         gf_isom_set_pl_indication(ctx->file, GF_ISOM_PL_VISUAL, p->value.uint);
    1250             :                                 }
    1251             :                         }
    1252             :                 }
    1253             : 
    1254        1453 :                 if (ctx->mudta && gf_isom_get_track_count(ctx->file)==1) {
    1255        1213 :                         p = gf_filter_pid_get_property(pid, GF_PROP_PID_ISOM_UDTA);
    1256        1213 :                         if (ctx->tktpl && p && p->value.data.ptr) {
    1257         164 :                                 gf_isom_load_extra_boxes(ctx->file, p->value.data.ptr, p->value.data.size, (ctx->mudta==2) ? GF_TRUE : GF_FALSE);
    1258             :                         }
    1259             :                 }
    1260             : 
    1261        1453 :                 if (ctx->sgpd_traf)
    1262           1 :                         gf_isom_set_sample_group_in_traf(ctx->file);
    1263             : 
    1264        1453 :                 if (ctx->noroll) {
    1265           0 :                         gf_isom_remove_sample_group(ctx->file, tkw->track_num, GF_ISOM_SAMPLE_GROUP_ROLL);
    1266             :                 }
    1267             : 
    1268             : 
    1269        1453 :                 if (ctx->dash_mode==MP4MX_DASH_VOD) {
    1270          18 :                         Bool use_cache = (ctx->vodcache == MP4MX_VODCACHE_ON) ? GF_TRUE : GF_FALSE;
    1271          18 :                         if ((ctx->vodcache == MP4MX_VODCACHE_REPLACE) && (!ctx->media_dur || !ctx->dash_dur.num) ) {
    1272             :                                 use_cache = GF_TRUE;
    1273             :                         }
    1274             : 
    1275          18 :                         if (ctx->vodcache==MP4MX_VODCACHE_INSERT) {
    1276           0 :                                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DISABLE_PROGRESSIVE, &PROP_UINT(GF_PID_FILE_PATCH_INSERT) );
    1277             :                         }
    1278          18 :                         else if (!use_cache) {
    1279           0 :                                 gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DISABLE_PROGRESSIVE, &PROP_UINT(GF_PID_FILE_PATCH_REPLACE) );
    1280             :                         }
    1281             :                 }
    1282             : 
    1283        1453 :                 if (gf_sys_old_arch_compat()) {
    1284        1433 :                         p = gf_filter_pid_get_property_str(pid, "isom_force_ctts");
    1285        1433 :                         if (p && p->value.boolean) tkw->force_ctts = GF_TRUE;
    1286             :                 }
    1287             :         }
    1288             : 
    1289        2786 :         if (!tkw->has_brands) {
    1290             :                 Bool is_isom = GF_FALSE;
    1291        2194 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_ISOM_MBRAND);
    1292        2194 :                 if (p) {
    1293         532 :                         if (!ctx->major_brand_set) {
    1294         478 :                                 gf_isom_set_brand_info(ctx->file, p->value.uint, 1);
    1295         478 :                                 ctx->major_brand_set = p->value.uint;
    1296             :                         } else {
    1297          54 :                                 gf_isom_modify_alternate_brand(ctx->file, p->value.uint, GF_TRUE);
    1298             :                         }
    1299         532 :                         if (p->value.uint == GF_ISOM_BRAND_ISOM) is_isom = GF_TRUE;
    1300             :                 }
    1301        2194 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_ISOM_BRANDS);
    1302        2194 :                 if (p && p->value.uint_list.nb_items) {
    1303         532 :                         tkw->has_brands = GF_TRUE;
    1304         532 :                         if (!ctx->major_brand_set) {
    1305           0 :                                 ctx->major_brand_set = p->value.uint_list.vals[0];
    1306           0 :                                 gf_isom_set_brand_info(ctx->file, p->value.uint_list.vals[0], 1);
    1307             :                         }
    1308             :                         //reset alt brands, push old ones
    1309         532 :                         gf_isom_reset_alt_brands_ex(ctx->file, GF_TRUE);
    1310        1424 :                         for (i=0; i<p->value.uint_list.nb_items; i++) {
    1311         892 :                                 gf_isom_modify_alternate_brand(ctx->file, p->value.uint_list.vals[i], GF_TRUE);
    1312         892 :                                 if (p->value.uint_list.vals[i] == GF_ISOM_BRAND_ISOM) is_isom = GF_TRUE;
    1313             :                         }
    1314             :                         //and in case it was not present add major brand
    1315         532 :                         gf_isom_modify_alternate_brand(ctx->file, ctx->major_brand_set, GF_TRUE);
    1316             :                 }
    1317        2194 :                 if (!ctx->m4sys && !is_isom && !ctx->def_brand_patched) {
    1318             :                         //remove default brand
    1319         945 :                         gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_ISOM, GF_FALSE);
    1320         945 :                         ctx->def_brand_patched = GF_TRUE;
    1321             :                 }
    1322             : 
    1323        2194 :                 if (ctx->cmaf) {
    1324           0 :                         gf_isom_modify_alternate_brand(ctx->file, (ctx->cmaf==MP4MX_CMAF_CMF2) ? GF_ISOM_BRAND_CMF2 : GF_ISOM_BRAND_CMFC, GF_TRUE);
    1325             :                 }
    1326             :         }
    1327             : 
    1328        2786 :         width = height = sr = nb_chan = z_order = txt_fsize = 0;
    1329             :         nb_bps = 16;
    1330             :         ch_layout = 0;
    1331             :         fps.num = 25;
    1332             :         fps.den = 1;
    1333             :         sar.num = sar.den = 0;
    1334        2786 :         codec_id = tkw->codecid;
    1335        2786 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_DASH_MULTI_PID);
    1336        2786 :         if (p) {
    1337           0 :                 multi_pid_stsd = p->value.ptr;
    1338             : 
    1339           0 :                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_DASH_MULTI_PID_IDX);
    1340             :                 assert(p);
    1341           0 :                 multi_pid_final_stsd_idx = p->value.uint;
    1342             : 
    1343             :                 //should never be the case
    1344           0 :                 ctx->xps_inband = 0;
    1345           0 :                 ctx->dref = GF_FALSE;
    1346             :                 orig_pid = pid;
    1347           0 :                 goto multipid_stsd_setup;
    1348             :         }
    1349             : 
    1350             : 
    1351             :         //WARNING !! from this point on until the goto multipid_stsd_setup, use pid and not tkw->ipid
    1352             :         //so that we setup the sample entry properly for each PIDs
    1353        2786 : sample_entry_setup:
    1354             : 
    1355        2786 :         use_m4sys = ctx->m4sys;
    1356             :         use_gen_sample_entry = GF_TRUE;
    1357        2786 :         use_dref = ctx->dref;
    1358             : 
    1359        2786 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_WIDTH);
    1360        2786 :         if (p) width = p->value.uint;
    1361        2786 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_HEIGHT);
    1362        2786 :         if (p) height = p->value.uint;
    1363        2786 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_FPS);
    1364        2786 :         if (p) fps = p->value.frac;
    1365        2786 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_SAR);
    1366        2786 :         if (p) sar = p->value.frac;
    1367        2786 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_ZORDER);
    1368        2786 :         if (p) z_order = p->value.uint;
    1369             : 
    1370        2786 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_SAMPLE_RATE);
    1371        2786 :         if (p) sr = p->value.uint;
    1372        2786 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_NUM_CHANNELS);
    1373        2786 :         if (p) nb_chan = p->value.uint;
    1374        2786 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_AUDIO_BPS);
    1375        2786 :         if (p) nb_bps = p->value.uint;
    1376        2786 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_CHANNEL_LAYOUT);
    1377        2786 :         if (p) ch_layout = p->value.longuint;
    1378             : 
    1379        2786 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_LANGUAGE);
    1380        2786 :         if (p) lang_name = p->value.string;
    1381             : 
    1382        2786 :         if (is_true_pid) {
    1383        2759 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_NB_FRAMES);
    1384        2759 :                 if (p) tkw->nb_frames = p->value.uint;
    1385        1595 :                 else tkw->nb_frames = 0;
    1386             :         }
    1387        2786 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_ISOM_SUBTYPE);
    1388        2786 :         if (p) m_subtype_src = p->value.uint;
    1389             : 
    1390             : 
    1391             :         //get our subtype
    1392        2786 :         switch (codec_id) {
    1393          82 :         case GF_CODECID_MPEG_AUDIO:
    1394             :         case GF_CODECID_MPEG2_PART3:
    1395             :                 m_subtype = GF_ISOM_SUBTYPE_MP3;
    1396             :                 comp_name = "MP3";
    1397             :                 //if source had a DSI, this was mpeg4 systems signaling, reuse that
    1398          82 :                 if (dsi)
    1399             :                         use_m4sys = GF_TRUE;
    1400             :                 break;
    1401         350 :         case GF_CODECID_AAC_MPEG4:
    1402             :         case GF_CODECID_AAC_MPEG2_MP:
    1403             :         case GF_CODECID_AAC_MPEG2_LCP:
    1404             :         case GF_CODECID_AAC_MPEG2_SSRP:
    1405             :                 m_subtype = GF_ISOM_SUBTYPE_MPEG4;
    1406             :                 use_m4sys = GF_TRUE;
    1407             :                 comp_name = "AAC";
    1408             :                 use_gen_sample_entry = GF_FALSE;
    1409             : 
    1410         350 :                 if (ctx->importer) {
    1411          74 :                         const char *pid_args = gf_filter_pid_get_args(pid);
    1412          74 :                         if (pid_args) {
    1413          74 :                                 Bool sbr_i = strstr(pid_args, "sbr=imp") ? GF_TRUE : GF_FALSE;
    1414          74 :                                 Bool sbr_x = strstr(pid_args, "sbr=exp") ? GF_TRUE : GF_FALSE;
    1415          74 :                                 Bool ps_i = strstr(pid_args, "ps=imp") ? GF_TRUE : GF_FALSE;
    1416          74 :                                 Bool ps_x = strstr(pid_args, "ps=exp") ? GF_TRUE : GF_FALSE;
    1417             : 
    1418          74 :                                 if (sbr_x) {
    1419           3 :                                         if (ps_i) imp_name = "AAC explicit SBR implict PS";
    1420           2 :                                         else if (ps_x) imp_name = "AAC explicit SBR+PS";
    1421             :                                         else imp_name = "AAC explicit SBR";
    1422          71 :                                 } else if (sbr_i) {
    1423           3 :                                         if (ps_i) imp_name = "AAC implicit SBR+PS";
    1424           2 :                                         else if (ps_x) imp_name = "AAC implicit SBR explicit PS";
    1425             :                                         else imp_name = "AAC implicit SBR";
    1426             :                                 } else {
    1427          68 :                                         if (ps_i) imp_name = "AAC implicit PS";
    1428          67 :                                         else if (ps_x) imp_name = "AAC explicit PS";
    1429             :                                         else imp_name = "AAC ";
    1430             :                                 }
    1431             :                         }
    1432             :                 }
    1433             :                 break;
    1434             :         case GF_CODECID_USAC:
    1435             :                 m_subtype = GF_ISOM_SUBTYPE_MPEG4;
    1436             :                 use_m4sys = GF_TRUE;
    1437             :                 comp_name = "xHE-AAC / USAC";
    1438             :                 use_gen_sample_entry = GF_FALSE;
    1439             :                 break;
    1440          38 :         case GF_CODECID_JPEG:
    1441             :                 m_subtype = GF_ISOM_BOX_TYPE_JPEG;
    1442             :                 comp_name = "JPEG";
    1443          38 :                 break;
    1444          21 :         case GF_CODECID_PNG:
    1445             :                 m_subtype = GF_ISOM_BOX_TYPE_PNG;
    1446             :                 comp_name = "PNG";
    1447          21 :                 break;
    1448           7 :         case GF_CODECID_J2K:
    1449             :                 m_subtype = GF_ISOM_BOX_TYPE_MJP2;
    1450             :                 comp_name = "JPEG2000";
    1451             :                 use_mj2 = GF_TRUE;
    1452           7 :                 break;
    1453             : 
    1454           8 :         case GF_CODECID_AMR:
    1455             :                 m_subtype = GF_ISOM_SUBTYPE_3GP_AMR;
    1456             :                 comp_name = "AMR";
    1457             :                 use_3gpp_config = GF_TRUE;
    1458           8 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_AMR_MODE_SET);
    1459           8 :                 if (p && (p->value.uint!=tkw->amr_mode_set)) {
    1460           3 :                         tkw->amr_mode_set = p->value.uint;
    1461             :                         needs_sample_entry = 2;
    1462             :                 }
    1463             :                 break;
    1464           4 :         case GF_CODECID_AMR_WB:
    1465             :                 m_subtype = GF_ISOM_SUBTYPE_3GP_AMR_WB;
    1466             :                 comp_name = "AMR-WB";
    1467             :                 use_3gpp_config = GF_TRUE;
    1468           4 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_AMR_MODE_SET);
    1469           4 :                 if (p && (p->value.uint!=tkw->amr_mode_set)) {
    1470           2 :                         tkw->amr_mode_set = p->value.uint;
    1471             :                         needs_sample_entry = 2;
    1472             :                 }
    1473             :                 break;
    1474           1 :         case GF_CODECID_EVRC:
    1475             :                 m_subtype = GF_ISOM_SUBTYPE_3GP_EVRC;
    1476             :                 comp_name = "EVRC";
    1477             :                 use_3gpp_config = GF_TRUE;
    1478           1 :                 break;
    1479           0 :         case GF_CODECID_SMV:
    1480             :                 m_subtype = GF_ISOM_SUBTYPE_3GP_SMV;
    1481             :                 comp_name = "SMV";
    1482             :                 use_3gpp_config = GF_TRUE;
    1483           0 :                 break;
    1484           3 :         case GF_CODECID_QCELP:
    1485             :                 m_subtype = GF_ISOM_SUBTYPE_3GP_QCELP;
    1486             :                 comp_name = "QCELP";
    1487             :                 use_3gpp_config = GF_TRUE;
    1488           3 :                 break;
    1489           5 :         case GF_CODECID_S263:
    1490             :         case GF_CODECID_H263:
    1491             :                 m_subtype = GF_ISOM_SUBTYPE_3GP_H263;
    1492             :                 comp_name = "H263";
    1493             :                 use_3gpp_config = GF_TRUE;
    1494           5 :                 break;
    1495           9 :         case GF_CODECID_AC3:
    1496             :                 m_subtype = GF_ISOM_SUBTYPE_AC3;
    1497             :                 comp_name = "AC-3";
    1498             :                 use_ac3_entry = GF_TRUE;
    1499           9 :                 break;
    1500           2 :         case GF_CODECID_EAC3:
    1501             :                 m_subtype = GF_ISOM_SUBTYPE_AC3;
    1502             :                 comp_name = "EAC-3";
    1503             :                 use_ac3_entry = GF_TRUE;
    1504           2 :                 break;
    1505           1 :         case GF_CODECID_MPHA:
    1506           1 :                 if ((m_subtype_src!=GF_ISOM_SUBTYPE_MH3D_MHA1) && (m_subtype_src!=GF_ISOM_SUBTYPE_MH3D_MHA2))
    1507             :                         m_subtype = GF_ISOM_SUBTYPE_MH3D_MHA1;
    1508             :                 else
    1509             :                         m_subtype = m_subtype_src;
    1510             :                 comp_name = "MPEG-H Audio";
    1511             :                 nb_chan = 0;
    1512             :                 break;
    1513           2 :         case GF_CODECID_MHAS:
    1514           2 :                 if ((m_subtype_src!=GF_ISOM_SUBTYPE_MH3D_MHM1) && (m_subtype_src!=GF_ISOM_SUBTYPE_MH3D_MHM2))
    1515             :                         m_subtype = GF_ISOM_SUBTYPE_MH3D_MHM1;
    1516             :                 else
    1517             :                         m_subtype = m_subtype_src;
    1518             :                 comp_name = "MPEG-H AudioMux";
    1519             :                 nb_chan = 0;
    1520             :                 break;
    1521           2 :         case GF_CODECID_FLAC:
    1522             :                 m_subtype = GF_ISOM_SUBTYPE_FLAC;
    1523             :                 comp_name = "FLAC";
    1524             :                 use_flac_entry = GF_TRUE;
    1525           2 :                 break;
    1526           2 :         case GF_CODECID_OPUS:
    1527             :                 m_subtype = GF_ISOM_SUBTYPE_OPUS;
    1528             :                 comp_name = "Opus";
    1529             :                 use_opus = GF_TRUE;
    1530           2 :                 break;
    1531          86 :         case GF_CODECID_MPEG4_PART2:
    1532             :                 m_subtype = GF_ISOM_SUBTYPE_MPEG4;
    1533             :                 use_m4sys = GF_TRUE;
    1534             :                 comp_name = "MPEG-4 Visual Part 2";
    1535             :                 use_gen_sample_entry = GF_FALSE;
    1536          86 :                 break;
    1537         519 :         case GF_CODECID_AVC:
    1538             :         case GF_CODECID_SVC:
    1539         519 :                 m_subtype = ((ctx->xps_inband==1) || (ctx->xps_inband==2)) ? GF_ISOM_SUBTYPE_AVC3_H264 : GF_ISOM_SUBTYPE_AVC_H264;
    1540             :                 use_avc = GF_TRUE;
    1541         519 :                 comp_name = (codec_id == GF_CODECID_SVC) ? "MPEG-4 SVC" : "MPEG-4 AVC";
    1542             :                 use_gen_sample_entry = GF_FALSE;
    1543         519 :                 if (ctx->xps_inband) {
    1544             :                         use_m4sys = GF_FALSE;
    1545          23 :                         if (ctx->xps_inband==1) skip_dsi = GF_TRUE;
    1546             :                 }
    1547             :                 break;
    1548         280 :         case GF_CODECID_HEVC:
    1549             :         case GF_CODECID_LHVC:
    1550         280 :                 m_subtype = ((ctx->xps_inband==1) || (ctx->xps_inband==2)) ? GF_ISOM_SUBTYPE_HEV1  : GF_ISOM_SUBTYPE_HVC1;
    1551             :                 use_hevc = GF_TRUE;
    1552         280 :                 comp_name = (codec_id == GF_CODECID_LHVC) ? "L-HEVC" : "HEVC";
    1553             :                 use_gen_sample_entry = GF_FALSE;
    1554         280 :                 if (ctx->xps_inband) {
    1555             :                         use_m4sys = GF_FALSE;
    1556          16 :                         if (ctx->xps_inband==1) skip_dsi = GF_TRUE;
    1557             :                 }
    1558         280 :                 if (codec_id==GF_CODECID_HEVC_TILES) {
    1559             :                         m_subtype = GF_ISOM_SUBTYPE_HVT1;
    1560             :                         skip_dsi = GF_TRUE;
    1561             :                 }
    1562             :                 break;
    1563          78 :         case GF_CODECID_HEVC_TILES:
    1564             :                 m_subtype = GF_ISOM_SUBTYPE_HVT1;
    1565             :                 skip_dsi = GF_TRUE;
    1566             :                 use_hvt1 = GF_TRUE;
    1567             :                 use_m4sys = GF_FALSE;
    1568             :                 comp_name = "HEVC Tiles";
    1569             :                 use_gen_sample_entry = GF_FALSE;
    1570          78 :                 break;
    1571           0 :         case GF_CODECID_VVC:
    1572           0 :                 m_subtype = ((ctx->xps_inband==1) || (ctx->xps_inband==2)) ? GF_ISOM_SUBTYPE_VVI1  : GF_ISOM_SUBTYPE_VVC1;
    1573             :                 use_vvc = GF_TRUE;
    1574             :                 comp_name = "HEVC";
    1575             :                 use_gen_sample_entry = GF_FALSE;
    1576           0 :                 if (ctx->xps_inband==1) skip_dsi = GF_TRUE;
    1577             :                 break;
    1578          45 :         case GF_CODECID_MPEG1:
    1579             :         case GF_CODECID_MPEG2_422:
    1580             :         case GF_CODECID_MPEG2_SNR:
    1581             :         case GF_CODECID_MPEG2_HIGH:
    1582             :         case GF_CODECID_MPEG2_MAIN:
    1583             :         case GF_CODECID_MPEG2_SIMPLE:
    1584             :         case GF_CODECID_MPEG2_SPATIAL:
    1585             :                 m_subtype = GF_ISOM_SUBTYPE_MPEG4;
    1586             :                 use_m4sys = GF_TRUE;
    1587             :                 comp_name = "MPEG-2 Video";
    1588             :                 use_gen_sample_entry = GF_FALSE;
    1589          45 :                 break;
    1590           0 :         case 0:
    1591           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] muxing codecID %d not yet implemented - patch welcome\n", codec_id));
    1592             :                 return GF_NOT_SUPPORTED;
    1593             : 
    1594          45 :         case GF_ISOM_SUBTYPE_TX3G:
    1595             :                 m_subtype = GF_ISOM_SUBTYPE_TX3G;
    1596             :                 use_tx3g = GF_TRUE;
    1597             :                 comp_name = "Timed Text";
    1598             :                 is_text_subs = GF_TRUE;
    1599          45 :                 break;
    1600          42 :         case GF_ISOM_SUBTYPE_WVTT:
    1601             :                 m_subtype = GF_ISOM_SUBTYPE_WVTT;
    1602             :                 use_webvtt = GF_TRUE;
    1603             :                 comp_name = "WebVTT";
    1604             :                 is_text_subs = GF_TRUE;
    1605          42 :                 break;
    1606           1 :         case GF_CODECID_SUBPIC:
    1607             :                 use_m4sys = GF_TRUE;
    1608             :                 override_stype = GF_STREAM_ND_SUBPIC;
    1609             :                 comp_name = "VobSub";
    1610           1 :                 break;
    1611           1 :         case GF_CODECID_TEXT_MPEG4:
    1612             :                 use_m4sys = GF_TRUE;
    1613           1 :                 gf_isom_set_media_type(ctx->file, tkw->track_num, GF_ISOM_MEDIA_SCENE);
    1614             :                 comp_name = "MPEG4 Streaming Text";
    1615           1 :                 break;
    1616         226 :         case GF_CODECID_AV1:
    1617             :                 use_gen_sample_entry = GF_FALSE;
    1618             :                 m_subtype = GF_ISOM_SUBTYPE_AV01;
    1619             :                 use_av1 = GF_TRUE;
    1620             :                 comp_name = "AOM AV1 Video";
    1621         226 :                 break;
    1622             : 
    1623           1 :         case GF_CODECID_VP8:
    1624             :                 use_gen_sample_entry = GF_FALSE;
    1625             :                 m_subtype = GF_ISOM_SUBTYPE_VP08;
    1626             :                 use_vpX = GF_TRUE;
    1627             :                 comp_name = "VP8 Video";
    1628           1 :                 break;
    1629         132 :         case GF_CODECID_VP9:
    1630             :                 use_gen_sample_entry = GF_FALSE;
    1631             :                 m_subtype = GF_ISOM_SUBTYPE_VP09;
    1632             :                 use_vpX = GF_TRUE;
    1633             :                 comp_name = "VP9 Video";
    1634         132 :                 break;
    1635           0 :         case GF_CODECID_VP10:
    1636             :                 use_gen_sample_entry = GF_FALSE;
    1637             :                 m_subtype = GF_ISOM_SUBTYPE_VP10;
    1638             :                 use_vpX = GF_TRUE;
    1639             :                 comp_name = "VP10 Video";
    1640           0 :                 break;
    1641             : 
    1642          10 :         case GF_CODECID_VORBIS:
    1643             :         case GF_CODECID_THEORA:
    1644             :                 use_m4sys = GF_TRUE;
    1645          10 :                 break;
    1646             : 
    1647         693 :         case GF_CODECID_TRUEHD:
    1648             :                 m_subtype = GF_ISOM_SUBTYPE_MLPA;
    1649             :                 comp_name = "Dolby TrueHD";
    1650         693 :                 break;
    1651             : 
    1652             : 
    1653          27 :         case GF_CODECID_BIFS:
    1654             : /* ==  GF_CODECID_OD_V1:*/
    1655             :         case GF_CODECID_BIFS_V2:
    1656             : /*      == GF_CODECID_OD_V2:*/
    1657             :         case GF_CODECID_BIFS_EXTENDED:
    1658             :         case GF_CODECID_LASER:
    1659             :                 use_m4sys = GF_TRUE;
    1660          27 :                 break;
    1661           0 :         case GF_CODECID_V210:
    1662             :                 m_subtype = GF_QT_SUBTYPE_YUV422_10;
    1663             :                 comp_name = "v210 YUV 422 10 bit";
    1664             :                 use_gen_sample_entry = GF_TRUE;
    1665             :                 unknown_generic = GF_FALSE;
    1666           0 :                 break;
    1667             : 
    1668           6 :         case GF_CODECID_RAW:
    1669             :                 m_subtype = codec_id;
    1670             :                 unknown_generic = GF_TRUE;
    1671             :                 use_gen_sample_entry = GF_TRUE;
    1672             :                 use_m4sys = GF_FALSE;
    1673           6 :                 tkw->skip_bitrate_update = GF_TRUE;
    1674           6 :                 if (tkw->stream_type == GF_STREAM_AUDIO) {
    1675             :                         u32 req_non_planar_type = 0;
    1676           5 :                         p = gf_filter_pid_get_property(pid, GF_PROP_PID_AUDIO_FORMAT);
    1677           5 :                         if (!p) break;
    1678             :                         comp_name = "RawAudio";
    1679             :                         unknown_generic = GF_FALSE;
    1680             :                         //m_subtype used for QTFF-style raw media, m_subtype_alt_raw for ISOBMFF raw audio
    1681           5 :                         switch (p->value.uint) {
    1682           0 :                         case GF_AUDIO_FMT_U8P:
    1683             :                                 req_non_planar_type = GF_AUDIO_FMT_U8;
    1684             :                         case GF_AUDIO_FMT_U8:
    1685             :                                 m_subtype = GF_QT_SUBTYPE_RAW;
    1686             :                                 break;
    1687           0 :                         case GF_AUDIO_FMT_S16P:
    1688             :                                 req_non_planar_type = GF_AUDIO_FMT_S16;
    1689             :                         case GF_AUDIO_FMT_S16:
    1690             :                                 m_subtype = GF_QT_SUBTYPE_SOWT;
    1691             :                                 m_subtype_alt_raw = GF_ISOM_SUBTYPE_IPCM;
    1692             :                                 break;
    1693           0 :                         case GF_AUDIO_FMT_S24P:
    1694             :                                 req_non_planar_type = GF_AUDIO_FMT_S24;
    1695             :                         case GF_AUDIO_FMT_S24:
    1696             :                                 m_subtype = GF_QT_SUBTYPE_IN24;
    1697             :                                 m_subtype_alt_raw = GF_ISOM_SUBTYPE_IPCM;
    1698             :                                 break;
    1699           0 :                         case GF_AUDIO_FMT_S32P:
    1700             :                                 req_non_planar_type = GF_AUDIO_FMT_S32P;
    1701             :                         case GF_AUDIO_FMT_S32:
    1702             :                                 m_subtype = GF_QT_SUBTYPE_IN32;
    1703             :                                 m_subtype_alt_raw = GF_ISOM_SUBTYPE_IPCM;
    1704             :                                 break;
    1705           0 :                         case GF_AUDIO_FMT_FLTP:
    1706             :                                 req_non_planar_type = GF_AUDIO_FMT_FLTP;
    1707             :                         case GF_AUDIO_FMT_FLT:
    1708             :                                 m_subtype = GF_QT_SUBTYPE_FL32;
    1709             :                                 m_subtype_alt_raw = GF_ISOM_SUBTYPE_FPCM;
    1710             :                                 break;
    1711           0 :                         case GF_AUDIO_FMT_DBLP:
    1712             :                                 req_non_planar_type = GF_AUDIO_FMT_DBL;
    1713             :                         case GF_AUDIO_FMT_DBL:
    1714             :                                 m_subtype = GF_QT_SUBTYPE_FL64;
    1715             :                                 m_subtype_alt_raw = GF_ISOM_SUBTYPE_FPCM;
    1716             :                                 break;
    1717             :                         default:
    1718             :                                 unknown_generic = GF_TRUE;
    1719             :                                 m_subtype = p->value.uint;
    1720             :                                 break;
    1721             :                         }
    1722           5 :                         if (req_non_planar_type) {
    1723           0 :                                 if (is_true_pid)
    1724           0 :                                         gf_filter_pid_negociate_property(pid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(GF_AUDIO_FMT_S16));
    1725             :                                 else {
    1726           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] raw audio format planar in DASH multi-stsd mode is not supported, try assigning a resampler before the dasher\n"));
    1727             :                                         return GF_NOT_SUPPORTED;
    1728             :                                 }
    1729             :                         }
    1730           5 :                         raw_bitdepth = gf_audio_fmt_bit_depth(p->value.uint);
    1731             :                         tkw->raw_audio_bytes_per_sample = raw_bitdepth;
    1732           5 :                         tkw->raw_audio_bytes_per_sample *= nb_chan;
    1733           5 :                         tkw->raw_audio_bytes_per_sample /= 8;
    1734           5 :                         p = gf_filter_pid_get_property(pid, GF_PROP_PID_SAMPLE_RATE);
    1735           5 :                         tkw->raw_samplerate = p ? p->value.uint : 0;
    1736             :                         //force timescale to be samplerate, except if explicit overwrite
    1737           5 :                         if (ctx->mediats==0)
    1738           5 :                                 tkw->tk_timescale = tkw->raw_samplerate;
    1739             :                 }
    1740           1 :                 else if (tkw->stream_type == GF_STREAM_VISUAL) {
    1741           1 :                         p = gf_filter_pid_get_property(pid, GF_PROP_PID_PIXFMT);
    1742           1 :                         if (!p) break;
    1743             :                         comp_name = "RawVideo";
    1744             :                         unknown_generic = GF_FALSE;
    1745           1 :                         tkw->skip_bitrate_update = GF_TRUE;
    1746             : 
    1747           1 :                         m_subtype = gf_pixel_fmt_to_qt_type(p->value.uint);
    1748           1 :                         if (m_subtype) {
    1749           1 :                                 if (gf_pixel_fmt_is_yuv(p->value.uint))
    1750             :                                         force_colr = GF_TRUE;
    1751             :                         } else {
    1752             :                                 unknown_generic = GF_TRUE;
    1753           0 :                                 m_subtype = p->value.uint;
    1754             :                         }
    1755             :                 }
    1756             :                 break;
    1757             : 
    1758          55 :         default:
    1759             :                 m_subtype = codec_id;
    1760             :                 unknown_generic = GF_TRUE;
    1761             :                 use_gen_sample_entry = GF_TRUE;
    1762             :                 use_m4sys = GF_FALSE;
    1763          55 :                 if (is_prores)
    1764             :                         unknown_generic = GF_FALSE;
    1765             : 
    1766          55 :                 p = gf_filter_pid_get_property_str(pid, "meta:mime");
    1767          55 :                 if (p) meta_mime = p->value.string;
    1768          55 :                 p = gf_filter_pid_get_property_str(pid, "meta:encoding");
    1769          55 :                 if (p) meta_encoding = p->value.string;
    1770          55 :                 p = gf_filter_pid_get_property_str(pid, "meta:content_encoding");
    1771          55 :                 if (p) meta_content_encoding = p->value.string;
    1772          55 :                 p = gf_filter_pid_get_property_str(pid, "meta:xmlns");
    1773          55 :                 if (p) meta_xmlns = p->value.string;
    1774          55 :                 p = gf_filter_pid_get_property_str(pid, "meta:schemaloc");
    1775          55 :                 if (p) meta_schemaloc = p->value.string;
    1776          55 :                 p = gf_filter_pid_get_property_str(pid, "meta:aux_mimes");
    1777          55 :                 if (p) meta_auxmimes = p->value.string;
    1778             :                 break;
    1779             :         }
    1780        2786 :         if (!comp_name) comp_name = gf_codecid_name(codec_id);
    1781        2786 :         if (!comp_name) comp_name = gf_4cc_to_str(m_subtype);
    1782             : 
    1783        2786 :         if (dsi)
    1784        2499 :                 meta_config = dsi->value.data.ptr;
    1785             : 
    1786        2786 :         if (is_text_subs && !width && !height) {
    1787          66 :                 mp4_mux_get_video_size(ctx, &width, &height);
    1788             :         }
    1789             : 
    1790        2786 :         if (!ctx->init_movie_done && !tkw->nb_samples && (ctx->mediats<0) && (tkw->tk_timescale==1000)) {
    1791           0 :                 if (sr) {
    1792           0 :                         tkw->tk_timescale = sr;
    1793           0 :                         gf_isom_set_media_timescale(ctx->file, tkw->track_num, sr, 0, 1);
    1794             :                 }
    1795           0 :                 else if (width && fps.den) {
    1796           0 :                         tkw->tk_timescale = fps.den;
    1797           0 :                         gf_isom_set_media_timescale(ctx->file, tkw->track_num, fps.den, 0, 1);
    1798             :                 }
    1799             :         }
    1800        4332 :         if (!needs_sample_entry || tkw->is_item) {
    1801             :                 goto sample_entry_done;
    1802             :         }
    1803             : 
    1804             :         //we are fragmented, init movie done, we cannot update the sample description
    1805        1498 :         if (ctx->init_movie_done) {
    1806           8 :                 if (needs_sample_entry==1) {
    1807           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Cannot create a new sample description entry (codec change) for finalized movie in fragmented mode\n"));
    1808             :                         return GF_NOT_SUPPORTED;
    1809             :                 }
    1810             :                 force_mix_xps = GF_TRUE;
    1811        1490 :         } else if (ctx->store < MP4MX_MODE_FRAG) {
    1812        1099 :                 if ((needs_sample_entry==2) && (ctx->xps_inband==2)) {
    1813             :                         force_mix_xps = GF_TRUE;
    1814             :                 }
    1815        1092 :                 else if ((needs_sample_entry==2) && ((ctx->xps_inband==1)||(ctx->xps_inband==3)) ) {
    1816             :                         needs_sample_entry = 0;
    1817             :                         make_inband_headers = GF_TRUE;
    1818             :                 }
    1819             :         }
    1820             :         
    1821        1498 :         if (force_mix_xps) {
    1822             : 
    1823             :                 //for AVC and HEVC, move to inband params if config changed
    1824          15 :                 if (use_avc && dsi) {
    1825           9 :                         if (tkw->avcc) gf_odf_avc_cfg_del(tkw->avcc);
    1826             : 
    1827           9 :                         tkw->avcc = gf_odf_avc_cfg_read(dsi->value.data.ptr, dsi->value.data.size);
    1828             : 
    1829           9 :                         if (enh_dsi) {
    1830           0 :                                 if (tkw->svcc) gf_odf_avc_cfg_del(tkw->svcc);
    1831           0 :                                 tkw->svcc = gf_odf_avc_cfg_read(enh_dsi->value.data.ptr, enh_dsi->value.data.size);
    1832             :                         }
    1833           9 :                         if (!ctx->xps_inband) {
    1834           0 :                                 if (ctx->init_movie_done) {
    1835           0 :                                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] AVC config update after movie has been finalized, moving all SPS/PPS inband (file might not be compliant)\n"));
    1836             :                                 }
    1837           0 :                                 ctx->xps_inband = 2;
    1838             :                         }
    1839           9 :                         mp4_mux_make_inband_header(ctx, tkw, GF_FALSE);
    1840           9 :                         if (ctx->pps_inband)
    1841           0 :                                 mp4_mux_make_inband_header(ctx, tkw, GF_TRUE);
    1842             :                         return GF_OK;
    1843             :                 }
    1844           6 :                 else if (use_hevc && dsi) {
    1845           6 :                         if (tkw->hvcc) gf_odf_hevc_cfg_del(tkw->hvcc);
    1846           6 :                         tkw->hvcc = gf_odf_hevc_cfg_read(dsi->value.data.ptr, dsi->value.data.size,  (codec_id == GF_CODECID_LHVC) ? GF_TRUE : GF_FALSE);
    1847             : 
    1848           6 :                         if (enh_dsi) {
    1849           0 :                                 if (tkw->lvcc) gf_odf_hevc_cfg_del(tkw->lvcc);
    1850           0 :                                 tkw->lvcc = gf_odf_hevc_cfg_read(enh_dsi->value.data.ptr, enh_dsi->value.data.size, GF_TRUE);
    1851             :                         }
    1852           6 :                         if (!ctx->xps_inband) {
    1853           0 :                                 if (ctx->init_movie_done) {
    1854           0 :                                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] HEVC config update after movie has been finalized, moving all SPS/PPS inband (file might not be compliant)\n"));
    1855             :                                 }
    1856           0 :                                 ctx->xps_inband = 2;
    1857             :                         }
    1858           6 :                         mp4_mux_make_inband_header(ctx, tkw, GF_FALSE);
    1859           6 :                         if (ctx->pps_inband)
    1860           0 :                                 mp4_mux_make_inband_header(ctx, tkw, GF_TRUE);
    1861             :                         return GF_OK;
    1862             :                 }
    1863           0 :                 else if (use_vvc && dsi) {
    1864           0 :                         if (tkw->vvcc) gf_odf_vvc_cfg_del(tkw->vvcc);
    1865           0 :                         tkw->vvcc = gf_odf_vvc_cfg_read(dsi->value.data.ptr, dsi->value.data.size);
    1866             : 
    1867           0 :                         if (!ctx->xps_inband) {
    1868           0 :                                 if (ctx->init_movie_done) {
    1869           0 :                                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] VVC config update after movie has been finalized, moving all SPS/PPS inband (file might not be compliant)\n"));
    1870             :                                 }
    1871           0 :                                 ctx->xps_inband = 2;
    1872             :                         }
    1873           0 :                         mp4_mux_make_inband_header(ctx, tkw, GF_FALSE);
    1874           0 :                         if (ctx->pps_inband)
    1875           0 :                                 mp4_mux_make_inband_header(ctx, tkw, GF_TRUE);
    1876             :                         return GF_OK;
    1877             :                 }
    1878           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Cannot create a new sample description entry (config changed) for finalized movie in fragmented mode\n"));
    1879             :                 return GF_NOT_SUPPORTED;
    1880             :         }
    1881             : 
    1882             : 
    1883             :         //little optim here: if no samples were added on the stream description remove it
    1884        1483 :         if (!tkw->samples_in_stsd && tkw->stsd_idx) {
    1885          14 :                 gf_isom_remove_stream_description(ctx->file, tkw->track_num, tkw->stsd_idx);
    1886             :         }
    1887             : 
    1888        1483 :         if (!use_dref) src_url = NULL;
    1889             : 
    1890        1483 :         if (use_m4sys && !gf_codecid_oti(codec_id)) {
    1891             :                 use_m4sys = GF_FALSE;
    1892             :         }
    1893             :         //nope, create sample entry
    1894        1482 :         if (use_m4sys) {
    1895         401 :                 GF_ESD *esd = gf_odf_desc_esd_new(2);
    1896         401 :                 esd->decoderConfig->streamType = override_stype ? override_stype : tkw->stream_type;
    1897         401 :                 esd->decoderConfig->objectTypeIndication = gf_codecid_oti(codec_id);
    1898         401 :                 if (!esd->decoderConfig->objectTypeIndication) {
    1899           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Codec %s does not have an official MPEG-4 systems mapping, cannot mux\n", gf_codecid_name(codec_id) ));
    1900             :                         return GF_NOT_SUPPORTED;
    1901             : 
    1902             :                 }
    1903         401 :                 esd->slConfig->timestampResolution = tkw->tk_timescale;
    1904         401 :                 if (dsi && !skip_dsi) {
    1905         355 :                         esd->decoderConfig->decoderSpecificInfo->data = dsi->value.data.ptr;
    1906         355 :                         esd->decoderConfig->decoderSpecificInfo->dataLength = dsi->value.data.size;
    1907             :                 }
    1908             : 
    1909         401 :                 e = gf_isom_new_mpeg4_description(ctx->file, tkw->track_num, esd, (char *)src_url, NULL, &tkw->stsd_idx);
    1910         401 :                 if (dsi && !skip_dsi) {
    1911         355 :                         esd->decoderConfig->decoderSpecificInfo->data = NULL;
    1912         355 :                         esd->decoderConfig->decoderSpecificInfo->dataLength = 0;
    1913             :                 }
    1914         401 :                 gf_odf_desc_del((GF_Descriptor *) esd);
    1915             : 
    1916         401 :                 if (e) {
    1917           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new MPEG-4 Systems sample description for stream type %d OTI %d: %s\n", tkw->stream_type, codec_id, gf_error_to_string(e) ));
    1918             :                         return e;
    1919             :                 }
    1920             : 
    1921         401 :                 tkw->use_dref = src_url ? GF_TRUE : GF_FALSE;
    1922             : 
    1923         401 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_IN_IOD);
    1924         401 :                 if (p && p->value.boolean)
    1925          27 :                         gf_isom_add_track_to_root_od(ctx->file, tkw->track_num);
    1926             : 
    1927             : 
    1928             : #ifndef GPAC_DISABLE_AV_PARSERS
    1929         401 :                 if (dsi && (tkw->stream_type==GF_STREAM_AUDIO)) {
    1930             :                         GF_M4ADecSpecInfo acfg;
    1931         216 :                         gf_m4a_get_config(dsi->value.data.ptr, dsi->value.data.size, &acfg);
    1932         216 :                         audio_pli = acfg.audioPL;
    1933             :                 }
    1934             :                 //patch to align old arch (IOD not written in dash) with new
    1935         401 :                 if (audio_pli && !ctx->dash_mode)
    1936         278 :                         gf_isom_set_pl_indication(ctx->file, GF_ISOM_PL_AUDIO, audio_pli);
    1937             : #endif
    1938             : 
    1939        1082 :         } else if (use_avc) {
    1940         397 :                 if (tkw->avcc) gf_odf_avc_cfg_del(tkw->avcc);
    1941             : 
    1942             :                 //not yet known
    1943         397 :                 if (!dsi && !enh_dsi) return GF_OK;
    1944             : 
    1945         397 :                 if (!dsi) {
    1946             :                         dsi = enh_dsi;
    1947             :                         enh_dsi = NULL;
    1948             :                 }
    1949         397 :                 tkw->avcc = gf_odf_avc_cfg_read(dsi->value.data.ptr, dsi->value.data.size);
    1950             : 
    1951         397 :                 if (needs_sample_entry) {
    1952             : 
    1953         393 :                         if (tkw->codecid == GF_CODECID_SVC) {
    1954           2 :                                 e = gf_isom_svc_config_new(ctx->file, tkw->track_num, tkw->avcc, NULL, NULL, &tkw->stsd_idx);
    1955         391 :                         } else if (tkw->codecid == GF_CODECID_MVC) {
    1956           0 :                                 e = gf_isom_mvc_config_new(ctx->file, tkw->track_num, tkw->avcc, NULL, NULL, &tkw->stsd_idx);
    1957             :                         } else {
    1958         391 :                                 e = gf_isom_avc_config_new(ctx->file, tkw->track_num, tkw->avcc, NULL, NULL, &tkw->stsd_idx);
    1959             :                         }
    1960             : 
    1961         393 :                         if (!e && enh_dsi) {
    1962           6 :                                 if (tkw->svcc) gf_odf_avc_cfg_del(tkw->svcc);
    1963           6 :                                 tkw->svcc = gf_odf_avc_cfg_read(enh_dsi->value.data.ptr, enh_dsi->value.data.size);
    1964           6 :                                 if (tkw->svcc) {
    1965           6 :                                         if ((tkw->svcc->AVCProfileIndication==118) || (tkw->svcc->AVCProfileIndication==128)) {
    1966           0 :                                                 e = gf_isom_mvc_config_update(ctx->file, tkw->track_num, tkw->stsd_idx, tkw->svcc, GF_TRUE);
    1967             :                                         } else {
    1968           6 :                                                 e = gf_isom_svc_config_update(ctx->file, tkw->track_num, tkw->stsd_idx, tkw->svcc, GF_TRUE);
    1969             :                                         }
    1970           6 :                                         if (e) {
    1971           0 :                                                 gf_odf_avc_cfg_del(tkw->svcc);
    1972           0 :                                                 tkw->svcc = NULL;
    1973             :                                         }
    1974             : 
    1975           6 :                                         if (ctx->xps_inband) {
    1976           0 :                                                 gf_isom_avc_set_inband_config(ctx->file, tkw->track_num, tkw->stsd_idx, (ctx->xps_inband==2) ? GF_TRUE : GF_FALSE);
    1977             :                                         }
    1978             :                                 }
    1979             :                         }
    1980         393 :                         if (e) {
    1981           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new AVC sample description: %s\n", gf_error_to_string(e) ));
    1982             :                                 return e;
    1983             :                         }
    1984             :                 }
    1985             :                 
    1986         397 :                 if (ctx->xps_inband) {
    1987             :                         //this will cleanup all PS in avcC / svcC
    1988          14 :                         gf_isom_avc_set_inband_config(ctx->file, tkw->track_num, tkw->stsd_idx, (ctx->xps_inband==2) ? GF_TRUE : GF_FALSE);
    1989          14 :                         if (ctx->xps_inband==2) make_inband_headers = GF_TRUE;
    1990             :                 } else {
    1991         383 :                         gf_odf_avc_cfg_del(tkw->avcc);
    1992         383 :                         tkw->avcc = NULL;
    1993             :                 }
    1994             :                 //patch to align old arch with filters
    1995         397 :                 if (!ctx->dash_mode && !ctx->make_qt && !gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_ISOM_TREX_TEMPLATE) )
    1996         246 :                         gf_isom_set_pl_indication(ctx->file, GF_ISOM_PL_VISUAL, 0x7F);
    1997             : 
    1998         397 :                 if (!tkw->has_brands)
    1999         210 :                         gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_AVC1, GF_TRUE);
    2000             : 
    2001         397 :                 tkw->is_nalu = NALU_AVC;
    2002             : 
    2003         397 :                 tkw->use_dref = GF_FALSE;
    2004             : 
    2005         685 :         } else if (use_hvt1) {
    2006          78 :                 if (tkw->hvcc) gf_odf_hevc_cfg_del(tkw->hvcc);
    2007          78 :                 tkw->hvcc = gf_odf_hevc_cfg_new();
    2008          78 :                 e = gf_isom_hevc_config_new(ctx->file, tkw->track_num, tkw->hvcc, NULL, NULL, &tkw->stsd_idx);
    2009          78 :                 if (!e) {
    2010          78 :                         gf_isom_hevc_set_tile_config(ctx->file, tkw->track_num, tkw->stsd_idx, NULL, GF_FALSE);
    2011             :                 }
    2012          78 :                 gf_odf_hevc_cfg_del(tkw->hvcc);
    2013          78 :                 tkw->hvcc = NULL;
    2014          78 :                 tkw->is_nalu = NALU_HEVC;
    2015          78 :                 tkw->use_dref = GF_FALSE;
    2016          78 :                 if (!tkw->has_brands)
    2017          33 :                         gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_HVTI, GF_TRUE);
    2018         607 :         } else if (use_hevc) {
    2019         154 :                 if (tkw->hvcc) gf_odf_hevc_cfg_del(tkw->hvcc);
    2020             : 
    2021         154 :                 if (!dsi && !enh_dsi) {
    2022             :                         //not yet known
    2023             :                         return GF_OK;
    2024             :                 }
    2025         154 :                 if (dsi) {
    2026         154 :                         tkw->hvcc = gf_odf_hevc_cfg_read(dsi->value.data.ptr, dsi->value.data.size,  (codec_id == GF_CODECID_LHVC) ? GF_TRUE : GF_FALSE);
    2027             :                 } else {
    2028           0 :                         tkw->hvcc = gf_odf_hevc_cfg_new();
    2029             :                 }
    2030         154 :                 tkw->is_nalu = NALU_HEVC;
    2031             : 
    2032         154 :                 if (needs_sample_entry) {
    2033         151 :                         e = gf_isom_hevc_config_new(ctx->file, tkw->track_num, tkw->hvcc, NULL, NULL, &tkw->stsd_idx);
    2034             : 
    2035         151 :                         if (!tkw->has_brands) {
    2036          95 :                                 gf_isom_set_brand_info(ctx->file, GF_ISOM_BRAND_ISO4, 1);
    2037          95 :                                 gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_ISOM, GF_FALSE);
    2038             :                         }
    2039             :                         //patch for old arch
    2040          56 :                         else if (ctx->dash_mode) {
    2041             :                                 Bool force_brand=GF_FALSE;
    2042          22 :                                 if (((ctx->major_brand_set>>24)=='i') && (((ctx->major_brand_set>>16)&0xFF)=='s') && (((ctx->major_brand_set>>8)&0xFF)=='o')) {
    2043          22 :                                         if ( (ctx->major_brand_set&0xFF) <'6') force_brand=GF_TRUE;
    2044             :                                 }
    2045             : 
    2046           1 :                                 if (!force_brand && ctx->major_brand_set) {
    2047           1 :                                         gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_ISO6, GF_TRUE);
    2048             :                                 } else {
    2049          21 :                                         gf_isom_set_brand_info(ctx->file, GF_ISOM_BRAND_ISO6, 1);
    2050          21 :                                         gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_ISOM, GF_FALSE);
    2051             :                                 }
    2052             :                         }
    2053             : 
    2054         151 :                         if (!e && enh_dsi) {
    2055           8 :                                 if (tkw->lvcc) gf_odf_hevc_cfg_del(tkw->lvcc);
    2056           8 :                                 tkw->lvcc = gf_odf_hevc_cfg_read(enh_dsi->value.data.ptr, enh_dsi->value.data.size, GF_TRUE);
    2057           8 :                                 if (tkw->lvcc) {
    2058           8 :                                         e = gf_isom_lhvc_config_update(ctx->file, tkw->track_num, tkw->stsd_idx, tkw->lvcc, dsi ? GF_ISOM_LEHVC_WITH_BASE_BACKWARD : GF_ISOM_LEHVC_ONLY);
    2059           8 :                                         if (e) {
    2060           0 :                                                 gf_odf_hevc_cfg_del(tkw->lvcc);
    2061           0 :                                                 tkw->lvcc = NULL;
    2062             :                                         }
    2063             : 
    2064           8 :                                         if (!dsi && ctx->xps_inband) {
    2065           0 :                                                 gf_isom_hevc_set_inband_config(ctx->file, tkw->track_num, tkw->stsd_idx, (ctx->xps_inband==2) ? GF_TRUE : GF_FALSE);
    2066             :                                         }
    2067             :                                 }
    2068         143 :                         } else if (codec_id == GF_CODECID_LHVC) {
    2069           0 :                                 gf_isom_lhvc_config_update(ctx->file, tkw->track_num, tkw->stsd_idx, tkw->hvcc, GF_ISOM_LEHVC_ONLY);
    2070         143 :                         } else if (is_tile_base) {
    2071           5 :                                 gf_isom_lhvc_config_update(ctx->file, tkw->track_num, tkw->stsd_idx, tkw->hvcc, GF_ISOM_HEVC_TILE_BASE);
    2072             :                         }
    2073         151 :                         if (e) {
    2074           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new HEVC sample description: %s\n", gf_error_to_string(e) ));
    2075             :                                 return e;
    2076             :                         }
    2077             :                 }
    2078             : 
    2079         154 :                 if (dsi && ctx->xps_inband) {
    2080             :                         //this will cleanup all PS in avcC / svcC
    2081          10 :                         gf_isom_hevc_set_inband_config(ctx->file, tkw->track_num, tkw->stsd_idx, (ctx->xps_inband==2) ? GF_TRUE : GF_FALSE);
    2082             :                 } else {
    2083         144 :                         gf_odf_hevc_cfg_del(tkw->hvcc);
    2084         144 :                         tkw->hvcc = NULL;
    2085             :                 }
    2086             : 
    2087         154 :                 tkw->use_dref = GF_FALSE;
    2088         453 :         } else if (use_vvc) {
    2089           0 :                 if (tkw->vvcc) gf_odf_vvc_cfg_del(tkw->vvcc);
    2090             : 
    2091           0 :                 if (!dsi) {
    2092             :                         //not yet known
    2093             :                         return GF_OK;
    2094             :                 }
    2095           0 :                 tkw->vvcc = gf_odf_vvc_cfg_read(dsi->value.data.ptr, dsi->value.data.size);
    2096             : 
    2097           0 :                 tkw->is_nalu = NALU_VVC;
    2098             : 
    2099           0 :                 if (needs_sample_entry) {
    2100           0 :                         e = gf_isom_vvc_config_new(ctx->file, tkw->track_num, tkw->vvcc, NULL, NULL, &tkw->stsd_idx);
    2101             : 
    2102           0 :                         if (!tkw->has_brands) {
    2103           0 :                                 gf_isom_set_brand_info(ctx->file, GF_ISOM_BRAND_ISO4, 1);
    2104           0 :                                 gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_ISOM, GF_FALSE);
    2105             :                         }
    2106             :                         //patch for old arch
    2107           0 :                         else if (ctx->dash_mode) {
    2108             :                                 Bool force_brand=GF_FALSE;
    2109           0 :                                 if (((ctx->major_brand_set>>24)=='i') && (((ctx->major_brand_set>>16)&0xFF)=='s') && (((ctx->major_brand_set>>8)&0xFF)=='o')) {
    2110           0 :                                         if ( (ctx->major_brand_set&0xFF) <'6') force_brand=GF_TRUE;
    2111             :                                 }
    2112             : 
    2113           0 :                                 if (!force_brand && ctx->major_brand_set) {
    2114           0 :                                         gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_ISO6, GF_TRUE);
    2115             :                                 } else {
    2116           0 :                                         gf_isom_set_brand_info(ctx->file, GF_ISOM_BRAND_ISO6, 1);
    2117           0 :                                         gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_ISOM, GF_FALSE);
    2118             :                                 }
    2119             :                         }
    2120             : 
    2121           0 :                         if (e) {
    2122           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new HEVC sample description: %s\n", gf_error_to_string(e) ));
    2123             :                                 return e;
    2124             :                         }
    2125             :                 }
    2126             : 
    2127           0 :                 if (ctx->xps_inband) {
    2128             :                         //this will cleanup all PS in vvcC
    2129           0 :                         gf_isom_vvc_set_inband_config(ctx->file, tkw->track_num, tkw->stsd_idx, (ctx->xps_inband==2) ? GF_TRUE : GF_FALSE);
    2130             :                 } else {
    2131           0 :                         gf_odf_vvc_cfg_del(tkw->vvcc);
    2132           0 :                         tkw->vvcc = NULL;
    2133             :                 }
    2134             : 
    2135           0 :                 tkw->use_dref = GF_FALSE;
    2136         453 :         } else if (use_av1) {
    2137             :                 GF_AV1Config *av1c;
    2138             : 
    2139         154 :                 if (!dsi) {
    2140           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] No decoder specific info found for AV1\n"));
    2141             :                         return GF_NON_COMPLIANT_BITSTREAM;
    2142             :                 }
    2143         154 :                 av1c = gf_odf_av1_cfg_read(dsi->value.data.ptr, dsi->value.data.size);
    2144         154 :                 if (!av1c) {
    2145           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Failed to parser AV1 decoder specific info\n"));
    2146             :                         return GF_NON_COMPLIANT_BITSTREAM;
    2147             :                 }
    2148             : 
    2149         154 :                 e = gf_isom_av1_config_new(ctx->file, tkw->track_num, av1c, (char *) src_url, NULL, &tkw->stsd_idx);
    2150         154 :                 if (e) {
    2151           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new AV1 sample description: %s\n", gf_error_to_string(e) ));
    2152             :                         return e;
    2153             :                 }
    2154         154 :                 tkw->is_av1 = GF_TRUE;
    2155             : 
    2156         154 :                 if (!tkw->has_brands) {
    2157          64 :                         gf_isom_set_brand_info(ctx->file, GF_ISOM_BRAND_ISO4, 1);
    2158          64 :                         gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_ISOM, GF_FALSE);
    2159          64 :                         gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_AV01, GF_TRUE);
    2160             :                 }
    2161             : 
    2162         154 :                 gf_odf_av1_cfg_del(av1c);
    2163         299 :         } else if (use_vpX) {
    2164             :                 GF_VPConfig *vpc;
    2165             : 
    2166          28 :                 if (!dsi) {
    2167           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] No decoder specific info found for %s\n", gf_4cc_to_str(codec_id) ));
    2168             :                         return GF_NON_COMPLIANT_BITSTREAM;
    2169             :                 }
    2170          28 :                 vpc = gf_odf_vp_cfg_read(dsi->value.data.ptr, dsi->value.data.size);
    2171          28 :                 if (!vpc) {
    2172           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Failed to parser %s decoder specific info\n", gf_4cc_to_str(codec_id)));
    2173             :                         return GF_NON_COMPLIANT_BITSTREAM;
    2174             :                 }
    2175             : 
    2176          28 :                 e = gf_isom_vp_config_new(ctx->file, tkw->track_num, vpc, (char *) src_url, NULL, &tkw->stsd_idx, m_subtype);
    2177          28 :                 if (e) {
    2178           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new %s sample description: %s\n", gf_4cc_to_str(codec_id), gf_error_to_string(e) ));
    2179             :                         return e;
    2180             :                 }
    2181          28 :                 tkw->is_vpx = GF_TRUE;
    2182          28 :                 gf_odf_vp_cfg_del(vpc);
    2183         271 :         } else if (use_3gpp_config) {
    2184             :                 GF_3GPConfig gpp_cfg;
    2185             :                 memset(&gpp_cfg, 0, sizeof(GF_3GPConfig));
    2186          21 :                 gpp_cfg.type = m_subtype;
    2187          21 :                 gpp_cfg.vendor = GF_VENDOR_GPAC;
    2188             : 
    2189          21 :                 if (use_dref) {
    2190           0 :                         gpp_cfg.frames_per_sample  = 1;
    2191             :                 } else {
    2192          21 :                         gpp_cfg.frames_per_sample = ctx->pack3gp;
    2193          21 :                         if (!gpp_cfg.frames_per_sample) gpp_cfg.frames_per_sample  = 1;
    2194          21 :                         else if (gpp_cfg.frames_per_sample >15) gpp_cfg.frames_per_sample = 15;
    2195             :                 }
    2196          21 :                 gpp_cfg.AMR_mode_set = tkw->amr_mode_set;
    2197          21 :                 if (tkw->stream_type==GF_STREAM_VISUAL) {
    2198             :                         /*FIXME - we need more in-depth parsing of the bitstream to detect P3@L10 (streaming wireless)*/
    2199           5 :                         gpp_cfg.H263_profile = 0;
    2200           5 :                         gpp_cfg.H263_level = 10;
    2201           5 :                         gpp_cfg.frames_per_sample = 0;
    2202             :                 }
    2203          21 :                 tkw->nb_frames_per_sample = gpp_cfg.frames_per_sample;
    2204             : 
    2205          21 :                 e = gf_isom_3gp_config_new(ctx->file, tkw->track_num, &gpp_cfg, (char *) src_url, NULL, &tkw->stsd_idx);
    2206          21 :                 if (e) {
    2207           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new 3GPP audio sample description for stream type %d codecid %d: %s\n", tkw->stream_type, codec_id, gf_error_to_string(e) ));
    2208           0 :                         return e;
    2209             :                 }
    2210          21 :                 tkw->use_dref = src_url ? GF_TRUE : GF_FALSE;
    2211             : 
    2212          21 :                 if (!tkw->has_brands) {
    2213          21 :                         switch (gpp_cfg.type) {
    2214           4 :                         case GF_ISOM_SUBTYPE_3GP_QCELP:
    2215             :                         case GF_ISOM_SUBTYPE_3GP_EVRC:
    2216             :                         case GF_ISOM_SUBTYPE_3GP_SMV:
    2217           4 :                                 gf_isom_set_brand_info(ctx->file, GF_ISOM_BRAND_3G2A, 65536);
    2218           4 :                                 break;
    2219           5 :                         case GF_ISOM_SUBTYPE_3GP_H263:
    2220           5 :                                 gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_3GG6, GF_TRUE);
    2221           5 :                                 gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_3GG5, GF_TRUE);
    2222           5 :                                 break;
    2223             :                         }
    2224             :                 }
    2225          21 :                 tkw->skip_bitrate_update = GF_TRUE;
    2226         250 :         } else if (use_ac3_entry) {
    2227             :                 GF_AC3Config ac3cfg;
    2228             :                 memset(&ac3cfg, 0, sizeof(GF_AC3Config));
    2229             : 
    2230          11 :                 if (dsi) {
    2231           8 :                         gf_odf_ac3_config_parse(dsi->value.data.ptr, dsi->value.data.size, (codec_id==GF_CODECID_EAC3) ? GF_TRUE : GF_FALSE, &ac3cfg);
    2232             :                 }
    2233          11 :                 e = gf_isom_ac3_config_new(ctx->file, tkw->track_num, &ac3cfg, (char *)src_url, NULL, &tkw->stsd_idx);
    2234          11 :                 if (e) {
    2235           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new AC3 audio sample description for stream type %d codecid %d: %s\n", tkw->stream_type, codec_id, gf_error_to_string(e) ));
    2236           0 :                         return e;
    2237             :                 }
    2238          11 :                 tkw->use_dref = src_url ? GF_TRUE : GF_FALSE;
    2239         239 :         } else if (use_flac_entry) {
    2240           2 :                 e = gf_isom_flac_config_new(ctx->file, tkw->track_num, dsi ? dsi->value.data.ptr : NULL, dsi ? dsi->value.data.size : 0, (char *)src_url, NULL, &tkw->stsd_idx);
    2241           2 :                 if (e) {
    2242           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new FLAC audio sample description for stream type %d codecid %d: %s\n", tkw->stream_type, codec_id, gf_error_to_string(e) ));
    2243             :                         return e;
    2244             :                 }
    2245           2 :                 tkw->use_dref = src_url ? GF_TRUE : GF_FALSE;
    2246         237 :         } else if (use_opus) {
    2247           2 :                 GF_OpusSpecificBox *opus_cfg = NULL;
    2248             :                 GF_BitStream *bs;
    2249             : 
    2250           2 :                 if (!dsi) {
    2251           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] No decoder specific info found for opus\n" ));
    2252           0 :                         return GF_NON_COMPLIANT_BITSTREAM;
    2253             :                 }
    2254             : 
    2255           2 :                 bs = gf_bs_new(dsi->value.data.ptr, dsi->value.data.size, GF_BITSTREAM_READ);
    2256           2 :                 e = gf_isom_box_parse((GF_Box**)&opus_cfg, bs);
    2257           2 :                 gf_bs_del(bs);
    2258           2 :                 if (e) {
    2259           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error parsing opus configuration data: %s\n", gf_error_to_string(e) ));
    2260             :                         return e;
    2261             :                 }
    2262             : 
    2263           2 :                 e = gf_isom_opus_config_new(ctx->file, tkw->track_num, opus_cfg, (char *)src_url, NULL, &tkw->stsd_idx);
    2264           2 :                 if (opus_cfg) gf_isom_box_del((GF_Box*)opus_cfg);
    2265           2 :                 if (e) {
    2266           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new AC3 audio sample description for stream type %d codecid %d: %s\n", tkw->stream_type, codec_id, gf_error_to_string(e) ));
    2267             :                         return e;
    2268             :                 }
    2269           2 :                 tkw->use_dref = src_url ? GF_TRUE : GF_FALSE;
    2270         235 :         } else if (m_subtype == GF_ISOM_SUBTYPE_METX) {
    2271             :                 comp_name = "XML Metadata";
    2272           3 :                 e = gf_isom_new_xml_metadata_description(ctx->file, tkw->track_num, meta_xmlns, meta_schemaloc, meta_encoding, &tkw->stsd_idx);
    2273           3 :                 if (e) {
    2274           1 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new METX sample description: %s\n", gf_error_to_string(e) ));
    2275             :                         return e;
    2276             :                 }
    2277         232 :         } else if (m_subtype == GF_ISOM_SUBTYPE_METT) {
    2278             :                 comp_name = "Text Metadata";
    2279           8 :                 e = gf_isom_new_stxt_description(ctx->file, tkw->track_num, GF_ISOM_SUBTYPE_METT, meta_mime, meta_encoding, meta_config, &tkw->stsd_idx);
    2280           8 :                 if (e) {
    2281           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new METT sample description: %s\n", gf_error_to_string(e) ));
    2282             :                         return e;
    2283             :                 }
    2284         224 :         } else if (m_subtype == GF_ISOM_SUBTYPE_STPP) {
    2285          21 :                 if (meta_xmlns && !strcmp(meta_xmlns, "http://www.w3.org/ns/ttml")) {
    2286             :                         comp_name = "TTML";
    2287             :                 } else {
    2288             :                         comp_name = "XML Subtitle";
    2289             :                 }
    2290          21 :                 e = gf_isom_new_xml_subtitle_description(ctx->file, tkw->track_num, meta_xmlns, meta_schemaloc, meta_auxmimes, &tkw->stsd_idx);
    2291          21 :                 if (e) {
    2292           1 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new XML subtitle sample description: %s\n", gf_error_to_string(e) ));
    2293             :                         return e;
    2294             :                 }
    2295             : 
    2296             :                 //CMAF 11.3.2
    2297          20 :                 if (ctx->cmaf) {
    2298           0 :                         if (!meta_mime) meta_mime = gf_isom_subtitle_get_mime(ctx->file, tkw->track_num, tkw->stsd_idx);
    2299           0 :                         if (!meta_mime || (!strstr(meta_mime, "im1t") && !strstr(meta_mime, "im1i"))) {
    2300           0 :                                 gf_isom_subtitle_set_mime(ctx->file, tkw->track_num, tkw->stsd_idx, "application/ttml+xml;codecs=im1t");
    2301             :                         }
    2302             :                 }
    2303             : 
    2304             : 
    2305         203 :         } else if ((m_subtype == GF_ISOM_SUBTYPE_SBTT) || (m_subtype == GF_ISOM_SUBTYPE_STXT) ) {
    2306          17 :                 comp_name = (m_subtype == GF_ISOM_SUBTYPE_STXT) ? "Simple Timed Text" : "Textual Subtitle";
    2307          17 :                 e = gf_isom_new_stxt_description(ctx->file, tkw->track_num, m_subtype, meta_mime, meta_content_encoding, meta_config, &tkw->stsd_idx);
    2308          17 :                 if (e) {
    2309           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new %s sample description: %s\n", gf_4cc_to_str(m_subtype), gf_error_to_string(e) ));
    2310             :                         return e;
    2311             :                 }
    2312          17 :                 if (m_subtype == GF_ISOM_SUBTYPE_STXT) force_tk_layout = GF_TRUE;
    2313         186 :         } else if (use_tx3g) {
    2314             :                 GF_TextSampleDescriptor *txtc;
    2315          45 :                 if (!dsi) {
    2316           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] No decoder specific info found for TX3G\n"));
    2317             :                         return GF_NON_COMPLIANT_BITSTREAM;
    2318             :                 }
    2319          45 :                 txtc = gf_odf_tx3g_read(dsi->value.data.ptr, dsi->value.data.size);
    2320          45 :                 if (!txtc) {
    2321           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Failed to parse TX3G config\n"));
    2322             :                         return GF_NON_COMPLIANT_BITSTREAM;
    2323             :                 }
    2324             : 
    2325          45 :                 if (!txtc->default_pos.right) txtc->default_pos.right = width + txtc->default_pos.left;
    2326          45 :                 if (!txtc->default_pos.bottom) txtc->default_pos.bottom = height + txtc->default_pos.top;
    2327             : 
    2328             : 
    2329          45 :                 e = gf_isom_new_text_description(ctx->file, tkw->track_num, txtc, NULL, NULL, &tkw->stsd_idx);
    2330          45 :                 if (e) {
    2331           0 :                         gf_odf_desc_del((GF_Descriptor *)txtc);
    2332           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new %s sample description: %s\n", gf_4cc_to_str(m_subtype), gf_error_to_string(e) ));
    2333             :                         return e;
    2334             :                 }
    2335          45 :                 if (ctx->importer) {
    2336          29 :                         txt_fsize = txtc->default_style.font_size;
    2337          29 :                         if (txtc->font_count && txtc->fonts[0].fontName) txt_font = gf_strdup(txtc->fonts[0].fontName);
    2338             :                 }
    2339          45 :                 gf_odf_desc_del((GF_Descriptor *)txtc);
    2340             : 
    2341          45 :                 tkw->skip_bitrate_update = GF_TRUE;
    2342         141 :         } else if (use_webvtt) {
    2343          42 :                 e = gf_isom_new_webvtt_description(ctx->file, tkw->track_num, NULL, NULL, &tkw->stsd_idx, dsi ? dsi->value.data.ptr : NULL);
    2344          42 :                 if (e) {
    2345           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new %s sample description: %s\n", gf_4cc_to_str(m_subtype), gf_error_to_string(e) ));
    2346             :                         return e;
    2347             :                 }
    2348          42 :                 tkw->skip_bitrate_update = GF_TRUE;
    2349          99 :         } else if (use_mj2) {
    2350           7 :                 e = gf_isom_new_mj2k_description(ctx->file, tkw->track_num, NULL, NULL, &tkw->stsd_idx, dsi ? dsi->value.data.ptr : NULL, dsi ? dsi->value.data.size : 0);
    2351           7 :                 if (e) {
    2352           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new %s sample description: %s\n", gf_4cc_to_str(m_subtype), gf_error_to_string(e) ));
    2353             :                         return e;
    2354             :                 }
    2355          92 :         } else if (codec_id==GF_CODECID_TMCD) {
    2356             :                 u32 tmcd_flags=0, tmcd_fps_num=0, tmcd_fps_den=0;
    2357             :                 s32 tmcd_fpt=0;
    2358             : 
    2359           0 :                 p = gf_filter_pid_get_property_str(pid, "tmcd:flags");
    2360           0 :                 if (p) tmcd_flags = p->value.uint;
    2361           0 :                 p = gf_filter_pid_get_property_str(pid, "tmcd:framerate");
    2362           0 :                 if (p) {
    2363           0 :                         tmcd_fps_num = p->value.frac.num;
    2364           0 :                         tmcd_fps_den = p->value.frac.den;
    2365             :                 }
    2366           0 :                 p = gf_filter_pid_get_property_str(pid, "tmcd:frames_per_tick");
    2367           0 :                 if (p) tmcd_fpt = p->value.uint;
    2368           0 :                 if (tkw->tk_timescale != tmcd_fps_num) {
    2369           0 :                         tmcd_fps_den *= tmcd_fps_num;
    2370           0 :                         tmcd_fps_den /= tkw->tk_timescale;
    2371             :                 }
    2372             : 
    2373           0 :                 e = gf_isom_tmcd_config_new(ctx->file, tkw->track_num, tmcd_fps_num, tmcd_fps_den, tmcd_fpt, (tmcd_flags & 0x1), (tmcd_flags & 0x8), &tkw->stsd_idx);
    2374           0 :                 if (e) {
    2375           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new tmcd sample description: %s\n", gf_error_to_string(e) ));
    2376             :                         return e;
    2377             :                 }
    2378          92 :         } else if (codec_id==GF_CODECID_DIMS) {
    2379             :                 GF_DIMSDescription dims_c;
    2380             :                 memset(&dims_c, 0, sizeof(GF_DIMSDescription));
    2381           2 :                 dims_c.contentEncoding = meta_content_encoding;
    2382           2 :                 dims_c.mime_type = meta_mime;
    2383           2 :                 dims_c.textEncoding = meta_encoding;
    2384           2 :                 dims_c.xml_schema_loc = meta_xmlns;
    2385             : 
    2386           2 :                 p = gf_filter_pid_get_property_str(tkw->ipid, "dims:profile");
    2387           2 :                 if (p) dims_c.profile = p->value.uint;
    2388           2 :                 p = gf_filter_pid_get_property_str(tkw->ipid, "dims:level");
    2389           2 :                 if (p) dims_c.level = p->value.uint;
    2390           2 :                 p = gf_filter_pid_get_property_str(tkw->ipid, "dims:pathComponents");
    2391           2 :                 if (p) dims_c.pathComponents = p->value.uint;
    2392           2 :                 p = gf_filter_pid_get_property_str(tkw->ipid, "dims:fullRequestHost");
    2393           2 :                 if (p) dims_c.fullRequestHost = p->value.uint;
    2394           2 :                 p = gf_filter_pid_get_property_str(tkw->ipid, "dims:streamType");
    2395           2 :                 if (p) dims_c.streamType = p->value.boolean;
    2396           2 :                 p = gf_filter_pid_get_property_str(tkw->ipid, "dims:redundant");
    2397           2 :                 if (p) dims_c.containsRedundant = p->value.uint;
    2398           2 :                 p = gf_filter_pid_get_property_str(tkw->ipid, "dims:scriptTypes");
    2399           2 :                 if (p) dims_c.content_script_types = p->value.string;
    2400             : 
    2401           2 :                 e = gf_isom_new_dims_description(ctx->file, tkw->track_num, &dims_c, NULL, NULL, &tkw->stsd_idx);
    2402           2 :                 if (e) {
    2403           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new DIMS sample description: %s\n", gf_error_to_string(e) ));
    2404           0 :                         return e;
    2405             :                 }
    2406          90 :         } else if (codec_id==GF_CODECID_MPHA) {
    2407             :                 //not ready yet
    2408           1 :                 if (!dsi) return GF_OK;
    2409             : 
    2410           1 :                 e = gf_isom_new_mpha_description(ctx->file, tkw->track_num, NULL, NULL, &tkw->stsd_idx, dsi->value.data.ptr, dsi->value.data.size);
    2411           1 :                 if (e) {
    2412           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new MPEG-H Audio sample description: %s\n", gf_error_to_string(e) ));
    2413             :                         return e;
    2414             :                 }
    2415          89 :         } else if (codec_id==GF_CODECID_TRUEHD) {
    2416             :                 u32 fmt=0, prate=0;
    2417             :                 //not ready yet
    2418           1 :                 if (!dsi) return GF_OK;
    2419           1 :                 if (dsi->value.data.size < 6) return GF_NON_COMPLIANT_BITSTREAM;
    2420             : 
    2421           1 :                 fmt = dsi->value.data.ptr[0];
    2422           1 :                 fmt <<= 8;
    2423           1 :                 fmt |= dsi->value.data.ptr[1];
    2424           1 :                 prate = dsi->value.data.ptr[2];
    2425           1 :                 prate <<= 8;
    2426           1 :                 prate |= dsi->value.data.ptr[3];
    2427           1 :                 prate >>= 1;
    2428             : 
    2429           1 :                 e = gf_isom_truehd_config_new(ctx->file, tkw->track_num, (char *)src_url, NULL, fmt, prate, &tkw->stsd_idx);
    2430           1 :                 if (e) {
    2431           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new TrueHD Audio sample description: %s\n", gf_error_to_string(e) ));
    2432             :                         return e;
    2433             :                 }
    2434          88 :         } else if (use_gen_sample_entry) {
    2435             :                 u8 isor_ext_buf[14];
    2436             :                 u32 len = 0;
    2437             :                 GF_GenericSampleDescription udesc;
    2438             :                 memset(&udesc, 0, sizeof(GF_GenericSampleDescription));
    2439             : 
    2440          88 :                 if (!comp_name) comp_name = "Unknown";
    2441          88 :                 len = (u32) strlen(comp_name);
    2442          88 :                 if (len>32) len = 32;
    2443          88 :                 udesc.compressor_name[0] = len;
    2444          88 :                 memcpy(udesc.compressor_name+1, comp_name, len);
    2445          88 :                 if ((codec_id==GF_CODECID_RAW) || unknown_generic)
    2446           6 :                         udesc.vendor_code = GF_4CC('G','P','A','C');
    2447             : 
    2448          88 :                 udesc.samplerate = sr;
    2449          88 :                 udesc.nb_channels = nb_chan;
    2450          88 :                 if (codec_id==GF_CODECID_RAW) {
    2451           6 :                         if (ase_mode==GF_IMPORT_AUDIO_SAMPLE_ENTRY_v1_MPEG) {
    2452             :                                 m_subtype = m_subtype_alt_raw;
    2453           5 :                                 udesc.extension_buf_size = 14;
    2454           5 :                                 udesc.extension_buf = isor_ext_buf;
    2455             :                                 memset(isor_ext_buf, 0, sizeof(u8)*14);
    2456           5 :                                 isor_ext_buf[3] = 14;
    2457           5 :                                 isor_ext_buf[4] = 'p';
    2458           5 :                                 isor_ext_buf[5] = 'c';
    2459           5 :                                 isor_ext_buf[6] = 'm';
    2460           5 :                                 isor_ext_buf[7] = 'C';
    2461           5 :                                 isor_ext_buf[12] = 1; //little endian only for now
    2462           5 :                                 isor_ext_buf[13] = raw_bitdepth; //little endian only for now
    2463             :                         } else {
    2464           1 :                                 udesc.is_qtff = GF_TRUE;
    2465           1 :                                 udesc.version = 1;
    2466             :                                 ase_mode = GF_IMPORT_AUDIO_SAMPLE_ENTRY_v1_QTFF;
    2467             :                         }
    2468             :                 }
    2469          88 :                 udesc.codec_tag = m_subtype;
    2470          88 :                 udesc.width = width;
    2471          88 :                 udesc.height = height;
    2472          88 :                 if (width) {
    2473          20 :                         udesc.v_res = 72;
    2474          20 :                         udesc.h_res = 72;
    2475          20 :                         udesc.depth = 24;
    2476             :                 }
    2477          88 :                 if (unknown_generic) {
    2478           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] muxing unknown codec ID %s, using generic sample entry with 4CC \"%s\"\n", gf_codecid_name(codec_id), gf_4cc_to_str(m_subtype) ));
    2479             :                 }
    2480             :                 
    2481          88 :                 e = gf_isom_new_generic_sample_description(ctx->file, tkw->track_num, (char *)src_url, NULL, &udesc, &tkw->stsd_idx);
    2482          88 :                 if (e) {
    2483           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error creating new sample description for stream type %d codecid %d: %s\n", tkw->stream_type, codec_id, gf_error_to_string(e) ));
    2484           0 :                         return e;
    2485             :                 }
    2486          88 :                 tkw->use_dref = src_url ? GF_TRUE : GF_FALSE;
    2487             :         } else {
    2488             :                 assert(0);
    2489             :         }
    2490             : 
    2491        1481 :         if (ctx->btrt && !tkw->skip_bitrate_update) {
    2492             :                 u32 avg_rate, max_rate, dbsize;
    2493        1364 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_BITRATE);
    2494        1364 :                 avg_rate = p ? p->value.uint : 0;
    2495        1364 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_MAXRATE);
    2496        1364 :                 max_rate = p ? p->value.uint : 0;
    2497        1364 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_DBSIZE);
    2498        1364 :                 dbsize = p ? p->value.uint : 0;
    2499             : 
    2500        1364 :                 if (avg_rate && max_rate) {
    2501         580 :                         gf_isom_update_bitrate(ctx->file, tkw->track_num, tkw->stsd_idx, avg_rate, max_rate, dbsize);
    2502             :                 }
    2503             :         } else {
    2504         117 :                 gf_isom_update_bitrate(ctx->file, tkw->track_num, tkw->stsd_idx, 0, 0, 0);
    2505             :         }
    2506             : 
    2507        1481 : multipid_stsd_setup:
    2508        1481 :         if (multi_pid_stsd) {
    2509           0 :                 if (multi_pid_idx<gf_list_count(multi_pid_stsd)) {
    2510             : 
    2511           0 :                         if (multi_pid_final_stsd_idx == multi_pid_idx) {
    2512           0 :                                 frames_per_sample_backup = tkw->nb_frames_per_sample;
    2513           0 :                                 is_nalu_backup = tkw->is_nalu;
    2514             :                         }
    2515           0 :                         pid = gf_list_get(multi_pid_stsd, multi_pid_idx);
    2516           0 :                         multi_pid_idx ++;
    2517             :                         //reload codecID, decoder config and enhancement decoder config
    2518           0 :                         p = gf_filter_pid_get_property(pid, GF_PROP_PID_CODECID);
    2519           0 :                         if (p) codec_id = p->value.uint;
    2520           0 :                         dsi = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
    2521           0 :                         enh_dsi = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG_ENHANCEMENT);
    2522             :                         //force stsd idx to be 0 to avoid removing the stsd
    2523           0 :                         tkw->stsd_idx = 0;
    2524           0 :                         goto sample_entry_setup;
    2525             :                 }
    2526           0 :                 tkw->stsd_idx = multi_pid_final_stsd_idx;
    2527             :                 //restore input pid
    2528             :                 pid = orig_pid;
    2529           0 :                 codec_id = tkw->codecid;
    2530             : 
    2531           0 :                 tkw->is_nalu = is_nalu_backup;
    2532           0 :                 tkw->nb_frames_per_sample = frames_per_sample_backup;
    2533             :         }
    2534             : 
    2535             : 
    2536             :         //final opt: we couldn't detect before if the same stsd was possible, now that we have create a new one, check again
    2537        1481 :         if (needs_sample_entry) {
    2538             :                 reuse_stsd = 0;
    2539             :                 //don't try to reuse STSDs in multi STSD setup for DASH
    2540        1474 :                 if (multi_pid_stsd) count = 0;
    2541        1474 :                 else count = gf_isom_get_sample_description_count(ctx->file, tkw->track_num);
    2542        4423 :                 for (i=0; i<count; i++) {
    2543        1480 :                         if (i+1 == tkw->stsd_idx) continue;
    2544             : 
    2545          11 :                         if (gf_isom_is_same_sample_description(ctx->file, tkw->track_num, tkw->stsd_idx, ctx->file, tkw->track_num, i+1) ) {
    2546           5 :                                 gf_isom_remove_stream_description(ctx->file, tkw->track_num, tkw->stsd_idx);
    2547           5 :                                 tkw->stsd_idx = i+1;
    2548             :                                 reuse_stsd = 1;
    2549             :                                 break;
    2550             :                         }
    2551             :                 }
    2552             :                 if (!reuse_stsd) {
    2553        1469 :                         tkw->samples_in_stsd = 0;
    2554           5 :                 } else if (use_3gpp_config) {
    2555           0 :                         GF_3GPConfig *gpp_cfg = gf_isom_3gp_config_get(ctx->file, tkw->track_num, tkw->stsd_idx);
    2556           0 :                         if (gpp_cfg) {
    2557           0 :                                 gpp_cfg->AMR_mode_set = tkw->amr_mode_set;
    2558           0 :                                 gf_isom_3gp_config_update(ctx->file, tkw->track_num, gpp_cfg, tkw->stsd_idx);
    2559           0 :                                 gf_free(gpp_cfg);
    2560             :                         }
    2561             :                 }
    2562             :         }
    2563             : 
    2564        1481 :         if (tkw->is_encrypted) {
    2565             :                 const char *scheme_uri=NULL;
    2566             :                 const char *kms_uri=NULL;
    2567             :                 u32 scheme_version=0;
    2568             :                 u32 scheme_type = 0;
    2569             :                 Bool is_sel_enc = GF_FALSE;
    2570             :                 u32 KI_length=0;
    2571             :                 u32 IV_length=0;
    2572             :                 /*todo !*/
    2573             :                 const char *oma_contentID=0;
    2574             :                 u32 oma_encryption_type=0;
    2575             :                 u64 oma_plainTextLength=0;
    2576             :                 const char *oma_textual_headers=NULL;
    2577             :                 u32 textual_headers_len=0;
    2578             : 
    2579         229 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_PROTECTION_SCHEME_TYPE);
    2580         229 :                 if (p) scheme_type = p->value.uint;
    2581         229 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_PROTECTION_SCHEME_VERSION);
    2582         229 :                 if (p) scheme_version = p->value.uint;
    2583         229 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_PROTECTION_SCHEME_URI);
    2584         229 :                 if (p) scheme_uri = p->value.string;
    2585         229 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_PROTECTION_KMS_URI);
    2586         229 :                 if (p) kms_uri = p->value.string;
    2587             : 
    2588         229 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_ISMA_SELECTIVE_ENC);
    2589         229 :                 if (p) is_sel_enc = p->value.boolean;
    2590         229 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_ISMA_IV_LENGTH);
    2591         229 :                 if (p) IV_length = p->value.uint;
    2592         229 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_ISMA_KI_LENGTH);
    2593         229 :                 if (p) KI_length = p->value.uint;
    2594             : 
    2595         229 :                 tkw->scheme_type = scheme_type;
    2596         229 :                 switch (scheme_type) {
    2597          11 :                 case GF_ISOM_ISMACRYP_SCHEME:
    2598          11 :                         gf_isom_set_ismacryp_protection(ctx->file, tkw->track_num, tkw->stsd_idx, scheme_type, scheme_version, (char *) scheme_uri, (char *) kms_uri, is_sel_enc, KI_length, IV_length);
    2599          11 :                         break;
    2600           0 :                 case GF_ISOM_OMADRM_SCHEME:
    2601           0 :                         p = gf_filter_pid_get_property(pid, GF_PROP_PID_OMA_CRYPT_TYPE);
    2602           0 :                         if (p) oma_encryption_type = p->value.uint;
    2603           0 :                         p = gf_filter_pid_get_property(pid, GF_PROP_PID_OMA_CID);
    2604           0 :                         if (p) oma_contentID = p->value.string;
    2605           0 :                         p = gf_filter_pid_get_property(pid, GF_PROP_PID_OMA_TXT_HDR);
    2606           0 :                         if (p) oma_textual_headers = p->value.string;
    2607           0 :                         if (oma_textual_headers) textual_headers_len = (u32) strlen(oma_textual_headers);
    2608           0 :                         p = gf_filter_pid_get_property(pid, GF_PROP_PID_OMA_CLEAR_LEN);
    2609           0 :                         if (p) oma_plainTextLength = p->value.longuint;
    2610           0 :                         gf_isom_set_oma_protection(ctx->file, tkw->track_num, tkw->stsd_idx, (char *) oma_contentID, (char*) kms_uri, oma_encryption_type, oma_plainTextLength, (char*)oma_textual_headers, textual_headers_len,
    2611             :                                   is_sel_enc, KI_length, IV_length);
    2612             : 
    2613           0 :                         break;
    2614          10 :                 case GF_ISOM_ADOBE_SCHEME:
    2615          10 :                         p = gf_filter_pid_get_property(pid, GF_PROP_PID_ADOBE_CRYPT_META);
    2616          10 :                         gf_isom_set_adobe_protection(ctx->file, tkw->track_num, tkw->stsd_idx, scheme_type, 1/*scheme_version*/, 1/*is_sel_enc*/,p ? p->value.data.ptr : NULL, p ? p->value.data.size : 0);
    2617          10 :                         break;
    2618         208 :                 case GF_ISOM_PIFF_SCHEME:
    2619             :                 case GF_ISOM_CENC_SCHEME:
    2620             :                 case GF_ISOM_CENS_SCHEME:
    2621             :                 case GF_ISOM_CBC_SCHEME:
    2622             :                 case GF_ISOM_CBCS_SCHEME:
    2623         208 :                         tkw->cenc_state = CENC_NEED_SETUP;
    2624         208 :                         if (tkw->is_nalu || tkw->is_av1 || tkw->is_vpx) tkw->cenc_subsamples = GF_TRUE;
    2625             :                         break;
    2626           0 :                 default:
    2627           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] Unrecognized protection scheme type %s, using generic signaling\n", gf_4cc_to_str(tkw->stream_type) ));
    2628           0 :                         switch (tkw->stream_type) {
    2629           0 :                         case GF_STREAM_VISUAL:
    2630           0 :                                 gf_isom_set_media_type(ctx->file, tkw->track_num, GF_ISOM_BOX_TYPE_ENCV);
    2631           0 :                                 break;
    2632           0 :                         case GF_STREAM_AUDIO:
    2633           0 :                                 gf_isom_set_media_type(ctx->file, tkw->track_num, GF_ISOM_BOX_TYPE_ENCA);
    2634           0 :                                 break;
    2635           0 :                         case GF_STREAM_TEXT:
    2636           0 :                                 gf_isom_set_media_type(ctx->file, tkw->track_num, GF_ISOM_BOX_TYPE_ENCT);
    2637           0 :                                 break;
    2638           0 :                         case GF_STREAM_FONT:
    2639           0 :                                 gf_isom_set_media_type(ctx->file, tkw->track_num, GF_ISOM_BOX_TYPE_ENCF);
    2640           0 :                                 break;
    2641           0 :                         default:
    2642           0 :                                 gf_isom_set_media_type(ctx->file, tkw->track_num, GF_ISOM_BOX_TYPE_ENCS);
    2643           0 :                                 break;
    2644             :                         }
    2645           0 :                         gf_isom_set_generic_protection(ctx->file, tkw->track_num, tkw->stsd_idx, scheme_type, scheme_version, (char*)scheme_uri, (char*)kms_uri);
    2646             :                 }
    2647             :         } else {
    2648             :                 //in case we used track template
    2649        1252 :                 gf_isom_remove_samp_enc_box(ctx->file, tkw->track_num);
    2650        1252 :                 gf_isom_remove_samp_group_box(ctx->file, tkw->track_num);
    2651             :         }
    2652             : 
    2653        1481 :         if (is_true_pid) {
    2654        1454 :                 mp4_mux_write_track_refs(ctx, tkw, "isom:scal", GF_ISOM_REF_SCAL);
    2655        1454 :                 mp4_mux_write_track_refs(ctx, tkw, "isom:sabt", GF_ISOM_REF_SABT);
    2656        1454 :                 mp4_mux_write_track_refs(ctx, tkw, "isom:tbas", GF_ISOM_REF_TBAS);
    2657             :                 //whenever we add a new tile track, rewrite sabt on main tile track
    2658        1454 :                 if (codec_id==GF_CODECID_HEVC_TILES) {
    2659          51 :                         count = gf_list_count(ctx->tracks);
    2660         168 :                         for (i=0; i<count; i++) {
    2661         117 :                                 TrackWriter *base_tk = gf_list_get(ctx->tracks, i);
    2662         117 :                                 if (base_tk->is_hevc_tile_base)
    2663          15 :                                         mp4_mux_write_track_refs(ctx, base_tk, "isom:sabt", GF_ISOM_REF_SABT);
    2664             :                         }
    2665             :                 }
    2666             : 
    2667             :                 //check if we have sample-accurate seek info for the pid. If so, enable seek ts checking
    2668        1454 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PCK_SKIP_BEGIN);
    2669        1454 :                 if (p && p->value.sint)
    2670          10 :                         tkw->check_seek_ts = GF_TRUE;
    2671             : 
    2672          27 :         } else if (codec_id==GF_CODECID_HEVC_TILES) {
    2673          27 :                 mp4_mux_write_track_refs(ctx, tkw, "isom:tbas", GF_ISOM_REF_TBAS);
    2674             :         }
    2675             : 
    2676        1481 :         if (is_true_pid && ctx->dash_mode && is_tile_base) {
    2677           3 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_DASH_MULTI_TRACK);
    2678           3 :                 if (p) {
    2679           3 :                         GF_List *multi_tracks = p->value.ptr;
    2680           3 :                         count = gf_list_count(multi_tracks);
    2681          30 :                         for (i=0; i<count; i++) {
    2682          27 :                                 GF_FilterPid *a_ipid = gf_list_get(multi_tracks, i);
    2683          27 :                                 mp4_mux_setup_pid(filter, a_ipid, GF_FALSE);
    2684             :                         }
    2685             :                 }
    2686             :         }
    2687             : 
    2688        1481 :         if (width) {
    2689        1082 :                 if (ctx->ccst) {
    2690           0 :                         e = gf_isom_set_image_sequence_coding_constraints(ctx->file, tkw->track_num, tkw->stsd_idx, GF_FALSE, GF_FALSE, GF_TRUE, 15);
    2691           0 :                         if (e) {
    2692           0 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] Failed to set coding constraints parameter: %s\n", gf_error_to_string(e) ));
    2693             :                         }
    2694             :                 }
    2695        1082 :                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_ALPHA);
    2696        1083 :                 if (p && p->value.boolean) {
    2697           1 :                         e = gf_isom_set_image_sequence_alpha(ctx->file, tkw->track_num, tkw->stsd_idx, GF_FALSE);
    2698           1 :                         if (e) {
    2699           0 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] Failed to set alpha config: %s\n", gf_error_to_string(e) ));
    2700             :                         }
    2701             :                 }
    2702             :         }
    2703             : 
    2704        5538 : sample_entry_done:
    2705        2769 :         if (!tkw->is_item) {
    2706        2721 :                 if (ctx->maxchunk)
    2707           0 :                         gf_isom_hint_max_chunk_size(ctx->file, tkw->track_num, ctx->maxchunk);
    2708             : 
    2709        2721 :                 if (ctx->store==MP4MX_MODE_FLAT)
    2710           0 :                         gf_isom_hint_max_chunk_duration(ctx->file, tkw->track_num, tkw->tk_timescale * ctx->cdur.num / ctx->cdur.den);
    2711             : 
    2712        2721 :                 if (sr) {
    2713        1150 :                         if (use_flac_entry) {
    2714           2 :                                 while (sr>65535) {
    2715           0 :                                         u32 val = sr/2;
    2716           0 :                                         if (val*2 != sr) {
    2717             :                                                 sr=65535;
    2718             :                                                 break;
    2719             :                                         }
    2720             :                                         sr = val;
    2721             :                                 }
    2722             :                         }
    2723        1150 :                         gf_isom_set_audio_info(ctx->file, tkw->track_num, tkw->stsd_idx, sr, nb_chan, nb_bps, ctx->make_qt ? GF_IMPORT_AUDIO_SAMPLE_ENTRY_v1_QTFF : ase_mode);
    2724        1150 :                         if ((m_subtype==GF_ISOM_SUBTYPE_IPCM) || (m_subtype==GF_ISOM_SUBTYPE_FPCM)) {
    2725             :                                 GF_AudioChannelLayout layout;
    2726             :                                 memset(&layout, 0, sizeof(GF_AudioChannelLayout));
    2727           5 :                                 layout.stream_structure = 1;
    2728           5 :                                 layout.channels_count = nb_chan;
    2729           5 :                                 if (ch_layout)
    2730           0 :                                         layout.definedLayout = gf_audio_fmt_get_cicp_from_layout(ch_layout);
    2731             :                                 else
    2732           5 :                                         layout.definedLayout = gf_audio_fmt_get_cicp_layout(nb_chan, 0, 0);
    2733           5 :                                 gf_isom_set_audio_layout(ctx->file, tkw->track_num, tkw->stsd_idx, &layout);
    2734             :                         }
    2735             :                 }
    2736        1571 :                 else if (width) {
    2737        1458 :                         u32 colour_type=0;
    2738        1458 :                         u16 colour_primaries=0, transfer_characteristics=0, matrix_coefficients=0;
    2739        1458 :                         Bool full_range_flag=GF_FALSE;
    2740             : 
    2741        1458 :                         gf_isom_set_visual_info(ctx->file, tkw->track_num, tkw->stsd_idx, width, height);
    2742        1458 :                         if (sar.den) {
    2743         113 :                                 if (sar.num != sar.den) {
    2744          26 :                                         gf_isom_set_pixel_aspect_ratio(ctx->file, tkw->track_num, tkw->stsd_idx, sar.num, sar.den, GF_FALSE);
    2745          26 :                                         width = width * sar.num / sar.den;
    2746             :                                 }
    2747             :                                 //old importer did not set PASP for
    2748          87 :                                 else if (!gf_sys_old_arch_compat() || (codec_id!=GF_CODECID_MPEG4_PART2) ) {
    2749          39 :                                         gf_isom_set_pixel_aspect_ratio(ctx->file, tkw->track_num, tkw->stsd_idx, 1, 1, GF_TRUE);
    2750             :                                 }
    2751             :                         }
    2752             : 
    2753        1458 :                         gf_isom_set_track_layout_info(ctx->file, tkw->track_num, width<<16, height<<16, 0, 0, z_order);
    2754        1458 :                         if (codec_id==GF_CODECID_HEVC_TILES) {
    2755          78 :                                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_ORIG_SIZE);
    2756          78 :                                 if (p) {
    2757          45 :                                         gf_isom_set_track_layout_info(ctx->file, tkw->track_num, p->value.vec2i.x<<16, p->value.vec2i.y<<16, 0, 0, z_order);
    2758             :                                 }
    2759             :                         }
    2760             : 
    2761        1458 :                         p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_COLR_PRIMARIES);
    2762        1458 :                         if (p) colour_primaries = p->value.uint;
    2763        1458 :                         p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_COLR_TRANSFER);
    2764        1458 :                         if (p) transfer_characteristics = p->value.uint;
    2765        1458 :                         p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_COLR_MX);
    2766        1458 :                         if (p) matrix_coefficients = p->value.uint;
    2767        1458 :                         p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_COLR_RANGE);
    2768        1458 :                         if (p) full_range_flag = p->value.boolean;
    2769             : 
    2770        1458 :                         if (ctx->cmaf) {
    2771           0 :                                 u32 hspac=0, vspac=0;
    2772             :                                 force_colr = GF_TRUE;
    2773           0 :                                 gf_isom_get_pixel_aspect_ratio(ctx->file, tkw->track_num, tkw->stsd_idx, &hspac, &vspac);
    2774           0 :                                 if (hspac && vspac) {
    2775           0 :                                         sar.num = hspac;
    2776           0 :                                         sar.den = vspac;
    2777             :                                 } else {
    2778             :                                         sar.den = 0;
    2779             :                                 }
    2780             :                         }
    2781             : 
    2782        1458 :                         if ((ctx->prores_track == tkw) || force_colr) {
    2783             :                                 u32 colr_mode;
    2784             : 
    2785           4 :                                 if ((ctx->prores_track == tkw) || ctx->make_qt)
    2786             :                                         colr_mode = GF_4CC('n','c','l','c');
    2787             :                                 else
    2788             :                                         colr_mode = GF_4CC('n','c','l','x');
    2789             : 
    2790             : 
    2791             :                                 //other conditions were set above, here we force 1:1 pasp box even if no sar or 1:1
    2792           4 :                                 if (!sar.den || (sar.num == 1)) {
    2793           3 :                                         gf_isom_set_pixel_aspect_ratio(ctx->file, tkw->track_num, tkw->stsd_idx, -1, -1, GF_TRUE);
    2794             :                                 }
    2795             : 
    2796           4 :                                 if (colour_primaries || transfer_characteristics || matrix_coefficients) {
    2797           2 :                                         gf_isom_set_visual_color_info(ctx->file, tkw->track_num, tkw->stsd_idx, colr_mode, colour_primaries, transfer_characteristics, matrix_coefficients, GF_FALSE, NULL, 0);
    2798             :                                 } else {
    2799           2 :                                         e = gf_isom_get_color_info(ctx->file, tkw->track_num, tkw->stsd_idx, &colour_type, &colour_primaries, &transfer_characteristics, &matrix_coefficients, &full_range_flag);
    2800           2 :                                         if (e==GF_NOT_FOUND) {
    2801           1 :                                                 e = gf_media_get_color_info(ctx->file, tkw->track_num, tkw->stsd_idx, &colour_type, &colour_primaries, &transfer_characteristics, &matrix_coefficients, &full_range_flag);
    2802           1 :                                                 if (e)
    2803             :                                                         e = GF_NOT_FOUND;
    2804             :                                         }
    2805           1 :                                         if (e==GF_NOT_FOUND) {
    2806           1 :                                                 colour_primaries = 1;
    2807           1 :                                                 transfer_characteristics = 1;
    2808           1 :                                                 matrix_coefficients = 1;
    2809           1 :                                                 full_range_flag = GF_FALSE;
    2810           1 :                                                 if (ctx->make_qt==1) {
    2811           0 :                                                         GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[ProRes] No color info present in visual track, defaulting to BT709\n"));
    2812             :                                                 }
    2813           1 :                                                 else if (ctx->cmaf) {
    2814           0 :                                                         GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[CMAF] No color info present in visual track, defaulting to BT709\n"));
    2815             :                                                 }
    2816             :                                         }
    2817           2 :                                         gf_isom_set_visual_color_info(ctx->file, tkw->track_num, tkw->stsd_idx, colr_mode, colour_primaries, transfer_characteristics, matrix_coefficients, full_range_flag, NULL, 0);
    2818             :                                 }
    2819             : 
    2820           4 :                                 if (ctx->prores_track == tkw) {
    2821             :                                         u32 chunk_size;
    2822           4 :                                         if ((width<=720) && (height<=576)) chunk_size = 2000000;
    2823             :                                         else chunk_size = 4000000;
    2824           4 :                                         gf_isom_hint_max_chunk_size(ctx->file, tkw->track_num, chunk_size);
    2825             :                                 }
    2826             :                         } else {
    2827        1454 :                                 if (colour_primaries || transfer_characteristics || matrix_coefficients) {
    2828          75 :                                         gf_isom_set_visual_color_info(ctx->file, tkw->track_num, tkw->stsd_idx, GF_4CC('n','c','l','x'), colour_primaries, transfer_characteristics, matrix_coefficients, full_range_flag, NULL, 0);
    2829             :                                 }
    2830             : 
    2831             :                         }
    2832             :                 }
    2833             :                 //default for old arch
    2834         113 :                 else if (force_tk_layout
    2835         106 :                         || (use_m4sys && (tkw->stream_type==GF_STREAM_VISUAL) && !width && !height)
    2836             :                 )  {
    2837          35 :                         gf_isom_set_track_layout_info(ctx->file, tkw->track_num, 320<<16, 240<<16, 0, 0, 0);
    2838             :                 }
    2839             : 
    2840        2721 :                 if (lang_name) gf_isom_set_media_language(ctx->file, tkw->track_num, (char*)lang_name);
    2841             : 
    2842        2721 :                 p = gf_filter_pid_get_property(pid, GF_PROP_PID_ISOM_STSD_TEMPLATE);
    2843        2721 :                 if (ctx->tktpl && p && p->value.data.ptr) {
    2844        1109 :                         gf_isom_update_sample_description_from_template(ctx->file, tkw->track_num, tkw->stsd_idx, p->value.data.ptr, p->value.data.size);
    2845             :                 }
    2846             :         }
    2847             : 
    2848        2769 :         if (tkw->is_encrypted) {
    2849         575 :                 tkw->cenc_ki = gf_filter_pid_get_property(pid, GF_PROP_PID_CENC_KEY_INFO);
    2850         575 :                 if (tkw->cenc_ki && ((tkw->cenc_ki->type != GF_PROP_DATA) || !gf_cenc_validate_key_info(tkw->cenc_ki->value.data.ptr, tkw->cenc_ki->value.data.size))
    2851             :                 ) {
    2852           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Invalid CENC key info\n"));
    2853           0 :                         tkw->cenc_ki = NULL;
    2854             :                 }
    2855             : 
    2856         575 :                 tkw->constant_IV_size = 0;
    2857         575 :                 if (tkw->cenc_ki && tkw->cenc_ki->value.data.ptr) {
    2858         554 :                         tkw->cenc_multikey = tkw->cenc_ki->value.data.ptr[0] ? GF_TRUE : GF_FALSE;
    2859             : 
    2860         554 :                         if (!tkw->cenc_ki->value.data.ptr[3])
    2861          19 :                                 tkw->constant_IV_size = !tkw->cenc_ki->value.data.ptr[20];
    2862             : 
    2863         554 :                         tkw->cenc_key_info_crc = gf_crc_32(tkw->cenc_ki->value.data.ptr, tkw->cenc_ki->value.data.size);
    2864             :                 }
    2865             :         }
    2866             : 
    2867        2769 :         if (is_true_pid) {
    2868        2742 :                 const GF_PropertyValue *ster = gf_filter_pid_get_property(pid, GF_PROP_PID_STEREO_TYPE);
    2869        2742 :                 const GF_PropertyValue *proj = gf_filter_pid_get_property(pid, GF_PROP_PID_PROJECTION_TYPE);
    2870        2742 :                 const GF_PropertyValue *pose = gf_filter_pid_get_property(pid, GF_PROP_PID_VR_POSE);
    2871             : 
    2872        2742 :                 if (ster || proj) {
    2873             :                         GF_ISOM_Y3D_Info yt3d;
    2874             :                         memset(&yt3d, 0, sizeof(GF_ISOM_Y3D_Info));
    2875           0 :                         yt3d.projection_type = proj ? proj->value.uint : 0;
    2876           0 :                         yt3d.stereo_type = ster ? ster->value.uint : 0;
    2877           0 :                         if (pose) {
    2878           0 :                                 yt3d.pose_present = GF_TRUE;
    2879           0 :                                 yt3d.yaw = pose->value.vec3i.x;
    2880           0 :                                 yt3d.pitch = pose->value.vec3i.y;
    2881           0 :                                 yt3d.roll = pose->value.vec3i.z;
    2882           0 :                                 yt3d.stereo_type = ster ? ster->value.uint : 0;
    2883             :                         }
    2884           0 :                         if (yt3d.projection_type==GF_PROJ360_CUBE_MAP) {
    2885           0 :                                 proj = gf_filter_pid_get_property(pid, GF_PROP_PID_CUBE_MAP_PAD);
    2886           0 :                                 yt3d.padding = proj ? proj->value.uint : 0;
    2887             :                         }
    2888           0 :                         else if (yt3d.projection_type==GF_PROJ360_EQR) {
    2889           0 :                                 proj = gf_filter_pid_get_property(pid, GF_PROP_PID_EQR_CLAMP);
    2890           0 :                                 if (proj) {
    2891           0 :                                         yt3d.top = proj->value.vec4i.x;
    2892           0 :                                         yt3d.bottom = proj->value.vec4i.y;
    2893           0 :                                         yt3d.left = proj->value.vec4i.z;
    2894           0 :                                         yt3d.right = proj->value.vec4i.w;
    2895             :                                 }
    2896             :                         }
    2897           0 :                         gf_isom_set_y3d_info(ctx->file, tkw->track_num, tkw->stsd_idx, &yt3d);
    2898             :                 }
    2899             :         }
    2900             : 
    2901             : 
    2902        2769 :         if (is_true_pid && ctx->importer && !tkw->import_msg_header_done) {
    2903             : #ifndef GPAC_DISABLE_LOG
    2904         613 :                 const char *dst_type = tkw->is_item ? "Item Importing" : "Track Importing";
    2905             : #endif
    2906         613 :                 tkw->import_msg_header_done = GF_TRUE;
    2907         613 :                 if (!imp_name) imp_name = comp_name;
    2908         613 :                 if (sr) {
    2909         120 :                         if (nb_chan) {
    2910         119 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("%s %s - SampleRate %d Num Channels %d\n", dst_type, imp_name, sr, nb_chan));
    2911             :                         } else {
    2912           1 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("%s %s - SampleRate %d\n", dst_type, imp_name, sr));
    2913             :                         }
    2914         493 :                 } else if (is_text_subs) {
    2915          70 :                         if (txt_fsize || txt_font) {
    2916          28 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("%s %s - Text track %d x %d font %s (size %d) layer %d\n", dst_type, imp_name, width, height, txt_font ? txt_font : "unspecified", txt_fsize, z_order));
    2917             :                         } else {
    2918          42 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("%s %s - Text track %d x %d layer %d\n", dst_type, imp_name, width, height, z_order));
    2919             : 
    2920             :                         }
    2921         423 :                 } else if (width) {
    2922         379 :                         if (sar.den && sar.num) {
    2923          37 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("%s %s - Width %d Height %d FPS %d/%d SAR %d/%u\n", dst_type, imp_name, width, height, fps.num, fps.den, sar.num, sar.den));
    2924             :                         } else {
    2925         342 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("%s %s - Width %d Height %d FPS %d/%d\n", dst_type, imp_name, width, height, fps.num, fps.den));
    2926             :                         }
    2927             :                 } else {
    2928          44 :                         GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("%s %s\n", dst_type, imp_name));
    2929             :                 }
    2930             : #ifndef GPAC_DISABLE_AV_PARSERS
    2931         613 :                 if (tkw->svcc) {
    2932             :                         AVCState avc;
    2933             :                         memset(&avc, 0, sizeof(AVCState));
    2934           3 :                         count = gf_list_count(tkw->svcc->sequenceParameterSets);
    2935           8 :                         for (i=0; i<count; i++) {
    2936           5 :                                 GF_NALUFFParam *sl = gf_list_get(tkw->svcc->sequenceParameterSets, i);
    2937           5 :                                 u8 nal_type = sl->data[0] & 0x1F;
    2938           5 :                                 Bool is_subseq = (nal_type == GF_AVC_NALU_SVC_SUBSEQ_PARAM) ? GF_TRUE : GF_FALSE;
    2939           5 :                                 s32 ps_idx = gf_avc_read_sps(sl->data, sl->size, &avc, is_subseq, NULL);
    2940           5 :                                 if (ps_idx>=0) {
    2941           5 :                                         GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("SVC Detected - SSPS ID %d - frame size %d x %d\n", ps_idx-GF_SVC_SSPS_ID_SHIFT, avc.sps[ps_idx].width, avc.sps[ps_idx].height ));
    2942             : 
    2943             :                                 }
    2944             :                         }
    2945             :                 }
    2946             : #endif
    2947             : 
    2948             :         }
    2949        2769 :         if (txt_font) gf_free(txt_font);
    2950        2769 :         if (!ctx->xps_inband || tkw->is_item) {
    2951        2745 :                 if (tkw->svcc) {
    2952           6 :                         gf_odf_avc_cfg_del(tkw->svcc);
    2953           6 :                         tkw->svcc = NULL;
    2954             :                 }
    2955        2745 :                 if (tkw->lvcc) {
    2956           8 :                         gf_odf_hevc_cfg_del(tkw->lvcc);
    2957           8 :                         tkw->lvcc = NULL;
    2958             :                 }
    2959          24 :         } else if (needs_sample_entry || make_inband_headers) {
    2960          24 :                 mp4_mux_make_inband_header(ctx, tkw, GF_FALSE);
    2961          24 :                 if (ctx->pps_inband)
    2962           0 :                         mp4_mux_make_inband_header(ctx, tkw, GF_TRUE);
    2963             :         }
    2964             : 
    2965        2769 :         tkw->negctts_shift = 0;
    2966        2769 :         tkw->probe_min_ctts = GF_FALSE;
    2967        2769 :         if (is_true_pid && !tkw->nb_samples && !tkw->is_item) {
    2968             :                 Bool use_negccts = GF_FALSE;
    2969             :                 Bool remove_edits = GF_FALSE;
    2970        1461 :                 s64 moffset=0;
    2971        1461 :                 ctx->config_timing = GF_TRUE;
    2972        1461 :                 ctx->update_report = GF_TRUE;
    2973             : 
    2974             :                 //if we have an edit list (due to track template) only providing media offset, trash it
    2975        1461 :                 if (!gf_isom_get_edit_list_type(ctx->file, tkw->track_num, &moffset)) {
    2976        1461 :                         if (!gf_sys_old_arch_compat()) {
    2977          11 :                                 gf_isom_remove_edits(ctx->file, tkw->track_num);
    2978             :                         } else {
    2979             :                                 //old arch compat: if we had a simple edit list in source, keep dur and offset
    2980             :                                 //and avoid rewriting it when recomputing edit for b-frames
    2981             :                                 u64 etime, sdur;
    2982             :                                 GF_ISOEditType etype;
    2983        1450 :                                 gf_isom_get_edit(ctx->file, tkw->track_num, 1, &etime, &sdur, &moffset, &etype);
    2984        1450 :                                 if (!etime && sdur) {
    2985         192 :                                         tkw->imported_edit_sdur = sdur;
    2986         192 :                                         tkw->imported_edit_offset = moffset;
    2987             :                                 }
    2988             :                                 remove_edits = GF_TRUE;
    2989             :                         }
    2990             :                 }
    2991        1461 :                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_DELAY);
    2992        1461 :                 if (p) {
    2993             :                         //media skip
    2994         136 :                         if (p->value.longsint < 0) {
    2995             :                                 //if cmf2, remove edits and use negctss
    2996         136 :                                 if ((ctx->cmaf==MP4MX_CMAF_CMF2) && (tkw->stream_type==GF_STREAM_VISUAL)) {
    2997           0 :                                         ctx->ctmode = MP4MX_CT_NEGCTTS;
    2998           0 :                                         gf_isom_remove_edits(ctx->file, tkw->track_num);
    2999           0 :                                         use_negccts = GF_TRUE;
    3000             :                                 }
    3001         136 :                                 else if ((ctx->ctmode==MP4MX_CT_NEGCTTS) && (tkw->stream_type==GF_STREAM_VISUAL)) {
    3002             :                                         use_negccts = GF_TRUE;
    3003             :                                 } else {
    3004         136 :                                         if (remove_edits) {
    3005         136 :                                                 gf_isom_remove_edits(ctx->file, tkw->track_num);
    3006             :                                         }
    3007         136 :                                         gf_isom_set_edit(ctx->file, tkw->track_num, 0, 0, -p->value.longsint, GF_ISOM_EDIT_NORMAL);
    3008             :                                 }
    3009             :                         }
    3010             :                         //media delay
    3011           0 :                         else if (p->value.longsint > 0) {
    3012             :                                 //if cmaf (whether cmfc or cmf2), remove edits and add delay to tfdt
    3013           0 :                                 if (ctx->cmaf) {
    3014           0 :                                         gf_isom_remove_edits(ctx->file, tkw->track_num);
    3015           0 :                                         tkw->patch_tfdt = GF_TRUE;
    3016             :                                 } else {
    3017             :                                         s64 dur = p->value.longsint;
    3018           0 :                                         dur *= (u32) ctx->moovts;
    3019           0 :                                         dur /= tkw->src_timescale;
    3020           0 :                                         if (remove_edits) {
    3021           0 :                                                 gf_isom_remove_edits(ctx->file, tkw->track_num);
    3022             :                                         }
    3023           0 :                                         gf_isom_set_edit(ctx->file, tkw->track_num, 0, dur, 0, GF_ISOM_EDIT_DWELL);
    3024           0 :                                         gf_isom_set_edit(ctx->file, tkw->track_num, dur, 0, 0, GF_ISOM_EDIT_NORMAL);
    3025             :                                 }
    3026             :                         }
    3027         136 :                         tkw->ts_delay = p->value.sint;
    3028        1325 :                 } else if (tkw->stream_type==GF_STREAM_VISUAL) {
    3029         824 :                         tkw->probe_min_ctts = GF_TRUE;
    3030             :                 }
    3031         136 :                 if (use_negccts) {
    3032           0 :                         gf_isom_set_composition_offset_mode(ctx->file, tkw->track_num, GF_TRUE);
    3033             : 
    3034           0 :                         if (!tkw->has_brands) {
    3035           0 :                                 gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_ISO4, GF_TRUE);
    3036           0 :                                 gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_ISOM, GF_FALSE);
    3037           0 :                                 gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_ISO1, GF_FALSE);
    3038           0 :                                 gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_ISO2, GF_FALSE);
    3039           0 :                                 gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_ISO3, GF_FALSE);
    3040             :                         }
    3041             : 
    3042           0 :                         tkw->negctts_shift = (tkw->ts_delay<0) ? -tkw->ts_delay : 0;
    3043             :                 } else {
    3044             :                         //this will remove any cslg in the track due to template
    3045        1461 :                         gf_isom_set_composition_offset_mode(ctx->file, tkw->track_num, GF_FALSE);
    3046             :                 }
    3047             : 
    3048        1461 :                 mp4_mux_set_tags(ctx, tkw);
    3049             :         }
    3050             :         return GF_OK;
    3051             : }
    3052             : 
    3053             : static GF_Err mp4_mux_flush_fragmented(GF_Filter *filter, GF_MP4MuxCtx *ctx);
    3054             : static GF_Err mp4_mux_done(GF_Filter *filter, GF_MP4MuxCtx *ctx, Bool is_final);
    3055             : 
    3056        2778 : static GF_Err mp4_mux_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
    3057             : {
    3058        2778 :         GF_MP4MuxCtx *ctx = gf_filter_get_udta(filter);
    3059             : 
    3060        2778 :         if (is_remove) {
    3061          11 :                 TrackWriter *tkw = gf_filter_pid_get_udta(pid);
    3062          11 :                 if (tkw) {
    3063          11 :                         gf_list_del_item(ctx->tracks, tkw);
    3064          11 :                         gf_free(tkw);
    3065             :                 }
    3066             :                 //removing last pid
    3067          11 :                 if (ctx->opid && !gf_list_count(ctx->tracks)) {
    3068           9 :                         if (ctx->file) {
    3069             :                                 //non-frag file, flush file
    3070           9 :                                 if (!ctx->init_movie_done) {
    3071           0 :                                         mp4_mux_done(filter, ctx, GF_TRUE);
    3072             :                                 }
    3073             :                         } else {
    3074           0 :                                 while (ctx->flush_size) {
    3075           0 :                                         GF_Err e = mp4_mux_flush_fragmented(filter, ctx);
    3076           0 :                                         if (e) break;
    3077             :                                 }
    3078             :                         }
    3079             :                         //delete output pid (to flush destruction of filter chain)
    3080           9 :                         gf_filter_pid_remove(ctx->opid);
    3081           9 :                         ctx->opid = NULL;
    3082             :                 }
    3083             :                 return GF_OK;
    3084             :         }
    3085        2767 :         return mp4_mux_setup_pid(filter, pid, GF_TRUE);
    3086             : }
    3087             : 
    3088      283757 : static Bool mp4_mux_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
    3089             : {
    3090      283757 :         GF_MP4MuxCtx *ctx = gf_filter_get_udta(filter);
    3091             : 
    3092      283757 :         if (evt->base.on_pid && (evt->base.type==GF_FEVT_INFO_UPDATE) ) {
    3093      283068 :                 TrackWriter *tkw = gf_filter_pid_get_udta(evt->base.on_pid);
    3094      283068 :                 if (tkw) {
    3095      283068 :                         GF_PropertyEntry *pe=NULL;
    3096             :                         const GF_PropertyValue *p;
    3097      283068 :                         p = gf_filter_pid_get_info(tkw->ipid, GF_PROP_PID_DOWN_BYTES, &pe);
    3098      283068 :                         if (p) tkw->down_bytes = p->value.longuint;
    3099             : 
    3100      283068 :                         p = gf_filter_pid_get_info(tkw->ipid, GF_PROP_PID_DOWN_SIZE, &pe);
    3101      283068 :                         if (p) tkw->down_size = p->value.longuint;
    3102             : 
    3103      283068 :                         gf_filter_release_property(pe);
    3104             :                 }
    3105             : 
    3106             :                 return GF_FALSE;
    3107             :         }
    3108         689 :         if (!evt->base.on_pid && (evt->base.type==GF_FEVT_STOP) ) {
    3109           0 :                 if (ctx->file && ctx->owns_mov) {
    3110           0 :                         mp4_mux_done(filter, ctx, GF_TRUE);
    3111             :                 }
    3112             :         }
    3113         689 :         if (evt->base.on_pid && (evt->base.type==GF_FEVT_PLAY) ) {
    3114             :                 u32 i, count;
    3115             :                 GF_FilterEvent anevt;
    3116         663 :                 ctx->force_play = GF_TRUE;
    3117         663 :                 if (evt->play.speed<0)
    3118           1 :                         ctx->is_rewind = GF_TRUE;
    3119             : 
    3120         663 :                 if (ctx->start == 0)
    3121             :                         return GF_FALSE;
    3122             : 
    3123           0 :                 count = gf_list_count(ctx->tracks);
    3124           0 :                 for (i=0; i<count; i++) {
    3125           0 :                         TrackWriter *tkw = gf_list_get(ctx->tracks, i);
    3126           0 :                         if (tkw->fake_track) continue;
    3127             : 
    3128           0 :                         anevt.play = evt->play;
    3129           0 :                         gf_filter_pid_init_play_event(tkw->ipid, &anevt, ctx->start, 0, "MP4Mux");
    3130           0 :                         if (anevt.play.start_range > 0)
    3131           0 :                                 tkw->wait_sap = GF_TRUE;
    3132             : 
    3133           0 :                         gf_filter_pid_send_event(tkw->ipid, &anevt);
    3134             :                 }
    3135             :                 return GF_TRUE;
    3136             :         }
    3137             :         return GF_FALSE;
    3138             : }
    3139             : 
    3140             : enum
    3141             : {
    3142             :         CENC_CONFIG=0,
    3143             :         CENC_ADD_NORMAL,
    3144             :         CENC_ADD_FRAG,
    3145             : };
    3146             : 
    3147         218 : static void mp4_mux_cenc_insert_pssh(GF_MP4MuxCtx *ctx, TrackWriter *tkw)
    3148             : {
    3149             :         bin128 *keyIDs=NULL;
    3150             :         u32 max_keys = 0;
    3151             :         u32 i, nb_pssh;
    3152             : 
    3153             :         //set pssh
    3154         218 :         const GF_PropertyValue *p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_CENC_PSSH);
    3155         218 :         if (!p) return;
    3156             : 
    3157         218 :         if (!ctx->bs_r) ctx->bs_r = gf_bs_new(p->value.data.ptr, p->value.data.size, GF_BITSTREAM_READ);
    3158           0 :         else gf_bs_reassign_buffer(ctx->bs_r, p->value.data.ptr, p->value.data.size);
    3159             : 
    3160         218 :         nb_pssh = gf_bs_read_u32(ctx->bs_r);
    3161         296 :         for (i = 0; i < nb_pssh; i++) {
    3162             :                 u32 mode;
    3163             :                 bin128 sysID;
    3164             :                 u32 j, kid_count, version=0;
    3165             :                 char *data;
    3166             :                 u32 len;
    3167             : 
    3168         296 :                 gf_bs_read_data(ctx->bs_r, sysID, 16);
    3169         296 :                 version = gf_bs_read_u32(ctx->bs_r);
    3170         296 :                 kid_count = gf_bs_read_u32(ctx->bs_r);
    3171             : 
    3172         296 :                 if (kid_count>=max_keys) {
    3173             :                         max_keys = kid_count;
    3174         296 :                         keyIDs = gf_realloc(keyIDs, sizeof(bin128)*max_keys);
    3175             :                 }
    3176         273 :                 for (j=0; j<kid_count; j++) {
    3177         273 :                         gf_bs_read_data(ctx->bs_r, keyIDs[j], 16);
    3178             :                 }
    3179         296 :                 len = gf_bs_read_u32(ctx->bs_r);
    3180         296 :                 data = p->value.data.ptr + gf_bs_get_position(ctx->bs_r);
    3181             : 
    3182         296 :                 if (tkw->is_item) mode = 2;
    3183         281 :                 else if (tkw->scheme_type==GF_ISOM_PIFF_SCHEME) mode = 1;
    3184             :                 else mode = 0;
    3185             : 
    3186         296 :                 gf_cenc_set_pssh(ctx->file, sysID, version, kid_count, keyIDs, data, len, mode);
    3187         296 :                 gf_bs_skip_bytes(ctx->bs_r, len);
    3188             :         }
    3189         218 :         if (keyIDs) gf_free(keyIDs);
    3190             : }
    3191             : 
    3192       41855 : static GF_Err mp4_mux_cenc_update(GF_MP4MuxCtx *ctx, TrackWriter *tkw, GF_FilterPacket *pck, u32 act_type, u32 pck_size)
    3193             : {
    3194             :         const GF_PropertyValue *p;
    3195             :         GF_Err e;
    3196             :         Bool pck_is_encrypted;
    3197             :         u32 skip_byte_block=0, crypt_byte_block=0;
    3198             :         u32 IV_size=0;
    3199             :         u32 scheme_type=0;
    3200             :         u32 scheme_version=0;
    3201             :         u8 *fake_sai = NULL;
    3202             :         u8 *sai = NULL;
    3203             :         u32 sai_size = 0;
    3204             :         Bool needs_seig = GF_FALSE;
    3205             :         u32 sample_num;
    3206             : 
    3207       41855 :         if (tkw->cenc_state == CENC_SETUP_ERROR)
    3208             :                 return GF_SERVICE_ERROR;
    3209             : 
    3210       41855 :         p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_CENC_PATTERN);
    3211       41855 :         if (p) {
    3212        8697 :                 skip_byte_block = p->value.frac.num;
    3213        8697 :                 crypt_byte_block = p->value.frac.den;
    3214             :         }
    3215             : 
    3216       41855 :         if (pck) {
    3217       41854 :                 p = gf_filter_pck_get_property(pck, GF_PROP_PCK_CENC_SAI);
    3218       41854 :                 if (p) {
    3219       36201 :                         sai = p->value.data.ptr;
    3220       36201 :                         sai_size = p->value.data.size;
    3221             :                 }
    3222             :         }
    3223             : 
    3224             : 
    3225       41855 :         p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_PROTECTION_SCHEME_TYPE);
    3226       41855 :         if (p) scheme_type = p->value.uint;
    3227       41855 :         p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_PROTECTION_SCHEME_VERSION);
    3228       41855 :         if (p) scheme_version = p->value.uint;
    3229             : 
    3230             :         //initial setup
    3231       41855 :         if (tkw->cenc_state==CENC_NEED_SETUP) {
    3232             :                 u32 cenc_stsd_mode=0;
    3233             :                 u32 container_type = GF_ISOM_BOX_TYPE_SENC;
    3234             : 
    3235         208 :                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_CENC_STSD_MODE);
    3236         208 :                 if (p) cenc_stsd_mode = p->value.uint;
    3237             : 
    3238         208 :                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_ENCRYPTED);
    3239         208 :                 if (p) pck_is_encrypted = p->value.boolean;
    3240             :                 else pck_is_encrypted = GF_FALSE;
    3241             : 
    3242             : 
    3243         208 :                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_CENC_STORE);
    3244         208 :                 if (p && p->value.uint) container_type = p->value.uint;
    3245             : 
    3246         208 :                 tkw->clear_stsd_idx = 0;
    3247         208 :                 if (cenc_stsd_mode) {
    3248             :                         u32 clone_stsd_idx;
    3249           6 :                         e = gf_isom_clone_sample_description(ctx->file, tkw->track_num, ctx->file, tkw->track_num, tkw->stsd_idx, NULL, NULL, &clone_stsd_idx);
    3250           6 :                         if (e) {
    3251           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Failed to clone sample description: %s\n", gf_error_to_string(e) ));
    3252           0 :                                 return e;
    3253             :                         }
    3254             :                         //before
    3255           6 :                         if (cenc_stsd_mode==1) {
    3256           2 :                                 tkw->clear_stsd_idx = tkw->stsd_idx;
    3257           2 :                                 tkw->stsd_idx = clone_stsd_idx;
    3258             :                         }
    3259             :                         //after
    3260             :                         else {
    3261           4 :                                 tkw->clear_stsd_idx = clone_stsd_idx;
    3262             :                         }
    3263             :                 }
    3264             : 
    3265         208 :                 tkw->cenc_state = CENC_SETUP_DONE;
    3266         208 :                 tkw->def_cenc_key_info_crc = tkw->cenc_key_info_crc;
    3267         208 :                 e = gf_isom_set_cenc_protection(ctx->file, tkw->track_num, tkw->stsd_idx, scheme_type, scheme_version, pck_is_encrypted, crypt_byte_block, skip_byte_block, tkw->cenc_ki->value.data.ptr, tkw->cenc_ki->value.data.size);
    3268             : 
    3269         208 :                 if (e) {
    3270           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Failed to setup CENC information: %s\n", gf_error_to_string(e) ));
    3271           0 :                         tkw->cenc_state = CENC_SETUP_ERROR;
    3272             :                         return e;
    3273             :                 }
    3274             : 
    3275         208 :                 if (ctx->psshs == MP4MX_PSSH_MOOV)
    3276         208 :                         mp4_mux_cenc_insert_pssh(ctx, tkw);
    3277             : 
    3278         208 :                 tkw->def_crypt_byte_block = crypt_byte_block;
    3279         208 :                 tkw->def_skip_byte_block = skip_byte_block;
    3280             : 
    3281         208 :                 if (!tkw->has_brands && (scheme_type==GF_ISOM_OMADRM_SCHEME))
    3282           0 :                         gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_OPF2, GF_TRUE);
    3283             : 
    3284         208 :                 if (container_type) {
    3285         208 :                         if (container_type==GF_ISOM_BOX_UUID_PSEC) {
    3286          12 :                                 e = gf_isom_piff_allocate_storage(ctx->file, tkw->track_num, 0, 0, NULL);
    3287             :                         } else {
    3288         196 :                                 e = gf_isom_cenc_allocate_storage(ctx->file, tkw->track_num);
    3289             :                         }
    3290         208 :                         if (e) {
    3291           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Failed to setup CENC storage: %s\n", gf_error_to_string(e) ));
    3292           0 :                                 tkw->cenc_state = CENC_SETUP_ERROR;
    3293             :                                 return e;
    3294             :                         }
    3295             :                 }
    3296             :         }
    3297       41855 :         if (act_type==CENC_CONFIG) return GF_OK;
    3298             : 
    3299             :         pck_is_encrypted = GF_FALSE;
    3300       41647 :         if (pck)
    3301       41647 :                 pck_is_encrypted = gf_filter_pck_get_crypt_flags(pck);
    3302             : 
    3303             :         //!! tkw->nb_samples / tkw->samples_in_frag not yet incremented !!
    3304       41647 :         if (act_type == CENC_ADD_FRAG) {
    3305       20396 :                 sample_num = tkw->samples_in_frag + 1;
    3306             : 
    3307       20396 :                 if (ctx->cmaf) {
    3308           0 :                         if (!tkw->samples_in_frag) {
    3309           0 :                                 tkw->cenc_frag_protected = pck_is_encrypted;
    3310             :                         } else {
    3311           0 :                                 if (tkw->cenc_frag_protected != pck_is_encrypted) {
    3312           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] CMAF forbids mixing protected and unprotected samples in a single fragment, please re-encrypt or change target segment duration\n"));
    3313             :                                         return GF_NON_COMPLIANT_BITSTREAM;
    3314             :                                 }
    3315             :                         }
    3316             :                 }
    3317             :         } else {
    3318       21251 :                 sample_num = tkw->nb_samples + 1;
    3319             :         }
    3320       41647 :         if (!pck_is_encrypted) {
    3321        4983 :                 if (tkw->clear_stsd_idx) {
    3322         546 :                         if (act_type==CENC_ADD_FRAG) {
    3323         273 :                                 return gf_isom_fragment_set_cenc_sai(ctx->file, tkw->track_id, NULL, 0, GF_FALSE, ctx->saio32, tkw->cenc_multikey);
    3324             :                         } else {
    3325         273 :                                 return gf_isom_track_cenc_add_sample_info(ctx->file, tkw->track_num, GF_ISOM_BOX_TYPE_SENC, NULL, 0, tkw->cenc_subsamples, ctx->saio32, tkw->cenc_multikey);
    3326             :                         }
    3327             :                 } else {
    3328             :                         char dumb_key[20];
    3329             :                         memset(dumb_key, 0, 20); //dumb key, IV size 0, not protected
    3330        4437 :                         e = gf_isom_set_sample_cenc_group(ctx->file, tkw->track_num, sample_num, GF_FALSE, 0, 0, dumb_key, 20);
    3331             :                         IV_size = 0;
    3332        4437 :                         tkw->has_seig = GF_TRUE;
    3333             :                 }
    3334             :         } else {
    3335             :         
    3336             :                 e = GF_OK;
    3337             :                 //multikey ALWAYS uses seig
    3338       36664 :                 if (tkw->cenc_ki->value.data.ptr[0])
    3339             :                         needs_seig = GF_TRUE;
    3340       34414 :                 else if (tkw->def_crypt_byte_block != crypt_byte_block)
    3341             :                         needs_seig = GF_TRUE;
    3342       34414 :                 else if (tkw->def_skip_byte_block != skip_byte_block)
    3343             :                         needs_seig = GF_TRUE;
    3344       34414 :                 else if (tkw->def_cenc_key_info_crc != tkw->cenc_key_info_crc)
    3345             :                         needs_seig = GF_TRUE;
    3346             : 
    3347             :                 if (needs_seig) {
    3348        4102 :                         e = gf_isom_set_sample_cenc_group(ctx->file, tkw->track_num, sample_num, 1, crypt_byte_block, skip_byte_block, tkw->cenc_ki->value.data.ptr, tkw->cenc_ki->value.data.size);
    3349        4102 :                         tkw->has_seig = GF_TRUE;
    3350       32562 :                 } else if (tkw->has_seig) {
    3351         690 :                         e = gf_isom_set_sample_cenc_default_group(ctx->file, tkw->track_num, sample_num);
    3352             :                 }
    3353             :         }
    3354        9229 :         if (e) {
    3355           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Failed to set sample encryption group entry: %s)\n", gf_error_to_string(e) ));
    3356             :                 return e;
    3357             :         }
    3358             : 
    3359       41101 :         if (!sai) {
    3360        5098 :                 if (tkw->constant_IV_size && !tkw->cenc_subsamples)
    3361             :                         return GF_OK;
    3362             : 
    3363             :                 if (IV_size) {
    3364             :                         //generate clear SAI data with a non-0 IV
    3365             :                         u32 olen = pck_size;
    3366             :                         GF_BitStream *bs = gf_bs_new(NULL, 9, GF_BITSTREAM_WRITE);
    3367             :                         if (tkw->cenc_multikey) {
    3368             :                                 gf_bs_write_u16(bs, 0);
    3369             :                         } else {
    3370             :                                 gf_bs_write_long_int(bs, 0, IV_size*8);
    3371             :                         }
    3372             : 
    3373             :                         if (tkw->cenc_subsamples) {
    3374             :                                 u32 i;
    3375             :                                 u32 subsample_count = 1;
    3376             :                                 while (olen>0xFFFF) {
    3377             :                                         olen -= 0xFFFF;
    3378             :                                         subsample_count ++;
    3379             :                                 }
    3380             :                                 gf_bs_write_u16(bs, subsample_count);
    3381             :                                 olen = pck_size;
    3382             :                                 for (i = 0; i < subsample_count; i++) {
    3383             :                                         u32 clear_size;
    3384             :                                         if (olen<0xFFFF) {
    3385             :                                                 clear_size = olen;
    3386             :                                         } else {
    3387             :                                                 clear_size = 0xFFFF;
    3388             :                                                 olen -= 0xFFFF;
    3389             :                                         }
    3390             : 
    3391             :                                         if (tkw->cenc_multikey)
    3392             :                                                 gf_bs_write_u16(bs, 0);
    3393             :                                         gf_bs_write_u16(bs, clear_size);
    3394             :                                         gf_bs_write_u32(bs, 0);
    3395             :                                 }
    3396             :                         }
    3397             :                         gf_bs_get_content(bs, &fake_sai, &sai_size);
    3398             :                         gf_bs_del(bs);
    3399             :                         sai = fake_sai;
    3400             :                 }
    3401             :         }
    3402             : 
    3403       41101 :         if (act_type==CENC_ADD_FRAG) {
    3404       20123 :                 if (pck_is_encrypted) {
    3405       17990 :                         e = gf_isom_fragment_set_cenc_sai(ctx->file, tkw->track_id, sai, sai_size, tkw->cenc_subsamples, ctx->saio32, tkw->cenc_multikey);
    3406             :                 } else {
    3407        2133 :                         e = gf_isom_fragment_set_cenc_sai(ctx->file, tkw->track_id, NULL, 0, GF_FALSE, ctx->saio32, tkw->cenc_multikey);
    3408             :                 }
    3409             :         } else {
    3410       20978 :                 if (sai) {
    3411       18344 :                         e = gf_isom_track_cenc_add_sample_info(ctx->file, tkw->track_num, GF_ISOM_BOX_TYPE_SENC, sai, sai_size, tkw->cenc_subsamples, ctx->saio32, tkw->cenc_multikey);
    3412        2634 :                 } else if (!pck_is_encrypted) {
    3413        2304 :                         e = gf_isom_track_cenc_add_sample_info(ctx->file, tkw->track_num, GF_ISOM_BOX_TYPE_SENC, NULL, 0, tkw->cenc_subsamples, ctx->saio32, tkw->cenc_multikey);
    3414             :                 }
    3415             :         }
    3416             :         if (fake_sai) gf_free(fake_sai);
    3417             :         return e;
    3418             : }
    3419             : 
    3420           0 : GF_FilterSAPType mp4_mux_get_sap(GF_MP4MuxCtx *ctx, GF_FilterPacket *pck)
    3421             : {
    3422      562170 :         GF_FilterSAPType sap = gf_filter_pck_get_sap(pck);
    3423      562170 :         if (!sap) return sap;
    3424      196556 :         if (ctx->forcesync) return GF_FILTER_SAP_1;
    3425           0 :         return sap;
    3426             : }
    3427             : 
    3428      562238 : static GF_Err mp4_mux_process_sample(GF_MP4MuxCtx *ctx, TrackWriter *tkw, GF_FilterPacket *pck, Bool for_fragment)
    3429             : {
    3430             :         GF_Err e=GF_OK;
    3431             :         u64 cts, prev_dts;
    3432             :         u32 prev_size=0;
    3433             :         u32 duration = 0;
    3434             :         u32 timescale = 0;
    3435             :         const GF_PropertyValue *subs;
    3436             :         GF_FilterSAPType sap_type;
    3437             :         u32 insert_subsample_dsi_size = 0;
    3438             :         u32 first_nal_is_audelim = GF_FALSE;
    3439      562238 :         u32 sample_desc_index = tkw->stsd_idx;
    3440             : 
    3441      562238 :         timescale = gf_filter_pck_get_timescale(pck);
    3442             : 
    3443      562238 :         prev_dts = tkw->nb_samples ? tkw->sample.DTS : GF_FILTER_NO_TS;
    3444      562238 :         prev_size = tkw->sample.dataLength;
    3445      562238 :         tkw->sample.CTS_Offset = 0;
    3446      562238 :         tkw->sample.data = (char *)gf_filter_pck_get_data(pck, &tkw->sample.dataLength);
    3447             : 
    3448      562238 :         ctx->update_report = GF_TRUE;
    3449      562238 :         ctx->total_bytes_in += tkw->sample.dataLength;
    3450      562238 :         ctx->total_samples++;
    3451             : 
    3452      562238 :         tkw->sample.DTS = gf_filter_pck_get_dts(pck);
    3453      562238 :         cts = gf_filter_pck_get_cts(pck);
    3454             : 
    3455      562238 :         if (tkw->sample.DTS == GF_FILTER_NO_TS) {
    3456           0 :                 if (cts == GF_FILTER_NO_TS) {
    3457           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Sample with no DTS/CTS, cannot add (last DTS "LLU", last size %d)\n", prev_dts, prev_size ));
    3458             :                         return GF_NON_COMPLIANT_BITSTREAM;
    3459             :                 } else {
    3460           0 :                         u32 min_pck_dur = gf_filter_pid_get_min_pck_duration(tkw->ipid);
    3461           0 :                         if (min_pck_dur) {
    3462           0 :                                 tkw->sample.DTS = prev_dts;
    3463           0 :                                 if (timescale != tkw->tk_timescale) {
    3464           0 :                                         tkw->sample.DTS *= timescale;
    3465           0 :                                         tkw->sample.DTS /= tkw->tk_timescale;
    3466             :                                 }
    3467           0 :                                 tkw->sample.DTS += min_pck_dur;
    3468             :                         } else {
    3469           0 :                                 tkw->sample.DTS = cts;
    3470             :                         }
    3471             :                 }
    3472             :         } else {
    3473      562238 :                 tkw->sample.CTS_Offset = (s32) ((s64) cts - (s64) tkw->sample.DTS);
    3474             :         }
    3475             : 
    3476             :         //tkw->ts_shift is in source timescale, apply it before rescaling TSs/duration
    3477      562238 :         if (tkw->ts_shift) {
    3478       17980 :                 if (ctx->is_rewind) {
    3479          30 :                         if (tkw->sample.DTS <= tkw->ts_shift) {
    3480          30 :                                 tkw->sample.DTS = tkw->ts_shift - tkw->sample.DTS;
    3481          30 :                                 cts = tkw->ts_shift - cts;
    3482             :                         } else {
    3483           0 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] broken timing in track, initial ts "LLU" less than TS "LLU"\n", tkw->ts_shift, tkw->sample.DTS));
    3484             :                         }
    3485             :                 } else {
    3486       17950 :                         if (tkw->sample.DTS >= tkw->ts_shift) {
    3487       17950 :                                 tkw->sample.DTS -= tkw->ts_shift;
    3488       17950 :                                 cts -= tkw->ts_shift;
    3489             :                         } else {
    3490           0 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] broken timing in track, initial ts "LLU" greater than TS "LLU"\n", tkw->ts_shift, tkw->sample.DTS));
    3491             :                         }
    3492             :                 }
    3493             :         }
    3494             : 
    3495             :         //sample-accurate seek info, start logging min CTS of packets marked as non-sync
    3496      562238 :         if (tkw->check_seek_ts && !gf_filter_pck_get_seek_flag(pck)) {
    3497             :                 u64 ts_check = cts;
    3498          20 :                 subs = gf_filter_pck_get_property(pck, GF_PROP_PCK_SKIP_BEGIN);
    3499          20 :                 if (subs)
    3500           8 :                         ts_check += subs->value.uint;
    3501             : 
    3502          20 :                 if (!tkw->min_ts_seek_plus_one) {
    3503           6 :                         tkw->min_ts_seek_plus_one = ts_check + 1;
    3504          14 :                 } else if (tkw->min_ts_seek_plus_one > ts_check + 1) {
    3505           4 :                         tkw->min_ts_seek_plus_one = ts_check + 1;
    3506             :                 } else {
    3507             :                         //TS is greater than last non-seek packet TS, we're done seeking
    3508          10 :                         tkw->check_seek_ts = GF_FALSE;
    3509             :                 }
    3510             :         }
    3511             : 
    3512      562238 :         duration = gf_filter_pck_get_duration(pck);
    3513      562238 :         if (timescale != tkw->tk_timescale) {
    3514             :                 s64 ctso;
    3515          92 :                 tkw->sample.DTS *= tkw->tk_timescale;
    3516          92 :                 tkw->sample.DTS /= timescale;
    3517          92 :                 ctso = (s64) tkw->sample.CTS_Offset;
    3518          92 :                 ctso *= tkw->tk_timescale;
    3519          92 :                 ctso /= timescale;
    3520          92 :                 tkw->sample.CTS_Offset = (s32) ctso;
    3521          92 :                 duration *= tkw->tk_timescale;
    3522          92 :                 duration /= timescale;
    3523             :         }
    3524             : 
    3525             : 
    3526      562238 :         tkw->sample.IsRAP = 0;
    3527      562238 :         if (tkw->codecid==GF_CODECID_RAW) {
    3528             :                 sap_type = GF_FILTER_SAP_1;
    3529             :         } else {
    3530             :                 sap_type = mp4_mux_get_sap(ctx, pck);
    3531             :         }
    3532      562118 :         if (sap_type==GF_FILTER_SAP_1)
    3533      195683 :                 tkw->sample.IsRAP = SAP_TYPE_1;
    3534      366555 :         else if ( (sap_type == GF_FILTER_SAP_4) && (tkw->stream_type != GF_STREAM_VISUAL) )
    3535           0 :                 tkw->sample.IsRAP = SAP_TYPE_1;
    3536             : 
    3537             :         /*RFC8216bis is not clear here:
    3538             :         "if the Partial Segment contains an independent frame."
    3539             :                 -> this would allow SAP1,2,3 (independent being only defined for segments)
    3540             : 
    3541             :         but
    3542             : 
    3543             :         "Partial Segment containing an independent frame SHOULD carry it to increase the efficiency with which clients can join and switch Renditions"
    3544             :                 -> if used for switching, this only allows SAP 1 and 2
    3545             : 
    3546             :         Spec should be fixed to allow for both cases (fast tune-in or in-segment switchingà)
    3547             :         */
    3548      562238 :         if ((tkw->sample.IsRAP == SAP_TYPE_1) || (tkw->sample.IsRAP == SAP_TYPE_2))
    3549      195683 :                 ctx->frag_has_intra = GF_TRUE;
    3550             : 
    3551      562238 :         tkw->sample.DTS += tkw->dts_patch;
    3552      562238 :         if (tkw->nb_samples && (prev_dts >= tkw->sample.DTS) ) {
    3553             :                 //the fragmented API will patch the duration on the fly
    3554           7 :                 if (!for_fragment) {
    3555           4 :                         gf_isom_patch_last_sample_duration(ctx->file, tkw->track_num, prev_dts ? prev_dts : 1);
    3556             :                 }
    3557           7 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] PID %s ID %d Sample %d with DTS "LLU" less than previous sample DTS "LLU", adjusting prev sample duration\n", gf_filter_pid_get_name(tkw->ipid), tkw->track_id, tkw->nb_samples+1, tkw->sample.DTS, prev_dts ));
    3558             : 
    3559           7 :                 if (prev_dts) {
    3560           7 :                         tkw->dts_patch = prev_dts - tkw->sample.DTS;
    3561           7 :                         tkw->sample.DTS += tkw->dts_patch;
    3562             :                 } else {
    3563           0 :                         tkw->sample.DTS += 1;
    3564           0 :                         if (tkw->sample.CTS_Offset) tkw->sample.CTS_Offset -= 1;
    3565           0 :                         duration-=1;
    3566             :                 }
    3567             :         }
    3568             : 
    3569             : 
    3570      562238 :         if (tkw->negctts_shift)
    3571           0 :                 tkw->sample.CTS_Offset -= tkw->negctts_shift;
    3572             : 
    3573      562238 :         if (tkw->probe_min_ctts) {
    3574      334953 :                 s32 diff = (s32) ((s64) cts - (s64) tkw->sample.DTS);
    3575      334953 :                 if (diff < tkw->min_neg_ctts)
    3576         246 :                         tkw->min_neg_ctts = diff;
    3577             :         }
    3578      562238 :         if (tkw->sample.CTS_Offset) tkw->has_ctts = GF_TRUE;
    3579             : 
    3580      562238 :         if (tkw->sample.CTS_Offset < tkw->min_neg_ctts)
    3581           0 :                 tkw->min_neg_ctts = tkw->sample.CTS_Offset;
    3582             : 
    3583      562238 :         tkw->sample.nb_pack = 0;
    3584      562238 :         if (tkw->raw_audio_bytes_per_sample) {
    3585          90 :                 tkw->sample.nb_pack = tkw->sample.dataLength / tkw->raw_audio_bytes_per_sample;
    3586          90 :                 if (tkw->sample.nb_pack) {
    3587             :                         duration = 1;
    3588          90 :                         if (tkw->raw_samplerate && (tkw->tk_timescale != tkw->raw_samplerate)) {
    3589             :                                 duration *= tkw->tk_timescale;
    3590           0 :                                 duration /= tkw->raw_samplerate;
    3591             :                         }
    3592             :                 }
    3593             :         }
    3594             : 
    3595      562238 :         if (tkw->cenc_state && tkw->clear_stsd_idx && !gf_filter_pck_get_crypt_flags(pck)) {
    3596         546 :                 sample_desc_index = tkw->clear_stsd_idx;
    3597             :         }
    3598             : 
    3599      562238 :         if (tkw->use_dref) {
    3600           0 :                 u64 data_offset = gf_filter_pck_get_byte_offset(pck);
    3601           0 :                 if (data_offset != GF_FILTER_NO_BO) {
    3602           0 :                         e = gf_isom_add_sample_reference(ctx->file, tkw->track_num, sample_desc_index, &tkw->sample, data_offset);
    3603           0 :                         if (e) {
    3604           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Failed to add sample DTS "LLU" as reference: %s\n", tkw->sample.DTS, gf_error_to_string(e) ));
    3605             :                         }
    3606             :                 } else {
    3607           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Cannot add sample reference at DTS "LLU" , input sample data is not continous in source\n", tkw->sample.DTS ));
    3608             :                 }
    3609      562238 :         } else if (tkw->nb_frames_per_sample && (tkw->nb_samples % tkw->nb_frames_per_sample)) {
    3610           0 :                 if (for_fragment) {
    3611           0 :                         e = gf_isom_fragment_append_data(ctx->file, tkw->track_id, tkw->sample.data, tkw->sample.dataLength, 0);
    3612             :                 } else {
    3613           0 :                         e = gf_isom_append_sample_data(ctx->file, tkw->track_num, tkw->sample.data, tkw->sample.dataLength);
    3614             :                 }
    3615           0 :                 tkw->has_append = GF_TRUE;
    3616           0 :                 if (e) {
    3617           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Failed to append sample DTS "LLU" data: %s\n", tkw->sample.DTS, gf_error_to_string(e) ));
    3618             :                 }
    3619             :         } else {
    3620      562238 :                 if ((tkw->sample.IsRAP || tkw->force_inband_inject || ctx->pps_inband) && ctx->xps_inband) {
    3621             :                         u8 *inband_xps;
    3622             :                         u32 inband_xps_size;
    3623             :                         char *au_delim=NULL;
    3624             :                         u32 au_delim_size=0;
    3625         202 :                         char *pck_data = tkw->sample.data;
    3626         202 :                         u32 pck_data_len = tkw->sample.dataLength;
    3627         202 :                         if (tkw->sample.IsRAP || tkw->force_inband_inject) {
    3628         202 :                                 inband_xps = tkw->inband_hdr;
    3629         202 :                                 inband_xps_size = tkw->inband_hdr_size;
    3630         202 :                                 tkw->force_inband_inject = GF_FALSE;
    3631             :                         } else {
    3632           0 :                                 inband_xps = tkw->inband_hdr_non_rap;
    3633           0 :                                 inband_xps_size = tkw->inband_hdr_non_rap_size;
    3634             :                         }
    3635         202 :                         tkw->sample.data = inband_xps;
    3636         202 :                         tkw->sample.dataLength = inband_xps_size;
    3637             : 
    3638         202 :                         if (tkw->is_nalu==NALU_AVC) {
    3639          30 :                                 char *nal = pck_data + tkw->nal_unit_size;
    3640          30 :                                 if ((nal[0] & 0x1F) == GF_AVC_NALU_ACCESS_UNIT) {
    3641           2 :                                         first_nal_is_audelim = au_delim_size = 2 + tkw->nal_unit_size;
    3642             :                                         au_delim = pck_data;
    3643             :                                 }
    3644             :                         } else {
    3645         172 :                                 char *nal = pck_data + tkw->nal_unit_size;
    3646         172 :                                 if (((nal[0] & 0x7E)>>1) == GF_HEVC_NALU_ACCESS_UNIT) {
    3647          11 :                                         first_nal_is_audelim = au_delim_size = 3 + tkw->nal_unit_size;
    3648             :                                         au_delim = pck_data;
    3649             :                                 }
    3650             :                         }
    3651             : 
    3652         202 :                         if (au_delim) {
    3653          13 :                                 tkw->sample.data = au_delim;
    3654          13 :                                 tkw->sample.dataLength = au_delim_size;
    3655          13 :                                 pck_data += au_delim_size;
    3656          13 :                                 pck_data_len -= au_delim_size;
    3657             :                         }
    3658             : 
    3659         202 :                         if (for_fragment) {
    3660          16 :                                 e = gf_isom_fragment_add_sample(ctx->file, tkw->track_id, &tkw->sample, sample_desc_index, duration, 0, 0, 0);
    3661          16 :                                 if (!e && au_delim) {
    3662           0 :                                         e = gf_isom_fragment_append_data(ctx->file, tkw->track_id, inband_xps, inband_xps_size, 0);
    3663             :                                 }
    3664          16 :                                 if (!e) e = gf_isom_fragment_append_data(ctx->file, tkw->track_id, pck_data, pck_data_len, 0);
    3665             :                         } else {
    3666         186 :                                 e = gf_isom_add_sample(ctx->file, tkw->track_num, sample_desc_index, &tkw->sample);
    3667         186 :                                 if (au_delim && !e) {
    3668          13 :                                         e = gf_isom_append_sample_data(ctx->file, tkw->track_num, inband_xps, inband_xps_size);
    3669             :                                 }
    3670         186 :                                 if (!e) e = gf_isom_append_sample_data(ctx->file, tkw->track_num, pck_data, pck_data_len);
    3671             :                         }
    3672             :                         insert_subsample_dsi_size = inband_xps_size;
    3673      562036 :                 } else if (for_fragment) {
    3674      111898 :                         e = gf_isom_fragment_add_sample(ctx->file, tkw->track_id, &tkw->sample, sample_desc_index, duration, 0, 0, 0);
    3675             :                 } else {
    3676      450138 :                         e = gf_isom_add_sample(ctx->file, tkw->track_num, sample_desc_index, &tkw->sample);
    3677      450138 :                         if (!e && !duration) {
    3678         190 :                                 gf_isom_set_last_sample_duration(ctx->file, tkw->track_num, 0);
    3679             :                         }
    3680             :                 }
    3681             : 
    3682      562238 :                 if (e) {
    3683           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Failed to add sample DTS "LLU" - prev DTS "LLU": %s\n", tkw->sample.DTS, prev_dts, gf_error_to_string(e) ));
    3684             :                 } else {
    3685      562238 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[MP4Mux] added sample DTS "LLU" - prev DTS "LLU" - prev size %d\n", tkw->sample.DTS, prev_dts, prev_size));
    3686             :                 }
    3687             : 
    3688      562238 :                 if (!e && tkw->cenc_state) {
    3689       41647 :                         e = mp4_mux_cenc_update(ctx, tkw, pck, for_fragment ? CENC_ADD_FRAG : CENC_ADD_NORMAL, tkw->sample.dataLength);
    3690       41647 :                         if (e) {
    3691           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Failed to set sample CENC information: %s\n", gf_error_to_string(e) ));
    3692             :                                 return e;
    3693             :                         }
    3694             :                 }
    3695             :         }
    3696             : 
    3697      562238 :         tkw->nb_samples++;
    3698      562238 :         tkw->samples_in_stsd++;
    3699      562238 :         tkw->samples_in_frag++;
    3700             : 
    3701      562238 :         if (e) return e;
    3702             : 
    3703      562238 :         if (!for_fragment) {
    3704             :                 u64 samp_cts;
    3705      450324 :                 if (!tkw->clamp_ts_plus_one) {
    3706      450324 :                         const GF_PropertyValue *skp = gf_filter_pck_get_property(pck, GF_PROP_PCK_SKIP_PRES);
    3707      450324 :                         if (skp && skp->value.boolean) {
    3708           1 :                                 tkw->clamp_ts_plus_one = 1 + tkw->sample.DTS + tkw->sample.CTS_Offset;
    3709             :                         }
    3710             :                 }
    3711             :                 //store min max cts for edit list updates
    3712      450324 :                 samp_cts = tkw->sample.DTS + tkw->sample.CTS_Offset;
    3713      450324 :                 if (!tkw->clamp_ts_plus_one || (samp_cts + 1 < tkw->clamp_ts_plus_one)) {
    3714      450323 :                         if (samp_cts > tkw->max_cts) {
    3715      355637 :                                 tkw->max_cts = samp_cts;
    3716      355637 :                                 tkw->max_cts_samp_dur = duration;
    3717             :                         }
    3718             : 
    3719      450323 :                         if (tkw->min_cts > samp_cts)
    3720        1056 :                                 tkw->min_cts = samp_cts;
    3721             :                 }
    3722             :         }
    3723             : 
    3724             :         //compat with old arch: write sample to group info for all samples
    3725      562238 :         if ((sap_type==3) || tkw->has_open_gop)  {
    3726       22565 :                 if (for_fragment) {
    3727        8111 :                         e = gf_isom_fragment_set_sample_rap_group(ctx->file, tkw->track_id, tkw->samples_in_frag, (sap_type==3) ? GF_TRUE : GF_FALSE, 0);
    3728       14454 :                 } else if (sap_type==3) {
    3729         479 :                         e = gf_isom_set_sample_rap_group(ctx->file, tkw->track_num, tkw->nb_samples, GF_TRUE /*(sap_type==3) ? GF_TRUE : GF_FALSE*/, 0);
    3730             :                 }
    3731       22565 :                 if (e) {
    3732           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Failed to set sample DTS "LLU" SAP 3 in RAP group: %s\n", tkw->sample.DTS, gf_error_to_string(e) ));
    3733             :                 }
    3734       22565 :                 tkw->has_open_gop = GF_TRUE;
    3735             :         }
    3736      562238 :         if (!ctx->noroll) {
    3737      562238 :                 if ((sap_type==GF_FILTER_SAP_4) || (sap_type==GF_FILTER_SAP_4_PROL) || tkw->gdr_type) {
    3738             :                         GF_ISOSampleRollType roll_type = 0;
    3739        1484 :                         s16 roll = gf_filter_pck_get_roll_info(pck);
    3740        1484 :                         if (sap_type==GF_FILTER_SAP_4) roll_type = GF_ISOM_SAMPLE_ROLL;
    3741        1298 :                         else if (sap_type==GF_FILTER_SAP_4_PROL) roll_type = GF_ISOM_SAMPLE_PREROLL;
    3742        1298 :                         else if (tkw->gdr_type==GF_FILTER_SAP_4_PROL) {
    3743             :                                 roll_type = GF_ISOM_SAMPLE_PREROLL_NONE;
    3744             :                         }
    3745             : 
    3746        1484 :                         if (for_fragment) {
    3747         742 :                                 e = gf_isom_fragment_set_sample_roll_group(ctx->file, tkw->track_id, tkw->samples_in_frag, roll_type, roll);
    3748             :                         } else {
    3749         742 :                                 e = gf_isom_set_sample_roll_group(ctx->file, tkw->track_num, tkw->nb_samples, roll_type, roll);
    3750             :                         }
    3751        1484 :                         if (e) {
    3752           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Failed to set sample DTS "LLU" SAP 4 roll %s in roll group: %s\n", tkw->sample.DTS, roll, gf_error_to_string(e) ));
    3753             :                         }
    3754        1484 :                         if (sap_type && !tkw->gdr_type)
    3755           2 :                                 tkw->gdr_type = sap_type;
    3756             :                 }
    3757             :         }
    3758             :         
    3759      562238 :         subs = gf_filter_pck_get_property(pck, GF_PROP_PCK_SUBS);
    3760      562238 :         if (subs) {
    3761             :                 //if no AUDelim nal and inband header injection, push new subsample
    3762        1532 :                 if (!first_nal_is_audelim && insert_subsample_dsi_size) {
    3763           0 :                         if (for_fragment) {
    3764           0 :                                 gf_isom_fragment_add_subsample(ctx->file, tkw->track_id, 0, insert_subsample_dsi_size, 0, 0, 0);
    3765             :                         } else {
    3766           0 :                                 gf_isom_add_subsample(ctx->file, tkw->track_num, tkw->nb_samples, 0, insert_subsample_dsi_size, 0, 0, 0);
    3767             :                         }
    3768             :                         insert_subsample_dsi_size = 0;
    3769             :                 }
    3770        1532 :                 tkw->has_subs = GF_TRUE;
    3771             : 
    3772        1532 :                 if (!ctx->bs_r) ctx->bs_r = gf_bs_new(subs->value.data.ptr, subs->value.data.size, GF_BITSTREAM_READ);
    3773        1527 :                 else gf_bs_reassign_buffer(ctx->bs_r, subs->value.data.ptr, subs->value.data.size);
    3774             : 
    3775        4598 :                 while (gf_bs_available(ctx->bs_r)) {
    3776        3066 :                         u32 flags = gf_bs_read_u32(ctx->bs_r);
    3777        3066 :                         u32 subs_size = gf_bs_read_u32(ctx->bs_r);
    3778        3066 :                         u32 reserved = gf_bs_read_u32(ctx->bs_r);
    3779        3066 :                         u8 priority = gf_bs_read_u8(ctx->bs_r);
    3780        3066 :                         u8 discardable = gf_bs_read_u8(ctx->bs_r);
    3781             : 
    3782        3066 :                         if (for_fragment) {
    3783        1523 :                                 gf_isom_fragment_add_subsample(ctx->file, tkw->track_id, flags, subs_size, priority, reserved, discardable);
    3784             :                         } else {
    3785        1543 :                                 gf_isom_add_subsample(ctx->file, tkw->track_num, tkw->nb_samples, flags, subs_size, priority, reserved, discardable);
    3786             :                         }
    3787             : 
    3788             :                         //we have AUDelim nal and inband header injection, push new subsample for inband header once we have pushed the first subsample (au delim)
    3789        3066 :                         if (insert_subsample_dsi_size) {
    3790           0 :                                 if (first_nal_is_audelim != subs_size) {
    3791           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] inserting inband param after AU delimiter NALU, but sample has subsample information not aligned on NALU (got %d subsample size but expecting %d) - file might be broken!\n", subs_size, first_nal_is_audelim));
    3792             :                                 }
    3793           0 :                                 if (for_fragment) {
    3794           0 :                                         gf_isom_fragment_add_subsample(ctx->file, tkw->track_id, 0, insert_subsample_dsi_size, 0, 0, 0);
    3795             :                                 } else {
    3796           0 :                                         gf_isom_add_subsample(ctx->file, tkw->track_num, tkw->nb_samples, 0, insert_subsample_dsi_size, 0, 0, 0);
    3797             :                                 }
    3798             :                                 insert_subsample_dsi_size = GF_FALSE;
    3799             :                         }
    3800             :                 }
    3801      560706 :         } else if (for_fragment && tkw->has_subs && ctx->cmaf && (tkw->codecid==GF_CODECID_SUBS_XML)) {
    3802             :                 //tentative implemntation of CMAF 7.5.20 which is just nonsense text !!:
    3803             :                 //"the value of subsample_count shall equal 1 for the first image sub-sample, and the subsample_count of the TTML document shall equal 0."
    3804             :                 //
    3805             :                 //we simply signal a single subsample
    3806           0 :                 gf_isom_fragment_add_subsample(ctx->file, tkw->track_id, 0, tkw->sample.dataLength, 0, 0, 0);
    3807             :         }
    3808             : 
    3809      562238 :         if (ctx->deps) {
    3810      562238 :                 u8 dep_flags = gf_filter_pck_get_dependency_flags(pck);
    3811      562238 :                 if (dep_flags) {
    3812        4921 :                         u32 is_leading = (dep_flags>>6) & 0x3;
    3813        4921 :                         u32 depends_on = (dep_flags>>4) & 0x3;
    3814        4921 :                         u32 depended_on = (dep_flags>>2) & 0x3;
    3815        4921 :                         u32 redundant = (dep_flags) & 0x3;
    3816        4921 :                         if (for_fragment) {
    3817        1575 :                                 gf_isom_fragment_set_sample_flags(ctx->file, tkw->track_id, is_leading, depends_on, depended_on, redundant);
    3818             :                         } else {
    3819        3346 :                                 gf_isom_set_sample_flags(ctx->file, tkw->track_num, tkw->nb_samples, is_leading, depends_on, depended_on, redundant);
    3820             :                         }
    3821             :                 }
    3822             :         }
    3823             : 
    3824             : 
    3825      562238 :         tkw->next_is_first_sample = GF_FALSE;
    3826             : 
    3827      562238 :         if (duration && !for_fragment && !tkw->raw_audio_bytes_per_sample)
    3828      450044 :                 gf_isom_set_last_sample_duration(ctx->file, tkw->track_num, duration);
    3829             : 
    3830      562238 :         if (ctx->idur.num) {
    3831             :                 Bool abort = GF_FALSE;
    3832        8983 :                 if (ctx->idur.num>0) {
    3833        8982 :                         u64 mdur = gf_isom_get_media_duration(ctx->file, tkw->track_num);
    3834             : 
    3835             :                         /*patch to align to old arch */
    3836        8982 :                         if (gf_sys_old_arch_compat() && (tkw->stream_type==GF_STREAM_VISUAL)) {
    3837        3862 :                                 mdur = tkw->sample.DTS;
    3838             :                         }
    3839             : 
    3840        8982 :                         if (ctx->importer) {
    3841        8982 :                                 tkw->prog_done = mdur * ctx->idur.den;
    3842        8982 :                                 tkw->prog_total =  ((u64)tkw->tk_timescale) * ctx->idur.num;
    3843             :                         }
    3844             : 
    3845             :                         /*patch to align to old arch */
    3846        8982 :                         if (gf_sys_old_arch_compat()) {
    3847        8982 :                                 if (mdur * (u64) ctx->idur.den > tkw->tk_timescale * (u64) ctx->idur.num)
    3848             :                                         abort = GF_TRUE;
    3849             :                         } else {
    3850           0 :                                 if (mdur * (u64) ctx->idur.den >= tkw->tk_timescale * (u64) ctx->idur.num)
    3851             :                                         abort = GF_TRUE;
    3852             :                         }
    3853             :                 } else {
    3854           1 :                         if ((s32) tkw->nb_samples >= -ctx->idur.num)
    3855             :                                 abort = GF_TRUE;
    3856             :                 }
    3857             : 
    3858             :                 if (abort) {
    3859             :                         GF_FilterEvent evt;
    3860          82 :                         GF_FEVT_INIT(evt, GF_FEVT_STOP, tkw->ipid);
    3861          82 :                         gf_filter_pid_send_event(tkw->ipid, &evt);
    3862             : 
    3863          82 :                         tkw->aborted = GF_TRUE;
    3864             :                 }
    3865      553255 :         } else if (ctx->importer) {
    3866      346937 :                 if (tkw->nb_frames) {
    3867          47 :                         tkw->prog_done = tkw->nb_samples;
    3868          47 :                         tkw->prog_total = tkw->nb_frames;
    3869             :                 } else {
    3870      346890 :                         u64 data_offset = gf_filter_pck_get_byte_offset(pck);
    3871      346890 :                         if (data_offset == GF_FILTER_NO_BO) {
    3872      239435 :                                 data_offset = tkw->down_bytes;
    3873             :                         }
    3874      346890 :                         if ((data_offset != GF_FILTER_NO_BO) && tkw->down_size) {
    3875      338684 :                                 tkw->prog_done = data_offset;
    3876      338684 :                                 tkw->prog_total = tkw->down_size;
    3877             :                         } else {
    3878        8206 :                                 if (tkw->pid_dur.den && tkw->pid_dur.num) {
    3879           0 :                                         tkw->prog_done = tkw->sample.DTS * tkw->pid_dur.den;
    3880           0 :                                         tkw->prog_total = tkw->pid_dur.num * tkw->tk_timescale;
    3881             :                                 } else {
    3882        8206 :                                         tkw->prog_done = 0;
    3883        8206 :                                         tkw->prog_total = 1;
    3884             :                                 }
    3885             : 
    3886             :                         }
    3887             :                 }
    3888             :         }
    3889             :         return GF_OK;
    3890             : }
    3891             : 
    3892          64 : static GF_Err mp4_mux_process_item(GF_MP4MuxCtx *ctx, TrackWriter *tkw, GF_FilterPacket *pck)
    3893             : {
    3894             :         GF_Err e;
    3895             :         u32 meta_type, item_id, size, item_type, nb_items, media_brand;
    3896             :         GF_ImageItemProperties image_props;
    3897             :         GF_ImageItemProtection cenc_info;
    3898             :         const char *data, *item_name=NULL;
    3899             :         const GF_PropertyValue *p, *dsi, *dsi_enh;
    3900             :         GF_Box *config_box = NULL;
    3901             : 
    3902             : 
    3903          64 :         if (ctx->init_movie_done) {
    3904           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Cannot add item to a finalized movie, not supported\n"));
    3905             :                 return GF_NOT_SUPPORTED;
    3906             :         }
    3907             : 
    3908          64 :         if (tkw->stream_type != GF_STREAM_VISUAL) {
    3909           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Cannot add item other than visual, not supported - use MP4Box for this\n"));
    3910             :                 return GF_NOT_SUPPORTED;
    3911             :         }
    3912          64 :         ctx->update_report = GF_TRUE;
    3913             : 
    3914          64 :         meta_type = gf_isom_get_meta_type(ctx->file, GF_TRUE, 0);
    3915          64 :         if (!meta_type) {
    3916          29 :                 e = gf_isom_set_meta_type(ctx->file, GF_TRUE, 0, GF_META_ITEM_TYPE_PICT);
    3917          35 :         } else if (meta_type != GF_META_ITEM_TYPE_PICT) {
    3918           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] File already has a root 'meta' box of type %s\n", gf_4cc_to_str(meta_type)));
    3919             :                 e= GF_BAD_PARAM;
    3920             :         } else {
    3921             :                 e = GF_OK;
    3922             :         }
    3923          29 :         if (e) return e;
    3924             : 
    3925          64 :         data = (char *)gf_filter_pck_get_data(pck, &size);
    3926          64 :         if (!data) {
    3927           0 :                 if (gf_filter_pck_get_frame_interface(pck)) {
    3928           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Cannot add items from raw decoder outputs, not supported\n"));
    3929             :                         return GF_NOT_SUPPORTED;
    3930             :                 }
    3931             :                 return GF_OK;
    3932             :         }
    3933          64 :         ctx->total_bytes_in += size;
    3934          64 :         ctx->total_samples++;
    3935             : 
    3936             : 
    3937          64 :         item_id = 0;
    3938          64 :         p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_ITEM_ID);
    3939          64 :         if (p) item_id = p->value.uint;
    3940             : 
    3941             :         item_name = "Image";
    3942          64 :         p = gf_filter_pid_get_property_str(tkw->ipid, "meta:name");
    3943          64 :         if (p && p->value.string) item_name = p->value.string;
    3944             : 
    3945             :         memset(&image_props, 0, sizeof(GF_ImageItemProperties));
    3946             : 
    3947          64 :         dsi = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_DECODER_CONFIG);
    3948          64 :         dsi_enh = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_DECODER_CONFIG_ENHANCEMENT);
    3949             : 
    3950          64 :         switch (tkw->codecid) {
    3951          20 :         case GF_CODECID_AVC:
    3952             :         case GF_ISOM_SUBTYPE_SVC_H264:
    3953             :         case GF_ISOM_SUBTYPE_MVC_H264:
    3954          20 :                 if (!dsi) return GF_OK;
    3955             : 
    3956          20 :                 if (tkw->codecid==GF_CODECID_AVC) {
    3957          20 :                         config_box = gf_isom_box_new(GF_ISOM_BOX_TYPE_AVCC);
    3958             :                         item_type = GF_ISOM_SUBTYPE_AVC_H264;
    3959           0 :                 } else if (tkw->codecid==GF_CODECID_MVC) {
    3960           0 :                         config_box = gf_isom_box_new(GF_ISOM_BOX_TYPE_MVCC);
    3961             :                         item_type = GF_ISOM_SUBTYPE_MVC_H264;
    3962           0 :                         if (dsi_enh) dsi = dsi_enh;
    3963             :                 } else {
    3964           0 :                         config_box = gf_isom_box_new(GF_ISOM_BOX_TYPE_SVCC);
    3965             :                         item_type = GF_ISOM_SUBTYPE_SVC_H264;
    3966           0 :                         if (dsi_enh) dsi = dsi_enh;
    3967             :                 }
    3968             : 
    3969          20 :                 ((GF_AVCConfigurationBox *)config_box)->config = gf_odf_avc_cfg_read(dsi->value.data.ptr, dsi->value.data.size);
    3970          20 :                 if (! ((GF_AVCConfigurationBox *)config_box)->config) return GF_NON_COMPLIANT_BITSTREAM;
    3971             : 
    3972          20 :                 image_props.num_channels = 3;
    3973          20 :                 image_props.bits_per_channel[0] = ((GF_AVCConfigurationBox *)config_box)->config->luma_bit_depth;
    3974          20 :                 image_props.bits_per_channel[1] = ((GF_AVCConfigurationBox *)config_box)->config->chroma_bit_depth;
    3975          20 :                 image_props.bits_per_channel[2] = ((GF_AVCConfigurationBox *)config_box)->config->chroma_bit_depth;
    3976             :                 media_brand = GF_ISOM_BRAND_AVCI;
    3977          20 :                 break;
    3978             : 
    3979          41 :         case GF_CODECID_HEVC:
    3980             :         case GF_CODECID_HEVC_TILES:
    3981             :         case GF_CODECID_LHVC:
    3982          41 :                 if (tkw->codecid == GF_CODECID_LHVC) {
    3983           0 :                         if (dsi_enh) dsi = dsi_enh;
    3984           0 :                         if (!dsi) return GF_OK;
    3985             :                 }
    3986          41 :                 config_box = gf_isom_box_new(GF_ISOM_BOX_TYPE_HVCC);
    3987             : 
    3988          41 :                 if (dsi_enh) {
    3989           0 :                         ((GF_HEVCConfigurationBox *)config_box)->config = gf_odf_hevc_cfg_read(dsi->value.data.ptr, dsi->value.data.size, GF_TRUE);
    3990             :                         item_type = GF_ISOM_SUBTYPE_LHV1;
    3991             :                 } else {
    3992          41 :                         if ((tkw->codecid == GF_CODECID_HEVC) && !dsi) return GF_OK;
    3993             : 
    3994          41 :                         ((GF_HEVCConfigurationBox *)config_box)->config = gf_odf_hevc_cfg_read(dsi->value.data.ptr, dsi->value.data.size, GF_FALSE);
    3995          41 :                         item_type = (tkw->codecid == GF_CODECID_HEVC_TILES) ? GF_ISOM_SUBTYPE_HVT1 : GF_ISOM_SUBTYPE_HVC1;
    3996             :                 }
    3997          41 :                 if (! ((GF_HEVCConfigurationBox *)config_box)->config) {
    3998           0 :                         if ((tkw->codecid != GF_CODECID_HEVC_TILES) && !dsi) return GF_NON_COMPLIANT_BITSTREAM;
    3999             :                 } else {
    4000          41 :                         image_props.num_channels = 3;
    4001          41 :                         image_props.bits_per_channel[0] = ((GF_HEVCConfigurationBox *)config_box)->config->luma_bit_depth;
    4002          41 :                         image_props.bits_per_channel[1] = ((GF_HEVCConfigurationBox *)config_box)->config->chroma_bit_depth;
    4003          41 :                         image_props.bits_per_channel[2] = ((GF_HEVCConfigurationBox *)config_box)->config->chroma_bit_depth;
    4004             :                 }
    4005             :                 media_brand = GF_ISOM_BRAND_HEIC;
    4006          41 :                 if (tkw->codecid==GF_CODECID_LHVC) {
    4007             :                         media_brand = GF_ISOM_BRAND_HEIM;
    4008             :                 }
    4009             :                 break;
    4010           0 :         case GF_CODECID_AV1:
    4011           0 :                 if (!dsi) return GF_OK;
    4012             : 
    4013           0 :                 config_box = gf_isom_box_new(GF_ISOM_BOX_TYPE_AV1C);
    4014           0 :                 ((GF_AV1ConfigurationBox *)config_box)->config = gf_odf_av1_cfg_read(dsi->value.data.ptr, dsi->value.data.size);
    4015             : 
    4016           0 :                 if (! ((GF_AV1ConfigurationBox *)config_box)->config) return GF_NON_COMPLIANT_BITSTREAM;
    4017             : 
    4018             :                 item_type = GF_ISOM_SUBTYPE_AV01;
    4019           0 :                 u8 depth = ((GF_AV1ConfigurationBox *)config_box)->config->high_bitdepth ? (((GF_AV1ConfigurationBox *)config_box)->config->twelve_bit ? 12 : 10 ) : 8;
    4020           0 :                 if (((GF_AV1ConfigurationBox *)config_box)->config->monochrome) {
    4021           0 :                         image_props.num_channels = 1;
    4022           0 :                         image_props.bits_per_channel[0] = depth;
    4023           0 :                         image_props.bits_per_channel[1] = 0;
    4024           0 :                         image_props.bits_per_channel[2] = 0;
    4025             :                 } else {
    4026           0 :                         image_props.num_channels = 3;
    4027           0 :                         image_props.bits_per_channel[0] = depth;
    4028           0 :                         image_props.bits_per_channel[1] = depth;
    4029           0 :                         image_props.bits_per_channel[2] = depth;
    4030             :                 }
    4031             :                 media_brand = GF_ISOM_BRAND_AVIF;
    4032             :                 break;
    4033             :         case GF_CODECID_JPEG:
    4034             :                 item_type = GF_ISOM_SUBTYPE_JPEG;
    4035             :                 media_brand = GF_ISOM_SUBTYPE_JPEG /* == GF_4CC('j', 'p', 'e', 'g') */;
    4036             :                 break;
    4037           0 :         case GF_CODECID_J2K:
    4038             :                 item_type = GF_ISOM_SUBTYPE_JP2K;
    4039             :                 media_brand = GF_4CC('j', '2', 'k', 'i');
    4040           0 :                 break;
    4041           0 :         case GF_CODECID_PNG:
    4042             :                 item_type = GF_ISOM_SUBTYPE_PNG;
    4043             :                 //not defined !
    4044             :                 media_brand = GF_ISOM_SUBTYPE_PNG /* == GF_4CC('j', 'p', 'e', 'g') */;
    4045           0 :                 break;
    4046           0 :         default:
    4047           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error: Codec %s not supported to create HEIF image items\n", gf_codecid_name(tkw->codecid) ));
    4048             :                 return GF_NOT_SUPPORTED;
    4049             :         }
    4050             : 
    4051          64 :         p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_WIDTH);
    4052          64 :         if (p) image_props.width = p->value.uint;
    4053          64 :         p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_HEIGHT);
    4054          64 :         if (p) image_props.height = p->value.uint;
    4055          64 :         p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_ALPHA);
    4056          64 :         if (p) image_props.alpha = p->value.boolean;
    4057          64 :         p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_SAR);
    4058          64 :         if (p) {
    4059           0 :                 image_props.hSpacing = p->value.frac.num;
    4060           0 :                 image_props.vSpacing = p->value.frac.den;
    4061             :         } else {
    4062          64 :                 image_props.hSpacing = image_props.vSpacing = 1;
    4063             :         }
    4064          64 :         image_props.config = config_box;
    4065          64 :         p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_HIDDEN);
    4066          64 :         if (p) image_props.hidden = p->value.boolean;
    4067             : 
    4068             :         //setup crypto
    4069          64 :         if (tkw->is_encrypted && gf_filter_pck_get_crypt_flags(pck)) {
    4070             :                 memset(&cenc_info, 0, sizeof(GF_ImageItemProtection));
    4071          10 :                 p = gf_filter_pck_get_property(pck, GF_PROP_PCK_CENC_SAI);
    4072          10 :                 if (!p) {
    4073           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error: Missing CENC SAI on protected packet\n"));
    4074             :                         return GF_SERVICE_ERROR;
    4075             :                 }
    4076          10 :                 cenc_info.sai_data = p->value.data.ptr;
    4077          10 :                 cenc_info.sai_data_size = p->value.data.size;
    4078             : 
    4079          10 :                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_PROTECTION_SCHEME_TYPE);
    4080          10 :                 if (!p) {
    4081           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error: Missing CENC scheme type on protected item\n"));
    4082             :                         return GF_SERVICE_ERROR;
    4083             :                 }
    4084          10 :                 cenc_info.scheme_type = p->value.uint;
    4085             : 
    4086          10 :                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_PROTECTION_SCHEME_VERSION);
    4087          10 :                 if (!p) {
    4088           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error: Missing CENC scheme version on protected item\n"));
    4089             :                         return GF_SERVICE_ERROR;
    4090             :                 }
    4091          10 :                 cenc_info.scheme_version = p->value.uint;
    4092             : 
    4093          10 :                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_CENC_KEY_INFO);
    4094          10 :                 if (!p || (p->type != GF_PROP_DATA) || !gf_cenc_validate_key_info(p->value.data.ptr, p->value.data.size)) {
    4095           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error: %s CENC Key info on protected item\n", p ? "Corrupted" : "Missing"));
    4096             :                         return GF_NON_COMPLIANT_BITSTREAM;
    4097             :                 }
    4098          10 :                 cenc_info.key_info = p->value.data.ptr;
    4099          10 :                 cenc_info.key_info_size = p->value.data.size;
    4100             : 
    4101          10 :                 image_props.cenc_info = &cenc_info;
    4102             : 
    4103          10 :                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_CENC_PATTERN);
    4104          10 :                 if (p) {
    4105           4 :                         cenc_info.skip_byte_block = p->value.frac.num;
    4106           4 :                         cenc_info.crypt_byte_block = p->value.frac.den;
    4107             :                 }
    4108             : 
    4109             : 
    4110          10 :                 if (tkw->insert_pssh) {
    4111          10 :                         mp4_mux_cenc_insert_pssh(ctx, tkw);
    4112          10 :                         tkw->insert_pssh = GF_FALSE;
    4113             :                 }
    4114             :         }
    4115             : 
    4116          64 :         nb_items = gf_isom_get_meta_item_count(ctx->file, GF_TRUE, 0);
    4117             : 
    4118          64 :         e = gf_isom_add_meta_item_memory(ctx->file, GF_TRUE, 0, item_name, &item_id, item_type, NULL, NULL, &image_props, (u8 *)data, size, NULL);
    4119             : 
    4120          64 :         if (config_box) gf_isom_box_del(config_box);
    4121             : 
    4122          64 :         if (e) return e;
    4123             : 
    4124             : 
    4125             :         //retrieve the final itemID
    4126          64 :         gf_isom_get_meta_item_info(ctx->file, GF_TRUE, 0, nb_items+1, &item_id, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    4127          64 :         tkw->item_id = item_id;
    4128             : 
    4129          64 :         p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_PRIMARY_ITEM);
    4130          64 :         if (p && p->value.boolean) {
    4131          10 :                 e = gf_isom_set_meta_primary_item(ctx->file, GF_TRUE, 0, item_id);
    4132          10 :                 if (e) return e;
    4133             :         }
    4134             :         //if primary item is not set, assign one
    4135          54 :         else if (! gf_isom_get_meta_primary_item_id(ctx->file, GF_TRUE, 0)) {
    4136          19 :                 e = gf_isom_set_meta_primary_item(ctx->file, GF_TRUE, 0, item_id);
    4137          19 :                 if (e) return e;
    4138             :         }
    4139             : 
    4140          64 :         if (!ctx->major_brand_set) {
    4141          29 :                 gf_isom_set_brand_info(ctx->file, GF_ISOM_BRAND_MIF1, 0);
    4142          29 :                 gf_isom_reset_alt_brands(ctx->file);
    4143          29 :                 ctx->major_brand_set = 2;
    4144             :         }
    4145          64 :         if (media_brand && (ctx->major_brand_set==2)) {
    4146          64 :                 gf_isom_modify_alternate_brand(ctx->file, media_brand, 1);
    4147             :         }
    4148             : #if 0
    4149             :         if (e == GF_OK && meta->ref_type) {
    4150             :                 e = gf_isom_meta_add_item_ref(file, meta->root_meta, tk, meta->item_id, meta->ref_item_id, meta->ref_type, NULL);
    4151             :         }
    4152             : #endif
    4153             :         return GF_OK;
    4154             : }
    4155             : 
    4156       40961 : static void mp4mux_send_output(GF_MP4MuxCtx *ctx)
    4157             : {
    4158       40961 :         if (ctx->dst_pck) {
    4159       20901 :                 if (ctx->notify_filename) {
    4160          83 :                         gf_filter_pck_set_framing(ctx->dst_pck, GF_TRUE, GF_FALSE);
    4161          83 :                         gf_filter_pck_set_property(ctx->dst_pck, GF_PROP_PCK_FILENUM, &PROP_UINT(ctx->cur_file_idx_plus_one-1) );
    4162          83 :                         if (ctx->cur_file_suffix) {
    4163          83 :                                 gf_filter_pck_set_property(ctx->dst_pck, GF_PROP_PCK_FILESUF, &PROP_STRING_NO_COPY(ctx->cur_file_suffix) );
    4164          83 :                                 ctx->cur_file_suffix = NULL;
    4165             :                         }
    4166          83 :                         ctx->notify_filename = 0;
    4167             :                 }
    4168       20901 :                 gf_filter_pck_send(ctx->dst_pck);
    4169       20901 :                 ctx->dst_pck = NULL;
    4170             :         }
    4171       40961 : }
    4172             : 
    4173         330 : static void mp4_mux_flush_frag_hls(GF_MP4MuxCtx *ctx)
    4174             : {
    4175             :         GF_FilterEvent evt;
    4176             :         TrackWriter *tkw = NULL;
    4177             :         //send event on first track only
    4178         330 :         tkw = gf_list_get(ctx->tracks, 0);
    4179         330 :         GF_FEVT_INIT(evt, GF_FEVT_FRAGMENT_SIZE, tkw->ipid);
    4180         330 :         evt.frag_size.is_last = ctx->flush_seg ? GF_TRUE : GF_FALSE;
    4181         330 :         evt.frag_size.offset = ctx->frag_offset;
    4182         330 :         evt.frag_size.size = ctx->frag_size;
    4183         330 :         evt.frag_size.duration.num = (s64) ctx->frag_duration;
    4184         330 :         evt.frag_size.duration.den = ctx->frag_timescale;
    4185         330 :         evt.frag_size.independent = ctx->frag_has_intra;
    4186             : 
    4187         330 :         gf_filter_pid_send_event(tkw->ipid, &evt);
    4188             : 
    4189         330 :         ctx->frag_offset += ctx->frag_size;
    4190         330 :         ctx->frag_size = 0;
    4191         330 :         ctx->frag_duration = 0;
    4192         330 :         ctx->frag_has_intra = GF_FALSE;
    4193         330 : }
    4194             : 
    4195        3417 : static void mp4_mux_flush_seg(GF_MP4MuxCtx *ctx, Bool is_init, u64 idx_start_range, u64 idx_end_range)
    4196             : {
    4197             :         GF_FilterEvent evt;
    4198             :         TrackWriter *tkw = NULL;
    4199             : 
    4200        3417 :         if (ctx->dst_pck) {
    4201        3124 :                 if (!ctx->single_file) {
    4202             :                         Bool s, e;
    4203        2725 :                         gf_filter_pck_get_framing(ctx->dst_pck, &s, &e);
    4204        2725 :                         gf_filter_pck_set_framing(ctx->dst_pck, s, GF_TRUE);
    4205        2725 :                         if (!is_init) {
    4206        2487 :                                 u64 dur = ctx->next_seg_start - (ctx->min_cts_plus_one-1);
    4207        2487 :                                 gf_filter_pck_set_duration(ctx->dst_pck, (u32) dur);
    4208             :                         }
    4209        2725 :                         ctx->first_pck_sent = GF_FALSE;
    4210        2725 :                         ctx->current_offset = 0;
    4211        2725 :                         if (is_init && s)
    4212         238 :                                 gf_filter_pck_set_property(ctx->dst_pck, GF_PROP_PCK_INIT, &PROP_BOOL(GF_TRUE) );
    4213             :                 }
    4214        3124 :                 if (is_init) {
    4215         294 :                         gf_filter_pck_set_dependency_flags(ctx->dst_pck, 0xFF);
    4216         294 :                         gf_filter_pck_set_carousel_version(ctx->dst_pck, 1);
    4217             :                 }
    4218        3124 :                 mp4mux_send_output(ctx);
    4219             :         }
    4220        3417 :         if (!is_init && ctx->llhls_mode && ctx->frag_size) {
    4221          51 :                 mp4_mux_flush_frag_hls(ctx);
    4222             :         }
    4223        3417 :         if (ctx->dash_mode) {
    4224             :                 //send event on first track only
    4225        3324 :                 tkw = gf_list_get(ctx->tracks, 0);
    4226        3324 :                 GF_FEVT_INIT(evt, GF_FEVT_SEGMENT_SIZE, tkw->ipid);
    4227             :                 evt.seg_size.seg_url = NULL;
    4228        3324 :                 evt.seg_size.is_init = is_init ? GF_TRUE : GF_FALSE;
    4229        3324 :                 if (!is_init || !idx_end_range) {
    4230        3307 :                         evt.seg_size.media_range_start = ctx->current_offset;
    4231        3307 :                         evt.seg_size.media_range_end = ctx->current_offset + ctx->current_size - 1;
    4232             :                 }
    4233        3324 :                 evt.seg_size.idx_range_start = idx_start_range;
    4234        3324 :                 evt.seg_size.idx_range_end = idx_end_range;
    4235        3324 :                 gf_filter_pid_send_event(tkw->ipid, &evt);
    4236             : 
    4237        3324 :                 ctx->current_offset += ctx->current_size;
    4238        3324 :                 ctx->current_size = 0;
    4239        3324 :                 ctx->frag_offset = 0;
    4240        3324 :                 ctx->frag_size = 0;
    4241        3324 :                 ctx->frag_num = 0;
    4242        3324 :                 ctx->frag_has_intra = GF_FALSE;
    4243             :                 //changing file
    4244        3324 :                 if (ctx->seg_name) {
    4245        2484 :                         ctx->first_pck_sent = GF_FALSE;
    4246             :                 }
    4247             :         }
    4248        3417 : }
    4249             : 
    4250             : 
    4251         339 : static GF_Err mp4_mux_initialize_movie(GF_MP4MuxCtx *ctx)
    4252             : {
    4253             :         GF_Err e;
    4254         339 :         u32 i, count = gf_list_count(ctx->tracks);
    4255             :         TrackWriter *ref_tkw = NULL;
    4256             :         u64 min_dts = 0;
    4257             :         u32 min_dts_scale=0;
    4258             :         u32 def_fake_dur=0;
    4259             :         u32 def_fake_scale=0;
    4260             : #ifdef GF_ENABLE_CTRN
    4261             :         u32 traf_inherit_base_id=0;
    4262             : #endif
    4263             :         u32 nb_segments=0;
    4264             :         GF_Fraction64 max_dur;
    4265         339 :         ctx->single_file = GF_TRUE;
    4266         339 :         ctx->current_offset = ctx->current_size = 0;
    4267             :         max_dur.den = 1;
    4268             :         max_dur.num = 0;
    4269             : 
    4270         339 :         if (ctx->sseg && ctx->noinit)
    4271           3 :                 ctx->single_file = GF_FALSE;
    4272             : 
    4273         339 :         if (ctx->idur.num && ctx->idur.den) {
    4274           0 :                 max_dur.num = ctx->idur.num;
    4275           0 :                 max_dur.den = ctx->idur.den;
    4276             :         }
    4277             : 
    4278             :         //make sure we have one sample from each PID. This will trigger potential pending reconfigure
    4279             :         //for filters updating the PID caps before the first packet dispatch
    4280         389 :         for (i=0; i<count; i++) {
    4281             :                 const GF_PropertyValue *p;
    4282         389 :                 TrackWriter *tkw = gf_list_get(ctx->tracks, i);
    4283             :                 GF_FilterPacket *pck;
    4284         389 :                 if (tkw->fake_track) continue;
    4285             : 
    4286         362 :                 pck = gf_filter_pid_get_packet(tkw->ipid);
    4287         362 :                 if (!pck) {
    4288           0 :                         if (gf_filter_pid_is_eos(tkw->ipid)) continue;
    4289             :                         return GF_OK;
    4290             :                 }
    4291             : 
    4292         362 :                 if (!ctx->dash_mode && !ctx->cur_file_idx_plus_one) {
    4293          14 :                         p = gf_filter_pck_get_property(pck, GF_PROP_PCK_FILENUM);
    4294          14 :                         if (p) {
    4295           4 :                                 ctx->cur_file_idx_plus_one = p->value.uint + 1;
    4296           4 :                                 if (!ctx->cur_file_suffix) {
    4297           4 :                                         p = gf_filter_pck_get_property(pck, GF_PROP_PCK_FILESUF);
    4298           4 :                                         if (p && p->value.string) ctx->cur_file_suffix = gf_strdup(p->value.string);
    4299             :                                 }
    4300           4 :                                 ctx->notify_filename = GF_TRUE;
    4301             :                         }
    4302             :                 }
    4303             : 
    4304         362 :                 if (tkw->cenc_state==CENC_NEED_SETUP) {
    4305         112 :                         mp4_mux_cenc_update(ctx, tkw, pck, CENC_CONFIG, 0);
    4306             :                 }
    4307             : 
    4308         362 :                 p = gf_filter_pck_get_property(pck, GF_PROP_PCK_FILENAME);
    4309         362 :                 if (p && strlen(p->value.string)) ctx->single_file = GF_FALSE;
    4310             : 
    4311         362 :                 def_fake_dur = gf_filter_pck_get_duration(pck);
    4312         362 :                 def_fake_scale = tkw->src_timescale;
    4313             : 
    4314         362 :                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_DURATION);
    4315         362 :                 if (p && p->value.lfrac.num>0 && p->value.lfrac.den) {
    4316         350 :                         tkw->pid_dur = p->value.lfrac;
    4317         350 :                         if (max_dur.num * (s64) p->value.lfrac.den < (s64) max_dur.den * p->value.lfrac.num) {
    4318             :                                 max_dur.num = p->value.lfrac.num;
    4319             :                                 max_dur.den = p->value.lfrac.den;
    4320             :                         }
    4321             :                 }
    4322             : #ifdef GF_ENABLE_CTRN
    4323             :                 if (tkw->codecid==GF_CODECID_HEVC)
    4324             :                         traf_inherit_base_id = tkw->track_id;
    4325             : #endif
    4326             :         }
    4327             :         //good to go, finalize for fragments
    4328         389 :         for (i=0; i<count; i++) {
    4329             :                 u32 def_pck_dur;
    4330             :                 u32 def_samp_size=0;
    4331             :                 u32 def_is_rap;
    4332             : #ifdef GF_ENABLE_CTRN
    4333             :                 u32 inherit_traf_from_track = 0;
    4334             : #endif
    4335             :                 u64 dts;
    4336             :                 const GF_PropertyValue *p;
    4337             : 
    4338         389 :                 TrackWriter *tkw = gf_list_get(ctx->tracks, i);
    4339             : 
    4340         389 :                 if (tkw->fake_track) {
    4341          27 :                         if (def_fake_scale) {
    4342             :                                 def_pck_dur = def_fake_dur;
    4343          27 :                                 def_pck_dur *= tkw->src_timescale;
    4344          27 :                                 def_pck_dur /= def_fake_scale;
    4345             :                         } else {
    4346             :                                 def_pck_dur = 0;
    4347             :                         }
    4348             :                 } else {
    4349         362 :                         GF_FilterPacket *pck = gf_filter_pid_get_packet(tkw->ipid);
    4350             :                         //can be null if eos
    4351         362 :                         if (pck) {
    4352             :                                 u32 tscale;
    4353             :                                 //otherwise setup fragmentation, using first sample desc as default idx
    4354             :                                 //first pck dur as default
    4355         362 :                                 def_pck_dur = gf_filter_pck_get_duration(pck);
    4356             : 
    4357         362 :                                 dts = gf_filter_pck_get_dts(pck);
    4358         362 :                                 if (dts == GF_FILTER_NO_TS)
    4359           0 :                                         dts = gf_filter_pck_get_cts(pck);
    4360         362 :                                 tscale = gf_filter_pck_get_timescale(pck);
    4361             : 
    4362         362 :                                 if (!min_dts || min_dts * tscale > dts * min_dts_scale) {
    4363             :                                         min_dts = dts;
    4364             :                                         min_dts_scale = tscale;
    4365             :                                 }
    4366         362 :                                 if (tkw->raw_audio_bytes_per_sample) {
    4367             :                                         u32 pck_size;
    4368           0 :                                         gf_filter_pck_get_data(pck, &pck_size);
    4369           0 :                                         pck_size /= tkw->raw_audio_bytes_per_sample;
    4370           0 :                                         if (pck_size)
    4371           0 :                                                 def_pck_dur /= pck_size;
    4372             :                                 }
    4373             :                         } else {
    4374             :                                 def_pck_dur = 0;
    4375             :                         }
    4376         362 :                         if (tkw->raw_audio_bytes_per_sample)
    4377             :                                 def_samp_size = tkw->raw_audio_bytes_per_sample;
    4378             :                 }
    4379         389 :                 if (tkw->src_timescale != tkw->tk_timescale) {
    4380           0 :                         def_pck_dur *= tkw->tk_timescale;
    4381           0 :                         def_pck_dur /= tkw->src_timescale;
    4382             :                 }
    4383             : 
    4384             :                 //and consider audio & text all RAPs, the rest not rap - this will need refinement later on
    4385             :                 //but won't break the generated files
    4386         389 :                 switch (tkw->stream_type) {
    4387          89 :                 case GF_STREAM_AUDIO:
    4388             :                 case GF_STREAM_TEXT:
    4389             :                         def_is_rap = GF_TRUE;
    4390          89 :                         p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_HAS_SYNC);
    4391          89 :                         if (p && p->value.boolean)
    4392             :                                 def_is_rap = GF_FALSE;
    4393             :                         break;
    4394         296 :                 case GF_STREAM_VISUAL:
    4395         296 :                         switch (tkw->codecid) {
    4396             :                         case GF_CODECID_PNG:
    4397             :                         case GF_CODECID_JPEG:
    4398             :                         case GF_CODECID_J2K:
    4399             :                                 break;
    4400             :                         case GF_CODECID_HEVC_TILES:
    4401             : #ifdef GF_ENABLE_CTRN
    4402             :                                 if (ctx->ctrn && ctx->ctrni)
    4403             :                                         inherit_traf_from_track = traf_inherit_base_id;
    4404             : #endif
    4405             :                                 break;
    4406         233 :                         default:
    4407         233 :                                 if (!ref_tkw) ref_tkw = tkw;
    4408             :                                 break;
    4409             :                         }
    4410             :                         def_is_rap = GF_FALSE;
    4411             :                         break;
    4412             : 
    4413             :                 default:
    4414             :                         def_is_rap = GF_FALSE;
    4415             :                         break;
    4416             :                 }
    4417             : 
    4418         389 :                 mp4_mux_set_hevc_groups(ctx, tkw);
    4419             : 
    4420             :                 //use 1 for the default sample description index. If no multi stsd, this is always the case
    4421             :                 //otherwise we need to update the stsd idx in the traf headers
    4422         389 :                 e = gf_isom_setup_track_fragment(ctx->file, tkw->track_id, tkw->stsd_idx, def_pck_dur, def_samp_size, (u8) def_is_rap, 0, 0, ctx->nofragdef ? GF_TRUE : GF_FALSE);
    4423         389 :                 if (e) {
    4424           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Unable to setup fragmentation for track ID %d: %s\n", tkw->track_id, gf_error_to_string(e) ));
    4425             :                         return e;
    4426             :                 }
    4427             : 
    4428         389 :                 if (ctx->refrag) {
    4429           3 :                         p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_ISOM_TREX_TEMPLATE);
    4430           3 :                         if (p) {
    4431           3 :                                 gf_isom_setup_track_fragment_template(ctx->file, tkw->track_id, p->value.data.ptr, p->value.data.size, ctx->nofragdef);
    4432           0 :                         } else if (!ctx->nofragdef) {
    4433           0 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] Refragmentation with default track fragment flags signaling but no TREX found in source track %d, using defaults computed from PID, result might be broken\n", tkw->track_id));
    4434             :                         }
    4435             :                 }
    4436             : 
    4437             : 
    4438         389 :                 if (ctx->tfdt.den && ctx->tfdt.num) {
    4439           0 :                         tkw->offset_dts = ctx->tfdt.num * tkw->tk_timescale;
    4440           0 :                         tkw->offset_dts /= ctx->tfdt.den;
    4441             :                 }
    4442             : 
    4443         389 :                 if (tkw->fake_track) {
    4444          27 :                         gf_list_del_item(ctx->tracks, tkw);
    4445          27 :                         if (ref_tkw==tkw) ref_tkw=NULL;
    4446          27 :                         mp4_mux_track_writer_del(tkw);
    4447          27 :                         i--;
    4448          27 :                         count--;
    4449          27 :                         continue;
    4450             :                 }
    4451             : 
    4452             : #ifdef GF_ENABLE_CTRN
    4453             :                 if (inherit_traf_from_track)
    4454             :                         gf_isom_enable_traf_inherit(ctx->file, tkw->track_id, inherit_traf_from_track);
    4455             : #endif
    4456             : 
    4457         362 :                 if (!tkw->box_patched) {
    4458         353 :                         p = gf_filter_pid_get_property_str(tkw->ipid, "boxpatch");
    4459         353 :                         if (p && p->value.string) {
    4460           0 :                                 e = gf_isom_apply_box_patch(ctx->file, tkw->track_id, p->value.string, GF_FALSE);
    4461           0 :                                 if (e) {
    4462           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Unable to apply box patch %s to track %d: %s\n",
    4463             :                                                 p->value.string, tkw->track_id, gf_error_to_string(e) ));
    4464             :                                 }
    4465             :                         }
    4466         353 :                         tkw->box_patched = GF_TRUE;
    4467             :                 }
    4468             : 
    4469         362 :                 p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_DASH_SEGMENTS);
    4470         362 :                 if (p && (p->value.uint>nb_segments))
    4471             :                         nb_segments = p->value.uint;
    4472             : 
    4473         362 :                 if (!ctx->dash_mode)
    4474          28 :                         gf_isom_purge_track_reference(ctx->file, tkw->track_num);
    4475             :         }
    4476             : 
    4477         666 :         if (max_dur.num && max_dur.den) {
    4478         327 :                 u64 mdur = max_dur.num;
    4479         327 :                 if (ctx->moovts != max_dur.den) {
    4480         290 :                         mdur *= (u32) ctx->moovts;
    4481         290 :                         mdur /= max_dur.den;
    4482             :                 }
    4483         327 :                 gf_isom_set_movie_duration(ctx->file, mdur, GF_FALSE);
    4484             :         }
    4485          12 :         else if (ctx->cmaf) {
    4486             :                 //CMAF 7.3.2.1.c.6) "The MovieExtendsBox may contain a MovieExtendsHeaderBox,
    4487             :                 //as defined in ISO/IEC 14496-12, and if so, shall provide the overall duration
    4488             :                 //of the CMAF track. If the duration is unknown, this box shall be omitted."
    4489           0 :                 gf_isom_set_movie_duration(ctx->file, 0, GF_TRUE);
    4490             :         }
    4491             : 
    4492             :         //if we have an explicit track reference for fragmenting, move it first in our list
    4493         339 :         if (ref_tkw) {
    4494         230 :                 gf_list_del_item(ctx->tracks, ref_tkw);
    4495         230 :                 gf_list_insert(ctx->tracks, ref_tkw, 0);
    4496             :         }
    4497         339 :         ctx->ref_tkw = gf_list_get(ctx->tracks, 0);
    4498             : 
    4499         339 :         if (!ctx->abs_offset) {
    4500         335 :                 u32 mval = ctx->dash_mode ? '6' : '5';
    4501             :                 u32 mbrand, mcount, found=0;
    4502             :                 u8 szB[GF_4CC_MSIZE];
    4503         335 :                 gf_isom_set_fragment_option(ctx->file, 0, GF_ISOM_TFHD_FORCE_MOOF_BASE_OFFSET, 1);
    4504             : 
    4505         335 :                 gf_isom_get_brand_info(ctx->file, &mbrand, NULL, &mcount);
    4506         335 :                 strcpy(szB, gf_4cc_to_str(mbrand));
    4507         335 :                 if (!strncmp(szB, "iso", 3) && (szB[3] >= mval) && (szB[3] <= 'F') ) found = 1;
    4508             :                 i=0;
    4509        1143 :                 while (!found && (i<mcount)) {
    4510         485 :                         i++;
    4511         485 :                         gf_isom_get_alternate_brand(ctx->file, i, &mbrand);
    4512         485 :                         strcpy(szB, gf_4cc_to_str(mbrand));
    4513         485 :                         if (!strncmp(szB, "iso", 3) && (szB[3] >= mval) && (szB[3] <= 'F') ) found = 1;
    4514             :                 }
    4515             : 
    4516             :                 /*because of movie fragments MOOF based offset, ISOM <4 is forbidden*/
    4517         335 :                 if (!found) {
    4518         273 :                         gf_isom_set_brand_info(ctx->file, ctx->dash_mode ? GF_ISOM_BRAND_ISO6 : GF_ISOM_BRAND_ISO5, 1);
    4519             :                 }
    4520             : 
    4521         335 :                 gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_ISOM, GF_FALSE);
    4522         335 :                 gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_ISO1, GF_FALSE);
    4523         335 :                 gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_ISO2, GF_FALSE);
    4524         335 :                 gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_ISO3, GF_FALSE);
    4525         335 :                 gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_ISO4, GF_FALSE);
    4526         335 :                 gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_AVC1, GF_FALSE);
    4527         335 :                 gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_MP41, GF_FALSE);
    4528         335 :                 gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_MP42, GF_FALSE);
    4529             :         }
    4530             : 
    4531         339 :         if (ctx->dash_mode) {
    4532             :                 /*DASH self-init media segment*/
    4533         326 :                 if (ctx->dash_mode==MP4MX_DASH_VOD) {
    4534          17 :                         gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_DSMS, GF_TRUE);
    4535             :                 } else {
    4536         309 :                         gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_DASH, GF_TRUE);
    4537             :                 }
    4538         326 :                 gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_MSIX, ((ctx->dash_mode==MP4MX_DASH_VOD) && (ctx->subs_sidx>=0)) ? GF_TRUE : GF_FALSE);
    4539             :         }
    4540             : 
    4541         339 :         if (ctx->boxpatch && !ctx->box_patched) {
    4542           1 :                 e = gf_isom_apply_box_patch(ctx->file, 0, ctx->boxpatch, GF_FALSE);
    4543           1 :                 if (e) {
    4544           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Unable to apply box patch %s: %s\n", ctx->boxpatch, gf_error_to_string(e) ));
    4545             :                 }
    4546           1 :                 ctx->box_patched = GF_TRUE;
    4547             :         }
    4548             : 
    4549         339 :         e = gf_isom_finalize_for_fragment(ctx->file, ctx->dash_mode ? 1 : 0, ctx->mvex);
    4550         339 :         if (e) {
    4551           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Unable to finalize moov for fragmentation: %s\n", gf_error_to_string(e) ));
    4552             :                 return e;
    4553             :         }
    4554         339 :         ctx->init_movie_done = GF_TRUE;
    4555             : 
    4556         339 :         if (min_dts_scale) {
    4557             :                 u64 rs_dts = min_dts;
    4558         339 :                 rs_dts *= ctx->cdur.den;
    4559         339 :                 rs_dts /= min_dts_scale;
    4560         339 :                 ctx->next_frag_start = rs_dts;
    4561             :         }
    4562         339 :         ctx->next_frag_start += ctx->cdur.num;
    4563         339 :         ctx->adjusted_next_frag_start = ctx->next_frag_start;
    4564         339 :         ctx->fragment_started = GF_FALSE;
    4565             : 
    4566         339 :         if (ctx->noinit) {
    4567          45 :                 if (ctx->dst_pck) gf_filter_pck_discard(ctx->dst_pck);
    4568          45 :                 ctx->dst_pck = NULL;
    4569          45 :                 ctx->current_size = ctx->current_offset = 0;
    4570          45 :                 ctx->first_pck_sent = GF_FALSE;
    4571             :         } else {
    4572         294 :                 mp4_mux_flush_seg(ctx, GF_TRUE, 0, 0);
    4573             :         }
    4574             :         assert(!ctx->dst_pck);
    4575             : 
    4576             :         //change major brand for segments
    4577         339 :         if (ctx->styp && (strlen(ctx->styp)>=4)) {
    4578           0 :                 u32 styp_brand = GF_4CC(ctx->styp[0], ctx->styp[1], ctx->styp[2], ctx->styp[3]);
    4579             :                 u32 version = 0;
    4580           0 :                 char *sep = strchr(ctx->styp, '.');
    4581           0 :                 if (sep) version = atoi(sep+1);
    4582           0 :                 gf_isom_set_brand_info(ctx->file, styp_brand, version);
    4583             :         }
    4584             : 
    4585         339 :         if (ctx->dash_mode==MP4MX_DASH_VOD) {
    4586          17 :                 if ((ctx->vodcache==MP4MX_VODCACHE_REPLACE) && !nb_segments && (!ctx->media_dur || !ctx->dash_dur.num) ) {
    4587           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] Media duration unknown, cannot use replace mode of vodcache, using temp file for VoD storage\n"));
    4588           0 :                         ctx->vodcache = MP4MX_VODCACHE_ON;
    4589           0 :                         e = mp4mx_setup_dash_vod(ctx, NULL);
    4590           0 :                         if (e) return e;
    4591             :                 }
    4592             : 
    4593          17 :                 if (ctx->vodcache==MP4MX_VODCACHE_REPLACE) {
    4594             :                         GF_BitStream *bs;
    4595             :                         u8 *output;
    4596             :                         char *msg;
    4597             :                         GF_FilterPacket *pck;
    4598             :                         u32 len;
    4599             :                         Bool exact_sidx = GF_TRUE;
    4600             : 
    4601           0 :                         if (!nb_segments) {
    4602             :                                 exact_sidx = GF_FALSE;
    4603           0 :                                 nb_segments = (u32) ( ctx->media_dur * ctx->dash_dur.den / ctx->dash_dur.num);
    4604             :                                 //always add an extra segment
    4605           0 :                                 nb_segments ++;
    4606             :                                 //and safety alloc of 10%
    4607           0 :                                 if (nb_segments>10)
    4608           0 :                                         nb_segments += 10*nb_segments/100;
    4609             :                                 else
    4610           0 :                                         nb_segments ++;
    4611             :                         }
    4612             : 
    4613             :                         //max sidx size: full box + sidx fields + timing 64 bit + nb segs (each 12 bytes)
    4614           0 :                         ctx->sidx_max_size = 12 + (12 + 16) + 12 * nb_segments;
    4615             : 
    4616             :                         //we produce an ssix, add full box + nb subsegs + nb_segments * (range_count=2 + 2*(range+size))
    4617           0 :                         if (ctx->ssix) {
    4618           0 :                                 ctx->sidx_max_size += 12 + 4 + nb_segments * 12;
    4619             :                         }
    4620             : 
    4621           0 :                         if (!exact_sidx) {
    4622             :                                 //and a free box
    4623           0 :                                 ctx->sidx_max_size += 8;
    4624           0 :                                 ctx->sidx_size_exact = GF_FALSE;
    4625             :                         } else {
    4626           0 :                                 ctx->sidx_size_exact = GF_TRUE;
    4627             :                         }
    4628           0 :                         ctx->sidx_chunk_offset = (u32) (ctx->current_offset + ctx->current_size);
    4629             :                         //send a dummy packet
    4630           0 :                         pck = gf_filter_pck_new_alloc(ctx->opid, ctx->sidx_max_size, &output);
    4631           0 :                         if (!pck) return GF_OUT_OF_MEM;
    4632             : 
    4633           0 :                         gf_filter_pck_set_framing(pck, GF_FALSE, GF_FALSE);
    4634             :                         //format as free box for now
    4635           0 :                         bs = gf_bs_new(output, ctx->sidx_max_size, GF_BITSTREAM_WRITE);
    4636           0 :                         gf_bs_write_u32(bs, ctx->sidx_max_size);
    4637           0 :                         gf_bs_write_u32(bs, GF_ISOM_BOX_TYPE_FREE);
    4638             :                         msg = "GPAC " GPAC_VERSION" SIDX placeholder";
    4639             :                         len = (u32) strlen(msg);
    4640           0 :                         if (len+8>ctx->sidx_max_size) len = ctx->sidx_max_size - 8;
    4641           0 :                         gf_bs_write_data(bs, msg, len );
    4642           0 :                         gf_bs_del(bs);
    4643           0 :                         gf_filter_pck_send(pck);
    4644          17 :                 } else if (ctx->vodcache==MP4MX_VODCACHE_ON) {
    4645          17 :                         ctx->store_output = GF_TRUE;
    4646             :                 } else {
    4647           0 :                         ctx->store_output = GF_FALSE;
    4648           0 :                         ctx->sidx_chunk_offset = (u32) (ctx->current_offset + ctx->current_size);
    4649             :                 }
    4650          17 :                 gf_isom_allocate_sidx(ctx->file, ctx->subs_sidx, ctx->chain_sidx, 0, NULL, NULL, NULL, ctx->ssix);
    4651             :         }
    4652             :         return GF_OK;
    4653             : }
    4654             : 
    4655        3571 : static GF_Err mp4_mux_start_fragment(GF_MP4MuxCtx *ctx, GF_FilterPacket *pck)
    4656             : {
    4657             :         GF_Err e;
    4658        3571 :         u32 i, count = gf_list_count(ctx->tracks);
    4659        3571 :         Bool has_tfdt=GF_FALSE;
    4660             :         GF_ISOStartFragmentFlags flags=0;
    4661             : 
    4662             :         //setup some default
    4663        3571 :         gf_isom_set_next_moof_number(ctx->file, ctx->msn);
    4664        3571 :         ctx->msn += ctx->msninc;
    4665        3571 :         ctx->min_cts_plus_one = 0;
    4666             : 
    4667        3571 :         if (ctx->moof_first) flags |= GF_ISOM_FRAG_MOOF_FIRST;
    4668             : #ifdef GF_ENABLE_CTRN
    4669             :         if (ctx->ctrn) flags |= GF_ISOM_FRAG_USE_COMPACT;
    4670             : #endif
    4671             : 
    4672        3571 :         e = gf_isom_start_fragment(ctx->file, flags);
    4673        3571 :         if (e) {
    4674           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Unable to start new fragment: %s\n", gf_error_to_string(e) ));
    4675             :                 return e;
    4676             :         }
    4677        3571 :         if (pck) {
    4678         123 :                 const GF_PropertyValue *p = gf_filter_pck_get_property(pck, GF_PROP_PCK_MOOF_TEMPLATE);
    4679         123 :                 if (p && p->value.data.ptr) {
    4680          57 :                         GF_SegmentIndexBox *out_sidx = NULL;
    4681          57 :                         gf_isom_set_fragment_template(ctx->file, p->value.data.ptr, p->value.data.size, &has_tfdt, &out_sidx);
    4682          57 :                         if (out_sidx) {
    4683          57 :                                 if (ctx->cloned_sidx) gf_isom_box_del((GF_Box *)ctx->cloned_sidx);
    4684          57 :                                 ctx->cloned_sidx = out_sidx;
    4685          57 :                                 ctx->cloned_sidx_index = 0;
    4686             :                         }
    4687             :                 }
    4688             :         }
    4689             : 
    4690             :         //setup some default
    4691        3772 :         for (i=0; i<count; i++) {
    4692        3772 :                 TrackWriter *tkw = gf_list_get(ctx->tracks, i);
    4693             :                 e = GF_OK;
    4694        3772 :                 if (ctx->strun) {
    4695          57 :                         e = gf_isom_set_fragment_option(ctx->file, tkw->track_id, GF_ISOM_TRAF_RANDOM_ACCESS, 0);
    4696             :                 }
    4697             :                 //fragment at sap boundaries for video, but not in dash mode (compatibility with old arch)
    4698        3715 :                 else if (ctx->fsap && (tkw->stream_type == GF_STREAM_VISUAL) && !ctx->dash_mode) {
    4699          80 :                         e = gf_isom_set_fragment_option(ctx->file, tkw->track_id, GF_ISOM_TRAF_RANDOM_ACCESS, 1);
    4700             :                 }
    4701         137 :                 if (e) {
    4702           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] Unable set fragment options: %s\n", gf_error_to_string(e) ));
    4703             :                 }
    4704        3772 :                 tkw->fragment_done = GF_FALSE;
    4705        3772 :                 tkw->insert_tfdt = (has_tfdt || ctx->tfdt_traf) ? GF_TRUE : ctx->insert_tfdt;
    4706        3772 :                 tkw->dur_in_frag = 0;
    4707             : 
    4708        3772 :                 if (ctx->trun_inter) {
    4709           0 :                         gf_isom_set_fragment_option(ctx->file, tkw->track_id, GF_ISOM_TRUN_SET_INTERLEAVE_ID, 0);
    4710             :                 }
    4711        3772 :                 if (ctx->truns_first) {
    4712           0 :                         gf_isom_set_fragment_option(ctx->file, tkw->track_id, GF_ISOM_TRAF_TRUNS_FIRST, 1);
    4713             :                 }
    4714             :                 //7.7 cmf2 For video CMAF Tracks not contained in Track Files, Version 1 shall be used.
    4715        3772 :                 if ((ctx->cmaf==MP4MX_CMAF_CMF2) && (tkw->stream_type==GF_STREAM_VISUAL))
    4716           0 :                         gf_isom_set_fragment_option(ctx->file, tkw->track_id, GF_ISOM_TRAF_TRUN_V1, 1);
    4717             : 
    4718        3772 :                 if (ctx->sdtp_traf)
    4719           0 :                         gf_isom_set_fragment_option(ctx->file, tkw->track_id, GF_ISOM_TRAF_USE_SAMPLE_DEPS_BOX, ctx->sdtp_traf);
    4720             : 
    4721        3772 :                 if (ctx->tfdt64)
    4722           0 :                         gf_isom_set_fragment_option(ctx->file, tkw->track_id, GF_ISOM_TRAF_USE_LARGE_TFDT, ctx->tfdt64);
    4723             : 
    4724        3772 :                 if (ctx->insert_pssh)
    4725           0 :                         mp4_mux_cenc_insert_pssh(ctx, tkw);
    4726             :         }
    4727        3571 :         ctx->fragment_started = GF_TRUE;
    4728        3571 :         ctx->insert_tfdt = GF_FALSE;
    4729        3571 :         ctx->insert_pssh = GF_FALSE;
    4730        3571 :         return GF_OK;
    4731             : }
    4732             : 
    4733        2618 : static GF_Err mp4_mux_flush_fragmented(GF_Filter *filter, GF_MP4MuxCtx *ctx)
    4734             : {
    4735             :         GF_FilterPacket *pck;
    4736             :         u8 *output;
    4737        2618 :         u32 nb_read, blocksize = ctx->block_size;
    4738        2618 :         if (ctx->flush_done + blocksize>ctx->flush_size) {
    4739          17 :                 blocksize = (u32) (ctx->flush_size - ctx->flush_done);
    4740             :         }
    4741        2618 :         if (!blocksize) return GF_EOS;
    4742        2618 :         pck = gf_filter_pck_new_alloc(ctx->opid, blocksize, &output);
    4743        2618 :         if (!pck) return GF_OUT_OF_MEM;
    4744             : 
    4745        2618 :         nb_read = (u32) gf_fread(output, blocksize, ctx->tmp_store);
    4746        2618 :         if (nb_read != blocksize) {
    4747             :                 char tmp[1];
    4748             :                 //weird behavior on some file systems, dump debug info
    4749           0 :                 gf_fread(tmp, 1, ctx->tmp_store);
    4750           0 :                 Bool is_eof = gf_feof(ctx->tmp_store);
    4751           0 :                 GF_LOG(is_eof ? GF_LOG_WARNING : GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error reading from VOD temp cache, read %d bytes but asked %d bytes\n\tCache EOF %d - cache size "LLU" - read pos "LLU" - file pos "LLU"\n", nb_read, blocksize, is_eof, ctx->flush_size, ctx->flush_done, gf_ftell(ctx->tmp_store)));
    4752             :         }
    4753        2618 :         ctx->flush_done += nb_read;
    4754        2618 :         if (ctx->flush_done==ctx->flush_size) {
    4755          17 :                 gf_filter_pck_set_framing(pck, GF_FALSE, GF_TRUE);
    4756          17 :                 gf_filter_pck_send(pck);
    4757          17 :                 gf_filter_pid_set_eos(ctx->opid);
    4758          17 :                 return GF_EOS;
    4759             :         }
    4760        2601 :         gf_filter_pck_set_framing(pck, GF_FALSE, GF_FALSE);
    4761        2601 :         gf_filter_pck_send(pck);
    4762             :         //we are not done flushing but we have no more input packets, signal we still need processing
    4763        2601 :         gf_filter_ask_rt_reschedule(filter, 1);
    4764        2601 :         return GF_OK;
    4765             : }
    4766             : 
    4767        3571 : static void mp4mx_frag_box_patch(GF_MP4MuxCtx *ctx)
    4768             : {
    4769             :         GF_Err e;
    4770        3571 :         u32 i, count = gf_list_count(ctx->tracks);
    4771        7343 :         for (i=0; i<count; i++) {
    4772             :                 const GF_PropertyValue *p;
    4773        3772 :                 TrackWriter *tkw = gf_list_get(ctx->tracks, i);
    4774        3772 :                 if (!tkw->track_id) continue;
    4775             :                 //no box patched set (todo, do we want to allow changing boxpatch props ?)
    4776        3772 :                 if (!tkw->box_patched) continue;
    4777             : 
    4778        3772 :                 p = gf_filter_pid_get_property_str(tkw->ipid, "boxpatch");
    4779        3772 :                 if (p && p->value.string) {
    4780           0 :                         e = gf_isom_apply_box_patch(ctx->file, tkw->track_id ? tkw->track_id : tkw->item_id, p->value.string, GF_TRUE);
    4781           0 :                         if (e) {
    4782           0 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] Unable to apply box patch %s to track fragment %d: %s\n",
    4783             :                                         p->value.string, tkw->track_id, gf_error_to_string(e) ));
    4784             :                         }
    4785             :                 }
    4786             :         }
    4787             : 
    4788        3571 :         if (ctx->boxpatch) {
    4789           2 :                 e = gf_isom_apply_box_patch(ctx->file, 0, ctx->boxpatch, GF_TRUE);
    4790           2 :                 if (e) {
    4791           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] Unable to apply box patch %s to fragment: %s\n", ctx->boxpatch, gf_error_to_string(e) ));
    4792             :                 }
    4793           2 :                 ctx->box_patched = GF_TRUE;
    4794             :         }
    4795        3571 : }
    4796             : 
    4797             : 
    4798             : static GF_Err mp4_mux_initialize(GF_Filter *filter);
    4799             : 
    4800          60 : GF_Err mp4mx_reload_output(GF_Filter *filter, GF_MP4MuxCtx *ctx)
    4801             : {
    4802             :         GF_Err e;
    4803          60 :         u32 i, count = gf_list_count(ctx->tracks);
    4804             : 
    4805             :         //done with the file
    4806          60 :         if (ctx->file) {
    4807          60 :                 e = mp4_mux_done(filter, ctx, GF_FALSE);
    4808          60 :                 if (e) return e;
    4809          60 :                 ctx->file = NULL;
    4810             :         }
    4811          60 :         ctx->init_movie_done = GF_FALSE;
    4812          60 :         e = mp4_mux_initialize(filter);
    4813          60 :         if (e) return e;
    4814          60 :         ctx->config_timing = GF_TRUE;
    4815             : 
    4816         158 :         for (i=0; i<count; i++) {
    4817          98 :                 TrackWriter *tkw = gf_list_get(ctx->tracks, i);
    4818          98 :                 tkw->suspended = GF_FALSE;
    4819          98 :                 tkw->track_num = 0;
    4820          98 :                 tkw->nb_samples = 0;
    4821          98 :                 tkw->max_cts = 0;
    4822          98 :                 tkw->min_cts = (u64) -1;
    4823          98 :                 e = mp4_mux_configure_pid(filter, tkw->ipid, GF_FALSE);
    4824          98 :                 if (e) return e;
    4825          98 :                 tkw->nb_samples = 0;
    4826          98 :                 tkw->sample.DTS = 0;
    4827          98 :                 tkw->sample.CTS_Offset = 0;
    4828          98 :                 tkw->samples_in_stsd = 0;
    4829          98 :                 tkw->samples_in_frag = 0;
    4830             :         }
    4831             :         assert(ctx->next_file_idx);
    4832          60 :         ctx->cur_file_idx_plus_one = ctx->next_file_idx;
    4833          60 :         ctx->next_file_idx = 0;
    4834          60 :         ctx->notify_filename = GF_TRUE;
    4835             :         assert(!ctx->cur_file_suffix);
    4836          60 :         if (ctx->next_file_suffix) {
    4837          60 :                 ctx->cur_file_suffix = gf_strdup(ctx->next_file_suffix);
    4838          60 :                 ctx->next_file_suffix = NULL;
    4839             :         }
    4840             :         return GF_OK;
    4841             : }
    4842             : 
    4843             : 
    4844      120838 : static GF_Err mp4_mux_process_fragmented(GF_Filter *filter, GF_MP4MuxCtx *ctx)
    4845             : {
    4846             :         GF_Err e = GF_OK;
    4847             :         u32 nb_eos, nb_done, nb_suspended, i, count;
    4848             : 
    4849      120838 :         if (ctx->flush_size) {
    4850        2618 :                 return mp4_mux_flush_fragmented(filter, ctx);
    4851             :         }
    4852             : 
    4853      118220 :         if (!ctx->file)
    4854             :                 return GF_EOS;
    4855             : 
    4856             :         //init movie not yet produced
    4857      118220 :         if (!ctx->init_movie_done) {
    4858         339 :                 e = mp4_mux_initialize_movie(ctx);
    4859         339 :                 if (e) return e;
    4860         339 :                 if (!ctx->init_movie_done)
    4861             :                         return GF_OK;
    4862             :         }
    4863             :         /*get count after init, some tracks may have been remove*/
    4864      118220 :         count = gf_list_count(ctx->tracks);
    4865      118220 :         if (ctx->dash_mode && !ctx->segment_started) {
    4866             :                 //don't start a new segment if all pids are in eos
    4867             :                 nb_eos=0;
    4868        3207 :                 for (i=0; i<count; i++) {
    4869        3207 :                         TrackWriter *tkw = gf_list_get(ctx->tracks, i);
    4870        3207 :                         if (gf_filter_pid_is_eos(tkw->ipid)) {
    4871          28 :                                 nb_eos ++;
    4872             :                         }
    4873             :                 }
    4874        3069 :                 if (nb_eos==count)
    4875             :                         goto check_eos;
    4876             : 
    4877        3044 :                 ctx->segment_started = GF_TRUE;
    4878        3044 :                 ctx->insert_tfdt = GF_TRUE;
    4879        3044 :                 ctx->insert_pssh = (ctx->psshs == MP4MX_PSSH_MOOF) ? GF_TRUE : GF_FALSE;
    4880             : 
    4881        3044 :                 gf_isom_start_segment(ctx->file, ctx->single_file ? NULL : "_gpac_isobmff_redirect", GF_FALSE);
    4882             :         }
    4883             : 
    4884             :         //process pid by pid
    4885             :         nb_eos=0;
    4886             :         nb_done = 0;
    4887             :         nb_suspended = 0;
    4888        5329 :         for (i=0; i<count; i++) {
    4889             :                 u64 cts, dts, ncts;
    4890      119925 :                 TrackWriter *tkw = gf_list_get(ctx->tracks, i);
    4891             : 
    4892      119925 :                 if (ctx->fragment_started && tkw->fragment_done) {
    4893        1554 :                         nb_done ++;
    4894        1554 :                         continue;
    4895             :                 }
    4896      118371 :                 if (tkw->suspended) {
    4897           2 :                         if (ctx->fragment_started) nb_done++;
    4898           2 :                         nb_suspended++;
    4899           2 :                         continue;
    4900             :                 }
    4901             : 
    4902             :                 while (1) {
    4903             :                         const GF_PropertyValue *p;
    4904             :                         u32 orig_frag_bounds=0;
    4905      230283 :                         GF_FilterPacket *pck = gf_filter_pid_get_packet(tkw->ipid);
    4906             : 
    4907      230283 :                         if (!pck) {
    4908      114942 :                                 if (gf_filter_pid_is_eos(tkw->ipid)) {
    4909         346 :                                         tkw->fragment_done = GF_TRUE;
    4910         346 :                                         if (ctx->dash_mode) ctx->flush_seg = GF_TRUE;
    4911         346 :                                         if (ctx->next_file_idx)
    4912           0 :                                                 nb_suspended++;
    4913         346 :                                         nb_done ++;
    4914         346 :                                         nb_eos++;
    4915         346 :                                         break;
    4916             :                                 }
    4917             :                                 return GF_OK;
    4918             :                         }
    4919      115341 :                         if (tkw->aborted) {
    4920           0 :                                 gf_filter_pid_drop_packet(tkw->ipid);
    4921           0 :                                 nb_eos++;
    4922           0 :                                 nb_done ++;
    4923           0 :                                 tkw->fragment_done = GF_TRUE;
    4924           0 :                                 if (ctx->dash_mode) ctx->flush_seg = GF_TRUE;
    4925             :                                 break;
    4926             :                         }
    4927             : 
    4928      115341 :                         cts = gf_filter_pck_get_cts(pck);
    4929             : 
    4930      115341 :                         if (cts == GF_FILTER_NO_TS) {
    4931         104 :                                 p = gf_filter_pck_get_property(pck, GF_PROP_PCK_EODS);
    4932         104 :                                 if (p && p->value.boolean) {
    4933         104 :                                         nb_done ++;
    4934         104 :                                         tkw->fragment_done = GF_TRUE;
    4935         104 :                                         tkw->samples_in_frag = 0;
    4936         104 :                                         gf_filter_pid_drop_packet(tkw->ipid);
    4937         104 :                                         ctx->flush_seg = GF_TRUE;
    4938         104 :                                         tkw->next_seg_cts = tkw->cts_next;
    4939         104 :                                         break;
    4940             :                                 }
    4941           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MuxIsom] Packet with no CTS assigned, cannot store to track, ignoring\n"));
    4942           0 :                                 gf_filter_pid_drop_packet(tkw->ipid);
    4943           0 :                                 continue;
    4944             :                         }
    4945             : 
    4946      115237 :                         p = gf_filter_pck_get_property(pck, GF_PROP_PCK_FRAG_START);
    4947      115237 :                         if (p) {
    4948         216 :                                 orig_frag_bounds = p->value.uint;
    4949             : 
    4950         216 :                                 if (orig_frag_bounds==2) {
    4951          84 :                                         if (!ctx->segment_started) {
    4952           0 :                                                 ctx->dash_mode = 1;
    4953           0 :                                                 ctx->insert_tfdt = GF_TRUE;
    4954           0 :                                                 gf_isom_start_segment(ctx->file, ctx->single_file ? NULL : "_gpac_isobmff_redirect", GF_FALSE);
    4955          84 :                                         } else if (tkw->samples_in_frag) {
    4956          27 :                                                 tkw->fragment_done = GF_TRUE;
    4957          27 :                                                 tkw->samples_in_frag = 0;
    4958          27 :                                                 nb_done ++;
    4959             :                                                 //make sure we flush until the end of the segment
    4960          27 :                                                 ctx->flush_seg = GF_TRUE;
    4961             :                                                 //store CTS of next packet (first in next segment) for sidx compute
    4962          27 :                                                 tkw->next_seg_cts = cts;
    4963             :                                         }
    4964             :                                 }
    4965             :                         }
    4966             : 
    4967             :                         //get dash/file segment number
    4968      115237 :                         p = gf_filter_pck_get_property(pck, GF_PROP_PCK_FILENUM);
    4969             : 
    4970             :                         //not dash and file end, we need to wait for all streams and resetup
    4971      115237 :                         if (!ctx->dash_mode && p) {
    4972          27 :                                 if (!ctx->cur_file_idx_plus_one) {
    4973           0 :                                         ctx->cur_file_idx_plus_one = p->value.uint + 1;
    4974           0 :                                         if (!ctx->cur_file_suffix) {
    4975           0 :                                                 p = gf_filter_pck_get_property(pck, GF_PROP_PCK_FILESUF);
    4976           0 :                                                 if (p && p->value.string) ctx->cur_file_suffix = gf_strdup(p->value.string);
    4977             :                                         }
    4978           0 :                                         ctx->notify_filename = GF_TRUE;
    4979          27 :                                 } else if (ctx->cur_file_idx_plus_one == p->value.uint+1) {
    4980           9 :                                 } else if (!tkw->suspended) {
    4981           9 :                                         tkw->suspended = GF_TRUE;
    4982           9 :                                         nb_suspended++;
    4983           9 :                                         ctx->next_file_idx =  p->value.uint + 1;
    4984           9 :                                         p = gf_filter_pck_get_property(pck, GF_PROP_PCK_FILESUF);
    4985           9 :                                         if (p && p->value.string)
    4986           9 :                                                 ctx->next_file_suffix = p->value.string;
    4987             :                                         break;
    4988             :                                 }
    4989             :                         }
    4990             : 
    4991             : 
    4992      115228 :                         if (!ctx->fragment_started) {
    4993        3571 :                                 e = mp4_mux_start_fragment(ctx, orig_frag_bounds ? pck : NULL);
    4994        3571 :                                 if (e) return e;
    4995             : 
    4996        3571 :                                 ctx->nb_frags++;
    4997        3571 :                                 if (ctx->dash_mode)
    4998        3491 :                                         ctx->nb_frags_in_seg++;
    4999             : 
    5000             :                         }
    5001             : 
    5002             : 
    5003      115228 :                         if (ctx->dash_mode) {
    5004      111897 :                                 if (p) {
    5005             :                                         //start of next segment, abort fragmentation for this track and flush all other writers
    5006        5895 :                                         if (ctx->dash_seg_num_plus_one && (ctx->dash_seg_num_plus_one != 1 + p->value.uint) ) {
    5007        2739 :                                                 tkw->fragment_done = GF_TRUE;
    5008        2739 :                                                 tkw->samples_in_frag = 0;
    5009        2739 :                                                 nb_done ++;
    5010             :                                                 //make sure we flush until the end of the segment
    5011        2739 :                                                 ctx->flush_seg = GF_TRUE;
    5012             :                                                 //store CTS of next packet (first in next segment) for sidx compute
    5013        2739 :                                                 tkw->next_seg_cts = cts;
    5014             : 
    5015        2739 :                                                 break;
    5016             :                                         }
    5017             :                                         //start of current segment, remember segment number and name
    5018        3156 :                                         ctx->dash_seg_num_plus_one = 1 + p->value.uint;
    5019             :                                         //get file name prop if any - only send on one pid for muxed content
    5020        3156 :                                         p = gf_filter_pck_get_property(pck, GF_PROP_PCK_FILENAME);
    5021        3156 :                                         if (p && p->value.string) {
    5022        2484 :                                                 if (ctx->seg_name) gf_free(ctx->seg_name);
    5023        2484 :                                                 ctx->seg_name = gf_strdup(p->value.string);
    5024             :                                         }
    5025             :                                         //store PRFT only for reference track at segment start
    5026        3156 :                                         if (tkw==ctx->ref_tkw) {
    5027        3023 :                                                 p = gf_filter_pck_get_property(pck, GF_PROP_PCK_SENDER_NTP);
    5028        3023 :                                                 if (p) {
    5029           0 :                                                         gf_isom_set_fragment_reference_time(ctx->file, tkw->track_id, p->value.longuint, cts);
    5030           0 :                                                         GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MuxIsom] Segment %s, storing NTP TS "LLU" for CTS "LLU" at "LLU" us, at UTC "LLU"\n", ctx->seg_name ? ctx->seg_name : "singlefile", p->value.longuint, cts, gf_sys_clock_high_res(), gf_net_get_utc()));
    5031             :                                                 }
    5032             :                                         }
    5033             :                                 }
    5034             : 
    5035      109158 :                                 dts = gf_filter_pck_get_dts(pck);
    5036      109158 :                                 if (dts==GF_FILTER_NO_TS) dts = cts;
    5037      109158 :                                 if (tkw->first_dts_in_seg > dts)
    5038           0 :                                         tkw->first_dts_in_seg = dts;
    5039             :                         }
    5040      112489 :                         ncts = cts + gf_filter_pck_get_duration(pck);
    5041      112489 :                         if (tkw->cts_next < ncts)
    5042      101799 :                                 tkw->cts_next = ncts;
    5043             : 
    5044             : 
    5045      112489 :                         if (tkw->samples_in_frag && orig_frag_bounds) {
    5046          66 :                                 tkw->fragment_done = GF_TRUE;
    5047          66 :                                 nb_done ++;
    5048          66 :                                 tkw->samples_in_frag = 0;
    5049          66 :                                 tkw->dur_in_frag = 0;
    5050          66 :                                 break;
    5051      112423 :                         } else if (ctx->fragdur && (!ctx->dash_mode || !tkw->fragment_done) ) {
    5052             :                                 Bool frag_done = GF_FALSE;
    5053        6526 :                                 u32 dur = gf_filter_pck_get_duration(pck);
    5054        6526 :                                 if (tkw->dur_in_frag && (tkw->dur_in_frag * ctx->cdur.den >= ((u64)ctx->cdur.num) * tkw->src_timescale)) {
    5055             :                                         frag_done = GF_TRUE;
    5056        6039 :                                 } else if ((ctx->store==MP4MX_MODE_SFRAG)
    5057        1650 :                                         && (cts >= (u64) (ctx->adjusted_next_frag_start * tkw->src_timescale / ctx->cdur.den) + tkw->ts_delay)
    5058             :                                 ) {
    5059             :                                         GF_FilterSAPType sap = mp4_mux_get_sap(ctx, pck);
    5060           0 :                                         if ((sap && sap<GF_FILTER_SAP_3)) {
    5061             :                                                 frag_done = GF_TRUE;
    5062             :                                         }
    5063             :                                 }
    5064             :                                 if (frag_done) {
    5065         487 :                                         ctx->adjusted_next_frag_start = (cts - tkw->ts_delay);
    5066         487 :                                         ctx->adjusted_next_frag_start *= ctx->cdur.den;
    5067         487 :                                         ctx->adjusted_next_frag_start /= tkw->src_timescale;
    5068             : //
    5069         487 :                                         tkw->fragment_done = GF_TRUE;
    5070         487 :                                         nb_done ++;
    5071         487 :                                         tkw->dur_in_frag = 0;
    5072         487 :                                         tkw->samples_in_frag = 0;
    5073         487 :                                         break;
    5074             :                                 }
    5075        6039 :                                 tkw->dur_in_frag += dur;
    5076        6039 :                                 if (ctx->llhls_mode && (ctx->frag_duration * tkw->src_timescale <= tkw->dur_in_frag * ctx->frag_timescale)) {
    5077        1650 :                                         ctx->frag_duration = tkw->dur_in_frag;
    5078        1650 :                                         ctx->frag_timescale = tkw->src_timescale;
    5079             :                                 }
    5080      105897 :                         } else if (!ctx->flush_seg && !ctx->dash_mode
    5081         782 :                                 && (cts >= (u64) (ctx->adjusted_next_frag_start * tkw->src_timescale  / ctx->cdur.den) + tkw->ts_delay)
    5082             :                          ) {
    5083             :                                 GF_FilterSAPType sap = mp4_mux_get_sap(ctx, pck);
    5084          22 :                                 if ((ctx->store==MP4MX_MODE_FRAG) || (sap && sap<GF_FILTER_SAP_3)) {
    5085          22 :                                         tkw->fragment_done = GF_TRUE;
    5086          22 :                                         tkw->samples_in_frag = 0;
    5087          22 :                                         nb_done ++;
    5088          22 :                                         if (ctx->store==MP4MX_MODE_SFRAG) {
    5089           0 :                                                 ctx->adjusted_next_frag_start = (cts - tkw->ts_delay);
    5090           0 :                                                 ctx->adjusted_next_frag_start *= ctx->cdur.den;
    5091           0 :                                                 ctx->adjusted_next_frag_start /= tkw->src_timescale;
    5092             :                                         }
    5093             :                                         break;
    5094             :                                 }
    5095             :                         }
    5096      111914 :                         if (tkw->insert_tfdt) {
    5097        3438 :                                 u64 odts = gf_filter_pck_get_dts(pck);
    5098        3438 :                                 if (odts==GF_FILTER_NO_TS)
    5099           0 :                                         odts = gf_filter_pck_get_cts(pck);
    5100             : 
    5101        3438 :                                 if (tkw->offset_dts) odts += tkw->offset_dts;
    5102             : 
    5103        3438 :                                 tkw->insert_tfdt = GF_FALSE;
    5104        3438 :                                 if (tkw->patch_tfdt)
    5105           0 :                                         gf_isom_set_traf_base_media_decode_time(ctx->file, tkw->track_id, odts + tkw->ts_delay);
    5106             :                                 else
    5107        3438 :                                         gf_isom_set_traf_base_media_decode_time(ctx->file, tkw->track_id, odts);
    5108        3438 :                                 tkw->first_dts_in_seg = (u64) odts;
    5109             :                         }
    5110             : 
    5111      111914 :                         if (ctx->trun_inter) {
    5112             :                                 GF_FilterSAPType sap = mp4_mux_get_sap(ctx, pck);
    5113             :                                 s32 tid_group = 0;
    5114           0 :                                 if (sap) {
    5115           0 :                                         tkw->prev_tid_group = 0;
    5116             :                                 } else {
    5117             :                                         s64 dts_diff;
    5118           0 :                                         s64 p_dts = gf_filter_pck_get_dts(pck);
    5119           0 :                                         s64 p_cts = gf_filter_pck_get_cts(pck);
    5120           0 :                                         s64 cts_o = p_cts - p_dts;
    5121           0 :                                         dts_diff = p_dts - tkw->sample.DTS;
    5122           0 :                                         tid_group = (s32) (cts_o / dts_diff);
    5123           0 :                                         tid_group = 20 - tid_group;
    5124           0 :                                         if (tid_group != tkw->prev_tid_group) {
    5125           0 :                                                 tkw->prev_tid_group = tid_group;
    5126           0 :                                                 gf_isom_set_fragment_option(ctx->file, tkw->track_id, GF_ISOM_TRUN_SET_INTERLEAVE_ID, tid_group);
    5127             :                                         }
    5128             :                                 }
    5129             :                         }
    5130             : 
    5131             :                         //process packet
    5132      111914 :                         e = mp4_mux_process_sample(ctx, tkw, pck, GF_TRUE);
    5133             : 
    5134             :                         //discard
    5135      111914 :                         gf_filter_pid_drop_packet(tkw->ipid);
    5136             : 
    5137      111914 :                         cts *= 1000;
    5138      111914 :                         cts /= tkw->src_timescale;
    5139      111914 :                         if (!ctx->min_cts_plus_one) ctx->min_cts_plus_one = cts + 1;
    5140      108343 :                         else if (ctx->min_cts_plus_one-1 > cts) ctx->min_cts_plus_one = cts + 1;
    5141             : 
    5142      111914 :                         if (e) return e;
    5143             :                 }
    5144             :                 //done with this track - if single track per moof, request new fragment but don't touch the
    5145             :                 //fragmentation state of the track writers
    5146        3773 :                 if (ctx->straf && (i+1 < count)) {
    5147             :                         GF_ISOStartFragmentFlags flags = 0;
    5148           0 :                         if (ctx->moof_first) flags |= GF_ISOM_FRAG_MOOF_FIRST;
    5149             : #ifdef GF_ENABLE_CTRN
    5150             :                         if (ctx->ctrn) flags |= GF_ISOM_FRAG_USE_COMPACT;
    5151             : #endif
    5152           0 :                         e = gf_isom_start_fragment(ctx->file, flags);
    5153           0 :                         if (e) {
    5154           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Unable to start new fragment: %s\n", gf_error_to_string(e) ));
    5155             :                                 return e;
    5156             :                         }
    5157           0 :                         gf_isom_set_next_moof_number(ctx->file, ctx->msn);
    5158           0 :                         ctx->msn++;
    5159           0 :                         if (ctx->sdtp_traf)
    5160           0 :                                 gf_isom_set_fragment_option(ctx->file, tkw->track_id, GF_ISOM_TRAF_USE_SAMPLE_DEPS_BOX, ctx->sdtp_traf);
    5161             :                 }
    5162             :         }
    5163             : 
    5164             :         //all suspended tracks done, flush fragment
    5165        3599 :         if (nb_suspended && (nb_suspended==count)) {
    5166             :                 nb_done = count;
    5167             :         }
    5168             : 
    5169             : 
    5170        3599 :         if (nb_done==count) {
    5171        3571 :                 Bool is_eos = (count == nb_eos) ? GF_TRUE : GF_FALSE;
    5172             :                 u32 ref_timescale;
    5173        3571 :                 u64 next_ref_ts = ctx->ref_tkw->next_seg_cts;
    5174        3571 :                 if (is_eos)
    5175         316 :                         next_ref_ts = ctx->ref_tkw->cts_next;
    5176             : 
    5177        3571 :                 ref_timescale = ctx->ref_tkw->src_timescale;
    5178             :                 //both in ms
    5179        3571 :                 ctx->next_seg_start = (u64) (next_ref_ts) * 1000 / ref_timescale;
    5180        3571 :                 ctx->min_cts_next_frag = (u64) (ctx->next_frag_start) * 1000 / ctx->cdur.den;
    5181             : 
    5182        3571 :                 ctx->next_frag_start += ctx->cdur.num;
    5183        7148 :                 while (ctx->next_frag_start <= ctx->adjusted_next_frag_start) {
    5184           6 :                         ctx->next_frag_start += ctx->cdur.num;
    5185             :                 }
    5186        3571 :                 ctx->adjusted_next_frag_start = ctx->next_frag_start;
    5187             : 
    5188        3571 :                 mp4mx_frag_box_patch(ctx);
    5189             : 
    5190             :                 //end of DASH segment
    5191        6597 :                 if (ctx->dash_mode && (ctx->flush_seg || is_eos) ) {
    5192        3026 :                         u64 offset = ctx->single_file ? ctx->current_offset : 0;
    5193             :                         u64 idx_start_range, idx_end_range, segment_size_in_bytes;
    5194             :                         s32 subs_sidx = -1;
    5195             :                         u32 track_ref_id = 0;
    5196             : 
    5197        3026 :                         idx_start_range = idx_end_range = 0;
    5198        3026 :                         if (ctx->subs_sidx>=0) {
    5199             :                                 subs_sidx = ctx->subs_sidx;
    5200        2293 :                                 track_ref_id = ctx->ref_tkw->track_id;
    5201             :                         }
    5202        3026 :                         if (ctx->cloned_sidx && (ctx->subs_sidx!=-2) ) {
    5203          57 :                                 subs_sidx = (s32) ctx->cloned_sidx->nb_refs;
    5204          57 :                                 track_ref_id = ctx->cloned_sidx->reference_ID;
    5205          57 :                                 gf_isom_box_del((GF_Box *)ctx->cloned_sidx);
    5206          57 :                                 ctx->cloned_sidx = NULL;
    5207             :                         }
    5208             : 
    5209        3026 :                         e = gf_isom_close_segment(ctx->file, subs_sidx, track_ref_id, ctx->ref_tkw->first_dts_in_seg, ctx->ref_tkw->ts_delay, next_ref_ts, ctx->chain_sidx, ctx->ssix, ctx->sseg ? GF_FALSE : is_eos, GF_FALSE, ctx->eos_marker, &idx_start_range, &idx_end_range, &segment_size_in_bytes);
    5210        3026 :                         if (e) return e;
    5211             : 
    5212        3026 :                         GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MP4Mux] Done writing segment %d - estimated next fragment times start %g end %g\n", ctx->dash_seg_num_plus_one - 1, ((Double)next_ref_ts)/ref_timescale, ((Double)ctx->next_frag_start)/ctx->cdur.den ));
    5213             : 
    5214        3026 :                         if (ctx->dash_mode != MP4MX_DASH_VOD) {
    5215        2750 :                                 mp4_mux_flush_seg(ctx, GF_FALSE, offset + idx_start_range, idx_end_range ? offset + idx_end_range : 0);
    5216         276 :                         } else if (ctx->vodcache==MP4MX_VODCACHE_REPLACE) {
    5217           0 :                                 mp4_mux_flush_seg(ctx, GF_FALSE, 0, 0);
    5218             :                         } else {
    5219         276 :                                 if (ctx->nb_seg_sizes == ctx->alloc_seg_sizes) {
    5220          33 :                                          ctx->alloc_seg_sizes *= 2;
    5221          33 :                                          if (!ctx->alloc_seg_sizes) ctx->alloc_seg_sizes = 10;
    5222          33 :                                          ctx->seg_sizes = gf_realloc(ctx->seg_sizes, sizeof(u32) * ctx->alloc_seg_sizes);
    5223             :                                 }
    5224             :                                 assert(segment_size_in_bytes);
    5225         276 :                                 ctx->seg_sizes[ctx->nb_seg_sizes] = (u32) segment_size_in_bytes;
    5226         276 :                                 ctx->nb_seg_sizes++;
    5227             :                         }
    5228             :                 }
    5229             :                 //cannot flush in DASH mode if using sidx (vod single sidx or live 1 sidx/seg)
    5230         545 :                 else if (!ctx->dash_mode || ((ctx->subs_sidx<0) && (ctx->dash_mode<MP4MX_DASH_VOD) && !ctx->cloned_sidx) ) {
    5231         453 :                         gf_isom_flush_fragments(ctx->file, GF_FALSE);
    5232             : 
    5233         453 :                         if (ctx->llhls_mode) {
    5234         279 :                                 mp4_mux_flush_frag_hls(ctx);
    5235             :                         }
    5236             : 
    5237         453 :                         if (!ctx->dash_mode || ctx->flush_seg) {
    5238          80 :                                 mp4_mux_flush_seg(ctx, GF_FALSE, 0, 0);
    5239             :                         }
    5240             : 
    5241         453 :                         GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[MP4Mux] Done writing fragment - next fragment start time %g\n", ((Double)ctx->next_frag_start)/ctx->cdur.den ));
    5242             :                 }
    5243        3571 :                 ctx->fragment_started = GF_FALSE;
    5244             : 
    5245        3571 :                 if (ctx->flush_seg) {
    5246        3026 :                         ctx->segment_started = GF_FALSE;
    5247        3026 :                         ctx->flush_seg = GF_FALSE;
    5248        3026 :                         ctx->dash_seg_num_plus_one = 0;
    5249        3026 :                         ctx->nb_segs++;
    5250        3026 :                         ctx->nb_frags_in_seg=0;
    5251             :                 }
    5252             :         }
    5253             : 
    5254        3599 :         if (nb_suspended && (nb_suspended==count)) {
    5255           4 :                 ctx->nb_segs=0;
    5256           4 :                 return mp4mx_reload_output(filter, ctx);
    5257             :         }
    5258             : 
    5259        3620 : check_eos:
    5260        3620 :         if (count == nb_eos) {
    5261         341 :                 if (ctx->dash_mode==MP4MX_DASH_VOD) {
    5262          17 :                         if (ctx->vodcache!=MP4MX_VODCACHE_ON) {
    5263           0 :                                 ctx->final_sidx_flush = GF_TRUE;
    5264             :                                 //flush SIDX in given space - this will reserve 8 bytes for free box if not fitting
    5265           0 :                                 gf_isom_flush_sidx(ctx->file, ctx->sidx_max_size, (ctx->sidx_size_exact || ctx->tfdt64) ? GF_TRUE : GF_FALSE);
    5266             :                         } else {
    5267             :                                 u64 start_offset;
    5268             :                                 //reenable packet dispatch
    5269          17 :                                 ctx->store_output = GF_FALSE;
    5270          17 :                                 gf_isom_flush_sidx(ctx->file, 0, ctx->tfdt64);
    5271             :                                 //flush sidx packet
    5272          17 :                                 mp4mux_send_output(ctx);
    5273             : 
    5274          17 :                                 mp4_mux_flush_seg(ctx, GF_TRUE, ctx->current_offset, ctx->current_offset + ctx->current_size - 1);
    5275             : 
    5276          17 :                                 gf_fflush(ctx->tmp_store);
    5277          17 :                                 ctx->flush_size = gf_ftell(ctx->tmp_store);
    5278          17 :                                 ctx->flush_done = 0;
    5279          17 :                                 gf_fseek(ctx->tmp_store, 0, SEEK_SET);
    5280             : 
    5281          17 :                                 if (ctx->seg_sizes) {
    5282          17 :                                         start_offset = ctx->current_offset;
    5283         293 :                                         for (i=0; i<ctx->nb_seg_sizes; i++) {
    5284         276 :                                                 ctx->current_size = ctx->seg_sizes[i];
    5285         276 :                                                 mp4_mux_flush_seg(ctx, GF_FALSE, 0, 0);
    5286             :                                         }
    5287          17 :                                         ctx->current_offset = start_offset;
    5288          17 :                                         ctx->current_size = 0;
    5289             : 
    5290          17 :                                         gf_free(ctx->seg_sizes);
    5291          17 :                                         ctx->seg_sizes = NULL;
    5292          17 :                                         ctx->alloc_seg_sizes = ctx->nb_seg_sizes = 0;
    5293             :                                 }
    5294             :                         }
    5295             :                 }
    5296             :                 //only destroy file if not dash or not onDemand, otherwise (regular dash) the file will be needed to append further segments
    5297         341 :                 if (ctx->dash_mode!=MP4MX_DASH_ON) {
    5298             :                         //only delete file in vod mode
    5299          26 :                         if (ctx->file) {
    5300          26 :                                 gf_isom_close(ctx->file);
    5301          26 :                                 ctx->file = NULL;
    5302             :                         }
    5303             :                 }
    5304             : 
    5305         341 :                 mp4mux_send_output(ctx);
    5306             : 
    5307         341 :                 if (!ctx->flush_size) gf_filter_pid_set_eos(ctx->opid);
    5308             : 
    5309         341 :                 return ctx->flush_size ? GF_OK : GF_EOS;
    5310             :         }
    5311             : 
    5312             :         return GF_OK;
    5313             : }
    5314             : 
    5315        2885 : static void mp4_mux_config_timing(GF_MP4MuxCtx *ctx)
    5316             : {
    5317        2886 :         u32 i, count = gf_list_count(ctx->tracks);
    5318             :         //compute min dts of first packet on each track - this assume all tracks are synchronized, might need adjustment for MPEG4 Systems
    5319             :         u64 first_ts_min = (u64) -1;
    5320        5100 :         for (i=0; i<count; i++) {
    5321             :                 u64 ts, dts_min;
    5322             :                 GF_FilterPacket *pck;
    5323        3801 :                 TrackWriter *tkw = gf_list_get(ctx->tracks, i);
    5324        3801 :                 if (tkw->fake_track) continue;
    5325             : 
    5326             :                 //already setup (happens when new PIDs are declared after a packet has already been written on other PIDs)
    5327        3774 :                 if (tkw->nb_samples) {
    5328           0 :                         dts_min = tkw->ts_shift * 1000000;
    5329           0 :                         dts_min /= tkw->src_timescale;
    5330             : 
    5331           0 :                         if (first_ts_min > dts_min) {
    5332             :                                 first_ts_min = (u64) dts_min;
    5333             :                         }
    5334           0 :                         continue;
    5335             :                 }
    5336        3774 : retry_pck:
    5337        3774 :                 pck = gf_filter_pid_get_packet(tkw->ipid);
    5338             :                 //check this after fetching a packet since it may reconfigure the track
    5339        3774 :                 if (!tkw->track_num) {
    5340         577 :                         if (gf_filter_pid_is_eos(tkw->ipid)) {
    5341           0 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] PID has no input packet and configuration not known after 10 retries, aborting initial timing sync\n"));
    5342           0 :                                 continue;
    5343             :                         }
    5344             :                         return;
    5345             :                 }
    5346             : 
    5347        3197 :                 if (pck) {
    5348        2179 :                         if (tkw->wait_sap) {
    5349           0 :                                 GF_FilterSAPType sap = gf_filter_pck_get_sap(pck);
    5350           0 :                                 Bool seek = gf_filter_pck_get_seek_flag(pck);
    5351           0 :                                 if (seek || !sap) {
    5352           0 :                                         gf_filter_pid_drop_packet(tkw->ipid);
    5353           0 :                                         goto retry_pck;
    5354             :                                 } else {
    5355           0 :                                         if (sap)
    5356           0 :                                                 tkw->wait_sap = GF_FALSE;
    5357             : 
    5358           0 :                                         if (!ctx->wait_dts_plus_one) {
    5359           0 :                                                 ctx->wait_dts_plus_one = 1 + gf_filter_pck_get_dts(pck);
    5360           0 :                                                 ctx->wait_dts_timescale = tkw->src_timescale;
    5361             :                                         }
    5362             :                                 }
    5363             :                         }
    5364             : 
    5365        2179 :                         if (ctx->wait_dts_plus_one) {
    5366           0 :                                 ts = gf_filter_pck_get_dts(pck);
    5367           0 :                                 if (ts==GF_FILTER_NO_TS)
    5368           0 :                                         ts = gf_filter_pck_get_cts(pck);
    5369           0 :                                 if (ts==GF_FILTER_NO_TS)
    5370             :                                         ts=0;
    5371             : 
    5372           0 :                                 if (ts * ctx->wait_dts_timescale < (ctx->wait_dts_plus_one-1) * tkw->src_timescale) {
    5373           0 :                                         gf_filter_pid_drop_packet(tkw->ipid);
    5374           0 :                                         goto retry_pck;
    5375             :                                 }
    5376             :                         }
    5377             :                 }
    5378             : 
    5379        3197 :                 if (!pck) {
    5380        1018 :                         if (gf_filter_pid_is_eos(tkw->ipid)) {
    5381           9 :                                 if (tkw->cenc_state==CENC_NEED_SETUP)
    5382           1 :                                         mp4_mux_cenc_update(ctx, tkw, NULL, CENC_CONFIG, 0);
    5383             : 
    5384           9 :                                 if (!tkw->nb_samples) {
    5385           9 :                                         const GF_PropertyValue *p = gf_filter_pid_get_property(tkw->ipid, GF_PROP_PID_ISOM_TREX_TEMPLATE);
    5386           9 :                                         if (p) {
    5387           2 :                                                 gf_isom_setup_track_fragment_template(ctx->file, tkw->track_id, p->value.data.ptr, p->value.data.size, ctx->nofragdef);
    5388             :                                         }
    5389             :                                 }
    5390           9 :                                 continue;
    5391             :                         }
    5392             :                         return;
    5393             :                 }
    5394             :                 //we may have reorder tracks after the get_packet, redo
    5395        2179 :                 if (gf_list_find(ctx->tracks, tkw) != i) {
    5396             :                         mp4_mux_config_timing(ctx);
    5397             :                         return;
    5398             :                 }
    5399        2178 :                 ts = gf_filter_pck_get_dts(pck);
    5400        2178 :                 if (ts==GF_FILTER_NO_TS)
    5401           0 :                         ts = gf_filter_pck_get_cts(pck);
    5402        2178 :                 if (ts==GF_FILTER_NO_TS)
    5403             :                         ts=0;
    5404             : 
    5405        2178 :                 dts_min = ts * 1000000;
    5406        2178 :                 dts_min /= tkw->src_timescale;
    5407             : 
    5408        2178 :                 if (first_ts_min > dts_min) {
    5409             :                         first_ts_min = (u64) dts_min;
    5410             :                 }
    5411        2178 :                 tkw->ts_shift = ts;
    5412             :         }
    5413        1299 :         if (first_ts_min==(u64)-1)
    5414             :                 first_ts_min = 0;
    5415             : 
    5416             :         //for all packets with dts greater than min dts, we need to add a pause
    5417        2747 :         for (i=0; i<count; i++) {
    5418             :                 s64 dts_diff, dur;
    5419        1448 :                 TrackWriter *tkw = gf_list_get(ctx->tracks, i);
    5420             : 
    5421             :                 //compute offsets
    5422        1448 :                 dts_diff = first_ts_min;
    5423        1448 :                 dts_diff *= tkw->src_timescale;
    5424        1448 :                 dts_diff /= 1000000;
    5425        1448 :                 dts_diff = (s64) tkw->ts_shift - dts_diff;
    5426        1448 :                 if (ctx->is_rewind) dts_diff = -dts_diff;
    5427             :                 //negative could happen due to rounding, ignore them
    5428        1448 :                 if (dts_diff<=0) continue;
    5429             : 
    5430             :                 // dts_diff > 0, we need to delay the track
    5431             :                 dur = dts_diff;
    5432          85 :                 dur *= (u32) ctx->moovts;
    5433          85 :                 dur /= tkw->src_timescale;
    5434          85 :                 if (dur) {
    5435          52 :                         gf_isom_remove_edits(ctx->file, tkw->track_num);
    5436             : 
    5437          52 :                         gf_isom_set_edit(ctx->file, tkw->track_num, 0, dur, dts_diff, GF_ISOM_EDIT_EMPTY);
    5438          52 :                         gf_isom_set_edit(ctx->file, tkw->track_num, dur, 0, 0, GF_ISOM_EDIT_NORMAL);
    5439          52 :                         tkw->empty_init_dur = (u64) dur;
    5440             :                 }
    5441             :         }
    5442             : 
    5443        1299 :         ctx->config_timing = GF_FALSE;
    5444             : }
    5445             : 
    5446      684042 : void mp4_mux_format_report(GF_Filter *filter, GF_MP4MuxCtx *ctx, u64 done, u64 total)
    5447             : {
    5448             :         Bool status_changed=GF_FALSE;
    5449             :         u32 total_pc = 0;
    5450             :         char szStatus[2048], szTK[20];
    5451      684042 :         if (!gf_filter_reporting_enabled(filter))
    5452      684042 :                 return;
    5453           0 :         if (!ctx->update_report)
    5454             :                 return;
    5455             : 
    5456           0 :         ctx->update_report = GF_FALSE;
    5457             : 
    5458           0 :         if (ctx->config_timing) {
    5459             :                 sprintf(szStatus, "waiting for clock init");
    5460             :                 status_changed = GF_TRUE;
    5461           0 :         } else if (total) {
    5462           0 :                 if (done>=total) {
    5463             :                         Double ohead = 0;
    5464           0 :                         if (ctx->total_bytes_in) ohead =  ((Double) (ctx->total_bytes_out - ctx->total_bytes_in)*100 / ctx->total_bytes_in);
    5465             : 
    5466           0 :                         sprintf(szStatus, "done %d samples - bytes "LLU" in "LLU" out - overhead %02.02f%% (%02.02g B/sample)", ctx->total_samples, ctx->total_bytes_in, ctx->total_bytes_out, ohead, ((Double)(ctx->total_bytes_out-ctx->total_bytes_in))/ctx->total_samples);
    5467             :                         status_changed = GF_TRUE;
    5468             :                         total_pc = 10000;
    5469             : 
    5470             :                 } else {
    5471           0 :                         u32 pc = (u32) ((done*10000)/total);
    5472           0 :                         if (ctx->last_mux_pc == pc + 1) return;
    5473           0 :                         ctx->last_mux_pc = pc + 1;
    5474             :                         sprintf(szStatus, "mux %d%%", pc);
    5475             :                         status_changed = GF_TRUE;
    5476             :                 }
    5477             :         } else {
    5478           0 :                 u32 i, count = gf_list_count(ctx->tracks);
    5479             :                 Bool is_frag = GF_FALSE;
    5480             : 
    5481           0 :                 if (ctx->store>=MP4MX_MODE_FRAG) {
    5482           0 :                         Double next = ((Double)ctx->next_frag_start)/ctx->cdur.den;
    5483             :                         is_frag = GF_TRUE;
    5484           0 :                         if (ctx->dash_mode) {
    5485           0 :                                 sprintf(szStatus, "mux segments %d (frags %d) next %02.02g", ctx->nb_segs, ctx->nb_frags_in_seg, next);
    5486             :                         } else {
    5487           0 :                                 sprintf(szStatus, "mux frags %d next %02.02g", ctx->nb_frags, next);
    5488             :                         }
    5489             :                 } else {
    5490           0 :                         sprintf(szStatus, "%s", ((ctx->store==MP4MX_MODE_FLAT) || (ctx->store==MP4MX_MODE_FASTSTART)) ? "mux" : "import");
    5491             :                 }
    5492           0 :                 for (i=0; i<count; i++) {
    5493             :                         u32 pc=0;
    5494           0 :                         TrackWriter *tkw = gf_list_get(ctx->tracks, i);
    5495           0 :                         if (tkw->aborted) {
    5496             :                                 pc=10000;
    5497           0 :                         } else if (ctx->idur.num) {
    5498           0 :                                 if (ctx->idur.num>0) {
    5499           0 :                                         u64 mdur = gf_isom_get_media_duration(ctx->file, tkw->track_num);
    5500           0 :                                         u64 tk_done = mdur * ctx->idur.den;
    5501           0 :                                         u64 tk_total = ((u64)tkw->tk_timescale) * ctx->idur.num;
    5502           0 :                                         pc = (u32) ((tk_done*10000)/tk_total);
    5503             :                                 } else {
    5504           0 :                                         pc = (u32) ( (10000 * (u64) tkw->nb_samples) / (-ctx->idur.num) );
    5505             :                                 }
    5506             :                         } else {
    5507           0 :                                 if (tkw->nb_frames) {
    5508           0 :                                         pc = (u32) ( (10000 * (u64) tkw->nb_samples) / tkw->nb_frames);
    5509             :                                 } else {
    5510           0 :                                         if (tkw->pid_dur.num && tkw->pid_dur.den) {
    5511           0 :                                                 pc = (u32) ((tkw->sample.DTS*10000 * tkw->pid_dur.den) / (tkw->pid_dur.num * tkw->tk_timescale));
    5512           0 :                                         } else if (tkw->down_bytes && tkw->down_size) {
    5513           0 :                                                 pc = (u32) (((tkw->down_bytes*10000) / tkw->down_size));
    5514             :                                         }
    5515             :                                 }
    5516             :                         }
    5517           0 :                         if (pc>10000)
    5518             :                                 pc=0;
    5519           0 :                         if (tkw->last_import_pc != pc + 1) {
    5520             :                                 status_changed = GF_TRUE;
    5521           0 :                                 tkw->last_import_pc = pc + 1;
    5522             :                         }
    5523           0 :                         if (!total_pc || (total_pc > pc))
    5524             :                                 total_pc = pc;
    5525             : 
    5526           0 :                         if (is_frag) {
    5527           0 :                                 sprintf(szTK, " TK%d(%c): %d", tkw->track_id, tkw->status_type, tkw->samples_in_frag);
    5528             :                                 strcat(szStatus, szTK);
    5529             :                                 status_changed = GF_TRUE;
    5530           0 :                                 if (pc) {
    5531           0 :                                         sprintf(szTK, " %d %%", pc/100);
    5532             :                                         strcat(szStatus, szTK);
    5533             :                                 }
    5534             :                         } else {
    5535           0 :                                 sprintf(szTK, " %s%d(%c): %d %%", tkw->is_item ? "IT" : "TK", tkw->track_id, tkw->status_type, pc/100);
    5536             :                                 strcat(szStatus, szTK);
    5537             :                         }
    5538             :                 }
    5539             :         }
    5540           0 :         if (status_changed) {
    5541           0 :                 gf_filter_update_status(filter, total_pc, szStatus);
    5542             :         }
    5543             : }
    5544             : 
    5545             : 
    5546      571765 : GF_Err mp4_mux_process(GF_Filter *filter)
    5547             : {
    5548      571765 :         GF_MP4MuxCtx *ctx = gf_filter_get_udta(filter);
    5549      571765 :         u32 nb_skip, nb_eos, nb_suspended, i, count = gf_list_count(ctx->tracks);
    5550             :         nb_skip = 0;
    5551             :         nb_eos = 0;
    5552             : 
    5553      571765 :         if (ctx->config_timing) {
    5554        2885 :                 mp4_mux_config_timing(ctx);
    5555        2885 :                 if (ctx->config_timing) {
    5556        1586 :                         mp4_mux_format_report(filter, ctx, 0, 0);
    5557        1586 :                         return GF_OK;
    5558             :                 }
    5559             :         }
    5560             : 
    5561             :         //fragmented mode
    5562      570179 :         if (ctx->store>=MP4MX_MODE_FRAG) {
    5563             :                 u32 done=0;
    5564      120838 :                 GF_Err e = mp4_mux_process_fragmented(filter, ctx);
    5565      120838 :                 if (e==GF_EOS) done=100;
    5566      120838 :                 mp4_mux_format_report(filter, ctx, done, done);
    5567      120838 :                 return e;
    5568             :         }
    5569             : 
    5570             :         //regular mode
    5571             :         nb_suspended = 0;
    5572      576735 :         for (i=0; i<count; i++) {
    5573      576735 :                 TrackWriter *tkw = gf_list_get(ctx->tracks, i);
    5574      576735 :                 GF_FilterPacket *pck = gf_filter_pid_get_packet(tkw->ipid);
    5575             : 
    5576      576735 :                 if (tkw->suspended) {
    5577         319 :                         nb_suspended++;
    5578         319 :                         continue;
    5579             :                 }
    5580             : 
    5581      576416 :                 if (!pck) {
    5582      125633 :                         if (gf_filter_pid_is_eos(tkw->ipid)) {
    5583       14866 :                                 tkw->suspended = GF_FALSE;
    5584       14866 :                                 nb_eos++;
    5585             :                         }
    5586      125633 :                         if (tkw->aborted) {
    5587         571 :                                 nb_eos++;
    5588             :                         }
    5589      125633 :                         continue;
    5590             :                 }
    5591             : 
    5592      450783 :                 if (tkw->aborted) {
    5593           8 :                         gf_filter_pid_drop_packet(tkw->ipid);
    5594           8 :                         nb_eos++;
    5595           8 :                         continue;
    5596             :                 }
    5597             : 
    5598      450775 :                 if (ctx->owns_mov) {
    5599             :                         const GF_PropertyValue *p;
    5600       94695 :                         p = gf_filter_pck_get_property(pck, GF_PROP_PCK_FILENUM);
    5601       94695 :                         if (p) {
    5602         213 :                                 if (!ctx->cur_file_idx_plus_one) {
    5603          20 :                                         ctx->cur_file_idx_plus_one = p->value.uint + 1;
    5604          20 :                                         if (!ctx->cur_file_suffix) {
    5605          20 :                                                 p = gf_filter_pck_get_property(pck, GF_PROP_PCK_FILESUF);
    5606          20 :                                                 if (p && p->value.string) ctx->cur_file_suffix = gf_strdup(p->value.string);
    5607             :                                         }
    5608          20 :                                         ctx->notify_filename = GF_TRUE;
    5609         193 :                                 } else if (ctx->cur_file_idx_plus_one == p->value.uint+1) {
    5610          89 :                                 } else if (!tkw->suspended) {
    5611          89 :                                         tkw->suspended = GF_TRUE;
    5612          89 :                                         nb_suspended++;
    5613          89 :                                         ctx->next_file_idx =  p->value.uint + 1;
    5614          89 :                                         p = gf_filter_pck_get_property(pck, GF_PROP_PCK_FILESUF);
    5615          89 :                                         if (p && p->value.string)
    5616          89 :                                                 ctx->next_file_suffix = p->value.string;
    5617          89 :                                         continue;
    5618             :                                 }
    5619             :                         }
    5620             :                 }
    5621             : 
    5622             :                 //basic regulation in case we do on-the-fly interleaving
    5623             :                 //we need to regulate because sources do not produce packets at the same rate
    5624      450686 :                 if ((ctx->store==MP4MX_MODE_FASTSTART) && ctx->cdur.num) {
    5625        1304 :                         u64 cts = gf_filter_pck_get_cts(pck);
    5626        1304 :                         if (ctx->is_rewind)
    5627           0 :                                 cts = tkw->ts_shift - cts;
    5628             :                         else
    5629        1304 :                                 cts -= tkw->ts_shift;
    5630             : 
    5631        1304 :                         if (!ctx->faststart_ts_regulate.num) {
    5632           2 :                                 ctx->faststart_ts_regulate = ctx->cdur;
    5633             :                         }
    5634             :                         //ahead of our interleaving window, don't write yet
    5635        1302 :                         else if (cts * ctx->faststart_ts_regulate.den > ((u64) ctx->faststart_ts_regulate.num) * tkw->src_timescale) {
    5636         298 :                                 nb_skip++;
    5637         298 :                                 continue;
    5638             :                         }
    5639             :                 }
    5640             : 
    5641      450388 :                 if (tkw->cenc_state==CENC_NEED_SETUP)
    5642          95 :                         mp4_mux_cenc_update(ctx, tkw, pck, CENC_CONFIG, 0);
    5643             : 
    5644      450388 :                 if (tkw->is_item) {
    5645          64 :                         mp4_mux_process_item(ctx, tkw, pck);
    5646             :                 } else {
    5647      450324 :                         mp4_mux_process_sample(ctx, tkw, pck, GF_FALSE);
    5648             :                 }
    5649             : 
    5650      450388 :                 gf_filter_pid_drop_packet(tkw->ipid);
    5651      450388 :                 if (tkw->aborted) {
    5652          82 :                         nb_eos++;
    5653             :                 }
    5654             :         }
    5655      449341 :         mp4_mux_format_report(filter, ctx, 0, 0);
    5656             : 
    5657      449341 :         if (nb_suspended && (nb_suspended+nb_eos==count)) {
    5658          56 :                 return mp4mx_reload_output(filter, ctx);
    5659             :         }
    5660             : 
    5661      449285 :         if (count == nb_eos) {
    5662        4268 :                 if (ctx->file) {
    5663         932 :                         GF_Err e = mp4_mux_done(filter, ctx, GF_TRUE);
    5664         932 :                         if (e) return e;
    5665             :                 }
    5666             :                 return GF_EOS;
    5667             :         }
    5668             :         //done with this interleaving window, start next one
    5669      445017 :         else if (nb_skip + nb_eos == count) {
    5670          21 :                 ctx->faststart_ts_regulate.num += ctx->cdur.num;
    5671      444996 :         } else if (ctx->importer) {
    5672             :                 u64 prog_done=0, prog_total=0;
    5673      362608 :                 for (i=0; i<count; i++) {
    5674      362608 :                         TrackWriter *tkw = gf_list_get(ctx->tracks, i);
    5675      362608 :                         if (prog_done * tkw->prog_total <= tkw->prog_done * prog_total) {
    5676             :                                 prog_done = tkw->prog_done;
    5677             :                                 prog_total = tkw->prog_total;
    5678             :                         }
    5679             :                 }
    5680      353532 :                 gf_set_progress("Import", prog_done, prog_total);
    5681             :         }
    5682             : 
    5683             :         return GF_OK;
    5684             : }
    5685             : 
    5686           2 : static GF_Err mp4_mux_on_data_patch(void *cbk, u8 *data, u32 block_size, u64 file_offset, Bool is_insert)
    5687             : {
    5688             :         GF_Filter *filter = (GF_Filter *) cbk;
    5689             :         u8 *output;
    5690           2 :         GF_MP4MuxCtx *ctx = gf_filter_get_udta(filter);
    5691             : 
    5692           2 :         GF_FilterPacket *pck = gf_filter_pck_new_alloc(ctx->opid, block_size, &output);
    5693           2 :         if (!pck) return GF_OUT_OF_MEM;
    5694             : 
    5695           2 :         memcpy(output, data, block_size);
    5696           2 :         gf_filter_pck_set_framing(pck, GF_FALSE, GF_FALSE);
    5697           2 :         gf_filter_pck_set_seek_flag(pck, GF_TRUE);
    5698           2 :         if (is_insert)
    5699           1 :                 gf_filter_pck_set_interlaced(pck, 1);
    5700           2 :         gf_filter_pck_set_byte_offset(pck, file_offset);
    5701           2 :         gf_filter_pck_send(pck);
    5702           2 :         return GF_OK;
    5703             : }
    5704             : 
    5705       21222 : static GF_Err mp4_mux_on_data(void *cbk, u8 *data, u32 block_size)
    5706             : {
    5707             :         GF_Filter *filter = (GF_Filter *) cbk;
    5708             :         u8 *output;
    5709       21222 :         GF_MP4MuxCtx *ctx = gf_filter_get_udta(filter);
    5710             : 
    5711       21222 :         ctx->total_bytes_out += block_size;
    5712             : 
    5713             :         //flush pending packet in frag mode
    5714       21222 :         mp4mux_send_output(ctx);
    5715             : 
    5716       21222 :         if (ctx->final_sidx_flush) {
    5717             :                 GF_FilterPacket *pck;
    5718             :                 u32 free_size=0;
    5719             : 
    5720           0 :                 if (ctx->vodcache==MP4MX_VODCACHE_INSERT) {
    5721           0 :                         pck = gf_filter_pck_new_alloc(ctx->opid, block_size, &output);
    5722           0 :                         if (!pck) return GF_OUT_OF_MEM;
    5723             : 
    5724           0 :                         memcpy(output, data, block_size);
    5725           0 :                         gf_filter_pck_set_framing(pck, GF_FALSE, GF_FALSE);
    5726           0 :                         gf_filter_pck_set_byte_offset(pck, ctx->sidx_chunk_offset);
    5727           0 :                         gf_filter_pck_set_seek_flag(pck, GF_TRUE);
    5728           0 :                         gf_filter_pck_set_interlaced(pck, 1);
    5729           0 :                         gf_filter_pck_send(pck);
    5730             :                 } else {
    5731             :                         GF_BitStream *bs;
    5732             :                         assert(!ctx->dst_pck);
    5733             : 
    5734           0 :                         if (block_size > ctx->sidx_max_size) {
    5735           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Final SIDX chunk larger than preallocated block, will not flush SIDX (output file still readable). Try disabling nocache mode\n"));
    5736             :                                 return GF_OK;
    5737             :                         }
    5738           0 :                         free_size = ctx->sidx_max_size - block_size;
    5739           0 :                         pck = gf_filter_pck_new_alloc(ctx->opid, ctx->sidx_max_size, &output);
    5740           0 :                         if (!pck) return GF_OUT_OF_MEM;
    5741             : 
    5742           0 :                         gf_filter_pck_set_framing(pck, GF_FALSE, GF_FALSE);
    5743           0 :                         gf_filter_pck_set_byte_offset(pck, ctx->sidx_chunk_offset);
    5744           0 :                         gf_filter_pck_set_seek_flag(pck, GF_TRUE);
    5745           0 :                         bs = gf_bs_new(output, ctx->sidx_max_size, GF_BITSTREAM_WRITE);
    5746           0 :                         if (free_size) {
    5747           0 :                                 gf_bs_write_u32(bs, free_size);
    5748           0 :                                 gf_bs_write_u32(bs, GF_ISOM_BOX_TYPE_FREE);
    5749           0 :                                 gf_bs_skip_bytes(bs, free_size-8);
    5750             :                         }
    5751           0 :                         gf_bs_write_data(bs, data, block_size);
    5752           0 :                         gf_bs_del(bs);
    5753           0 :                         gf_filter_pck_send(pck);
    5754             :                 }
    5755           0 :                 mp4_mux_flush_seg(ctx, GF_TRUE, ctx->sidx_chunk_offset+free_size, ctx->sidx_chunk_offset+free_size + block_size - 1);
    5756           0 :                 return GF_OK;
    5757             :         }
    5758             : 
    5759       21222 :         if (ctx->store_output) {
    5760         276 :                 u32 nb_write = (u32) gf_fwrite(data, block_size, ctx->tmp_store);
    5761         276 :                 if (nb_write != block_size) {
    5762           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Error writing to temp cache: %d bytes write instead of %d\n", nb_write, block_size));
    5763             :                         return GF_IO_ERR;
    5764             :                 }
    5765             :                 return GF_OK;
    5766             :         }
    5767             : 
    5768             :         //allocate new one
    5769       20946 :         ctx->dst_pck = gf_filter_pck_new_alloc(ctx->opid, block_size, &output);
    5770       20946 :         if (!ctx->dst_pck) return GF_OUT_OF_MEM;
    5771             : 
    5772       20946 :         memcpy(output, data, block_size);
    5773       20946 :         gf_filter_pck_set_framing(ctx->dst_pck, !ctx->first_pck_sent, GF_FALSE);
    5774             : 
    5775             :         //set packet prop as string since we may discard the seg_name  packet before this packet is processed
    5776       20946 :         if (!ctx->first_pck_sent && ctx->seg_name) {
    5777        2484 :                 ctx->current_offset = 0;
    5778        2484 :                 gf_filter_pck_set_property(ctx->dst_pck, GF_PROP_PCK_FILENAME, &PROP_STRING(ctx->seg_name) );
    5779        2484 :                 gf_filter_pck_set_property(ctx->dst_pck, GF_PROP_PCK_FILENUM, &PROP_UINT(ctx->dash_seg_num_plus_one-1) );
    5780             :         }
    5781       20946 :         if (ctx->min_cts_plus_one) {
    5782        4354 :                 u64 orig = ctx->min_cts_plus_one-1;
    5783        4354 :                 gf_filter_pck_set_cts(ctx->dst_pck, orig);
    5784        4354 :                 gf_filter_pck_set_duration(ctx->dst_pck, (u32) (ctx->min_cts_next_frag - orig) );
    5785             :         }
    5786             : 
    5787       20946 :         if ((ctx->llhls_mode>1) && ctx->fragment_started && !ctx->frag_size && ctx->dst_pck) {
    5788         130 :                 ctx->frag_num++;
    5789         130 :                 gf_filter_pck_set_property(ctx->dst_pck, GF_PROP_PCK_HLS_FRAG_NUM, &PROP_UINT(ctx->frag_num));
    5790             :         }
    5791       20946 :         ctx->frag_size += block_size;
    5792             : 
    5793       20946 :         ctx->first_pck_sent = GF_TRUE;
    5794       20946 :         ctx->current_size += block_size;
    5795             :         //non-frag mode, send right away
    5796       20946 :         if (ctx->store<MP4MX_MODE_FRAG) {
    5797       16257 :                 mp4mux_send_output(ctx);
    5798             :         }
    5799             :         return GF_OK;
    5800             : }
    5801             : 
    5802      112277 : void mp4_mux_progress_cbk(void *udta, u64 done, u64 total)
    5803             : {
    5804             :         GF_Filter *filter = (GF_Filter *)udta;
    5805      112277 :         GF_MP4MuxCtx *ctx = gf_filter_get_udta(filter);
    5806      112277 :         ctx->update_report = GF_TRUE;
    5807      112277 :         mp4_mux_format_report(filter, ctx, done, total);
    5808      112277 : }
    5809             : 
    5810        1332 : static GF_Err mp4_mux_initialize(GF_Filter *filter)
    5811             : {
    5812        1332 :         GF_MP4MuxCtx *ctx = gf_filter_get_udta(filter);
    5813        1332 :         gf_filter_set_max_extra_input_pids(filter, -1);
    5814             : 
    5815        1332 :         if (ctx->file) {
    5816         608 :                 if (gf_isom_get_mode(ctx->file) < GF_ISOM_OPEN_WRITE) return GF_BAD_PARAM;
    5817         608 :                 if (ctx->store>=MP4MX_MODE_FRAG) {
    5818           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Cannot use fragmented output on already opened ISOBMF file\n"));
    5819             :                         return GF_BAD_PARAM;
    5820             :                 }
    5821         608 :                 ctx->owns_mov = GF_FALSE;
    5822         608 :                 gf_filter_act_as_sink(filter);
    5823             :         } else {
    5824             :                 u32 open_mode = GF_ISOM_OPEN_WRITE;
    5825         724 :                 ctx->owns_mov = GF_TRUE;
    5826             : 
    5827         724 :                 switch (ctx->store) {
    5828         383 :                 case MP4MX_MODE_INTER:
    5829             :                 case MP4MX_MODE_TIGHT:
    5830             :                         open_mode = GF_ISOM_WRITE_EDIT;
    5831         383 :                         break;
    5832             :                 }
    5833         724 :                 ctx->file = gf_isom_open("_gpac_isobmff_redirect", open_mode, NULL);
    5834         724 :                 if (!ctx->file) return GF_OUT_OF_MEM;
    5835             : 
    5836         724 :                 gf_isom_set_write_callback(ctx->file, mp4_mux_on_data, mp4_mux_on_data_patch, filter, ctx->block_size);
    5837             : 
    5838         724 :                 gf_isom_set_progress_callback(ctx->file, mp4_mux_progress_cbk, filter);
    5839             : 
    5840         724 :                 if (ctx->dref && (ctx->store>=MP4MX_MODE_FRAG)) {
    5841           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] Cannot use data reference in movie fragments, not supported. Ignoring it\n"));
    5842           0 :                         ctx->dref = GF_FALSE;
    5843             :                 }
    5844             : 
    5845         724 :                 if (ctx->store==MP4MX_MODE_FASTSTART) {
    5846           1 :                         gf_isom_set_storage_mode(ctx->file, GF_ISOM_STORE_FASTSTART);
    5847             :                 }
    5848             : 
    5849             :         }
    5850        1332 :         if (!ctx->moovts)
    5851           0 :                 ctx->moovts=600;
    5852        1332 :         if (!ctx->cdur.den) {
    5853           0 :                 ctx->cdur.num = 0;
    5854           0 :                 ctx->cdur.den = 1000;
    5855             :         }
    5856             :         //we need at least ms precision for sfrag mode
    5857        1332 :         if (ctx->cdur.den < 1000) {
    5858        1262 :                 ctx->cdur.num = (s32) ( ((s64)ctx->cdur.num) * 1000 / ctx->cdur.den);
    5859        1262 :                 ctx->cdur.den = 1000;
    5860             :         }
    5861             : 
    5862        1332 :         if (ctx->mfra && (ctx->store>=MP4MX_MODE_FRAG)) {
    5863           1 :                 GF_Err e = gf_isom_enable_mfra(ctx->file);
    5864           1 :                 if (e) return e;
    5865             :         }
    5866             : 
    5867        1332 :         if (!ctx->tracks)
    5868        1272 :                 ctx->tracks = gf_list_new();
    5869             : 
    5870             : #ifdef GF_ENABLE_CTRN
    5871             :         if (ctx->ctrni)
    5872             :                 ctx->ctrn = GF_TRUE;
    5873             : #endif
    5874             : 
    5875        1332 :         if (ctx->m4cc) {
    5876           0 :                 if (strlen(ctx->m4cc)==4)
    5877           0 :                         ctx->eos_marker = GF_4CC(ctx->m4cc[0], ctx->m4cc[1], ctx->m4cc[2], ctx->m4cc[3]);
    5878             :                 else {
    5879           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] Invalid segment marker 4cc %s, ignoring\n", ctx->m4cc));
    5880             :                 }
    5881             :         }
    5882        1332 :         if (ctx->compress) {
    5883             :                 u32 flags = 0;
    5884           2 :                 if (ctx->fcomp) flags |= GF_ISOM_COMP_FORCE_ALL;
    5885           2 :                 if (ctx->otyp) flags |= GF_ISOM_COMP_WRAP_FTYPE;
    5886           2 :                 gf_isom_enable_compression(ctx->file, ctx->compress, flags);
    5887             :         }
    5888             : 
    5889        1332 :         if (ctx->cmaf) {
    5890             :                 //cf table 3, 4, 5 of CMAF
    5891           0 :                 ctx->mvex = GF_TRUE;
    5892           0 :                 ctx->truns_first = GF_TRUE;
    5893             :                 //single trun, single traf (table 5 of CMAF)
    5894           0 :                 ctx->strun = GF_TRUE;
    5895           0 :                 ctx->straf = GF_TRUE;
    5896             :                 //7.5.16 Every TrackFragmentBox shall contain a TrackFragmentBaseMediaDecodeTimeBox
    5897           0 :                 ctx->tfdt_traf = GF_TRUE;
    5898             :                 //7.3.3 : If SegmentIndexBoxes exist, each subsegment referenced in the SegmentIndexBox shall be a single CMAF fragment
    5899           0 :                 ctx->chain_sidx = GF_FALSE;
    5900           0 :                 if (ctx->subs_sidx>0)
    5901           0 :                         ctx->subs_sidx = 0;
    5902             : 
    5903           0 :                 if (ctx->cmaf==MP4MX_CMAF_CMF2) {
    5904             :                         /*7.7 cmf2
    5905             : - default_sample_flags, sample_flags and first_sample_flags shall be set in the TrackFragmentHeaderBox and/or TrackRunBox to provide sample dependency information within each CMAF chunk and CMAF fragment.
    5906             : - Default values or per sample values of sample duration and sample size shall be stored in each CMAF chunk’s TrackRunBox and/or TrackFragmentHeaderBox
    5907             :                         */
    5908           0 :                         ctx->nofragdef = GF_TRUE;
    5909             :                 }
    5910             :         }
    5911             :         return GF_OK;
    5912             : }
    5913             : 
    5914             : //old code, commented - we track min/max cts while adding to avoid the time-consuming rescan below
    5915             : #if 0
    5916             : static void mp4_mux_get_min_max_cts(GF_MP4MuxCtx *ctx, TrackWriter *tkw, u64 *omax_cts, u64 *omin_cts)
    5917             : {
    5918             :         u32 i, count, di;
    5919             :         u64 max_cts, min_cts, doff;
    5920             : 
    5921             :         count = gf_isom_get_sample_count(ctx->file, tkw->track_num);
    5922             :         max_cts = 0;
    5923             :         min_cts = (u64) -1;
    5924             :         for (i=0; i<count; i++) {
    5925             :                 GF_ISOSample *s = gf_isom_get_sample_info(ctx->file, tkw->track_num, i+1, &di, &doff);
    5926             :                 if (!s)
    5927             :                         break;
    5928             :                 if (tkw->clamp_ts_plus_one) {
    5929             :                         if (s->DTS + s->CTS_Offset + 1 >= tkw->clamp_ts_plus_one ) {
    5930             :                                 gf_isom_sample_del(&s);
    5931             :                                 continue;
    5932             :                         }
    5933             :                 }
    5934             : 
    5935             :                 if (s->DTS + s->CTS_Offset > max_cts)
    5936             :                         max_cts = s->DTS + s->CTS_Offset;
    5937             : 
    5938             :                 if (min_cts > s->DTS + s->CTS_Offset)
    5939             :                         min_cts = s->DTS + s->CTS_Offset;
    5940             : 
    5941             :                 gf_isom_sample_del(&s);
    5942             :         }
    5943             :         *omax_cts = max_cts;
    5944             :         *omin_cts = min_cts;
    5945             : }
    5946             : #endif
    5947             : 
    5948         276 : static void mp4_mux_update_edit_list_for_bframes(GF_MP4MuxCtx *ctx, TrackWriter *tkw)
    5949             : {
    5950             :         u64 max_cts, min_cts;
    5951             :         s64 moffset;
    5952             : 
    5953         276 :         if (ctx->ctmode > MP4MX_CT_EDIT) return;
    5954             : 
    5955             :         //if we have a complex edit list (due to track template), don't override
    5956         276 :         if (gf_isom_get_edit_list_type(ctx->file, tkw->track_num, &moffset)) return;
    5957             : 
    5958         276 :         gf_isom_remove_edits(ctx->file, tkw->track_num);
    5959             : 
    5960             : #if 0
    5961             :         mp4_mux_get_min_max_cts(ctx, tkw, &max_cts, &min_cts);
    5962             : #else
    5963         276 :         max_cts = tkw->max_cts - tkw->min_neg_ctts;
    5964         276 :         min_cts = tkw->min_cts - tkw->min_neg_ctts;
    5965             : #endif
    5966             : 
    5967         276 :         if (min_cts || tkw->empty_init_dur) {
    5968         276 :                 max_cts -= min_cts;
    5969         276 :                 u32 count = gf_isom_get_sample_count(ctx->file, tkw->track_num);
    5970         276 :                 max_cts += gf_isom_get_sample_duration(ctx->file, tkw->track_num, count);
    5971             : 
    5972         276 :                 max_cts *= ctx->moovts;
    5973         276 :                 max_cts /= tkw->tk_timescale;
    5974         276 :                 if (tkw->empty_init_dur) {
    5975             : 
    5976          27 :                         gf_isom_set_edit(ctx->file, tkw->track_num, 0, tkw->empty_init_dur, 0, GF_ISOM_EDIT_EMPTY);
    5977          27 :                         if (max_cts >= tkw->empty_init_dur) max_cts -= tkw->empty_init_dur;
    5978             :                         else max_cts = 0;
    5979             :                 }
    5980             :                 //old arch compat: if we had a simple edit list in source try to keep the original segduration indicated
    5981             :                 //we tolerate a diff of 100ms
    5982         249 :                 else if (gf_sys_old_arch_compat() && tkw->imported_edit_sdur && (tkw->imported_edit_offset==min_cts)) {
    5983             :                         s32 diff;
    5984          68 :                         u64 old_dur_ms = tkw->imported_edit_sdur * 1000 / tkw->src_timescale;
    5985          68 :                         u64 new_dur_ms = max_cts * 1000 / tkw->tk_timescale;
    5986          68 :                         diff = (s32) new_dur_ms - (s32) old_dur_ms;
    5987          68 :                         if (ABS(diff)<100)
    5988             :                                 max_cts = tkw->imported_edit_sdur;
    5989             :                 }
    5990             : 
    5991         276 :                 gf_isom_set_edit(ctx->file, tkw->track_num, tkw->empty_init_dur, max_cts, min_cts, GF_ISOM_EDIT_NORMAL);
    5992             :         }
    5993             : }
    5994             : 
    5995             : //todo: move from media_import.c to here once done
    5996             : void gf_media_update_bitrate(GF_ISOFile *file, u32 track);
    5997             : 
    5998             : 
    5999        1488 : static void mp4_mux_set_hevc_groups(GF_MP4MuxCtx *ctx, TrackWriter *tkw)
    6000             : {
    6001             :         u32 avc_base_track, hevc_base_track, ref_track_id;
    6002             :         avc_base_track = hevc_base_track = 0;
    6003             :         u32 i;
    6004        1488 :         GF_PropertyEntry *pe=NULL;
    6005        1488 :         const GF_PropertyValue *p = gf_filter_pid_get_info_str(tkw->ipid, "hevc:oinf", &pe);
    6006        1488 :         if (p) {
    6007           6 :                 u32 gi=0;
    6008           6 :                 gf_isom_add_sample_group_info(ctx->file, tkw->track_num, GF_ISOM_SAMPLE_GROUP_OINF, p->value.data.ptr, p->value.data.size, GF_TRUE, &gi);
    6009             : 
    6010           6 :                 p = gf_filter_pid_get_info_str(tkw->ipid, "hevc:linf", &pe);
    6011           6 :                 if (p) {
    6012           6 :                         gf_isom_add_sample_group_info(ctx->file, tkw->track_num, GF_ISOM_SAMPLE_GROUP_LINF, p->value.data.ptr, p->value.data.size, GF_TRUE, &gi);
    6013           6 :                         gf_isom_set_track_group(ctx->file, tkw->track_num, 1000+gf_isom_get_track_id(ctx->file, tkw->track_num), GF_ISOM_BOX_TYPE_CSTG, GF_TRUE);
    6014             :                 }
    6015             :         }
    6016             : 
    6017        1488 :         gf_filter_release_property(pe);
    6018             : 
    6019        1488 :         p = gf_filter_pid_get_property_str(tkw->ipid, "hevc:min_lid");
    6020        1488 :         if ((!p || !p->value.uint) && (tkw->codecid!=GF_CODECID_LHVC)) {
    6021        1488 :                 return;
    6022             :         }
    6023             :         //set linf
    6024           0 :         for (i=0; i < gf_isom_get_track_count(ctx->file); i++) {
    6025           0 :                 u32 subtype = gf_isom_get_media_subtype(ctx->file, i+1, 1);
    6026           0 :                 switch (subtype) {
    6027           0 :                 case GF_ISOM_SUBTYPE_AVC_H264:
    6028             :                 case GF_ISOM_SUBTYPE_AVC2_H264:
    6029             :                 case GF_ISOM_SUBTYPE_AVC3_H264:
    6030             :                 case GF_ISOM_SUBTYPE_AVC4_H264:
    6031           0 :                         if (!avc_base_track) {
    6032             :                                 avc_base_track = i+1;
    6033             :                         } else {
    6034           0 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] Warning: More than one AVC bitstream found, use track %d as base layer", avc_base_track));
    6035             :                         }
    6036             :                         break;
    6037           0 :                 case GF_ISOM_SUBTYPE_HVC1:
    6038             :                 case GF_ISOM_SUBTYPE_HEV1:
    6039             :                 case GF_ISOM_SUBTYPE_HVC2:
    6040             :                 case GF_ISOM_SUBTYPE_HEV2:
    6041           0 :                         if (!hevc_base_track) {
    6042             :                                 hevc_base_track = i+1;
    6043           0 :                                 if (avc_base_track) {
    6044           0 :                                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] Warning: Found both AVC and HEVC tracks, using HEVC track %d as base layer\n", hevc_base_track));
    6045             :                                 }
    6046             :                         } else {
    6047           0 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] Warning: More than one HEVC bitstream found, use track %d as base layer\n", avc_base_track));
    6048             :                         }
    6049             :                         break;
    6050             :                 }
    6051             :         }
    6052           0 :         if (!hevc_base_track && !avc_base_track) {
    6053           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] Using LHVC external base layer, but no base layer not found - NOT SETTING SBAS TRACK REFERENCE!\n"));
    6054             :         } else {
    6055           0 :                 ref_track_id = gf_isom_get_track_id(ctx->file, hevc_base_track ? hevc_base_track : avc_base_track);
    6056           0 :                 gf_isom_set_track_reference(ctx->file, tkw->track_num, GF_ISOM_REF_BASE, ref_track_id);
    6057             : 
    6058           0 :                 if (hevc_base_track) {
    6059           0 :                         ref_track_id = gf_isom_get_track_id(ctx->file, hevc_base_track);
    6060           0 :                         gf_isom_set_track_reference(ctx->file, tkw->track_num, GF_ISOM_REF_OREF, ref_track_id);
    6061             :                 }
    6062             :         }
    6063             : }
    6064             : 
    6065         992 : static GF_Err mp4_mux_done(GF_Filter *filter, GF_MP4MuxCtx *ctx, Bool is_final)
    6066             : {
    6067             :         GF_Err e = GF_OK;
    6068             :         u32 i, count;
    6069         992 :         GF_PropertyEntry *pe=NULL;
    6070             : 
    6071         992 :         count = gf_list_count(ctx->tracks);
    6072        1099 :         for (i=0; i<count; i++) {
    6073             :                 const GF_PropertyValue *p;
    6074             :                 Bool has_bframes = GF_FALSE;
    6075        1099 :                 TrackWriter *tkw = gf_list_get(ctx->tracks, i);
    6076             : 
    6077        1099 :                 if (tkw->min_neg_ctts<0) {
    6078             :                         //use ctts v1 negative offsets
    6079         177 :                         if (ctx->ctmode==MP4MX_CT_NEGCTTS) {
    6080           0 :                                 gf_isom_set_ctts_v1(ctx->file, tkw->track_num, (u32) -tkw->min_neg_ctts);
    6081             :                         }
    6082             :                         //ctts v0
    6083             :                         else {
    6084         177 :                                 gf_isom_set_cts_packing(ctx->file, tkw->track_num, GF_TRUE);
    6085         177 :                                 gf_isom_shift_cts_offset(ctx->file, tkw->track_num, (s32) tkw->min_neg_ctts);
    6086         177 :                                 gf_isom_set_cts_packing(ctx->file, tkw->track_num, GF_FALSE);
    6087         177 :                                 gf_isom_set_composition_offset_mode(ctx->file, tkw->track_num, GF_FALSE);
    6088             : 
    6089         177 :                                 mp4_mux_update_edit_list_for_bframes(ctx, tkw);
    6090             :                         }
    6091             :                         has_bframes = GF_TRUE;
    6092         922 :                 } else if (tkw->has_ctts && (tkw->stream_type==GF_STREAM_VISUAL)) {
    6093          99 :                         mp4_mux_update_edit_list_for_bframes(ctx, tkw);
    6094             : 
    6095             :                         has_bframes = GF_TRUE;
    6096         823 :                 } else if (tkw->ts_delay || tkw->empty_init_dur) {
    6097          20 :                         gf_isom_update_edit_list_duration(ctx->file, tkw->track_num);
    6098             :                 }
    6099             : 
    6100        1099 :                 if (tkw->min_ts_seek_plus_one) {
    6101           8 :                         u64 min_ts = tkw->min_ts_seek_plus_one - 1;
    6102           8 :                         u64 mdur = gf_isom_get_media_duration(ctx->file, tkw->track_num);
    6103             :                         u32 delay = 0;
    6104           8 :                         if (tkw->clamp_ts_plus_one) {
    6105             : #if 0
    6106             :                                 u64 maxcts, mincts;
    6107             :                                 mp4_mux_get_min_max_cts(ctx, tkw, &maxcts, &mincts);
    6108             :                                 mdur = maxcts - mincts;
    6109             : #else
    6110           0 :                                 mdur = tkw->max_cts - tkw->min_cts;
    6111           0 :                                 mdur += tkw->max_cts_samp_dur;
    6112             : #endif
    6113             :                         }
    6114           8 :                         if (mdur > min_ts)
    6115           6 :                                 mdur -= min_ts;
    6116             :                         else
    6117             :                                 mdur = 0;
    6118             : 
    6119           8 :                         if ((ctx->ctmode!=MP4MX_CT_NEGCTTS) && (tkw->ts_delay<0) && (tkw->stream_type==GF_STREAM_VISUAL)) {
    6120           0 :                                 delay = (u32) -tkw->ts_delay;
    6121             :                         }
    6122             : 
    6123           8 :                         if (tkw->src_timescale != tkw->tk_timescale) {
    6124           0 :                                 min_ts *= tkw->tk_timescale;
    6125           0 :                                 min_ts /= tkw->src_timescale;
    6126           0 :                                 delay *= tkw->tk_timescale;
    6127           0 :                                 delay /= tkw->src_timescale;
    6128             :                         }
    6129           8 :                         mdur += delay;
    6130             : 
    6131           8 :                         if (ctx->moovts != tkw->tk_timescale) {
    6132           8 :                                 mdur *= ctx->moovts;
    6133           8 :                                 mdur /= tkw->tk_timescale;
    6134             :                         }
    6135           8 :                         gf_isom_remove_edits(ctx->file, tkw->track_num);
    6136           8 :                         if (tkw->empty_init_dur)
    6137           2 :                                 gf_isom_set_edit(ctx->file, tkw->track_num, 0, tkw->empty_init_dur, 0, GF_ISOM_EDIT_EMPTY);
    6138           8 :                         gf_isom_set_edit(ctx->file, tkw->track_num, tkw->empty_init_dur, mdur, min_ts, GF_ISOM_EDIT_NORMAL);
    6139             :                 }
    6140             : 
    6141        1099 :                 if (tkw->force_ctts) {
    6142             :                         GF_Err gf_isom_force_ctts(GF_ISOFile *file, u32 track);
    6143          85 :                         gf_isom_force_ctts(ctx->file, tkw->track_num);
    6144             :                 }
    6145             : 
    6146        1099 :                 gf_isom_purge_track_reference(ctx->file, tkw->track_num);
    6147             :                 
    6148        1099 :                 if (ctx->importer && ctx->idur.num && ctx->idur.den) {
    6149          93 :                         u64 mdur = gf_isom_get_media_duration(ctx->file, tkw->track_num);
    6150          93 :                         u64 pdur = gf_isom_get_track_duration(ctx->file, tkw->track_num);
    6151          93 :                         if (pdur==mdur) {
    6152           1 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[MP4Mux] Imported %d frames - duration %g\n", tkw->nb_samples, ((Double)mdur)/tkw->tk_timescale ));
    6153             :                         } else {
    6154          92 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[MP4Mux] Imported %d frames - media duration %g - track duration %g\n", tkw->nb_samples, ((Double)mdur)/tkw->tk_timescale, ((Double)pdur)/ctx->moovts ));
    6155             :                         }
    6156             :                 }
    6157             : 
    6158             :                 /*this is plain ugly but since some encoders (divx) don't use the video PL correctly
    6159             :                  we force the system video_pl to ASP@L5 since we have I, P, B in base layer*/
    6160        1099 :                 if (tkw->codecid == GF_CODECID_MPEG4_PART2) {
    6161             :                         Bool force_rewrite = GF_FALSE;
    6162          78 :                         u32 PL = tkw->media_profile_level;
    6163          78 :                         if (!PL) PL = 0x01;
    6164             : 
    6165          78 :                         if (ctx->importer) {
    6166          21 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("Indicated Profile: %s\n", gf_m4v_get_profile_name((u8) PL) ));
    6167             :                         }
    6168             : 
    6169          78 :                         if (has_bframes && (tkw->media_profile_level <= 3)) {
    6170             :                                 PL = 0xF5;
    6171           1 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[MP4Mux] Indicated profile doesn't include B-VOPs - forcing %s\n", gf_m4v_get_profile_name((u8) PL) ));
    6172             :                                 force_rewrite = GF_TRUE;
    6173             :                         }
    6174          78 :                         if (PL != tkw->media_profile_level) {
    6175           1 :                                 if (force_rewrite) {
    6176             : #ifndef GPAC_DISABLE_AV_PARSERS
    6177           1 :                                         GF_ESD *esd = gf_isom_get_esd(ctx->file, tkw->track_num, tkw->stsd_idx);
    6178             :                                         assert(esd);
    6179           1 :                                         gf_m4v_rewrite_pl(&esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength, (u8) PL);
    6180           1 :                                         gf_isom_change_mpeg4_description(ctx->file, tkw->track_num, tkw->stsd_idx, esd);
    6181           1 :                                         gf_odf_desc_del((GF_Descriptor*)esd);
    6182             : #endif
    6183             : 
    6184             :                                 }
    6185           1 :                                 if (!ctx->make_qt)
    6186           1 :                                         gf_isom_set_pl_indication(ctx->file, GF_ISOM_PL_VISUAL, PL);
    6187             :                         }
    6188             :                 }
    6189             : 
    6190             : 
    6191        1099 :                 if (tkw->has_append)
    6192           0 :                         gf_isom_refresh_size_info(ctx->file, tkw->track_num);
    6193             : 
    6194        1099 :                 if ((tkw->nb_samples == 1) && (ctx->idur.num>0) && ctx->idur.den) {
    6195          11 :                         u32 dur = tkw->tk_timescale * ctx->idur.num;
    6196          11 :                         dur /= ctx->idur.den;
    6197          11 :                         gf_isom_set_last_sample_duration(ctx->file, tkw->track_num, dur);
    6198             :                 }
    6199             : 
    6200        1099 :                 if (tkw->has_open_gop) {
    6201          19 :                         if (ctx->importer) {
    6202          15 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("OpenGOP detected - adjusting file brand\n"));
    6203             :                         }
    6204          19 :                         gf_isom_modify_alternate_brand(ctx->file, GF_ISOM_BRAND_ISO6, GF_TRUE);
    6205             :                 }
    6206             : 
    6207        1099 :                 mp4_mux_set_hevc_groups(ctx, tkw);
    6208             : 
    6209        1099 :                 p = gf_filter_pid_get_info_str(tkw->ipid, "ttxt:rem_last", &pe);
    6210        1099 :                 if (p && p->value.boolean)
    6211           3 :                         gf_isom_remove_sample(ctx->file, tkw->track_num, tkw->nb_samples);
    6212             : 
    6213        1099 :                 p = gf_filter_pid_get_info_str(tkw->ipid, "ttxt:last_dur", &pe);
    6214        1099 :                 if (p) {
    6215          22 :                         u64 val = p->value.uint;
    6216          22 :                         if (tkw->src_timescale != tkw->tk_timescale) {
    6217           0 :                                 val *= tkw->tk_timescale;
    6218           0 :                                 val /= tkw->src_timescale;
    6219             :                         }
    6220          22 :                         gf_isom_set_last_sample_duration(ctx->file, tkw->track_num, (u32) val);
    6221             :                 }
    6222             : 
    6223        1099 :                 if (tkw->is_nalu && ctx->pack_nal && (gf_isom_get_mode(ctx->file)!=GF_ISOM_OPEN_WRITE)) {
    6224             :                         u32 msize = 0;
    6225             :                         Bool do_rewrite = GF_FALSE;
    6226           1 :                         u32 j, stsd_count = gf_isom_get_sample_description_count(ctx->file, tkw->track_num);
    6227           1 :                         p = gf_filter_pid_get_info(tkw->ipid, GF_PROP_PID_MAX_NALU_SIZE, &pe);
    6228           1 :                         msize = gf_get_bit_size(p->value.uint);
    6229           1 :                         if (msize<8) msize = 8;
    6230           1 :                         else if (msize<16) msize = 16;
    6231             :                         else msize = 32;
    6232             : 
    6233             :                         if (msize<=0xFFFF) {
    6234           2 :                                 for (j=0; j<stsd_count; j++) {
    6235           1 :                                         u32 k = 8 * gf_isom_get_nalu_length_field(ctx->file, tkw->track_num, j+1);
    6236           1 :                                         if (k > msize) {
    6237             :                                                 do_rewrite = GF_TRUE;
    6238             :                                         }
    6239             :                                 }
    6240           1 :                                 if (do_rewrite) {
    6241           1 :                                         GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[MP4Mux] Adjusting NALU SizeLength to %d bits\n", msize ));
    6242           1 :                                         gf_media_nal_rewrite_samples(ctx->file, tkw->track_num, msize);
    6243           1 :                                         msize /= 8;
    6244           2 :                                         for (j=0; j<stsd_count; j++) {
    6245           1 :                                                 gf_isom_set_nalu_length_field(ctx->file, tkw->track_num, j+1, msize);
    6246             :                                         }
    6247             :                                 }
    6248             :                         }
    6249             :                 }
    6250             : 
    6251             :                 //don't update bitrate info for single sample tracks, unless MPEG-4 Systems - compatibility with old arch
    6252        1099 :                 if (ctx->btrt && !tkw->skip_bitrate_update && ((tkw->nb_samples>1) || ctx->m4sys) )
    6253         863 :                         gf_media_update_bitrate(ctx->file, tkw->track_num);
    6254             : 
    6255        1099 :                 if (!tkw->box_patched) {
    6256        1002 :                         p = gf_filter_pid_get_property_str(tkw->ipid, "boxpatch");
    6257        1002 :                         if (p && p->value.string) {
    6258           4 :                                 e = gf_isom_apply_box_patch(ctx->file, tkw->track_id ? tkw->track_id : tkw->item_id, p->value.string, GF_FALSE);
    6259           4 :                                 if (e) {
    6260           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Unable to apply box patch %s to track %d: %s\n",
    6261             :                                                 p->value.string, tkw->track_id, gf_error_to_string(e) ));
    6262             :                                 }
    6263             :                         }
    6264        1002 :                         tkw->box_patched = GF_TRUE;
    6265             :                 }
    6266             :         }
    6267             : 
    6268         992 :         gf_filter_release_property(pe);
    6269             : 
    6270         992 :         if (ctx->boxpatch && !ctx->box_patched) {
    6271           3 :                 e = gf_isom_apply_box_patch(ctx->file, 0, ctx->boxpatch, GF_FALSE);
    6272           3 :                 if (e) {
    6273           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[MP4Mux] Unable to apply box patch %s: %s\n", ctx->boxpatch, gf_error_to_string(e) ));
    6274             :                 }
    6275           3 :                 ctx->box_patched = GF_TRUE;
    6276             :         }
    6277             : 
    6278             : 
    6279         992 :         if (ctx->owns_mov) {
    6280         386 :                 if (ctx->moovpad)
    6281           0 :                         gf_isom_set_inplace_padding(ctx->file, ctx->moovpad);
    6282             : 
    6283         386 :                 switch (ctx->store) {
    6284         381 :                 case MP4MX_MODE_INTER:
    6285         381 :                         if (ctx->cdur.num==0) {
    6286           0 :                                 e = gf_isom_set_storage_mode(ctx->file, GF_ISOM_STORE_STREAMABLE);
    6287             :                         } else {
    6288         381 :                                 e = gf_isom_make_interleave_ex(ctx->file, &ctx->cdur);
    6289             :                         }
    6290             :                         break;
    6291           0 :                 case MP4MX_MODE_FLAT:
    6292           0 :                         e = gf_isom_set_storage_mode(ctx->file, GF_ISOM_STORE_FLAT);
    6293             :                         break;
    6294           1 :                 case MP4MX_MODE_FASTSTART:
    6295           1 :                         e = gf_isom_set_storage_mode(ctx->file, GF_ISOM_STORE_FASTSTART);
    6296             :                         break;
    6297           0 :                 case MP4MX_MODE_TIGHT:
    6298           0 :                         e = gf_isom_set_storage_mode(ctx->file, GF_ISOM_STORE_TIGHT);
    6299             :                         break;
    6300             :                 }
    6301         386 :                 if (e) {
    6302           0 :                         GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[MP4Mux] Failed to set storage mode: %s\n", gf_error_to_string(e) ));
    6303             :                 } else {
    6304         386 :                         e = gf_isom_close(ctx->file);
    6305         386 :                         if (e) {
    6306           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[MP4Mux] Failed to write file: %s\n", gf_error_to_string(e) ));
    6307             :                         }
    6308             :                 }
    6309         386 :                 ctx->file = NULL;
    6310         386 :                 if (is_final)
    6311         326 :                         gf_filter_pid_set_eos(ctx->opid);
    6312             :         } else {
    6313         606 :                 ctx->file = NULL;
    6314             :         }
    6315         992 :         return e;
    6316             : }
    6317             : 
    6318        1272 : static void mp4_mux_finalize(GF_Filter *filter)
    6319             : {
    6320        1272 :         GF_MP4MuxCtx *ctx = gf_filter_get_udta(filter);
    6321             : 
    6322        1272 :         if (ctx->owns_mov && (ctx->file || (ctx->store>=MP4MX_MODE_FRAG))) {
    6323         338 :                 gf_isom_delete(ctx->file);
    6324             :         }
    6325             : 
    6326        2621 :         while (gf_list_count(ctx->tracks)) {
    6327        1349 :                 TrackWriter *tkw = gf_list_pop_back(ctx->tracks);
    6328        1349 :                 mp4_mux_track_writer_del(tkw);
    6329             :         }
    6330        1272 :         gf_list_del(ctx->tracks);
    6331        1272 :         if (ctx->bs_r) gf_bs_del(ctx->bs_r);
    6332        1272 :         if (ctx->seg_name) gf_free(ctx->seg_name);
    6333        1272 :         if (ctx->tmp_store) gf_fclose(ctx->tmp_store);
    6334        1272 :         if (ctx->seg_sizes) gf_free(ctx->seg_sizes);
    6335             : 
    6336        1272 :         if (ctx->cur_file_suffix) gf_free(ctx->cur_file_suffix);
    6337             : 
    6338        1272 : }
    6339             : 
    6340             : static const GF_FilterCapability MP4MuxCaps[] =
    6341             : {
    6342             :         //for now don't accept files as input, although we could store them as items, to refine
    6343             :         CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
    6344             :         CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_STREAM_TYPE, GF_STREAM_SCENE),
    6345             :         CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_STREAM_TYPE, GF_STREAM_OD),
    6346             :         //we want framed media only
    6347             :         CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
    6348             :         //and any codecid
    6349             :         CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_NONE),
    6350             :         CAP_STRING(GF_CAPS_OUTPUT_STATIC,  GF_PROP_PID_FILE_EXT, ISOM_FILE_EXT),
    6351             :         CAP_STRING(GF_CAPS_OUTPUT_STATIC,  GF_PROP_PID_MIME, ISOM_FILE_MIME),
    6352             :         {0},
    6353             :         //for scene / OD / text, we don't want raw codecid (filters modifying a scene graph we don't expose)
    6354             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_SCENE),
    6355             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_OD),
    6356             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_TEXT),
    6357             :         CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
    6358             :         CAP_UINT(GF_CAPS_INPUT_EXCLUDED,  GF_PROP_PID_CODECID, GF_CODECID_RAW),
    6359             : };
    6360             : 
    6361             : 
    6362             : #define OFFS(_n)        #_n, offsetof(GF_MP4MuxCtx, _n)
    6363             : static const GF_FilterArgs MP4MuxArgs[] =
    6364             : {
    6365             :         { OFFS(m4sys), "force MPEG-4 Systems signaling of tracks", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    6366             :         { OFFS(dref), "only references data from source file - not compatible with all media sources", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    6367             :         { OFFS(ctmode), "set composition offset mode for video tracks\n"
    6368             :         "- edit: uses edit lists to shift first frame to presentation time 0\n"
    6369             :         "- noedit: ignore edit lists and does not shift timeline\n"
    6370             :         "- negctts: uses ctts v1 with possibly negative offsets and no edit lists", GF_PROP_UINT, "edit", "edit|noedit|negctts", GF_FS_ARG_HINT_ADVANCED},
    6371             :         { OFFS(idur), "only import the specified duration. If negative, specify the number of coded frames to import", GF_PROP_FRACTION, "0", NULL, 0},
    6372             :         { OFFS(pack3gp), "pack a given number of 3GPP audio frames in one sample", GF_PROP_UINT, "1", NULL, GF_FS_ARG_HINT_ADVANCED},
    6373             :         { OFFS(importer), "compatibility with old importer, displays import progress", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    6374             :         { OFFS(pack_nal), "repack NALU size length to minimum possible size for NALU-based video (AVC/HEVC/...)", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT},
    6375             :         { OFFS(xps_inband), "use inband (in sample data) parameter set for NALU-based video (AVC/HEVC/...)\n"
    6376             :         "- no: paramater sets are not inband, several sample descriptions might be created\n"
    6377             :         "- all: paramater sets are inband, no parameter sets in sample description\n"
    6378             :         "- both: paramater sets are inband, signaled as inband, and also first set is kept in sample description\n"
    6379             :         "- mix: creates non-standard files using single sample entry with first PSs found, and moves other PS inband", GF_PROP_UINT, "no", "no|all|both|mix", 0},
    6380             :         { OFFS(store), "file storage mode\n"
    6381             :         "- inter: perform precise interleave of the file using [-cdur]() (requires temporary storage of all media)\n"
    6382             :         "- flat: write samples as they arrive and moov at end (fastest mode)\n"
    6383             :         "- fstart: write samples as they arrive and moov before mdat\n"
    6384             :         "- tight:  uses per-sample interleaving of all tracks (requires temporary storage of all media)\n"
    6385             :         "- frag: fragments the file using cdur duration\n"
    6386             :         "- sfrag: framents the file using cdur duration but adjusting to start with SAP1/3", GF_PROP_UINT, "inter", "inter|flat|fstart|tight|frag|sfrag", 0},
    6387             :         { OFFS(cdur), "chunk duration for flat and interleaving modes or fragment duration for fragmentation modes\n"
    6388             :         "- 0: no specific interleaving but moov first\n"
    6389             :         "- negative: defaults to 1.0 unless overridden by storage profile", GF_PROP_FRACTION, "-1/1", NULL, 0},
    6390             :         { OFFS(moovts), "timescale to use for movie. A negative value picks the media timescale of the first track added", GF_PROP_SINT, "600", NULL, GF_FS_ARG_HINT_ADVANCED},
    6391             :         { OFFS(moof_first), "generate fragments starting with moof then mdat", GF_PROP_BOOL, "true", NULL, GF_FS_ARG_HINT_ADVANCED},
    6392             :         { OFFS(abs_offset), "use absolute file offset in fragments rather than offsets from moof", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    6393             :         { OFFS(fsap), "split truns in video fragments at SAPs to reduce file size", GF_PROP_BOOL, "true", NULL, GF_FS_ARG_HINT_ADVANCED},
    6394             :         { OFFS(file), "pointer to a write/edit ISOBMF file used internally by importers and exporters", GF_PROP_POINTER, NULL, NULL, GF_FS_ARG_HINT_HIDE},
    6395             :         { OFFS(subs_sidx), "number of subsegments per sidx. negative value disables sidx, -2 removes sidx if present in source pid", GF_PROP_SINT, "-1", NULL, GF_FS_ARG_HINT_ADVANCED},
    6396             :         { OFFS(m4cc), "4 character code of empty box to append at the end of a segment", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_HINT_ADVANCED},
    6397             :         { OFFS(chain_sidx), "use daisy-chaining of SIDX", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT},
    6398             :         { OFFS(msn), "sequence number of first moof to N", GF_PROP_UINT, "1", NULL, 0},
    6399             :         { OFFS(msninc), "sequence number increase between moofs", GF_PROP_UINT, "1", NULL, 0},
    6400             :         { OFFS(tfdt), "set TFDT of first traf", GF_PROP_FRACTION64, "0", NULL, 0},
    6401             :         { OFFS(tfdt_traf), "set TFDT in each traf", GF_PROP_BOOL, "false", NULL, 0},
    6402             :         { OFFS(nofragdef), "disable default flags in fragments", GF_PROP_BOOL, "false", NULL, 0},
    6403             :         { OFFS(straf), "use a single traf per moof (smooth streaming and co)", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    6404             :         { OFFS(strun), "use a single trun per traf (smooth streaming and co)", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    6405             :         { OFFS(psshs), "set PSSH boxes store mode\n"
    6406             :         "- moof: in first moof of each segments\n"
    6407             :         "- moov: in movie box\n"
    6408             :         "- none: pssh is discarded", GF_PROP_UINT, "moov", "moov|moof|none", GF_FS_ARG_HINT_ADVANCED},
    6409             :         { OFFS(sgpd_traf), "store sample group descriptions in traf (duplicated for each traf). If not used, sample group descriptions are stored in the movie box", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    6410             :         { OFFS(vodcache), "enable temp storage for VoD dash modes - see filter help\n"
    6411             :                 "- on: use temp storage of complete file for sidx and ssix injection\n"
    6412             :                 "- insert: insert sidx and ssix by shifting bytes in output file\n"
    6413             :                 "- replace: precompute pace requirements for sidx and ssix and rewrite file range at end", GF_PROP_UINT, "replace", "on|insert|replace", 0},
    6414             :         { OFFS(noinit), "do not produce initial moov, used for DASH bitstream switching mode", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    6415             :         { OFFS(tktpl), "use track box from input if any as a template to create new track\n"
    6416             :         "- no: disables template\n"
    6417             :         "- yes: clones the track (except edits and decoder config)\n"
    6418             :         "- udta: only loads udta", GF_PROP_UINT, "yes", "no|yes|udta", GF_FS_ARG_HINT_EXPERT},
    6419             :         { OFFS(mudta), "use udta and other moov extension boxes from input if any\n"
    6420             :         "- no: disables import\n"
    6421             :         "- yes: clones all extension boxes\n"
    6422             :         "- udta: only loads udta", GF_PROP_UINT, "yes", "no|yes|udta", GF_FS_ARG_HINT_EXPERT},
    6423             :         { OFFS(mvex), "set mvex after tracks", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    6424             :         { OFFS(sdtp_traf), "use sdtp in traf rather than using flags in trun sample entries\n"
    6425             :                 "- no: do not use sdtp\n"
    6426             :                 "- sdtp: use sdtp box to indicate sample dependencies and do not write info in trun sample flags\n"
    6427             :                 "- both: use sdtp box to indicate sample dependencies and also write info in trun sample flags", GF_PROP_UINT, "no", "no|sdtp|both", GF_FS_ARG_HINT_EXPERT},
    6428             :         { OFFS(trackid), "track ID of created track for single track. Default 0 uses next available trackID", GF_PROP_UINT, "0", NULL, GF_FS_ARG_HINT_ADVANCED},
    6429             :         { OFFS(fragdur), "fragment based on fragment duration rather than CTS. Mostly used for MP4Box -frag option", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    6430             :         { OFFS(btrt), "set btrt box in sample description", GF_PROP_BOOL, "true", NULL, 0},
    6431             :         { OFFS(styp), "set segment styp major brand to the given 4CC[.version]", GF_PROP_STRING, NULL, NULL, 0},
    6432             :         { OFFS(mediats), "set media timescale. A value of 0 means inherit from pid, a value of -1 means derive from samplerate or frame rate", GF_PROP_SINT, "0", NULL, 0},
    6433             :         { OFFS(ase), "set audio sample entry mode for more than stereo layouts\n"\
    6434             :                         "- v0: use v0 signaling but channel count from stream, recommended for backward compatibility\n"\
    6435             :                         "- v0s: use v0 signaling and force channel count to 2 (stereo) if more than 2 channels\n"\
    6436             :                         "- v1: use v1 signaling, ISOBMFF style (will mux raw PCM as ISOBMFF style)\n"\
    6437             :                         "- v1qt: use v1 signaling, QTFF style"\
    6438             :                 , GF_PROP_UINT, "v0", "|v0|v0s|v1|v1qt", 0},
    6439             :         { OFFS(ssix), "create ssix when sidx is present, level 1 mapping I-frames byte ranges, level 0xFF mapping the rest", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    6440             :         { OFFS(ccst), "insert coding constraint box for video tracks", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    6441             :         { OFFS(maxchunk), "set max chunk size in bytes for runs (only used in non-fragmented mode). 0 means no constraints", GF_PROP_UINT, "0", NULL, GF_FS_ARG_HINT_ADVANCED},
    6442             :         { OFFS(noroll), "disable roll sample grouping", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT},
    6443             :         { OFFS(saio32), "use 32 bit offset for side data location instead of 64 bit offset", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT},
    6444             :         { OFFS(tfdt64), "use 64 bit tfdt and sidx even for 32 bits timestamps", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT},
    6445             : #ifdef GF_ENABLE_CTRN
    6446             :         { OFFS(ctrn), "use compact track run (experimental)", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    6447             :         { OFFS(ctrni), "use inheritance in compact track run for HEVC tile tracks (highly experimental)", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT},
    6448             : #endif
    6449             :         { OFFS(sseg), "set single segment mode for dash", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_HIDE},
    6450             : 
    6451             :         { OFFS(compress), "set top-level box compression mode\n"
    6452             :                                                 "- no: disable box compression\n"
    6453             :                                                 "- moov: compress only moov box\n"
    6454             :                                                 "- moof: compress only moof boxes\n"
    6455             :                                                 "- sidx: compress moof and sidx boxes\n"
    6456             :                                                 "- ssix: compress moof, sidx and ssix boxes\n"
    6457             :                                                 "- all: compress moov, moof, sidx and ssix boxes", GF_PROP_UINT, "no", "no|moov|moof|sidx|ssix|all", GF_FS_ARG_HINT_EXPERT},
    6458             :         { OFFS(fcomp), "force using compress box even when compressed size is larger than uncompressed", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT},
    6459             :         { OFFS(otyp), "inject original file type when using compressed boxes", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT},
    6460             : 
    6461             :         { OFFS(trun_inter), "interleave samples in trun based on the temporal level, the lowest level are stored first - this will create as many trun as required", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT},
    6462             :         { OFFS(truns_first), "store track runs before sample group description and sample encryption information", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT},
    6463             :         { OFFS(block_size), "target output block size, 0 for default internal value (10k)", GF_PROP_UINT, "10000", NULL, GF_FS_ARG_HINT_ADVANCED},
    6464             :         { OFFS(boxpatch), "apply box patch before writing", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_HINT_EXPERT},
    6465             :         { OFFS(deps), "add samples dependencies information", GF_PROP_BOOL, "true", NULL, GF_FS_ARG_HINT_EXPERT},
    6466             :         { OFFS(mfra), "enable movie fragment random access when fragmenting (ignored when dashing)", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT},
    6467             :         { OFFS(forcesync), "force all SAP types to be considered sync samples (might produce non-conformant files)", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT},
    6468             :         { OFFS(refrag), "indicate to use track fragment defaults from initial file if any rather than computing them from PID properties (used when processing standalone segments/fragments)", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    6469             :         { OFFS(itags), "tag injection mode\n"
    6470             :                         "- none: do not inject tags\n"
    6471             :                         "- strict: only inject recognized itunes tags\n"
    6472             :                         "- all: inject all possible tags"
    6473             :                         , GF_PROP_UINT, "strict", "none|strict|all", GF_FS_ARG_HINT_EXPERT},
    6474             : 
    6475             :         { OFFS(keep_utc), "force all new files and tracks to keep the source UTC creation and modification times", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
    6476             :         { OFFS(pps_inband), "when xps_inband is set, inject PPS in each non SAP 1/2/3 sample", GF_PROP_BOOL, "no", NULL, GF_FS_ARG_HINT_ADVANCED},
    6477             :         { OFFS(moovpad), "insert free box of given size after moov for future in-place editing", GF_PROP_UINT, "0", NULL, GF_FS_ARG_HINT_EXPERT},
    6478             :         { OFFS(cmaf), "use cmaf guidelines\n"
    6479             :                 "- no: CMAF not enforced\n"
    6480             :                 "- cmfc: use CMAF `cmfc` guidelines\n"
    6481             :                 "- cmf2: use CMAF `cmf2` guidelines"
    6482             :                 , GF_PROP_UINT, "no", "no|cmfc|cmf2", GF_FS_ARG_HINT_EXPERT},
    6483             :         { OFFS(start), "set playback start offset (MP4Box import only). Negative value means percent of media duration with -1 equal to duration", GF_PROP_DOUBLE, "0.0", NULL, GF_FS_ARG_HINT_HIDE},
    6484             :         {0}
    6485             : };
    6486             : 
    6487             : 
    6488             : GF_FilterRegister MP4MuxRegister = {
    6489             :         .name = "mp4mx",
    6490             :         GF_FS_SET_DESCRIPTION("ISOBMFF/QT muxer")
    6491             :         GF_FS_SET_HELP("Muxes file according to ISOBMFF (14496-12 and derived specifications) or QuickTime\n"
    6492             :         "  \n"
    6493             :         "# Tracks and Items\n"
    6494             :         "By default all input PIDs with ItemID property set are muxed as items, otherwise they are muxed as tracks.\n"
    6495             :         "To prevent source items to be muxed as items, use [-itemid](mp4dmx) option from ISOBMF demuxer.\n"
    6496             :         "EX -i source.mp4:itemid=false -o file.mp4\n"
    6497             :         "  \n"
    6498             :         "To force non-item streams to be muxed as items, use __#ItemID__ option on that PID:\n"
    6499             :         "EX -i source.jpg:#ItemID=1 -o file.mp4\n"
    6500             :         "  \n"
    6501             :         "# Storage\n"
    6502             :         "The [-store]() option allows controlling if the file is fragmented ot not, and when not fragmented, how interleaving is done. For cases where disk requirements are tight and fragmentation cannot be used, it is recommended to use either `flat` or `fstart` modes.\n"
    6503             :         "  \n"
    6504             :         "The [-vodcache]() option allows controlling how DASH onDemand segments are generated:\n"
    6505             :         "- If set to `on`, file data is stored to a temporary file on disk and flushed upon completion, no padding is present.\n"
    6506             :         "- If set to `insert`, SIDX/SSIX will be injected upon completion of the file by shifting bytes in file. In this case, no padding is required but this might not be compatible with all output sinks and will take longer to write the file.\n"
    6507             :         "- If set to `replace`, SIDX/SSIX size will be estimated based on duration and DASH segment length, and padding will be used in the file __before__ the final SIDX. If input pids have the properties `DSegs` set, this will be as the number of segments.\n"
    6508             :         "The `on` and `insert` modes will produce exactly the same file, while the mode `replace` may inject a `free` box before the sidx.\n"
    6509             :         "  \n"
    6510             :         "# Custom boxes\n"
    6511             :         "Custom boxes can be specified as box patches:\n"
    6512             :         "For movie-level patch, the [-boxpatch]() option of the filter should be used.\n"
    6513             :         "Per PID box patch can be specified through the PID property `boxpatch`.\n"
    6514             :         "EX src=source:#boxpatch=myfile.xml dst=mux.mp4\n"
    6515             :         "Per Item box patch can be specified through the PID property `boxpatch`.\n"
    6516             :         "EX src=source:1ItemID=1:#boxpatch=myfile.xml dst=mux.mp4\n"
    6517             :         "  \n"
    6518             :         "The box patch is applied before writing the initial moov box in fragmented mode, or when writing the complete file otherwise.\n"
    6519             :         "The box patch can either be a filename or the full XML string.\n"
    6520             :         "  \n"
    6521             :         "# Tagging\n"
    6522             :         "When tagging is enabled, the filter will watch the property `CoverArt` and all custom properties on incoming pid.\n"
    6523             :         "The built-in tag names are indicated by `MP4Box -h tags`.\n"
    6524             :         "Other tag class may be specified using `tag_NAME` property names, and will be added if [-tags]() is set to `all` using:\n"
    6525             :         "- `NAME` as a box 4CC if `NAME` is four characters long\n"
    6526             :         "- `NAME` as a box 4CC if `NAME` is 3 characters long, and will be prefixed by 0xA9\n"
    6527             :         "- the CRC32 of the `NAME` as a box 4CC if `NAME` is not four characters long\n"
    6528             :         "  \n"
    6529             :         "# Notes\n"
    6530             :         "The filter watches the property `FileNumber` on incoming packets to create new files or new segments in DASH mode.\n"
    6531             :         )
    6532             :         .private_size = sizeof(GF_MP4MuxCtx),
    6533             :         .args = MP4MuxArgs,
    6534             :         .initialize = mp4_mux_initialize,
    6535             :         .finalize = mp4_mux_finalize,
    6536             :         .flags = GF_FS_REG_DYNAMIC_REDIRECT,
    6537             :         SETCAPS(MP4MuxCaps),
    6538             :         .configure_pid = mp4_mux_configure_pid,
    6539             :         .process = mp4_mux_process,
    6540             :         .process_event = mp4_mux_process_event
    6541             : };
    6542             : 
    6543             : 
    6544        2877 : const GF_FilterRegister *mp4_mux_register(GF_FilterSession *session)
    6545             : {
    6546        2877 :         return &MP4MuxRegister;
    6547             : }
    6548             : 
    6549             : #else
    6550             : const GF_FilterRegister *mp4_mux_register(GF_FilterSession *session)
    6551             : {
    6552             :         return NULL;
    6553             : }
    6554             : #endif // GPAC_DISABLE_ISOM_WRITE
    6555             : 

Generated by: LCOV version 1.13