LCOV - code coverage report
Current view: top level - home/travis/build/gpac/gpac/applications/mp4box - main.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 2322 2983 77.8 %
Date: 2021-04-29 23:48:07 Functions: 78 89 87.6 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / mp4box application
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : 
      27             : #include "mp4box.h"
      28             : 
      29             : #ifdef GPAC_DISABLE_ISOM
      30             : 
      31             : #error "Cannot compile MP4Box if GPAC is not built with ISO File Format support"
      32             : 
      33             : #else
      34             : 
      35             : #if defined(WIN32) && !defined(_WIN32_WCE)
      36             : #include <io.h>
      37             : #include <fcntl.h>
      38             : #endif
      39             : 
      40             : #include <gpac/media_tools.h>
      41             : #include <gpac/main.h>
      42             : 
      43             : /*RTP packetizer flags*/
      44             : #ifndef GPAC_DISABLE_STREAMING
      45             : #include <gpac/ietf.h>
      46             : #endif
      47             : 
      48             : #ifndef GPAC_DISABLE_CRYPTO
      49             : #include <gpac/crypt_tools.h>
      50             : #endif
      51             : 
      52             : #include <gpac/constants.h>
      53             : #include <gpac/filters.h>
      54             : 
      55             : #include <gpac/mpd.h>
      56             : 
      57             : #define BUFFSIZE        8192
      58             : #define DEFAULT_INTERLEAVING_IN_SEC 0.5
      59             : 
      60             : //undefine to check validity of defined args' syntax
      61             : //#define TEST_ARGS
      62             : 
      63             : 
      64             : int mp4boxTerminal(int argc, char **argv);
      65             : 
      66             : static u32 mp4box_cleanup(u32 ret_code);
      67             : 
      68             : /*
      69             :  *              START OF ARGUMENT VALUES DECLARATION
      70             :  */
      71             : 
      72             : 
      73             : 
      74             : typedef struct
      75             : {
      76             :         GF_ISOTrackID trackID;
      77             :         char *line;
      78             : } SDPLine;
      79             : 
      80             : typedef enum {
      81             :         META_ACTION_SET_TYPE                    = 0,
      82             :         META_ACTION_ADD_ITEM                    = 1,
      83             :         META_ACTION_REM_ITEM                    = 2,
      84             :         META_ACTION_SET_PRIMARY_ITEM    = 3,
      85             :         META_ACTION_SET_XML                             = 4,
      86             :         META_ACTION_SET_BINARY_XML              = 5,
      87             :         META_ACTION_REM_XML                             = 6,
      88             :         META_ACTION_DUMP_ITEM                   = 7,
      89             :         META_ACTION_DUMP_XML                    = 8,
      90             :         META_ACTION_ADD_IMAGE_ITEM              = 9,
      91             :         META_ACTION_ADD_IMAGE_GRID              = 10,
      92             : } MetaActionType;
      93             : 
      94             : typedef struct {
      95             :         u32 ref_item_id;
      96             :         u32 ref_type;
      97             : } MetaRef;
      98             : 
      99             : typedef struct
     100             : {
     101             :         MetaActionType act_type;
     102             :         Bool root_meta, use_dref;
     103             :         GF_ISOTrackID trackID;
     104             :         u32 meta_4cc;
     105             :         char *szPath, *szName, *mime_type, *enc_type;
     106             :         u32 item_id;
     107             :         Bool primary;
     108             :         u32 item_type;
     109             :         u32 ref_item_id;
     110             :         GF_List *item_refs;
     111             :         u32 group_id;
     112             :         u32 group_type;
     113             :         GF_ImageItemProperties *image_props;
     114             : } MetaAction;
     115             : 
     116             : 
     117             : typedef enum {
     118             :         TRAC_ACTION_REM_TRACK= 0,
     119             :         TRAC_ACTION_SET_LANGUAGE,
     120             :         TRAC_ACTION_SET_DELAY,
     121             :         TRAC_ACTION_SET_KMS_URI,
     122             :         TRAC_ACTION_SET_PAR,
     123             :         TRAC_ACTION_SET_HANDLER_NAME,
     124             :         TRAC_ACTION_ENABLE,
     125             :         TRAC_ACTION_DISABLE,
     126             :         TRAC_ACTION_REFERENCE,
     127             :         TRAC_ACTION_RAW_EXTRACT,
     128             :         TRAC_ACTION_REM_NON_RAP,
     129             :         TRAC_ACTION_SET_KIND,
     130             :         TRAC_ACTION_REM_KIND,
     131             :         TRAC_ACTION_SET_ID,
     132             :         TRAC_ACTION_SET_UDTA,
     133             :         TRAC_ACTION_SWAP_ID,
     134             :         TRAC_ACTION_REM_NON_REFS,
     135             :         TRAC_ACTION_SET_CLAP,
     136             :         TRAC_ACTION_SET_MX,
     137             :         TRAC_ACTION_SET_EDITS,
     138             :         TRAC_ACTION_SET_TIME,
     139             :         TRAC_ACTION_SET_MEDIA_TIME,
     140             : } TrackActionType;
     141             : 
     142             : typedef struct
     143             : {
     144             :         TrackActionType act_type;
     145             :         GF_ISOTrackID trackID;
     146             :         char lang[10];
     147             :         GF_Fraction delay;
     148             :         const char *kms;
     149             :         const char *hdl_name;
     150             :         s32 par_num, par_den;
     151             :         u8 force_par, rewrite_bs;
     152             :         u32 dump_type, sample_num;
     153             :         char *out_name;
     154             :         char *src_name;
     155             :         char *string;
     156             :         u32 udta_type;
     157             :         char *kind_scheme, *kind_value;
     158             :         u32 newTrackID;
     159             :         s32 clap_wnum, clap_wden, clap_hnum, clap_hden, clap_honum, clap_hoden, clap_vonum, clap_voden;
     160             :         s32 mx[9];
     161             :         u64 time;
     162             :         u8 dump_track_type;
     163             : } TrackAction;
     164             : 
     165             : enum
     166             : {
     167             :         GF_ISOM_CONV_TYPE_ISMA = 1,
     168             :         GF_ISOM_CONV_TYPE_ISMA_EX,
     169             :         GF_ISOM_CONV_TYPE_3GPP,
     170             :         GF_ISOM_CONV_TYPE_IPOD,
     171             :         GF_ISOM_CONV_TYPE_PSP,
     172             :         GF_ISOM_CONV_TYPE_MOV
     173             : };
     174             : 
     175             : typedef enum {
     176             :         TSEL_ACTION_SET_PARAM = 0,
     177             :         TSEL_ACTION_REMOVE_TSEL = 1,
     178             :         TSEL_ACTION_REMOVE_ALL_TSEL_IN_GROUP = 2,
     179             : } TSELActionType;
     180             : 
     181             : typedef struct
     182             : {
     183             :         TSELActionType act_type;
     184             :         GF_ISOTrackID trackID;
     185             : 
     186             :         GF_ISOTrackID refTrackID;
     187             :         u32 criteria[30];
     188             :         u32 nb_criteria;
     189             :         Bool is_switchGroup;
     190             :         u32 switchGroupID;
     191             : } TSELAction;
     192             : 
     193             : GF_FileType get_file_type_by_ext(char *inName);
     194             : 
     195             : 
     196             : char outfile[GF_MAX_PATH];
     197             : GF_SMEncodeOptions smenc_opts;
     198             : GF_Fraction import_fps;
     199             : 
     200             : //things to free upon cleanup
     201             : MetaAction *metas = NULL;
     202             : TrackAction *tracks = NULL;
     203             : TSELAction *tsel_acts = NULL;
     204             : SDPLine *sdp_lines = NULL;
     205             : u32 *brand_add = NULL;
     206             : u32 *brand_rem = NULL;
     207             : char **mpd_base_urls = NULL;
     208             : u32 nb_mpd_base_urls = 0;
     209             : GF_DashSegmenterInput *dash_inputs = NULL;
     210             : u32 nb_dash_inputs = 0;
     211             : 
     212             : 
     213             : 
     214             : //all other options values - keep options with assignment other than 0 on a single line
     215             : 
     216             : u32 swf_flags = GF_SM_SWF_SPLIT_TIMELINE;
     217             : 
     218             : FILE *helpout = NULL;
     219             : u32 help_flags = 0;
     220             : 
     221             : Double interleaving_time=0.0, split_duration=0.0, split_start=-1.0, dash_duration=0.0, dash_subduration=0.0, swf_flatten_angle=0.0;
     222             : Bool dash_duration_strict=0, dvbhdemux=0, keep_sys_tracks=0;
     223             : 
     224             : u64 initial_tfdt=0;
     225             : s32 subsegs_per_sidx=0, laser_resolution=0, ast_offset_ms=0;
     226             : const char *split_range_str = NULL;
     227             : GF_DashSwitchingMode bitstream_switching_mode = GF_DASH_BSMODE_DEFAULT;
     228             : u32 stat_level=0, hint_flags=0, info_track_id=0, import_flags=0, nb_add=0, nb_cat=0, crypt=0, agg_samples=0, nb_sdp_ex=0, max_ptime=0, split_size=0, nb_meta_act=0, nb_track_act=0, rtp_rate=0, major_brand=0, nb_alt_brand_add=0, nb_alt_brand_rem=0, old_interleave=0, minor_version=0, conv_type=0, nb_tsel_acts=0, program_number=0, dump_nal=0, time_shift_depth=0, initial_moof_sn=0, dump_std=0, import_subtitle=0, dump_saps=0, dump_saps_mode=0, force_new=0;
     229             : GF_DashDynamicMode dash_mode=GF_DASH_STATIC;
     230             : #ifndef GPAC_DISABLE_SCENE_DUMP
     231             : GF_SceneDumpFormat dump_mode=GF_SM_DUMP_NONE;
     232             : #endif
     233             : 
     234             : /*align cat is the new default behavior for -cat*/
     235             : Bool align_cat=GF_TRUE;
     236             : 
     237             : Double mpd_live_duration=0;
     238             : Bool do_hint=0, do_save=0, full_interleave=0, do_frag=0, hint_interleave=0, dump_rtp=0, regular_iod=0, remove_sys_tracks=0, remove_hint=0, remove_root_od=0;
     239             : Bool print_sdp=0, open_edit=0, dump_cr=0, force_ocr=0, encode=0, do_scene_log=0, dump_srt=0, dump_ttxt=0, do_saf=0, dump_m2ts=0, dump_cart=0;
     240             : Bool do_hash=0, verbose=0, force_cat=0, pack_wgt=0, single_group=0, clean_groups=0, dash_live=0, no_fragments_defaults=0;
     241             : Bool single_traf_per_moof=0, tfdt_per_traf=0, hls_clock=0, do_mpd_rip=0, merge_vtt_cues=0, get_nb_tracks=0;
     242             : u32 compress_moov=0;
     243             : char *inName=NULL, *outName=NULL, *mediaSource=NULL, *input_ctx=NULL, *output_ctx=NULL, *drm_file=NULL, *avi2raw=NULL, *cprt=NULL;
     244             : char *chap_file=NULL, *chap_file_qt=NULL, *itunes_tags=NULL, *pack_file=NULL, *raw_cat=NULL, *seg_name=NULL, *dash_ctx_file=NULL;
     245             : char *compress_top_boxes=NULL, *high_dynamc_range_filename=NULL, *use_init_seg=NULL, *box_patch_filename=NULL, *udp_dest = NULL;
     246             : 
     247             : GF_ISOTrackID trackID=0;
     248             : u32 track_dump_type=0, dump_isom=0, dump_timestamps=0, dump_nal_type=0, do_flat=0, box_patch_trackID=0, print_info=0;
     249             : Bool no_inplace=0, merge_last_seg=0, freeze_box_order=0, no_odf_conf=0;
     250             : Double min_buffer = 1.5;
     251             : u32 size_top_box=0, fs_dump_flags=0, dump_chap=0, dump_udta_type=0, dump_udta_track=0, moov_pading=0, sdtp_in_traf=0, segment_marker=0, timescale=0;
     252             : 
     253             : u32 dash_scale = 1000;
     254             : GF_ISOFile *file = NULL;
     255             : 
     256             : Bool insert_utc=0, chunk_mode=0, HintCopy=0, hint_no_offset=0, do_bin_xml=0, frag_real_time=0, force_co64=0, live_scene=0, use_mfra=0;
     257             : Bool dump_iod=0, samplegroups_in_traf=0, mvex_after_traks=0, daisy_chain_sidx=0, use_ssix=0, single_segment=0, single_file=0, segment_timeline=0;
     258             : Bool has_add_image=0;
     259             : 
     260             : char *do_mpd_conv=NULL;
     261             : u32 MTUSize = 1450;
     262             : char *dash_start_date=NULL;
     263             : GF_DASH_ContentLocationMode cp_location_mode = GF_DASH_CPMODE_ADAPTATION_SET;
     264             : Double mpd_update_time = 0.0;
     265             : GF_MemTrackerType mem_track = GF_MemTrackerNone;
     266             : GF_DASHPSSHMode pssh_mode=0;
     267             : 
     268             : GF_DashProfile dash_profile=GF_DASH_PROFILE_AUTO;
     269             : char *dash_profile_extension = NULL;
     270             : char *dash_cues = NULL;
     271             : Bool strict_cues=0, use_url_template=0, seg_at_rap=0, frag_at_rap=0, memory_frags=0, keep_utc=0, has_next_arg=0, no_cache=0, no_loop=0;
     272             : u32 adjust_split_end=0;
     273             : char *do_wget = NULL;
     274             : char *mux_name = NULL;
     275             : char *seg_ext = NULL;
     276             : char *init_seg_ext = NULL;
     277             : char *dash_title = NULL;
     278             : char *dash_source = NULL;
     279             : char *dash_more_info = NULL;
     280             : 
     281             : FILE *logfile = NULL;
     282             : u32 run_for=0, dash_cumulated_time=0, dash_prev_time=0, dash_now_time=0;
     283             : GF_DASH_SplitMode dash_split_mode = GF_DASH_SPLIT_OUT;
     284             : 
     285             : 
     286             : typedef u32 (*parse_arg_fun)(char *arg_val, u32 param);
     287             : typedef u32 (*parse_arg_fun2)(char *arg_name, char *arg_val, u32 param);
     288             : 
     289             : //other custom option parsing functions definitions are in mp4box.h
     290             : static u32 parse_meta_args(char *opts, MetaActionType act_type);
     291             : static Bool parse_tsel_args(char *opts, TSELActionType act);
     292             : 
     293             : 
     294             : 
     295             : /*
     296             :  *              START OF ARGS PARSING AND HELP
     297             :  */
     298             : 
     299             : 
     300           2 : Bool print_version(char *arg_val, u32 param)
     301             : {
     302           2 :         fprintf(stderr, "MP4Box - GPAC version %s\n"
     303             :                 "%s\n"
     304             :                 "GPAC Configuration: " GPAC_CONFIGURATION "\n"
     305             :                 "Features: %s %s\n", gf_gpac_version(), gf_gpac_copyright_cite(), gf_sys_features(GF_FALSE), gf_sys_features(GF_TRUE));
     306           2 :         return GF_TRUE;
     307             : }
     308             : 
     309             : //arg will toggle open_edit
     310             : #define ARG_OPEN_EDIT           1
     311             : //arg will toggle do_save
     312             : #define ARG_NEED_SAVE           1<<1
     313             : #define ARG_NO_INPLACE          1<<2
     314             : #define ARG_BIT_MASK            1<<3
     315             : #define ARG_BIT_MASK_REM        1<<4
     316             : #define ARG_HAS_VALUE           1<<5
     317             : #define ARG_DIV_1000            1<<6
     318             : #define ARG_NON_ZERO            1<<7
     319             : #define ARG_64BITS                      1<<8
     320             : #define ARG_IS_4CC                      1<<9
     321             : #define ARG_BOOL_REV            1<<10
     322             : #define ARG_INT_INC                     1<<11
     323             : #define ARG_IS_FUN                      1<<12
     324             : #define ARG_EMPTY                       1<<13
     325             : #define ARG_PUSH_SYSARGS        1<<14
     326             : #define ARG_IS_FUN2                     1<<15
     327             : 
     328             : 
     329             : 
     330             : typedef struct
     331             : {
     332             :         GF_GPAC_ARG_BASE
     333             : 
     334             :         void *arg_ptr;
     335             :         u32 argv_val;
     336             :         u16 parse_flags;
     337             : } MP4BoxArg;
     338             : 
     339             : #define MP4BOX_ARG(_a, _c, _f, _g, _h, _i, _j) {_a, NULL, _c, NULL, NULL, _f, _g, _h, _i, _j}
     340             : #define MP4BOX_ARG_ALT(_a, _b, _c, _f, _g, _h, _i, _j) {_a, _b, _c, NULL, NULL, _f, _g, _h, _i, _j}
     341             : #define MP4BOX_ARG_S(_a, _s, _c, _g, _h, _i, _j) {_a, NULL, _c, _s, NULL, GF_ARG_CUSTOM, _g, _h, _i, _j}
     342             : #define MP4BOX_ARG_S_ALT(_a, _b, _s, _c, _g, _h, _i, _j) {_a, _b, _c, _s, NULL, GF_ARG_CUSTOM, _g, _h, _i, _j}
     343             : 
     344             : 
     345             : MP4BoxArg m4b_gen_args[] =
     346             : {
     347             : #ifdef GPAC_MEMORY_TRACKING
     348             :         MP4BOX_ARG("mem-track", "enable memory tracker", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, NULL, 0, 0),
     349             :         MP4BOX_ARG("mem-track-stack", "enable memory tracker with stack dumping", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, NULL, 0, 0),
     350             : #endif
     351             :         MP4BOX_ARG("p", "use indicated profile for the global GPAC config. If not found, config file is created. If a file path is indicated, this will load profile from that file. Otherwise, this will create a directory of the specified name and store new config there. Reserved name `0` means a new profile, not stored to disk. Works using -p=NAME or -p NAME", GF_ARG_STRING, GF_ARG_HINT_EXPERT, NULL, 0, 0),
     352             :         {"inter", NULL, "interleave file, producing track chunks with given duration in ms. A value of 0 disables interleaving ", "0.5", NULL, GF_ARG_DOUBLE, 0, parse_store_mode, 0, ARG_IS_FUN},
     353             :         MP4BOX_ARG("old-inter", "same as [-inter]() but without drift correction", GF_ARG_DOUBLE, GF_ARG_HINT_EXPERT, parse_store_mode, 1, ARG_IS_FUN),
     354             :         MP4BOX_ARG("tight", "tight interleaving (sample based) of the file. This reduces disk seek operations but increases file size", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &full_interleave, 0, ARG_OPEN_EDIT|ARG_NEED_SAVE),
     355             :         MP4BOX_ARG("flat", "store file with all media data first, non-interleaved. This speeds up writing time when creating new files", GF_ARG_BOOL, 0, &do_flat, 0, ARG_OPEN_EDIT| ARG_NO_INPLACE),
     356             :         MP4BOX_ARG("frag", "fragment file, producing track fragments of given duration in ms. This disables interleaving", GF_ARG_DOUBLE, 0, parse_store_mode, 2, ARG_IS_FUN),
     357             :         MP4BOX_ARG("out", "specify ISOBMFF output file name. By default input file is overwritten", GF_ARG_STRING, 0, &outName, 0, 0),
     358             :         MP4BOX_ARG("co64","force usage of 64-bit chunk offsets for ISOBMF files", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, &force_co64, 0, ARG_OPEN_EDIT),
     359             :         MP4BOX_ARG("new", "force creation of a new destination file", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, &force_new, 0, 0),
     360             :         MP4BOX_ARG("newfs", "force creation of a new destination file without temp file but interleaving support", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, parse_store_mode, 3, ARG_IS_FUN),
     361             :         MP4BOX_ARG_ALT("no-sys", "nosys", "remove all MPEG-4 Systems info except IOD, kept for profiles. This is the default when creating regular AV content", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, &remove_sys_tracks, 0, ARG_OPEN_EDIT),
     362             :         MP4BOX_ARG("no-iod", "remove MPEG-4 InitialObjectDescriptor from file", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &remove_root_od, 0, ARG_OPEN_EDIT),
     363             :         MP4BOX_ARG("mfra", "insert movie fragment random offset when fragmenting file (ignored in dash mode)", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, &use_mfra, 0, 0),
     364             :         MP4BOX_ARG("isma", "rewrite the file as an ISMA 1.0 file", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &conv_type, GF_ISOM_CONV_TYPE_ISMA, ARG_OPEN_EDIT),
     365             :         MP4BOX_ARG("ismax", "same as [-isma]() and remove all clock references", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &conv_type, GF_ISOM_CONV_TYPE_ISMA_EX, ARG_OPEN_EDIT),
     366             :         MP4BOX_ARG("3gp", "rewrite as 3GPP(2) file (no more MPEG-4 Systems Info), always enabled if destination file extension is `.3gp`, `.3g2` or `.3gpp`. Some tracks may be removed in the process", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &conv_type, GF_ISOM_CONV_TYPE_3GPP, ARG_OPEN_EDIT),
     367             :         MP4BOX_ARG("ipod", "rewrite the file for iPod/old iTunes", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &conv_type, GF_ISOM_CONV_TYPE_IPOD, ARG_OPEN_EDIT),
     368             :         MP4BOX_ARG("psp", "rewrite the file for PSP devices", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &conv_type, GF_ISOM_CONV_TYPE_PSP, ARG_OPEN_EDIT),
     369             :         MP4BOX_ARG("brand", "set major brand of file (`ABCD`) or brand with optional version (`ABCD:v`)", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, parse_brand, 0, ARG_IS_FUN),
     370             :         MP4BOX_ARG("ab", "add given brand to file's alternate brand list", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, parse_brand, 1, ARG_IS_FUN),
     371             :         MP4BOX_ARG("rb", "remove given brand to file's alternate brand list", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, parse_brand, 2, ARG_IS_FUN),
     372             :         MP4BOX_ARG("cprt", "add copyright string to file", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, &cprt, 0, 0),
     373             :         MP4BOX_ARG("chap", "set chapter information from given file. The following formats are supported (but cannot be mixed) in the chapter text file:\n"
     374             :                 "  - ZoomPlayer: `AddChapter(nb_frames,chapter name)`, `AddChapterBySeconds(nb_sec,chapter name)` and `AddChapterByTime(h,m,s,chapter name)` with 1 chapter per line\n"
     375             :                 "  - Time codes: `h:m:s chapter_name`, `h:m:s:ms chapter_name` and `h:m:s.ms chapter_name` with 1 chapter per line\n"
     376             :                 "  - SMPTE codes: `h:m:s;nb_f/fps chapter_name` and `h:m:s;nb_f chapter_name` with `nb_f` the number of frames and `fps` the framerate with 1 chapter per line\n"
     377             :                 "  - Common syntax: `CHAPTERX=h:m:s[:ms or .ms]` on first line and `CHAPTERXNAME=name` on next line (reverse order accepted)", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, &chap_file, 0, ARG_OPEN_EDIT),
     378             :         MP4BOX_ARG("chapqt", "set chapter information from given file, using QT signaling for text tracks", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, &chap_file_qt, 0, ARG_OPEN_EDIT),
     379             :         MP4BOX_ARG_S("set-track-id", "id1:id2", "change id of track with id1 to id2", 0, parse_track_action, TRAC_ACTION_SET_ID, ARG_IS_FUN),
     380             :         MP4BOX_ARG_S("swap-track-id", "id1:id2", "swap the id between tracks with id1 to id2", 0, parse_track_action, TRAC_ACTION_SWAP_ID, ARG_IS_FUN),
     381             :         MP4BOX_ARG("rem", "remove given track from file", GF_ARG_INT, 0, parse_track_action, TRAC_ACTION_REM_TRACK, ARG_IS_FUN),
     382             :         MP4BOX_ARG("rap", "remove all non-RAP samples from given track", GF_ARG_INT, GF_ARG_HINT_ADVANCED, parse_rap_ref, 0, ARG_IS_FUN | ARG_EMPTY),
     383             :         MP4BOX_ARG("refonly", "remove all non-reference pictures from given track", GF_ARG_INT, GF_ARG_HINT_ADVANCED, parse_rap_ref, 1, ARG_IS_FUN | ARG_EMPTY),
     384             :         MP4BOX_ARG("enable", "enable given track", GF_ARG_INT, 0, parse_track_action, TRAC_ACTION_ENABLE, ARG_IS_FUN),
     385             :         MP4BOX_ARG("disable", "disable given track", GF_ARG_INT, 0, parse_track_action, TRAC_ACTION_DISABLE, ARG_IS_FUN),
     386             :         {"timescale", NULL, "set movie timescale to given value (ticks per second)", "600", NULL, GF_ARG_INT, 0, &timescale, 0, ARG_OPEN_EDIT},
     387             :         MP4BOX_ARG_S("lang", "[tkID=]LAN", "set language. LAN is the BCP-47 code (eng, en-UK, ...). If no track ID is given, sets language to all tracks", 0, parse_track_action, TRAC_ACTION_SET_LANGUAGE, ARG_IS_FUN),
     388             :         MP4BOX_ARG_S("delay", "tkID=TIME", "set track start delay (>0) or initial skip (<0) in ms or in fractional seconds (`N/D`)", 0, parse_track_action, TRAC_ACTION_SET_DELAY, ARG_IS_FUN),
     389             :         MP4BOX_ARG_S("par", "tkID=PAR", "set visual track pixel aspect ratio. PAR is:\n"
     390             :                                         "  - N:D: set PAR to N:D in track, do not modify the bitstream\n"
     391             :                                         "  - wN:D: set PAR to N:D in track and try to modify the bitstream\n"
     392             :                                         "  - none: remove PAR info from track, do not modify the bitstream\n"
     393             :                                         "  - auto: retrieve PAR info from bitstream and set it in track\n"
     394             :                                         "  - force: force 1:1 PAR in track, do not modify the bitstream", GF_ARG_HINT_ADVANCED, parse_track_action, TRAC_ACTION_SET_PAR, ARG_IS_FUN
     395             :                                         ),
     396             :         MP4BOX_ARG_S("clap", "tkID=CLAP", "set visual track clean aperture. CLAP is `Wn,Wd,Hn,Hd,HOn,HOd,VOn,VOd` or `none`\n"
     397             :                         "- n, d: numerator, denominator\n"
     398             :                 "- W, H, HO, VO: clap width, clap height, clap horizontal offset, clap vertical offset\n"
     399             :                         , GF_ARG_HINT_ADVANCED, parse_track_action, TRAC_ACTION_SET_CLAP, ARG_IS_FUN),
     400             :         MP4BOX_ARG_S("mx", "tkID=MX", "set track matrix, with MX is M1:M2:M3:M4:M5:M6:M7:M8:M9 in 16.16 fixed point intergers or hexa"
     401             :                         , GF_ARG_HINT_ADVANCED, parse_track_action, TRAC_ACTION_SET_MX, ARG_IS_FUN),
     402             :         MP4BOX_ARG_S("kind", "tkID=schemeURI=value", "set kind for the track or for all tracks using `all=schemeURI=value`", 0, parse_track_action, TRAC_ACTION_SET_KIND, ARG_IS_FUN),
     403             :         MP4BOX_ARG_S("kind-rem", "tkID=schemeURI=value", "remove kind if given schemeID for the track or for all tracks with `all=schemeURI=value`", 0, parse_track_action, TRAC_ACTION_REM_KIND, ARG_IS_FUN),
     404             :         MP4BOX_ARG_S("name", "tkID=NAME", "set track handler name to NAME (UTF-8 string)", GF_ARG_HINT_ADVANCED, parse_track_action, TRAC_ACTION_SET_HANDLER_NAME, ARG_IS_FUN),
     405             :         MP4BOX_ARG("itags", "set iTunes tags to file, see `-h tags`", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, &itunes_tags, 0, ARG_OPEN_EDIT),
     406             :         MP4BOX_ARG("group-add", "create a new grouping information in the file. Format is a colon-separated list of following options:\n"
     407             :                 "- refTrack=ID: ID of the track used as a group reference. If not set, the track will belong to the same group as the "
     408             :                 "previous trackID specified. If 0 or no previous track specified, a new alternate group will be created\n"
     409             :                 "- switchID=ID: ID of the switch group to create. If 0, a new ID will be computed for you. If <0, disables SwitchGroup\n"
     410             :                 "- criteria=string: list of space-separated 4CCs\n"
     411             :                 "- trackID=ID: ID of the track to add to this group\n"
     412             :                 "  \n"
     413             :                 "Warning: Options modify state as they are parsed, `trackID=1:criteria=lang:trackID=2` is different from `criteria=lang:trackID=1:trackID=2`"
     414             :                 "\n", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, parse_tsel_args, TSEL_ACTION_SET_PARAM, ARG_IS_FUN),
     415             : 
     416             :         MP4BOX_ARG("group-rem-track", "remove given track from its group", GF_ARG_INT, GF_ARG_HINT_ADVANCED, parse_tsel_args, TSEL_ACTION_REMOVE_TSEL, ARG_IS_FUN),
     417             :         MP4BOX_ARG("group-rem", "remove the track's group", GF_ARG_INT, GF_ARG_HINT_ADVANCED, parse_tsel_args, TSEL_ACTION_REMOVE_ALL_TSEL_IN_GROUP, ARG_IS_FUN),
     418             :         MP4BOX_ARG("group-clean", "remove all group information from all tracks", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, &clean_groups, 0, ARG_OPEN_EDIT),
     419             :         MP4BOX_ARG_S("ref", "id:XXXX:refID", "add a reference of type 4CC from track ID to track refID", GF_ARG_HINT_ADVANCED, parse_track_action, TRAC_ACTION_REFERENCE, ARG_IS_FUN),
     420             :         MP4BOX_ARG("keep-utc", "keep UTC timing in the file after edit", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, &keep_utc, 0, 0),
     421             :         MP4BOX_ARG_S("udta", "tkID:[OPTS]", "set udta for given track or movie if tkID is 0. OPTS is a colon separated list of:\n"
     422             :                 "- type=CODE: 4CC code of the UDTA (not needed for `box=` option)\n"
     423             :                 "- box=FILE: location of the udta data, formatted as serialized boxes\n"
     424             :                 "- box=base64,DATA: base64 encoded udta data, formatted as serialized boxes\n"
     425             :                 "- src=FILE: location of the udta data (will be stored in a single box of type CODE)\n"
     426             :                 "- src=base64,DATA: base64 encoded udta data (will be stored in a single box of type CODE)\n"
     427             :                 "- str=STRING: use the given string as payload for the udta box\n"
     428             :                 "Note: If no source is set, UDTA of type CODE will be removed\n", GF_ARG_HINT_ADVANCED, parse_track_action, TRAC_ACTION_SET_UDTA, ARG_IS_FUN|ARG_OPEN_EDIT),
     429             :         MP4BOX_ARG_S("patch", "[tkID=]FILE", "apply box patch described in FILE, for given trackID if set", GF_ARG_HINT_ADVANCED, parse_boxpatch, 0, ARG_IS_FUN),
     430             :         MP4BOX_ARG("bo", "freeze the order of boxes in input file", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, &freeze_box_order, 0, 0),
     431             :         MP4BOX_ARG("init-seg", "use the given file as an init segment for dumping or for encryption", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, &use_init_seg, 0, 0),
     432             :         MP4BOX_ARG("zmov", "compress movie box according to ISOBMFF box compression", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, parse_compress, 0, ARG_IS_FUN),
     433             :         MP4BOX_ARG("xmov", "same as zmov and wraps ftyp in otyp", GF_ARG_BOOL, GF_ARG_HINT_ADVANCED, parse_compress, 1, ARG_IS_FUN),
     434             :         MP4BOX_ARG_S("edits", "tkID=EDITS", "set edit list. The following syntax is used (no separators between entries):\n"
     435             :                         " - `r`: removes all edits\n"
     436             :                         " - `eSTART`: add empty edit with given start time. START can be\n"
     437             :                         "   - `VAL`: start time in seconds (int, double, fraction), media duration used as edit duration\n"
     438             :                         "   - `VAL-DUR`: start time and duration in seconds (int, double, fraction)\n"
     439             :                         " - `eSTART,MEDIA[,RATE]`: add regular edit with given start, media start time in seconds (int, double, fraction) and rate (fraction or INT)\n"
     440             :                         " - Examples: \n"
     441             :                         "   - `re0-5e5-3,4`: remove edits, add empty edit at 0s for 5s, then add regular edit at 5s for 3s starting at 4s in media track\n"
     442             :                         "   - `re0-4,0,0.5`: remove edits, add single edit at 0s for 4s starting at 0s in media track and playing at speed 0.5\n"
     443             :                                 , 0, parse_track_action, TRAC_ACTION_SET_EDITS, ARG_IS_FUN),
     444             :         MP4BOX_ARG("moovpad", "specify amount of padding to keep after moov box for later inplace editing - if 0, moov padding is disabled", GF_ARG_INT, GF_ARG_HINT_EXPERT, &moov_pading, 0, ARG_NEED_SAVE),
     445             :         MP4BOX_ARG("no-inplace", "disable inplace rewrite", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &no_inplace, 0, 0),
     446             :         MP4BOX_ARG("hdr", "update HDR information based on given XML", GF_ARG_STRING, GF_ARG_HINT_EXPERT, &high_dynamc_range_filename, 0, ARG_OPEN_EDIT),
     447             :         MP4BOX_ARG_S("time", "[tkID=]DAY/MONTH/YEAR-H:M:S", "set movie or track creation time", GF_ARG_HINT_EXPERT, parse_track_action, TRAC_ACTION_SET_TIME, ARG_IS_FUN),
     448             :         MP4BOX_ARG_S("mtime", "tkID=DAY/MONTH/YEAR-H:M:S", "set media creation time", GF_ARG_HINT_EXPERT, parse_track_action, TRAC_ACTION_SET_MEDIA_TIME, ARG_IS_FUN),
     449             :         {0}
     450             : };
     451             : 
     452           4 : void PrintGeneralUsage()
     453             : {
     454             :         u32 i=0;
     455           4 :         gf_sys_format_help(helpout, help_flags, "# General Options\n"
     456             :                 "MP4Box is a multimedia packager, with a vast number of functionalities: conversion, splitting, hinting, dumping, DASH-ing, encryption, transcoding and others.\n"
     457             :                 "MP4Box provides a large set of options, classified by categories (see [-h]()). These options do not follow any particular ordering.\n"
     458             :                 "MP4Box performs in-place rewrite of IsoMedia files (the input file is overwritten). You can change this behavior by using the [-out]() option.\n"
     459             :                 "MP4Box stores by default the file with 0.5 second interleaving and meta-data (`moov` ...) at the beginning, making it suitable for HTTP streaming. This may however takes longer to store the file, use [-flat]() to change this behavior.\n"
     460             :                 "MP4Box usually generates a temporary file when creating a new IsoMedia file. The location of this temporary file is OS-dependent, and it may happen that the drive/partition the temporary file is created on has not enough space or no write access. In such a case, you can specify a temporary file location with [-tmp]().\n"
     461             :                 "Note: Track operations identify tracks through their ID (usually referred to as tkID in the help), not their order.\n"
     462             :                 "Option values:\n"
     463             :                 "Unless specified otherwise, an option of type `integer` expects a trackID value following it."
     464             :                 "An option of type `boolean` expects no following value."
     465             :                 "  \n"
     466             :         );
     467             : 
     468             : 
     469         252 :         while (m4b_gen_args[i].name) {
     470         244 :                 GF_GPACArg *arg = (GF_GPACArg *) &m4b_gen_args[i];
     471         244 :                 i++;
     472         244 :                 gf_sys_print_arg(helpout, help_flags, arg, "mp4box-gen");
     473             :         }
     474           4 : }
     475             : 
     476             : 
     477             : MP4BoxArg m4b_split_args[] =
     478             : {
     479             :         MP4BOX_ARG("split", "split in files of given max duration", GF_ARG_STRING, 0, parse_split, 0, ARG_IS_FUN),
     480             :         MP4BOX_ARG_ALT("split-rap", "splitr", "split in files at each new RAP", GF_ARG_STRING, 0, parse_split, 1, ARG_IS_FUN),
     481             :         MP4BOX_ARG_ALT("split-size", "splits", "split in files of given max size (in kb)", GF_ARG_STRING, 0, parse_split, 2, ARG_IS_FUN),
     482             :         MP4BOX_ARG_ALT("split-chunk", "splitx", "extract the specified time range formatted as:\n"
     483             :         "- `S:E` or `S-E`: `S` start time and `E` end time in seconds (int, double, fraction)\n"
     484             :         "- `S:end` or `S:end-N`: `S` start time in seconds (int, double), `N` number of seconds (int, double) before the end\n"
     485             :         "- `S-E`: start and end dates, each formatted as `HH:MM:SS.ms` or `MM:SS.ms`", GF_ARG_STRING, 0, parse_split, 3, ARG_IS_FUN),
     486             :         MP4BOX_ARG("splitz", "same as -splitx, but adjust range times so that ranges `A:B` and `B:C` share exactly the same boundary `B`:\n"
     487             :         "- the start time is moved to the RAP sample at or after the specified start time\n"
     488             :         "- the end time is moved to the frame preceeding the RAP sample at or following the specified end time"
     489             :         , GF_ARG_STRING, 0, parse_split, 4, ARG_IS_FUN),
     490             :         MP4BOX_ARG("splitg", "same as -splitx, but adjust range times so that:\n"
     491             :         "- the start time is moved to the RAP sample at or before the specified start time\n"
     492             :         "- the end time is moved to the frame preceeding the RAP sample at or following the specified end time"
     493             :         , GF_ARG_STRING, 0, parse_split, 5, ARG_IS_FUN),
     494             :         MP4BOX_ARG("splitf", "same as -splitx but insert edits such that the extracted output is exactly the specified range\n", GF_ARG_STRING, 0, parse_split, 6, ARG_IS_FUN),
     495             :         {0}
     496             : };
     497             : 
     498             : 
     499           3 : static void PrintSplitUsage()
     500             : {
     501             :         u32 i=0;
     502           3 :         gf_sys_format_help(helpout, help_flags, "  \n"
     503             :                 "# File splitting\n"
     504             :                 "MP4Box can split input files by size, duration or extract a given part of the file to new IsoMedia file(s).\n"
     505             :                 "This requires that at most one track in the input file has non random-access points (typically one video track at most).\n"
     506             :                 "Splitting will ignore all MPEG-4 Systems tracks and hint tracks, but will try to split private media tracks.\n"
     507             :                 "The input file must have enough random access points in order to be split. If this is not the case, you will have to re-encode the content.\n"
     508             :                 "You can add media to a file and split it in the same pass. In this case, the destination file (the one which would be obtained without splitting) will not be stored.\n"
     509             :                 "  \n"
     510             :                 "MP4Box splitting runs a filter session using the `reframer` filter as follows:\n"
     511             :                 "- `splitrange` option of the reframer is always set\n"
     512             :                 "- source is demuxed with `alltk` option set\n"
     513             :                 "- start and end ranges are passed to `xs` and `xe` options of the reframer\n"
     514             :                 "- for `-splitz`, options `xadjust` and `xround=after` are enforced\n"
     515             :                 "- for `-splitg`, options `xadjust` and `xround=before` are enforced\n"
     516             :                 "- for `-splitf`, option `xround=seek` is enforced and `propbe_ref`set if not specified at prompt\n"
     517             :                 "- for `-splitx`, option `xround=closest` and `propbe_ref` are enforced if not specified at prompt\n"
     518             :                 "  \n"
     519             :         );
     520             : 
     521             :         i=0;
     522          27 :         while (m4b_split_args[i].name) {
     523          21 :                 GF_GPACArg *arg = (GF_GPACArg *) &m4b_split_args[i];
     524          21 :                 i++;
     525          21 :                 gf_sys_print_arg(helpout, help_flags, arg, "mp4box-split");
     526             :         }
     527             : 
     528           3 : }
     529             : 
     530             : 
     531             : MP4BoxArg m4b_dash_args[] =
     532             : {
     533             :         MP4BOX_ARG ("dash", "create DASH from input files with given segment (subsegment for onDemand profile) duration in ms", GF_ARG_DOUBLE, 0, &dash_duration, 0, ARG_NON_ZERO),
     534             :         MP4BOX_ARG("dash-live", "generate a live DASH session using the given segment duration in ms; using `-dash-live=F` will also write the live context to `F`. MP4Box will run the live session until `q` is pressed or a fatal error occurs", GF_ARG_DOUBLE, 0, parse_dashlive, 0, ARG_IS_FUN2),
     535             :         MP4BOX_ARG("ddbg-live", "same as [-dash-live]() without time regulation for debug purposes", GF_ARG_DOUBLE, 0, parse_dashlive, 1, ARG_IS_FUN2),
     536             :         MP4BOX_ARG("frag", "specify the fragment duration in ms. If not set, this is the DASH duration (one fragment per segment)", GF_ARG_DOUBLE, 0, parse_store_mode, 2, ARG_IS_FUN),
     537             :         MP4BOX_ARG("out", "specify the output MPD file name", GF_ARG_STRING, 0, &outName, 0, 0),
     538             :         MP4BOX_ARG_ALT("profile", "dash-profile", "specify the target DASH profile, and set default options to ensure conformance to the desired profile. Default profile is `full` in static mode, `live` in dynamic mode (old syntax using `:live` instead of `.live` as separator still possible). Defined values are onDemand, live, main, simple, full, hbbtv1.5.live, dashavc264.live, dashavc264.onDemand, dashif.ll", GF_ARG_STRING, 0, parse_dash_profile, 0, ARG_IS_FUN),
     539             :         MP4BOX_ARG("profile-ext", "specify a list of profile extensions, as used by DASH-IF and DVB. The string will be colon-concatenated with the profile used", GF_ARG_STRING, 0, &dash_profile_extension, 0, 0),
     540             :         MP4BOX_ARG("rap", "ensure that segments begin with random access points, segment durations might vary depending on the source encoding", GF_ARG_BOOL, 0, parse_rap_ref, 0, ARG_IS_FUN | ARG_EMPTY),
     541             :         MP4BOX_ARG("frag-rap", "ensure that all fragments begin with random access points (duration might vary depending on the source encoding)", GF_ARG_BOOL, 0, &frag_at_rap, 0, 0),
     542             :         MP4BOX_ARG("segment-name", "set the segment name for generated segments. If not set (default), segments are concatenated in output file except in `live` profile where `dash_%%s`. Supported replacement strings are:\n"
     543             :                 "- $Number[%%0Nd]$ is replaced by the segment number, possibly prefixed with 0\n"
     544             :                 "- $RepresentationID$ is replaced by representation name\n"
     545             :                 "- $Time$ is replaced by segment start time\n"
     546             :                 "- $Bandwidth$ is replaced by representation bandwidth\n"
     547             :                 "- $Init=NAME$ is replaced by NAME for init segment, ignored otherwise\n"
     548             :                 "- $Index=NAME$ is replaced by NAME for index segments, ignored otherwise\n"
     549             :                 "- $Path=PATH$ is replaced by PATH when creating segments, ignored otherwise\n"
     550             :                 "- $Segment=NAME$ is replaced by NAME for media segments, ignored for init segments", GF_ARG_STRING, 0, &seg_name, 0, 0),
     551             :         {"segment-ext", NULL, "set the segment extension, `null` means no extension", "m4s", NULL, GF_ARG_STRING, 0, &seg_ext, 0, 0},
     552             :         {"init-segment-ext", NULL, "set the segment extension for init, index and bitstream switching segments, `null` means no extension\n", "mp4", NULL, GF_ARG_STRING, 0, &init_seg_ext, 0, 0},
     553             :         MP4BOX_ARG("segment-timeline", "use `SegmentTimeline` when generating segments", GF_ARG_BOOL, 0, &segment_timeline, 0, 0),
     554             :         MP4BOX_ARG("segment-marker", "add a box of given type (4CC) at the end of each DASH segment", GF_ARG_STRING, 0, &segment_marker, 0, ARG_IS_4CC),
     555             :         MP4BOX_ARG("insert-utc", "insert UTC clock at the beginning of each ISOBMF segment", GF_ARG_BOOL, 0, &insert_utc, 0, 0),
     556             :         MP4BOX_ARG("base-url", "set Base url at MPD level. Can be used several times.  \nWarning: this does not  modify generated files location", GF_ARG_STRING, 0, parse_base_url, 0, ARG_IS_FUN),
     557             :         MP4BOX_ARG("mpd-title", "set MPD title", GF_ARG_STRING, 0, &dash_title, 0, 0),
     558             :         MP4BOX_ARG("mpd-source", "set MPD source", GF_ARG_STRING, 0, &dash_source, 0, 0),
     559             :         MP4BOX_ARG("mpd-info-url", "set MPD info url", GF_ARG_STRING, 0, &dash_more_info, 0, 0),
     560             :         MP4BOX_ARG("cprt", "add copyright string to MPD", GF_ARG_STRING, GF_ARG_HINT_ADVANCED, &cprt, 0, 0),
     561             :         MP4BOX_ARG("dash-ctx", "store/restore DASH timing from indicated file", GF_ARG_STRING, 0, &dash_ctx_file, 0, 0),
     562             :         MP4BOX_ARG("dynamic", "use dynamic MPD type instead of static", GF_ARG_BOOL, 0, &dash_mode, GF_DASH_DYNAMIC, 0),
     563             :         MP4BOX_ARG("last-dynamic", "same as [-dynamic]() but close the period (insert lmsg brand if needed and update duration)", GF_ARG_BOOL, 0, &dash_mode, GF_DASH_DYNAMIC_LAST, 0),
     564             :         MP4BOX_ARG("mpd-duration", "set the duration in second of a live session (if `0`, you must use [-mpd-refresh]())", GF_ARG_DOUBLE, 0, &mpd_live_duration, 0, 0),
     565             :         MP4BOX_ARG("mpd-refresh", "specify MPD update time in seconds", GF_ARG_DOUBLE, 0, &mpd_update_time, 0, 0),
     566             :         MP4BOX_ARG("time-shift", "specify MPD time shift buffer depth in seconds, `-1` to keep all files)", GF_ARG_INT, 0, &time_shift_depth, 0, 0),
     567             :         MP4BOX_ARG("subdur", "specify maximum duration in ms of the input file to be dashed in LIVE or context mode. This does not change the segment duration, but stops dashing once segments produced exceeded the duration. If there is not enough samples to finish a segment, data is looped unless [-no-loop]() is used which triggers a period end", GF_ARG_DOUBLE, 0, &dash_subduration, 0, 0),
     568             :         MP4BOX_ARG("run-for", "run for given ms  the dash-live session then exits", GF_ARG_INT, 0, &run_for, 0, 0),
     569             :         MP4BOX_ARG("min-buffer", "specify MPD min buffer time in ms", GF_ARG_INT, 0, &min_buffer, 0, ARG_DIV_1000),
     570             :         MP4BOX_ARG("ast-offset", "specify MPD AvailabilityStartTime offset in ms if positive, or availabilityTimeOffset of each representation if negative", GF_ARG_INT, 0, &ast_offset_ms, 0, 0),
     571             :         MP4BOX_ARG("dash-scale", "specify that timing for [-dash](),  [-dash-live](), [-subdur]() and [-do_frag]() are expressed in given timescale (units per seconds) rather than ms", GF_ARG_INT, 0, &dash_scale, 0, ARG_NON_ZERO),
     572             :         MP4BOX_ARG("mem-frags", "fragmentation happens in memory rather than on disk before flushing to disk", GF_ARG_BOOL, 0, &memory_frags, 0, 0),
     573             :         MP4BOX_ARG("pssh", "set pssh store mode\n"
     574             :         "- v: initial movie\n"
     575             :         "- f: movie fragments\n"
     576             :         "- m: MPD\n"
     577             :         "- mv, vm: in initial movie and MPD\n"
     578             :         "- mf, fm: in movie fragments and MPD", GF_ARG_INT, 0, parse_pssh, 0, ARG_IS_FUN),
     579             :         MP4BOX_ARG("sample-groups-traf", "store sample group descriptions in traf (duplicated for each traf). If not set, sample group descriptions are stored in the initial movie", GF_ARG_BOOL, 0, &samplegroups_in_traf, 0, 0),
     580             :         MP4BOX_ARG("mvex-after-traks", "store `mvex` box after `trak` boxes within the moov box. If not set, `mvex` is before", GF_ARG_BOOL, 0, &mvex_after_traks, 0, 0),
     581             :         MP4BOX_ARG("sdtp-traf", "use `sdtp` box in `traf` (Smooth-like)\n"
     582             :         "- no: do not use sdtp\n"
     583             :         "- sdtp: use sdtp box to indicate sample dependencies and do not write info in trun sample flags\n"
     584             :         "- both: use sdtp box to indicate sample dependencies and also write info in trun sample flags\n", GF_ARG_INT, 0, parse_sdtp, 0, ARG_IS_FUN),
     585             :         MP4BOX_ARG("no-cache", "disable file cache for dash inputs", GF_ARG_BOOL, 0, &no_cache, 0, 0),
     586             :         MP4BOX_ARG("no-loop", "disable looping content in live mode and uses period switch instead", GF_ARG_BOOL, 0, &no_loop, 0, 0),
     587             :         MP4BOX_ARG("hlsc", "insert UTC in variant playlists for live HLS", GF_ARG_BOOL, 0, &hls_clock, 0, 0),
     588             :         MP4BOX_ARG("bound", "segmentation will always try to split before or at, but never after, the segment boundary", GF_ARG_BOOL, 0, &dash_split_mode, GF_DASH_SPLIT_IN, 0),
     589             :         MP4BOX_ARG("closest", "segmentation will use the closest frame to the segment boundary (before or after)", GF_ARG_BOOL, 0, &dash_split_mode, GF_DASH_SPLIT_CLOSEST, 0),
     590             :         MP4BOX_ARG_ALT("subsegs-per-sidx", "frags-per-sidx", "set the number of subsegments to be written in each SIDX box\n"
     591             :         "- 0: a single SIDX box is used per segment\n"
     592             :         "- -1: no SIDX box is used", GF_ARG_INT, GF_ARG_HINT_EXPERT, &subsegs_per_sidx, 0, 0),
     593             :         MP4BOX_ARG("ssix", "enable SubsegmentIndexBox describing 2 ranges, first one from moof to end of first I-frame, second one unmapped. This does not work with daisy chaining mode enabled", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &use_ssix, 0, 0),
     594             :         MP4BOX_ARG("url-template", "use SegmentTemplate instead of explicit sources in segments. Ignored if segments are stored in the output file", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &use_url_template, 1, 0),
     595             :         MP4BOX_ARG("url-template-sim", "use SegmentTemplate simulation while converting HLS to MPD", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &use_url_template, 2, 0),
     596             :         MP4BOX_ARG("daisy-chain", "use daisy-chain SIDX instead of hierarchical. Ignored if frags/sidx is 0", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &daisy_chain_sidx, 0, 0),
     597             :         MP4BOX_ARG("single-segment", "use a single segment for the whole file (OnDemand profile)", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &single_segment, 0, 0),
     598             :         {"single-file", NULL, "use a single file for the whole file (default)", "yes", NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &single_file, 0, 0},
     599             :         {"bs-switching", NULL, "set bitstream switching mode\n"
     600             :         "- inband: use inband param set and a single init segment\n"
     601             :         "- merge: try to merge param sets in a single sample description, fallback to `no`\n"
     602             :         "- multi: use several sample description, one per quality\n"
     603             :         "- no: use one init segment per quality\n"
     604             :         "- single: to test with single input", "inband", "inband|merge|multi|no|single", GF_ARG_STRING, GF_ARG_HINT_EXPERT, parse_bs_switch, 0, ARG_IS_FUN},
     605             :         MP4BOX_ARG("moof-sn", "set sequence number of first moof to given value", GF_ARG_INT, GF_ARG_HINT_EXPERT, &initial_moof_sn, 0, 0),
     606             :         MP4BOX_ARG("tfdt", "set TFDT of first traf to given value in SCALE units (cf -dash-scale)", GF_ARG_INT, GF_ARG_HINT_EXPERT, &initial_tfdt, 0, ARG_64BITS),
     607             :         MP4BOX_ARG("no-frags-default", "disable default fragments flags in trex (required by some dash-if profiles and CMAF/smooth streaming compatibility)", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &no_fragments_defaults, 0, 0),
     608             :         MP4BOX_ARG("single-traf", "use a single track fragment per moof (smooth streaming and derived specs may require this)", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &single_traf_per_moof, 0, 0),
     609             :         MP4BOX_ARG("tfdt-traf", "use a tfdt per track fragment (when -single-traf is used)", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &tfdt_per_traf, 0, 0),
     610             :         MP4BOX_ARG("dash-ts-prog", "program_number to be considered in case of an MPTS input file", GF_ARG_INT, GF_ARG_HINT_EXPERT, &program_number, 0, 0),
     611             :         MP4BOX_ARG("frag-rt", "when using fragments in live mode, flush fragments according to their timing", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &frag_real_time, 0, 0),
     612             :         MP4BOX_ARG("cp-location", "set ContentProtection element location\n"
     613             :                 "- as: sets ContentProtection in AdaptationSet element\n"
     614             :                 "- rep: sets ContentProtection in Representation element\n"
     615             :                 "- both: sets ContentProtection in both elements", GF_ARG_STRING, GF_ARG_HINT_EXPERT, parse_cp_loc, 0, ARG_IS_FUN),
     616             :         MP4BOX_ARG("start-date", "for live mode, set start date (as xs:date, eg YYYY-MM-DDTHH:MM:SSZ). Default is current UTC\n"
     617             :         "Warning: Do not use with multiple periods, nor when DASH duration is not a multiple of GOP size", GF_ARG_STRING, GF_ARG_HINT_EXPERT, &dash_start_date, 0, 0),
     618             :         MP4BOX_ARG("cues", "ignore dash duration and segment according to cue times in given XML file (tests/media/dash_cues for examples)", GF_ARG_STRING, GF_ARG_HINT_EXPERT, &dash_cues, 0, 0),
     619             :         MP4BOX_ARG("strict-cues", "throw error if something is wrong while parsing cues or applying cue-based segmentation", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &strict_cues, 0, 0),
     620             :         MP4BOX_ARG("merge-last-seg", "merge last segment if shorter than half the target duration", GF_ARG_BOOL, GF_ARG_HINT_EXPERT, &merge_last_seg, 0, 0),
     621             :         {0}
     622             : };
     623             : 
     624           4 : void PrintDASHUsage()
     625             : {
     626             :         u32 i=0;
     627           4 :         gf_sys_format_help(helpout, help_flags, "# DASH Options\n"
     628             :                 "Also see:\n"
     629             :                 "- the [dasher `gpac -h dash`](dasher) filter documentation\n"
     630             :                 "- [[DASH wiki|DASH-intro]].\n"
     631             :                 "\n"
     632             :                 "# Specifying input files\n"
     633             :                 "Input media files to dash can use the following modifiers\n"
     634             :                 "- #trackID=N: only use the track ID N from the source file\n"
     635             :                 "- #N: only use the track ID N from the source file (mapped to [-tkid](mp4dmx))\n"
     636             :                 "- #video: only use the first video track from the source file\n"
     637             :                 "- #audio: only use the first audio track from the source file\n"
     638             :                 "- :id=NAME: set the representation ID to NAME. Reserved value `NULL` disables representation ID for multiplexed inputs. If not set, a default value is computed and all selected tracks from the source will be in the same output mux.\n"
     639             :                 "- :dur=VALUE: process VALUE seconds (fraction) from the media. If VALUE is longer than media duration, last sample duration is extended.\n"
     640             :                 "- :period=NAME: set the representation's period to NAME. Multiple periods may be used. Periods appear in the MPD in the same order as specified with this option\n"
     641             :                 "- :BaseURL=NAME: set the BaseURL. Set multiple times for multiple BaseURLs\nWarning: This does not modify generated files location (see segment template).\n"
     642             :                 "- :bandwidth=VALUE: set the representation's bandwidth to a given value\n"
     643             :                 "- :pdur=VALUE: sets the duration of the associated period to VALUE seconds (fraction) (alias for period_duration:VALUE). This is only used when no input media is specified (remote period insertion), eg `:period=X:xlink=Z:pdur=Y`\n"
     644             :                 "- :ddur=VALUE: override target DASH segment duration to VALUE seconds (fraction) for this input (alias for duration:VALUE)\n"
     645             :                 "- :xlink=VALUE: set the xlink value for the period containing this element. Only the xlink declared on the first rep of a period will be used\n"
     646             :                 "- :asID=VALUE: set the AdaptationSet ID to NAME\n"
     647             :                 "- :role=VALUE: set the role of this representation (cf DASH spec). Media with different roles belong to different adaptation sets.\n"
     648             :                 "- :desc_p=VALUE: add a descriptor at the Period level. Value must be a properly formatted XML element.\n"
     649             :                 "- :desc_as=VALUE: add a descriptor at the AdaptationSet level. Value must be a properly formatted XML element. Two input files with different values will be in different AdaptationSet elements.\n"
     650             :                 "- :desc_as_c=VALUE: add a descriptor at the AdaptationSet level. Value must be a properly formatted XML element. Value is ignored while creating AdaptationSet elements.\n"
     651             :                 "- :desc_rep=VALUE: add a descriptor at the Representation level. Value must be a properly formatted XML element. Value is ignored while creating AdaptationSet elements.\n"
     652             :                 "- :sscale: force movie timescale to match media timescale of the first track in the segment.\n"
     653             :                 "- :trackID=N: only use the track ID N from the source file\n"
     654             :                 "- @f1[:args][@fN:args][@@fK:args]: set a filter chain to insert between the source and the dasher. Each filter in the chain is formatted as a regular filter, see [filter doc `gpac -h doc`](filters_general). If several filters are set:\n"
     655             :                 "  - they will be chained in the given order if separated by a single `@`\n"
     656             :                 "  - a new filter chain will be created if separated by a double `@@`. In this case, no representation ID is assigned to the source.\n"
     657             :                 "EX source.mp4:@enc:c=avc:b=1M@@enc:c=avc:b=500k\n"
     658             :                 "This will load a filter chain with two encoders connected to the source and to the dasher.\n"
     659             :                 "EX source.mp4:@enc:c=avc:b=1M@enc:c=avc:b=500k\n"
     660             :                 "This will load a filter chain with the second encoder connected to the output of the first (!!).\n"
     661             :                 "\n"
     662             :                 "Note: `@f` must be placed after all other options.\n"
     663             :                 "\n"
     664             :                 "# Options\n"
     665             :                 );
     666             : 
     667             : 
     668         252 :         while (m4b_dash_args[i].name) {
     669         244 :                 GF_GPACArg *arg = (GF_GPACArg *) &m4b_dash_args[i];
     670         244 :                 i++;
     671         244 :                 gf_sys_print_arg(helpout, help_flags, arg, "mp4box-dash");
     672             :         }
     673           4 : }
     674             : 
     675             : 
     676             : MP4BoxArg m4b_imp_args[] =
     677             : {
     678             :         MP4BOX_ARG("add", "add given file tracks to file. Multiple inputs can be specified using `+`, eg `-add url1+url2`", GF_ARG_STRING, 0, &nb_add, 0, ARG_INT_INC),
     679             :         MP4BOX_ARG("cat", "concatenate given file samples to file, creating tracks if needed. Multiple inputs can be specified using `+`, eg `-cat url1+url2`.  \nNote: This aligns initial timestamp of the file to be concatenated", GF_ARG_STRING, 0, &nb_cat, 0, ARG_INT_INC),
     680             :         MP4BOX_ARG("catx", "same as [-cat]() but new tracks can be imported before concatenation by specifying `+ADD_COMMAND` where `ADD_COMMAND` is a regular [-add]() syntax", GF_ARG_STRING, 0, &nb_cat, 0, ARG_INT_INC),
     681             :         MP4BOX_ARG("catpl", "concatenate files listed in the given playlist file (one file per line, lines starting with # are comments).  \nNote: Each listed file is concatenated as if called with -cat", GF_ARG_STRING, 0, &nb_cat, 0, ARG_INT_INC),
     682             :         MP4BOX_ARG("unalign-cat", "do not attempt to align timestamps of samples in-between tracks", GF_ARG_BOOL, 0, &align_cat, 0, ARG_BOOL_REV),
     683             :         MP4BOX_ARG("force-cat", "skip media configuration check when concatenating file.  \nWarning: THIS MAY BREAK THE CONCATENATED TRACK(S)", GF_ARG_BOOL, 0, &force_cat, 0, 0),
     684             :         MP4BOX_ARG("keep-sys", "keep all MPEG-4 Systems info when using [-add]() and [-cat]() (only used when adding IsoMedia files)", GF_ARG_BOOL, 0, &keep_sys_tracks, 0, 0),
     685             :         MP4BOX_ARG("dref", "keep media data in original file using `data referencing`. The resulting file only contains the meta-data of the presentation (frame sizes, timing, etc...) and references media data in the original file. This is extremely useful when developing content, since importing and storage of the MP4 file is much faster and the resulting file much smaller.  \nNote: Data referencing may fail on some files because it requires the framed data (eg an IsoMedia sample) to be continuous in the original file, which is not always the case depending on the original interleaving or bitstream format (__AVC__ or __HEVC__ cannot use this option)", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_USE_DATAREF, ARG_BIT_MASK),
     686             :         MP4BOX_ARG_ALT("no-drop", "nodrop", "force constant FPS when importing AVI video", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_NO_FRAME_DROP, ARG_BIT_MASK),
     687             :         MP4BOX_ARG("packed", "force packed bitstream when importing raw MPEG-4 part 2 Advanced Simple Profile", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_FORCE_PACKED, ARG_BIT_MASK),
     688             :         MP4BOX_ARG("sbr", "backward compatible signaling of AAC-SBR", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_SBR_IMPLICIT, ARG_BIT_MASK),
     689             :         MP4BOX_ARG("sbrx", "non-backward compatible signaling of AAC-SBR", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_SBR_EXPLICIT, ARG_BIT_MASK),
     690             :         MP4BOX_ARG("ps", "backward compatible signaling of AAC-PS", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_PS_IMPLICIT, ARG_BIT_MASK),
     691             :         MP4BOX_ARG("psx", "non-backward compatible signaling of AAC-PS", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_PS_EXPLICIT, ARG_BIT_MASK),
     692             :         MP4BOX_ARG("ovsbr", "oversample SBR import (SBR AAC, PS AAC and oversampled SBR cannot be detected at import time)", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_OVSBR, ARG_BIT_MASK),
     693             :         MP4BOX_ARG("fps", "force frame rate for video and SUB subtitles import to the given value, expressed as a number, as `TS-inc` or `TS/inc`.  \nNote: For raw H263 import, default FPS is `15`, otherwise `25`. This is ignored for ISOBMFF import, use `:rescale` option for that", GF_ARG_STRING, 0, parse_fps, 0, ARG_IS_FUN),
     694             :         MP4BOX_ARG("mpeg4", "force MPEG-4 sample descriptions when possible. For AAC, forces MPEG-4 AAC signaling even if MPEG-2", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_FORCE_MPEG4, ARG_BIT_MASK),
     695             :         MP4BOX_ARG("agg", "aggregate N audio frames in 1 sample (3GP media only, maximum value is 15)", GF_ARG_INT, 0, &agg_samples, 0, 0),
     696             :         {0}
     697             : };
     698             : 
     699             : 
     700             : static MP4BoxArg m4b_imp_fileopt_args [] = {
     701             :         GF_DEF_ARG("dur", NULL, "`XC` import only the specified duration from the media. Value can be:\n"
     702             :                 "  - positive float: specifies duration in seconds\n"
     703             :                 "  - fraction: specifies duration as NUM/DEN fraction\n"
     704             :                 "  - negative integer: specifies duration in number of coded frames", NULL, NULL, GF_ARG_INT, 0),
     705             :         GF_DEF_ARG("start", NULL, "`C` target start time in source media, may not be supported depending on the source", NULL, NULL, GF_ARG_DOUBLE, 0),
     706             :         GF_DEF_ARG("lang", NULL, "`S` set imported media language code", NULL, NULL, GF_ARG_STRING, 0),
     707             :         GF_DEF_ARG("delay", NULL, "`S` set imported media initial delay (>0) or initial skip (<0) in ms or as fractional seconds (`N/D`)", NULL, NULL, GF_ARG_INT, 0),
     708             :         GF_DEF_ARG("par", NULL, "`S` set visual pixel aspect ratio (see [-par](MP4B_GEN) )", NULL, NULL, GF_ARG_STRING, 0),
     709             :         GF_DEF_ARG("clap", NULL, "`S` set visual clean aperture (see [-clap](MP4B_GEN) )", NULL, NULL, GF_ARG_STRING, 0),
     710             :         GF_DEF_ARG("mx", NULL, "`S` set track matrix (see [-mx](MP4B_GEN) )", NULL, NULL, GF_ARG_STRING, 0),
     711             :         GF_DEF_ARG("name", NULL, "`S` set track handler name", NULL, NULL, GF_ARG_STRING, 0),
     712             :         GF_DEF_ARG("ext", NULL, "override file extension when importing", NULL, NULL, GF_ARG_STRING, 0),
     713             :         GF_DEF_ARG("hdlr", NULL, "`S` set track handler type to the given code point (4CC)", NULL, NULL, GF_ARG_STRING, 0),
     714             :         GF_DEF_ARG("tkhd", NULL, "`S` set track header flags has hex integer. Use `tkhd+=FLAGS` to add flags and `tkhd-=FLAGS` to remove flags", NULL, NULL, GF_ARG_INT, 0),
     715             :         GF_DEF_ARG("disable", NULL, "`S` disable imported track(s), use `disable=no` to force enabling a disabled track", NULL, NULL, GF_ARG_BOOL, 0),
     716             :         GF_DEF_ARG("group", NULL, "`S` add the track as part of the G alternate group. If G is 0, the first available GroupID will be picked", NULL, NULL, GF_ARG_INT, 0),
     717             :         GF_DEF_ARG("fps", NULL, "same as [-fps]()", NULL, NULL, GF_ARG_STRING, 0),
     718             :         GF_DEF_ARG("rap", NULL, "`DS` import only RAP samples", NULL, NULL, GF_ARG_BOOL, 0),
     719             :         GF_DEF_ARG("refs", NULL, "`DS` import only reference pictures", NULL, NULL, GF_ARG_BOOL, 0),
     720             :         GF_DEF_ARG("trailing", NULL, "keep trailing 0-bytes in AVC/HEVC samples", NULL, NULL, GF_ARG_BOOL, 0),
     721             :         GF_DEF_ARG("agg", NULL, "`X` same as [-agg]()", NULL, NULL, GF_ARG_INT, 0),
     722             :         GF_DEF_ARG("dref", NULL, "`XC` same as [-dref]()", NULL, NULL, GF_ARG_BOOL, 0),
     723             :         GF_DEF_ARG("keep_refs", NULL, "`C` keep track reference when importing a single track", NULL, NULL, GF_ARG_BOOL, 0),
     724             :         GF_DEF_ARG("nodrop", NULL, "same as [-nodrop]()", NULL, NULL, GF_ARG_BOOL, 0),
     725             :         GF_DEF_ARG("packed", NULL, "`X` same as [-packed]()", NULL, NULL, GF_ARG_BOOL, 0),
     726             :         GF_DEF_ARG("sbr", NULL, "same as [-sbr]()", NULL, NULL, GF_ARG_BOOL, 0),
     727             :         GF_DEF_ARG("sbrx", NULL, "same as [-sbrx]()", NULL, NULL, GF_ARG_BOOL, 0),
     728             :         GF_DEF_ARG("ovsbr", NULL, "same as [-ovsbr]()", NULL, NULL, GF_ARG_BOOL, 0),
     729             :         GF_DEF_ARG("ps", NULL, "same as [-ps]()", NULL, NULL, GF_ARG_BOOL, 0),
     730             :         GF_DEF_ARG("psx", NULL, "same as [-psx]()", NULL, NULL, GF_ARG_BOOL, 0),
     731             :         GF_DEF_ARG("asemode", NULL, "`XS` set the mode to create the AudioSampleEntry. Value can be:\n"
     732             :                 "  - v0-bs: use MPEG AudioSampleEntry v0 and the channel count from the bitstream (even if greater than 2) - default\n"
     733             :                 "  - v0-2: use MPEG AudioSampleEntry v0 and the channel count is forced to 2\n"
     734             :                 "  - v1: use MPEG AudioSampleEntry v1 and the channel count from the bitstream\n"
     735             :                 "  - v1-qt: use QuickTime Sound Sample Description Version 1 and the channel count from the bitstream (even if greater than 2). This will also trigger using alis data references instead of url, even for non-audio tracks", NULL, NULL, GF_ARG_STRING, 0),
     736             :         GF_DEF_ARG("audio_roll", NULL, "`S` add a roll sample group with roll_distance `N` for audio tracks", NULL, NULL, GF_ARG_INT, 0),
     737             :         GF_DEF_ARG("roll", NULL, "`S` add a roll sample group with roll_distance `N`", NULL, NULL, GF_ARG_INT, 0),
     738             :         GF_DEF_ARG("proll", NULL, "`S` add a preroll sample group with roll_distance `N`", NULL, NULL, GF_ARG_INT, 0),
     739             :         GF_DEF_ARG("mpeg4", NULL, "`X` same as [-mpeg4]() option", NULL, NULL, GF_ARG_BOOL, 0),
     740             :         GF_DEF_ARG("nosei", NULL, "discard all SEI messages during import", NULL, NULL, GF_ARG_BOOL, 0),
     741             :         GF_DEF_ARG("svc", NULL, "import SVC/LHVC with explicit signaling (no AVC base compatibility)", NULL, NULL, GF_ARG_BOOL, 0),
     742             :         GF_DEF_ARG("nosvc", NULL, "discard SVC/LHVC data when importing", NULL, NULL, GF_ARG_BOOL, 0),
     743             :         GF_DEF_ARG("svcmode", NULL, "`DS` set SVC/LHVC import mode. Value can be:\n"
     744             :                 "  - split: each layer is in its own track\n"
     745             :                 "  - merge: all layers are merged in a single track\n"
     746             :                 "  - splitbase: all layers are merged in a track, and the AVC base in another\n"
     747             :                 "  - splitnox: each layer is in its own track, and no extractors are written\n"
     748             :                 "  - splitnoxib: each layer is in its own track, no extractors are written, using inband param set signaling", NULL, NULL, GF_ARG_STRING, 0),
     749             :         GF_DEF_ARG("temporal", NULL, "`DS` set HEVC/LHVC temporal sublayer import mode. Value can be:\n"
     750             :                 "  - split: each sublayer is in its own track\n"
     751             :                 "  - splitbase: all sublayers are merged in a track, and the HEVC base in another\n"
     752             :                 "  - splitnox: each layer is in its own track, and no extractors are written", NULL, NULL, GF_ARG_STRING, 0),
     753             :         GF_DEF_ARG("subsamples", NULL, "add SubSample information for AVC+SVC", NULL, NULL, GF_ARG_BOOL, 0),
     754             :         GF_DEF_ARG("deps", NULL, "import sample dependency information for AVC and HEVC", NULL, NULL, GF_ARG_BOOL, 0),
     755             :         GF_DEF_ARG("ccst", NULL, "`S` add default HEIF ccst box to visual sample entry", NULL, NULL, GF_ARG_BOOL, 0),
     756             :         GF_DEF_ARG("forcesync", NULL, "force non IDR samples with I slices (OpenGOP or GDR) to be marked as sync points\n"
     757             :                 "Warning: RESULTING FILE IS NOT COMPLIANT WITH THE SPEC but will fix seeking in most players", NULL, NULL, GF_ARG_BOOL, 0),
     758             :         GF_DEF_ARG("xps_inband", NULL, "`XC` set xPS inband for AVC/H264 and HEVC (for reverse operation, re-import from raw media)", NULL, NULL, GF_ARG_BOOL, 0),
     759             :         GF_DEF_ARG("xps_inbandx", NULL, "`XC` same as xps_inband and also keep first xPS in sample description", NULL, NULL, GF_ARG_BOOL, 0),
     760             :         GF_DEF_ARG("au_delim", NULL, "keep AU delimiter NAL units in the imported file", NULL, NULL, GF_ARG_BOOL, 0),
     761             :         GF_DEF_ARG("max_lid", NULL, "set HEVC max layer ID to be imported to `N` (by default imports all layers)", NULL, NULL, GF_ARG_INT, 0),
     762             :         GF_DEF_ARG("max_tid", NULL, "set HEVC max temporal ID to be imported to `N` (by default imports all temporal sublayers)", NULL, NULL, GF_ARG_INT, 0),
     763             :         GF_DEF_ARG("tiles", NULL, "`S` add HEVC tiles signaling and NALU maps without splitting the tiles into different tile tracks", NULL, NULL, GF_ARG_BOOL, 0),
     764             :         GF_DEF_ARG("split_tiles", NULL, "`DS` split HEVC tiles into different tile tracks, one tile (or all tiles of one slice) per track", NULL, NULL, GF_ARG_BOOL, 0),
     765             :         GF_DEF_ARG("negctts", NULL, "`S` use negative CTS-DTS offsets (ISO4 brand). Use `negctts=no` to force using positive offset on existing track", NULL, NULL, GF_ARG_BOOL, 0),
     766             :         GF_DEF_ARG("chap", NULL, "`S` specify the track is a chapter track", NULL, NULL, GF_ARG_BOOL, 0),
     767             :         GF_DEF_ARG("chapter", NULL, "`S` add a single chapter (old nero format) with given name lasting the entire file", NULL, NULL, GF_ARG_STRING, 0),
     768             :         GF_DEF_ARG("chapfile", NULL, "`S` add a chapter file (old nero format)", NULL, NULL, GF_ARG_STRING, 0),
     769             :         GF_DEF_ARG("layout", NULL, "`S` specify the track layout as `WxH[xXxY][xLAYER]`. If `W` (resp `H`) is 0, the max width (resp height) of the tracks in the file are used", NULL, NULL, GF_ARG_STRING, 0),
     770             :         GF_DEF_ARG("rescale", NULL, "`S` force media timescale to TS  (int or fraction) and change the media duration", NULL, NULL, GF_ARG_INT, 0),
     771             :         GF_DEF_ARG("sampdur", NULL, "`S` force all samples duration (`D`) or sample durations and media timescale (`D/TS`), used to patch CFR files with broken timings", NULL, NULL, GF_ARG_INT, 0),
     772             :         GF_DEF_ARG("timescale", NULL, "`S` set imported media timescale to TS", NULL, NULL, GF_ARG_INT, 0),
     773             :         GF_DEF_ARG("moovts", NULL, "`S` set movie timescale to TS. A negative value picks the media timescale of the first track imported", NULL, NULL, GF_ARG_INT, 0),
     774             :         GF_DEF_ARG("noedit", NULL, "`XS` do not set edit list when importing B-frames video tracks", NULL, NULL, GF_ARG_BOOL, 0),
     775             :         GF_DEF_ARG("rvc", NULL, "`S` set RVC configuration for the media", NULL, NULL, GF_ARG_STRING, 0),
     776             :         GF_DEF_ARG("fmt", NULL, "override format detection with given format - disable data probing and force `ext` option on source", NULL, NULL, GF_ARG_STRING, 0),
     777             :         GF_DEF_ARG("profile", NULL, "`S` override AVC profile. Integer value, or `high444`, `high`, `extended`, `main`, `baseline`", NULL, NULL, GF_ARG_INT, 0),
     778             :         GF_DEF_ARG("level", NULL, "`S` override AVC level, if value < 6, interpreted as decimal expression", NULL, NULL, GF_ARG_INT, 0),
     779             :         GF_DEF_ARG("compat", NULL, "`S` force the profile compatibility flags for the H.264 content", NULL, NULL, GF_ARG_INT, 0),
     780             :         GF_DEF_ARG("novpsext", NULL, "remove VPS extensions from HEVC VPS", NULL, NULL, GF_ARG_BOOL, 0),
     781             :         GF_DEF_ARG("keepav1t", NULL, "keep AV1 temporal delimiter OBU in samples, might help if source file had losses", NULL, NULL, GF_ARG_BOOL, 0),
     782             :         GF_DEF_ARG("font", NULL, "specify font name for text import (default `Serif`)", NULL, NULL, GF_ARG_STRING, 0),
     783             :         GF_DEF_ARG("size", NULL, "specify font size for text import (default `18`)", NULL, NULL, GF_ARG_INT, 0),
     784             :         GF_DEF_ARG("text_layout", NULL, "specify the track text layout as WxHxXxY\n"
     785             :                 "  - if W (resp H) = 0: the max width (resp height) of the tracks in the file are used\n"
     786             :                 "  - if Y=-1: the layout is moved to the bottom of the track area\n"
     787             :                 "  - X and Y can be omitted: `:layout=WxH`", NULL, NULL, GF_ARG_STRING, 0),
     788             :         GF_DEF_ARG("swf-global", NULL, "all SWF defines are placed in first scene replace rather than when needed", NULL, NULL, GF_ARG_BOOL, 0),
     789             :         GF_DEF_ARG("swf-no-ctrl", NULL, "use a single stream for movie control and dictionary (this will disable ActionScript)", NULL, NULL, GF_ARG_BOOL, 0),
     790             :         GF_DEF_ARG("swf-no-text", NULL, "remove all SWF text", NULL, NULL, GF_ARG_BOOL, 0),
     791             :         GF_DEF_ARG("swf-no-font", NULL, "remove all embedded SWF Fonts (local playback host fonts used)", NULL, NULL, GF_ARG_BOOL, 0),
     792             :         GF_DEF_ARG("swf-no-line", NULL, "remove all lines from SWF shapes", NULL, NULL, GF_ARG_BOOL, 0),
     793             :         GF_DEF_ARG("swf-no-grad", NULL, "remove all gradients from SWF shapes", NULL, NULL, GF_ARG_BOOL, 0),
     794             :         GF_DEF_ARG("swf-quad", NULL, "use quadratic bezier curves instead of cubic ones", NULL, NULL, GF_ARG_BOOL, 0),
     795             :         GF_DEF_ARG("swf-xlp", NULL, "support for lines transparency and scalability", NULL, NULL, GF_ARG_BOOL, 0),
     796             :         GF_DEF_ARG("swf-ic2d", NULL, "use indexed curve 2D hardcoded proto", NULL, NULL, GF_ARG_BOOL, 0),
     797             :         GF_DEF_ARG("swf-same-app", NULL, "appearance nodes are reused", NULL, NULL, GF_ARG_BOOL, 0),
     798             :         GF_DEF_ARG("swf-flatten", NULL, "complementary angle below which 2 lines are merged, `0` means no flattening", NULL, NULL, GF_ARG_DOUBLE, 0),
     799             :         GF_DEF_ARG("kind", NULL, "`S` set kind for the track as `schemeURI=value`", NULL, NULL, GF_ARG_STRING, 0),
     800             :         GF_DEF_ARG("txtflags", NULL, "set display flags (hexa number) of text track. Use `txtflags+=FLAGS` to add flags and `txtflags-=FLAGS` to remove flags", NULL, NULL, GF_ARG_INT, 0),
     801             :         GF_DEF_ARG("rate", NULL, "force average rate and max rate to VAL (in bps) in btrt box. If 0, removes btrt box", NULL, NULL, GF_ARG_INT, 0),
     802             :         GF_DEF_ARG("stz2", NULL, "`S` use compact size table (for low-bitrates)", NULL, NULL, GF_ARG_BOOL, 0),
     803             :         GF_DEF_ARG("bitdepth", NULL, "set bit depth to VAL for imported video content (default is 24)", NULL, NULL, GF_ARG_INT, 0),
     804             :         GF_DEF_ARG("colr", NULL, "`S` set color profile for imported video content (see ISO/IEC 23001-8). Value is formatted as:\n"
     805             :                 "  - nclc,p,t,m: with p colour primary (int or string), t transfer characteristics (int or string) and m matrix coef (int or string)\n"
     806             :                 "  - nclx,p,t,m,r: same as `nclx` with r full range flag (`yes`, `on` or `no`, `off`)\n"
     807             :                 "  - prof,path: with path indicating the file containing the ICC color profile\n"
     808             :                 "  - rICC,path: with path indicating the file containing the restricted ICC color profile", NULL, NULL, GF_ARG_STRING, 0),
     809             :         GF_DEF_ARG("dv-profile", NULL, "`S` set the Dolby Vision profile", NULL, NULL, GF_ARG_INT, 0),
     810             :         GF_DEF_ARG("fullrange", NULL, "`S` force the video fullrange type in VUI for the AVC|H264 content (value `yes`, `on` or `no`, `off`)", NULL, NULL, GF_ARG_STRING, 0),
     811             :         GF_DEF_ARG("videofmt", NULL, "`S` force the video format in VUI for AVC|H264 and HEVC content, value can be `component`, `pal`, `ntsc`, `secam`, `mac`, `undef`", NULL, NULL, GF_ARG_STRING, 0),
     812             :         GF_DEF_ARG("colorprim", NULL, "`S` force the colour primaries in VUI for AVC|H264 and HEVC (int or string, cf `-h cicp`)", NULL, NULL, GF_ARG_STRING, 0),
     813             :         GF_DEF_ARG("colortfc", NULL, "`S` force transfer characteristics in VUI for AVC|H264 and HEVC (int or string, cf `-h cicp`)", NULL, NULL, GF_ARG_STRING, 0),
     814             :         GF_DEF_ARG("colormx", NULL, "`S` force the matrix coefficients in VUI for the AVC|H264 and HEVC content (int or string, cf `-h cicp`)", NULL, NULL, GF_ARG_STRING, 0),
     815             :         GF_DEF_ARG("tc", NULL, "`S` inject a single QT timecode. Value is formatted as:\n"
     816             :                 "  - [d]FPS[/FPS_den],h,m,s,f[,framespertick]: optional drop flag, framerate (integer or fractional), hours, minutes, seconds and frame number\n"
     817             :                 "  - : `d` is an optional flag used to indicate that the counter is in drop-frame format\n"
     818             :                 "  - : the `framespertick` is optional and defaults to round(framerate); it indicates the number of frames per counter tick", NULL, NULL, GF_ARG_STRING, 0),
     819             :         GF_DEF_ARG("edits", NULL, "`S` override edit list, same syntax as [-edits]()", NULL, NULL, GF_ARG_STRING, 0),
     820             :         GF_DEF_ARG("lastsampdur", NULL, "`S` set duration of the last sample. Value is formatted as:\n"
     821             :                 "  - no value: use the previous sample duration\n"
     822             :                 "  - integer: indicate the duration in milliseconds\n"
     823             :                 "  - N/D: indicate the duration as fractional second", NULL, NULL, GF_ARG_STRING, 0),
     824             :         GF_DEF_ARG("fstat", NULL, "`C` print filter session stats after import", NULL, NULL, GF_ARG_BOOL, 0),
     825             :         GF_DEF_ARG("fgraph", NULL, "`C` print filter session graph after import", NULL, NULL, GF_ARG_BOOL, 0),
     826             :         {"sopt:[OPTS]", NULL, "set `OPTS` as additional arguments to source filter. `OPTS` can be any usual filter argument, see [filter doc `gpac -h doc`](Filters)"},
     827             :         {"dopt:[OPTS]", NULL, "`X` set `OPTS` as additional arguments to [destination filter](mp4mx). OPTS can be any usual filter argument, see [filter doc `gpac -h doc`](Filters)"},
     828             :         {"@f1[:args][@fN:args]", NULL, "set a filter chain to insert before the muxer. Each filter in the chain is formatted as a regular filter, see [filter doc `gpac -h doc`](Filters). A `@@` separator starts a new chain (see DASH help). The last filter in each chain shall not have any ID specified"},
     829             :         {0}
     830             : };
     831             : 
     832           4 : void PrintImportUsage()
     833             : {
     834             :         u32 i;
     835             : 
     836           4 :         gf_sys_format_help(helpout, help_flags, "# Importing Options\n"
     837             :                 "# File importing\n"
     838             :                 "Syntax is [-add]() / [-cat]() `URL[#FRAGMENT][:opt1...:optN=val]`\n"
     839             :                 "This process will create the destination file if not existing, and add the track(s) to it. If you wish to always create a new destination file, add [-new](MP4B_GEN).\n"
     840             :                 "The supported input media types depend on your installation, check [filters documentation](Filters) for more info.\n"
     841             :                 "  \n"
     842             :                 "To select a desired media track from a source, a fragment identifier '#' can be specified, before any other options. The following syntax is used:\n"
     843             :                 "- `#video`: adds the first video track found in source\n"
     844             :                 "- `#audio`: adds the first audio track found in source\n"
     845             :                 "- `#auxv`: adds the first auxiliary video track found in source\n"
     846             :                 "- `#pict`: adds the first picture track found in source\n"
     847             :                 "- `#trackID=ID` or `#ID`: adds the specified track. For IsoMedia files, ID is the track ID. For other media files, ID is the value indicated by `MP4Box -info inputFile`\n"
     848             :                 "- `#pid=ID`: number of desired PID for MPEG-2 TS sources\n"
     849             :                 "- `#prog_id=ID`: number of desired program for MPEG-2 TS sources\n"
     850             :                 "- `#program=NAME`: name of desired program for MPEG-2 TS sources\n"
     851             :                 "  \n"
     852             :                 "By default all imports are performed sequentially, and final interleaving is done at the end; this however requires a temporary file holding original ISOBMF file (if any) and added files before creating the final output. Since this can become quite large, it is possible to add media to a new file without temporary storage, using [-flat](MP4B_GEN) option, but this disables media interleaving.\n"
     853             :                 "  \n"
     854             :                 "If you wish to create an interleaved new file with no temporary storage, use the [-newfs](MP4B_GEN) option. The interleaving might not be as precise as when using [-new]() since it is dependent on muxer input scheduling (each execution might lead to a slightly different result). Additionally in this mode: \n"
     855             :                 " - Some muxing options (marked with `X` below) will be activated for all inputs (e.g it is not possible to import one AVC track with `xps_inband` and another without).\n"
     856             :                 " - Some muxing options (marked as `D` below) cannot be used as they require temporary storage for file edition.\n"
     857             :                 " - Usage of [-cat]() is possible, but concatenated sources will not be interleaved in the output. If you wish to perform more complex cat/add operations without temp file, use a [playlist](flist).\n"
     858             :                 "  \n"
     859             :                 "Source URL can be any URL supported by GPAC, not limited to local files.\n"
     860             :                 "  \n"
     861             :                 "Note: When importing SRT or SUB files, MP4Box will choose default layout options to make the subtitle appear at the bottom of the video. You SHOULD NOT import such files before any video track is added to the destination file, otherwise the results will likely not be useful (default SRT/SUB importing uses default serif font, fontSize 18 and display size 400x60). For more details, check [TTXT doc](Subtitling-with-GPAC).\n"
     862             :                 "  \n"
     863             :                 "When importing several tracks/sources in one pass, all options will be applied if relevant to each source. These options are set for all imported streams. If you need to specify these options per stream, set per-file options using the syntax `-add stream[:opt1:...:optN]`.\n"
     864             :                 "  \n"
     865             :                 "The import file name may be set to empty or `self`, indicating that the import options should be applied to the destination file track(s).\n"
     866             :                 "EX -add self:moovts=-1:noedit src.mp4\n"
     867             :                 "This will apply `moovts` and `noedit` option to all tracks in src.mp4\n"
     868             :                 "EX -add self#2:moovts=-1:noedit src.mp4\n"
     869             :                 "This will apply `moovts` and `noedit` option to track with `ID=2` in src.mp4\n"
     870             :                 "Only per-file options marked with a `S` are possible in this mode.\n"
     871             :                 "  \n"
     872             :                 "When importing an ISOBMFF/QT file, only options marked as `C` or `S` can be used.\n"
     873             :                 "  \n"
     874             :                 "Allowed per-file options:\n\n"
     875             :         );
     876             : 
     877             :         i=0;
     878         404 :         while (m4b_imp_fileopt_args[i].name) {
     879         396 :                 GF_GPACArg *arg = (GF_GPACArg *) &m4b_imp_fileopt_args[i];
     880         396 :                 i++;
     881         396 :                 gf_sys_print_arg(helpout, help_flags | GF_PRINTARG_NO_DASH, arg, "mp4box-import");
     882             :         }
     883             : 
     884           4 :         gf_sys_format_help(helpout, help_flags, "\n"
     885             :                 "Note: `sopt`, `dopt` and `@f` must be placed after all other options.\n"
     886             :                 "# Global import options\n"
     887             :         );
     888             : 
     889             :         i=0;
     890          80 :         while (m4b_imp_args[i].name) {
     891          72 :                 GF_GPACArg *arg = (GF_GPACArg *) &m4b_imp_args[i];
     892          72 :                 i++;
     893          72 :                 gf_sys_print_arg(helpout, help_flags, arg, "mp4box-import");
     894             :         }
     895           4 : }
     896             : 
     897          25 : Bool mp4box_check_isom_fileopt(char *opt)
     898             : {
     899             :         GF_GPACArg *arg = NULL;
     900             :         u32 i=0;
     901             : 
     902        1147 :         while (m4b_imp_fileopt_args[i].name) {
     903        1122 :                 arg = (GF_GPACArg *) &m4b_imp_fileopt_args[i];
     904        1122 :                 i++;
     905        1122 :                 if (!stricmp(arg->name, opt)) break;
     906             :                 arg = NULL;
     907             :         }
     908          25 :         if (!arg) {
     909           0 :                 fprintf(stderr, "Option %s not described in doc, please report to GPAC devs!\n", opt);
     910           0 :                 return GF_FALSE;
     911             :         }
     912          25 :         if (arg->description[0] != '`')
     913             :                 return GF_FALSE;
     914          24 :         const char *d = arg->description+1;
     915          55 :         while (d[0] != '`') {
     916          31 :                 if (d[0]=='S') return GF_TRUE;
     917          11 :                 if (d[0]=='C') return GF_TRUE;
     918           7 :                 d++;
     919             :         }
     920             :         return GF_FALSE;
     921             : }
     922             : 
     923             : 
     924             : MP4BoxArg m4b_senc_args[] =
     925             : {
     926             :         MP4BOX_ARG("mp4", "specify input file is for BIFS/LASeR encoding", GF_ARG_BOOL, 0, &encode, 0, ARG_OPEN_EDIT),
     927             :         MP4BOX_ARG("def", "encode DEF names in BIFS", GF_ARG_BOOL, 0, &smenc_opts.flags, GF_SM_ENCODE_USE_NAMES, ARG_BIT_MASK),
     928             :         MP4BOX_ARG("sync", "force BIFS sync sample generation every given time in ms (cannot be used with [-shadow]() or [-carousel]() )", GF_ARG_INT, 0, parse_senc_param, 0, ARG_IS_FUN),
     929             :         MP4BOX_ARG("shadow", "force BIFS sync shadow sample generation every given time in ms (cannot be used with [-sync]() or [-carousel]() )", GF_ARG_INT, 0, parse_senc_param, 1, ARG_IS_FUN),
     930             :         MP4BOX_ARG("carousel", "use BIFS carousel (cannot be used with [-sync]() or [-shadow]() )", GF_ARG_INT, 0, parse_senc_param, 2, ARG_IS_FUN),
     931             : 
     932             :         MP4BOX_ARG("sclog", "generate scene codec log file if available", GF_ARG_BOOL, 0, &do_scene_log, 0, 0),
     933             :         MP4BOX_ARG("ms", "import tracks from the given file", GF_ARG_STRING, 0, &mediaSource, 0, 0),
     934             :         MP4BOX_ARG("ctx-in", "specify initial context (MP4/BT/XMT) file for chunk processing. Input file must be a commands-only file", GF_ARG_STRING, 0, parse_senc_param, 5, ARG_IS_FUN),
     935             :         MP4BOX_ARG("ctx-out", "specify storage of updated context (MP4/BT/XMT) file for chunk processing, optional", GF_ARG_STRING, 0, &output_ctx, 0, 0),
     936             :         MP4BOX_ARG("resolution", "resolution factor (-8 to 7, default 0) for LASeR encoding, and all coordinates are multiplied by `2^res` before truncation (LASeR encoding)", GF_ARG_INT, 0, &smenc_opts.resolution, 0, 0),
     937             :         MP4BOX_ARG("coord-bits", "number of bits used for encoding truncated coordinates (0 to 31, default 12) (LASeR encoding)", GF_ARG_INT, 0, &smenc_opts.coord_bits, 0, 0),
     938             :         MP4BOX_ARG("scale-bits", "extra bits used for encoding truncated scales (0 to 4, default 0) (LASeR encoding)", GF_ARG_INT, 0, &smenc_opts.scale_bits, 0, 0),
     939             :         MP4BOX_ARG("auto-quant", "resolution is given as if using [-resolution]() but coord-bits and scale-bits are infered (LASeR encoding)", GF_ARG_INT, 0, parse_senc_param, 3, ARG_IS_FUN),
     940             :         MP4BOX_ARG("global-quant", "resolution is given as if using [-resolution]() but the res is inferred (BIFS encoding)", GF_ARG_INT, 0, parse_senc_param, 4, ARG_IS_FUN),
     941             :         {0}
     942             : };
     943             : 
     944             : 
     945           4 : void PrintEncodeUsage()
     946             : {
     947             :         u32 i=0;
     948           4 :         gf_sys_format_help(helpout, help_flags, "# MPEG-4 Scene Encoding Options\n"
     949             :                 "## General considerations\n"
     950             :                 "MP4Box supports encoding and decoding of of BT, XMT, VRML and (partially) X3D formats int MPEG-4 BIFS, and encoding and decoding of XSR and SVG into MPEG-4 LASeR\n"
     951             :                 "Any media track specified through a `MuxInfo` element will be imported in the resulting MP4 file.\n"
     952             :                 "See https://wiki.gpac.io/MPEG-4-BIFS-Textual-Format and related pages.\n"
     953             :                 "## Scene Random Access\n"
     954             :                 "MP4Box can encode BIFS or LASeR streams and insert random access points at a given frequency. This is useful when packaging content for broadcast, where users will not turn in the scene at the same time. In MPEG-4 terminology, this is called the __scene carousel__."
     955             :                 "## BIFS Chunk Processing\n"
     956             :                 "The BIFS chunk encoding mode alows encoding single BIFS access units from an initial context and a set of commands.\n"
     957             :                 "The generated AUs are raw BIFS (not SL-packetized), in files called FILE-ESID-AUIDX.bifs, with FILE the basename of the input file.\n"
     958             :                 "Commands with a timing of 0 in the input will modify the carousel version only (i.e. output context).\n"
     959             :                 "Commands with a timing different from 0 in the input will generate new AUs.\n"
     960             :                 "  \n"
     961             :                 "Options:\n"
     962             :         );
     963             : 
     964          64 :         while (m4b_senc_args[i].name) {
     965          56 :                 GF_GPACArg *arg = (GF_GPACArg *) &m4b_senc_args[i];
     966          56 :                 i++;
     967          56 :                 gf_sys_print_arg(helpout, help_flags, arg, "mp4box-senc");
     968             :         }
     969           4 : }
     970             : 
     971             : MP4BoxArg m4b_crypt_args[] =
     972             : {
     973             :         MP4BOX_ARG("crypt", "encrypt the input file using the given `CryptFile`", GF_ARG_STRING, 0, parse_cryp, 0, ARG_IS_FUN),
     974             :         MP4BOX_ARG("decrypt", "decrypt the input file, potentially using the given `CryptFile`. If `CryptFile` is not given, will fail if the key management system is not supported", GF_ARG_STRING, 0, parse_cryp, 1, ARG_IS_FUN | ARG_EMPTY),
     975             :         MP4BOX_ARG_S("set-kms", "tkID=kms_uri", "change ISMA/OMA KMS location for a given track or for all tracks if `all=` is used", 0, parse_track_action, TRAC_ACTION_SET_KMS_URI, ARG_IS_FUN),
     976             :         {0}
     977             : };
     978             : 
     979           4 : void PrintEncryptUsage()
     980             : {
     981             :         u32 i=0;
     982           4 :         gf_sys_format_help(helpout, help_flags, "# Encryption/Decryption Options\n"
     983             :         "MP4Box supports encryption and decryption of ISMA, OMA and CENC content, see [encryption filter `gpac -h cecrypt`](cecrypt).\n"
     984             :         "It requires a specific XML file called `CryptFile`, whose syntax is available at https://wiki.gpac.io/Common-Encryption\n"
     985             :         "Image files (HEIF) can also be crypted / decrypted, using CENC only.\n"
     986             :         "  \n"
     987             :         "Options:\n"
     988             :         );
     989          20 :         while (m4b_crypt_args[i].name) {
     990          12 :                 GF_GPACArg *arg = (GF_GPACArg *) &m4b_crypt_args[i];
     991          12 :                 i++;
     992          12 :                 gf_sys_print_arg(helpout, help_flags, arg, "mp4box-crypt");
     993             :         }
     994           4 : }
     995             : 
     996             : MP4BoxArg m4b_hint_args[] =
     997             : {
     998             :         MP4BOX_ARG("hint", "hint the file for RTP/RTSP", GF_ARG_BOOL, 0, &do_hint, 0, ARG_OPEN_EDIT),
     999             :         {"mtu", NULL, "specify RTP MTU (max size) in bytes (this includes 12 bytes RTP header)", "1450", NULL, GF_ARG_INT, 0, &MTUSize, 0, 0},
    1000             :         MP4BOX_ARG("copy", "copy media data to hint track rather than reference (speeds up server but takes much more space)", GF_ARG_BOOL, 0, &HintCopy, 0, 0),
    1001             :         MP4BOX_ARG_S("multi", "[maxptime]", "enable frame concatenation in RTP packets if possible (with max duration 100 ms or `maxptime` ms if given)", 0, parse_multi_rtp, 0, ARG_IS_FUN),
    1002             :         {"rate", NULL, "specify rtp rate in Hz when no default for payload", "90000", NULL, GF_ARG_INT, 0, &rtp_rate, 0, 0},
    1003             :         MP4BOX_ARG("mpeg4", "force MPEG-4 generic payload whenever possible", GF_ARG_BOOL, 0, &import_flags, GF_IMPORT_FORCE_MPEG4, ARG_BIT_MASK),
    1004             :         MP4BOX_ARG("latm", "force MPG4-LATM transport for AAC streams", GF_ARG_BOOL, 0, &hint_flags, GP_RTP_PCK_USE_LATM_AAC, ARG_BIT_MASK),
    1005             :         MP4BOX_ARG("static", "enable static RTP payload IDs whenever possible (by default, dynamic payloads are always used)", GF_ARG_BOOL, 0, &hint_flags, GP_RTP_PCK_USE_STATIC_ID, ARG_BIT_MASK),
    1006             :         MP4BOX_ARG("add-sdp", "add given SDP string to hint track (`tkID:string`) or movie (`string`)", GF_ARG_STRING, 0, parse_sdp_ext, 0, ARG_IS_FUN),
    1007             :         MP4BOX_ARG("no-offset", "signal no random offset for sequence number and timestamp (support will depend on server)", GF_ARG_BOOL, 0, &hint_no_offset, 0, 0),
    1008             :         MP4BOX_ARG("unhint", "remove all hinting information from file", GF_ARG_BOOL, 0, &remove_hint, 0, ARG_OPEN_EDIT),
    1009             :         MP4BOX_ARG("group-single", "put all tracks in a single hint group", GF_ARG_BOOL, 0, &single_group, 0, 0),
    1010             :         MP4BOX_ARG("ocr", "force all MPEG-4 streams to be synchronized (MPEG-4 Systems only)", GF_ARG_BOOL, 0, &force_ocr, 0, 0),
    1011             :         MP4BOX_ARG("rap", "signal random access points in RTP packets (MPEG-4 Systems)", GF_ARG_BOOL, 0, parse_rap_ref, 0, ARG_IS_FUN | ARG_EMPTY),
    1012             :         MP4BOX_ARG("ts", "signal AU Time Stamps in RTP packets (MPEG-4 Systems)", GF_ARG_BOOL, 0, &hint_flags, GP_RTP_PCK_SIGNAL_TS, ARG_BIT_MASK),
    1013             :         MP4BOX_ARG("size", "signal AU size in RTP packets (MPEG-4 Systems)", GF_ARG_BOOL, 0, &hint_flags, GP_RTP_PCK_SIGNAL_SIZE, ARG_BIT_MASK),
    1014             :         MP4BOX_ARG("idx", "signal AU sequence numbers in RTP packets (MPEG-4 Systems)", GF_ARG_BOOL, 0, &hint_flags, GP_RTP_PCK_SIGNAL_AU_IDX, ARG_BIT_MASK),
    1015             :         MP4BOX_ARG("iod", "prevent systems tracks embedding in IOD (MPEG-4 Systems), not compatible with [-isma]()", GF_ARG_BOOL, 0, &regular_iod, 0, 0),
    1016             :         {0}
    1017             : };
    1018             : 
    1019           4 : void PrintHintUsage()
    1020             : {
    1021             :         u32 i=0;
    1022           4 :         gf_sys_format_help(helpout, help_flags, "# Hinting Options\n"
    1023             :                 "IsoMedia hinting consists in creating special tracks in the file that contain transport protocol specific information and optionally multiplexing information. These tracks are then used by the server to create the actual packets being sent over the network, in other words they provide the server with hints on how to build packets, hence their names `hint tracks`.\n"
    1024             :                 "MP4Box supports creation of hint tracks for RTSP servers supporting these such as QuickTime Streaming Server, DarwinStreaming Server or 3GPP-compliant RTSP servers.\n"
    1025             :                 "Note: GPAC streaming tools [rtp output](rtpout) and [rtsp server](rtspout) do not use hint tracks, they use on-the-fly packetization "
    1026             :                 "from any media sources, not just MP4\n"
    1027             :                 "  \n"
    1028             :                 "Options:\n"
    1029             :         );
    1030          80 :         while (m4b_hint_args[i].name) {
    1031          72 :                 GF_GPACArg *arg = (GF_GPACArg *) &m4b_hint_args[i];
    1032          72 :                 i++;
    1033          72 :                 gf_sys_print_arg(helpout, help_flags, arg, "mp4box-hint");
    1034             :         }
    1035           4 : }
    1036             : 
    1037             : 
    1038             : MP4BoxArg m4b_extr_args[] =
    1039             : {
    1040             :         MP4BOX_ARG("raw", "extract given track in raw format when supported. Use `tkID:output=FileName` to set output file name", GF_ARG_STRING, 0, parse_track_dump, GF_EXPORT_NATIVE, ARG_IS_FUN),
    1041             :         MP4BOX_ARG("raws", "extract each sample of the given track to a file. Use `tkID:N` to extract the Nth sample", GF_ARG_STRING, 0, parse_track_dump, GF_EXPORT_RAW_SAMPLES, ARG_IS_FUN),
    1042             :         MP4BOX_ARG("nhnt", "extract given track to [NHNT](nhntr) format", GF_ARG_INT, 0, parse_track_dump, GF_EXPORT_NHNT, ARG_IS_FUN),
    1043             :         MP4BOX_ARG("nhml", "extract given track to [NHML](nhmlr) format. Use `tkID:full` for full NHML dump with all packet properties", GF_ARG_STRING, 0, parse_track_dump, GF_EXPORT_NHML, ARG_IS_FUN),
    1044             :         MP4BOX_ARG("webvtt-raw", "extract given track as raw media in WebVTT as metadata. Use `tkID:embedded` to include media data in the WebVTT file", GF_ARG_STRING, 0, parse_track_dump, GF_EXPORT_WEBVTT_META, ARG_IS_FUN),
    1045             :         MP4BOX_ARG("single", "extract given track to a new mp4 file", GF_ARG_INT, 0, parse_track_dump, GF_EXPORT_MP4, ARG_IS_FUN),
    1046             :         MP4BOX_ARG("six", "extract given track as raw media in **experimental** XML streaming instructions", GF_ARG_INT, 0, parse_track_dump, GF_EXPORT_SIX, ARG_IS_FUN),
    1047             :         MP4BOX_ARG("mux", "mux input to given destination", GF_ARG_STRING, 0, &mux_name, 0, 0),
    1048             :         MP4BOX_ARG("qcp", "same as [-raw]() but defaults to QCP file for EVRC/SMV", GF_ARG_INT, 0, parse_track_dump, GF_EXPORT_NATIVE | GF_EXPORT_USE_QCP, ARG_IS_FUN),
    1049             :         MP4BOX_ARG("saf", "remux file to SAF multiplex", GF_ARG_BOOL, 0, &do_saf, 0, 0),
    1050             :         MP4BOX_ARG("dvbhdemux", "demux DVB-H file into IP Datagrams sent on the network", GF_ARG_BOOL, 0, &dvbhdemux, 0, 0),
    1051             :         MP4BOX_ARG("raw-layer", "same as [-raw]() but skips SVC/MVC/LHVC extractors when extracting", GF_ARG_INT, 0, parse_track_dump, GF_EXPORT_NATIVE | GF_EXPORT_SVC_LAYER, ARG_IS_FUN),
    1052             :         MP4BOX_ARG("diod", "extract file IOD in raw format", GF_ARG_BOOL, 0, &dump_iod, 0, 0),
    1053             :         MP4BOX_ARG("mpd", "convert given HLS or smooth manifest (local or remote http) to MPD.  \nWarning: This is not compatible with other DASH options and does not convert associated segments", GF_ARG_STRING, 0, &do_mpd_conv, 0, 0),
    1054             :         {0}
    1055             : };
    1056             : 
    1057           4 : void PrintExtractUsage()
    1058             : {
    1059             :         u32 i=0;
    1060           4 :         gf_sys_format_help(helpout, help_flags, "# Extracting Options\n"
    1061             :         "MP4Box can be used to extract media tracks from MP4 files. If you need to convert these tracks however, please check the [filters doc](Filters).\n"
    1062             :         "  \n"
    1063             :         "Options:\n"
    1064             :         );
    1065          64 :         while (m4b_extr_args[i].name) {
    1066          56 :                 GF_GPACArg *arg = (GF_GPACArg *) &m4b_extr_args[i];
    1067          56 :                 i++;
    1068          56 :                 gf_sys_print_arg(helpout, help_flags, arg, "mp4box-extract");
    1069             :         }
    1070           4 : }
    1071             : 
    1072             : MP4BoxArg m4b_dump_args[] =
    1073             : {
    1074             :         MP4BOX_ARG("std", "dump/write to stdout and assume stdout is opened in binary mode", GF_ARG_BOOL, 0, &dump_std, 2, 0),
    1075             :         MP4BOX_ARG("stdb", "dump/write to stdout and try to reopen stdout in binary mode", GF_ARG_BOOL, 0, &dump_std, 1, 0),
    1076             :         MP4BOX_ARG("tracks", "print the number of tracks on stdout", GF_ARG_BOOL, 0, &get_nb_tracks, 0, 0),
    1077             :         MP4BOX_ARG("info", "print movie info (no parameter) or track info with specified ID", GF_ARG_STRING, 0, parse_file_info, 0, ARG_IS_FUN|ARG_EMPTY),
    1078             :         MP4BOX_ARG("infon", "print track info for given track number, 1 being the first track in the file", GF_ARG_STRING, 0, parse_file_info, 1, ARG_IS_FUN|ARG_EMPTY),
    1079             :         MP4BOX_ARG_ALT("diso", "dmp4", "dump IsoMedia file boxes in XML output", GF_ARG_BOOL, 0, &dump_isom, 1, 0),
    1080             :         MP4BOX_ARG("dxml", "dump IsoMedia file boxes and known track samples in XML output", GF_ARG_BOOL, 0, &dump_isom, 2, 0),
    1081             :         MP4BOX_ARG("disox", "dump IsoMedia file boxes except sample tables in XML output", GF_ARG_BOOL, 0, &dump_isom, 3, 0),
    1082             :         MP4BOX_ARG("keep-ods", "do not translate ISOM ODs and ESDs tags (debug purpose only)", GF_ARG_BOOL, 0, &no_odf_conf, 0, 0),
    1083             :         MP4BOX_ARG("bt", "dump scene to BT format", GF_ARG_BOOL, 0, &dump_mode, GF_SM_DUMP_BT, ARG_HAS_VALUE),
    1084             :         MP4BOX_ARG("xmt", "dump scene to XMT format", GF_ARG_BOOL, 0, &dump_mode, GF_SM_DUMP_XMTA, 0),
    1085             :         MP4BOX_ARG("wrl", "dump scene to VRML format", GF_ARG_BOOL, 0, &dump_mode, GF_SM_DUMP_VRML, 0),
    1086             :         MP4BOX_ARG("x3d", "dump scene to X3D XML format", GF_ARG_BOOL, 0, &dump_mode, GF_SM_DUMP_X3D_XML, 0),
    1087             :         MP4BOX_ARG("x3dv", "dump scene to X3D VRML format", GF_ARG_BOOL, 0, &dump_mode, GF_SM_DUMP_X3D_VRML, 0),
    1088             :         MP4BOX_ARG("lsr", "dump scene to LASeR XML (XSR) format", GF_ARG_BOOL, 0, &dump_mode, GF_SM_DUMP_LASER, 0),
    1089             :         MP4BOX_ARG("svg", "dump scene to SVG", GF_ARG_BOOL, 0, &dump_mode, GF_SM_DUMP_SVG, 0),
    1090             :         MP4BOX_ARG("drtp", "dump rtp hint samples structure to XML output", GF_ARG_BOOL, 0, &dump_rtp, 0, 0),
    1091             :         MP4BOX_ARG("dts", "print sample timing, size and position in file to text output", GF_ARG_BOOL, 0, parse_dump_ts, 0, ARG_IS_FUN),
    1092             :         MP4BOX_ARG("dtsx", "same as [-dts]() but does not print offset", GF_ARG_BOOL, 0, &dump_timestamps, 2, 0),
    1093             :         MP4BOX_ARG("dtsc", "same as [-dts]() but analyses each sample for duplicated dts/cts (__slow !__)", GF_ARG_BOOL, 0, &dump_timestamps, 3, 0),
    1094             :         MP4BOX_ARG("dtsxc", "same as [-dtsc]() but does not print offset (__slow !__)", GF_ARG_BOOL, 0, &dump_timestamps, 4, 0),
    1095             :         MP4BOX_ARG("dnal", "print NAL sample info of given track", GF_ARG_INT, 0, parse_dnal, 0, ARG_IS_FUN),
    1096             :         MP4BOX_ARG("dnalc", "print NAL sample info of given track, adding CRC for each nal", GF_ARG_INT, 0, parse_dnal, 1, ARG_IS_FUN),
    1097             :         MP4BOX_ARG("dnald", "print NAL sample info of given track without DTS and CTS info", GF_ARG_INT, 0, parse_dnal, 2, ARG_IS_FUN),
    1098             :         MP4BOX_ARG("dnalx", "print NAL sample info of given track without DTS and CTS info and adding CRC for each nal", GF_ARG_INT, 0, parse_dnal, 2|1, ARG_IS_FUN),
    1099             :         MP4BOX_ARG("sdp", "dump SDP description of hinted file", GF_ARG_BOOL, 0, &print_sdp, 0, 0),
    1100             :         MP4BOX_ARG("dsap", "dump DASH SAP cues (see -cues) for a given track", GF_ARG_INT, 0, parse_dsap, 0, ARG_IS_FUN),
    1101             :         MP4BOX_ARG("dsaps", "same as [-dsap]() but only print sample number", GF_ARG_INT, 0, parse_dsap, 1, ARG_IS_FUN),
    1102             :         MP4BOX_ARG("dsapc", "same as [-dsap]() but only print CTS", GF_ARG_INT, 0, parse_dsap, 2, ARG_IS_FUN),
    1103             :         MP4BOX_ARG("dsapd", "same as [-dsap]() but only print DTS", GF_ARG_INT, 0, parse_dsap, 3, ARG_IS_FUN),
    1104             :         MP4BOX_ARG("dsapp", "same as [-dsap]() but only print presentation time", GF_ARG_INT, 4, parse_dsap, 4, ARG_IS_FUN),
    1105             :         MP4BOX_ARG("dcr", "dump ISMACryp samples structure to XML output", GF_ARG_BOOL, 0, &dump_cr, 0, 0),
    1106             :         MP4BOX_ARG("dump-cover", "extract cover art", GF_ARG_BOOL, 0, &dump_cart, 0, 0),
    1107             :         MP4BOX_ARG("dump-chap", "extract chapter file as TTXT format", GF_ARG_BOOL, 0, &dump_chap, 1, 0),
    1108             :         MP4BOX_ARG("dump-chap-ogg", "extract chapter file as OGG format", GF_ARG_BOOL, 0, &dump_chap, 2, 0),
    1109             :         MP4BOX_ARG("dump-chap-zoom", "extract chapter file as zoom format", GF_ARG_BOOL, 0, &dump_chap, 3, 0),
    1110             :         MP4BOX_ARG_S("dump-udta", "[tkID:]4cc", "extract user data for the given 4CC. If `tkID` is given, dumps from UDTA of the given track ID, otherwise moov is used", 0, parse_dump_udta, 0, ARG_IS_FUN),
    1111             :         MP4BOX_ARG("mergevtt", "merge vtt cues while dumping", GF_ARG_BOOL, 0, &merge_vtt_cues, 0, 0),
    1112             :         MP4BOX_ARG("ttxt", "convert input subtitle to GPAC TTXT format if no parameter. Otherwise, dump given text track to GPAC TTXT format", GF_ARG_INT, 0, parse_ttxt, 0, ARG_IS_FUN),
    1113             :         MP4BOX_ARG("srt", "convert input subtitle to SRT format if no parameter. Otherwise, dump given text track to SRT format", GF_ARG_INT, 0, parse_ttxt, 1, ARG_IS_FUN),
    1114             :         MP4BOX_ARG("stat", "generate node/field statistics for scene", GF_ARG_BOOL, 0, &stat_level, 1, 0),
    1115             :         MP4BOX_ARG("stats", "generate node/field statistics per Access Unit", GF_ARG_BOOL, 0, &stat_level, 2, 0),
    1116             :         MP4BOX_ARG("statx", "generate node/field statistics for scene after each AU", GF_ARG_BOOL, 0, &stat_level, 3, 0),
    1117             :         MP4BOX_ARG("hash", "generate SHA-1 Hash of the input file", GF_ARG_BOOL, 0, &do_hash, 0, 0),
    1118             :         MP4BOX_ARG("comp", "replace with compressed version all top level box types given as parameter, formatted as `orig_4cc_1=comp_4cc_1[,orig_4cc_2=comp_4cc_2]`", GF_ARG_STRING, 0, parse_comp_box, 0, ARG_IS_FUN),
    1119             :         MP4BOX_ARG("topcount", "print to stdout the number of top-level boxes matching box types given as parameter, formatted as `4cc_1,4cc_2N`", GF_ARG_STRING, 0, parse_comp_box, 2, ARG_IS_FUN),
    1120             :         MP4BOX_ARG("topsize", "print to stdout the number of bytes of top-level boxes matching types given as parameter, formatted as `4cc_1,4cc_2N` or `all` for all boxes", GF_ARG_STRING, 0, parse_comp_box, 1, ARG_IS_FUN),
    1121             :         MP4BOX_ARG("bin", "convert input XML file using NHML bitstream syntax to binary", GF_ARG_BOOL, 0, &do_bin_xml, 0, 0),
    1122             :         MP4BOX_ARG("mpd-rip", "fetch MPD and segment to disk", GF_ARG_BOOL, 0, &do_mpd_rip, 0, 0),
    1123             :         MP4BOX_ARG_S("udp-write", "IP[:port]", "write input name to UDP (default port 2345)", GF_FS_ARG_HINT_EXPERT, &udp_dest, 0, 0),
    1124             :         MP4BOX_ARG("raw-cat", "raw concatenation of given file with input file", GF_ARG_STRING, GF_FS_ARG_HINT_EXPERT, &raw_cat, 0, 0),
    1125             :         MP4BOX_ARG("wget", "fetch resource from http(s) URL", GF_ARG_STRING, GF_FS_ARG_HINT_EXPERT, &do_wget, 0, 0),
    1126             :         MP4BOX_ARG("dm2ts", "dump timing of an input MPEG-2 TS stream sample timing", GF_ARG_BOOL, 0, &dump_m2ts, 0, 0),
    1127             :         {0}
    1128             : };
    1129             : 
    1130           4 : void PrintDumpUsage()
    1131             : {
    1132             :         u32 i=0;
    1133           4 :         gf_sys_format_help(helpout, help_flags, "# File Dumping\n"
    1134             :         "  \n"
    1135             :         "MP4Box has many dump functionalities, from simple track listing to more complete reporting of special tracks.\n"
    1136             :         "  \n"
    1137             :         "Options:\n"
    1138             :         );
    1139         220 :         while (m4b_dump_args[i].name) {
    1140         212 :                 GF_GPACArg *arg = (GF_GPACArg *) &m4b_dump_args[i];
    1141         212 :                 i++;
    1142         212 :                 gf_sys_print_arg(helpout, help_flags, arg, "mp4box-extract");
    1143             :         }
    1144           4 : }
    1145             : 
    1146             : MP4BoxArg m4b_meta_args[] =
    1147             : {
    1148             :         MP4BOX_ARG_S("set-meta", "ABCD[:tk=tkID]", "set meta box type, with `ABCD` the four char meta type (NULL or 0 to remove meta)\n"
    1149             :                 "- tk not set: use root (file) meta\n"
    1150             :                 "- tkID == 0: use moov meta\n"
    1151             :                 "- tkID != 0: use meta of given track", 0, parse_meta_args, META_ACTION_SET_TYPE, ARG_IS_FUN),
    1152             :         MP4BOX_ARG("add-item", "add resource to meta, with parameter syntax `file_path[:opt1:optN]`\n"
    1153             :                 "- file_path `this` or `self`: item is the file itself\n"
    1154             :                 "- tk=tkID: meta location (file, moov, track)\n"
    1155             :                 "- name=str: item name\n"
    1156             :                 "- type=itype: item 4cc type (not needed if mime is provided)\n"
    1157             :                 "- mime=mtype: item mime type\n"
    1158             :                 "- encoding=enctype: item content-encoding type\n"
    1159             :                 "- id=ID: item ID\n"
    1160             :                 "- ref=4cc,id: reference of type 4cc to an other item (can be set multiple times)\n"
    1161             :                 "- group=id,type: indicate the id and type of an alternate group for this item"
    1162             :                 , GF_ARG_STRING, 0, parse_meta_args, META_ACTION_ADD_ITEM, ARG_IS_FUN),
    1163             :         MP4BOX_ARG("add-image", "add the given file as HEIF image item, with parameter syntax `file_path[:opt1:optN]`. If `filepath` is omitted, source is the input MP4 file\n"
    1164             :                 "- name, id, ref: see [-add-item]()\n"
    1165             :                 "- primary: indicate that this item should be the primary item\n"
    1166             :                 "- time=t[-e][/i]: use the next sync sample after time t (float, in sec, default 0). A negative time imports ALL intra frames as items\n"
    1167             :                 " - If `e` is set (float, in sec), import all sync samples between `t` and `e`\n"
    1168             :                 " - If `i` is set (float, in sec), sets time increment between samples to import\n"
    1169             :                 "- split_tiles: for an HEVC tiled image, each tile is stored as a separate item\n"
    1170             :                 "- image-size=wxh: force setting the image size and ignoring the bitstream info, used for grid images also\n"
    1171             :                 "- rotation=a: set the rotation angle for this image to 90*a degrees anti-clockwise\n"
    1172             :                 "- mirror-axis=axis: set the mirror axis: vertical, horizontal\n"
    1173             :                 "- clap=Wn,Wd,Hn,Hd,HOn,HOd,VOn,VOd: see track clap\n"
    1174             :                 "- hidden: indicate that this image item should be hidden\n"
    1175             :                 "- icc_path: path to icc data to add as color info\n"
    1176             :                 "- alpha: indicate that the image is an alpha image (should use ref=auxl also)\n"
    1177             :                 "- tk=tkID: indicate the track ID of the source sample. If 0, uses the first video track in the file\n"
    1178             :                 "- samp=N: indicate the sample number of the source sample\n"
    1179             :                 "- ref: do not copy the data but refer to the final sample location\n"
    1180             :                 "- agrid[=AR]: creates an automatic grid from the image items present in the file, in their declaration order. The grid will **try to** have `AR` aspect ratio if specified (float), or the aspect ratio of the source otherwise. The grid will be the primary item and all other images will be hidden\n"
    1181             :                 "- any other options will be passed as options to the media importer, see [-add]()"
    1182             :                 , GF_ARG_STRING, 0, parse_meta_args, META_ACTION_ADD_IMAGE_ITEM, ARG_IS_FUN),
    1183             :         MP4BOX_ARG("add-image-grid", "create an image grid item, with parameter syntax `grid[:opt1:optN]`\n"
    1184             :                 "- image-grid-size=rxc: set the number of rows and columns of the grid\n"
    1185             :             "- any other options from [-add-image]() can be used\n", GF_ARG_STRING, 0, parse_meta_args, META_ACTION_ADD_IMAGE_GRID, ARG_IS_FUN),
    1186             :         MP4BOX_ARG_S_ALT("rem-item", "rem-image", "item_ID[:tk=tkID]", "remove resource from meta", 0, parse_meta_args, META_ACTION_REM_ITEM, ARG_IS_FUN),
    1187             :         MP4BOX_ARG_S("set-primary", "item_ID[:tk=tkID]", "set item as primary for meta", 0, parse_meta_args, META_ACTION_SET_PRIMARY_ITEM, ARG_IS_FUN),
    1188             :         MP4BOX_ARG_S("set-xml", "xml_file_path[:tk=tkID][:binary]", "set meta XML data", 0, parse_meta_args, META_ACTION_SET_XML, ARG_IS_FUN),
    1189             :         MP4BOX_ARG_S("rem-xml", "[tk=tkID]", "remove meta XML data", 0, parse_meta_args, META_ACTION_REM_XML, ARG_IS_FUN),
    1190             :         MP4BOX_ARG_S("dump-xml", "file_path[:tk=tkID]", "dump meta XML to file", 0, parse_meta_args, META_ACTION_DUMP_XML, ARG_IS_FUN),
    1191             :         MP4BOX_ARG_S("dump-item", "item_ID[:tk=tkID][:path=fileName]", "dump item to file", 0, parse_meta_args, META_ACTION_DUMP_ITEM, ARG_IS_FUN),
    1192             :         MP4BOX_ARG("package", "package input XML file into an ISO container, all media referenced except hyperlinks are added to file", GF_ARG_STRING, 0, &pack_file, 0, 0),
    1193             :         MP4BOX_ARG("mgt", "package input XML file into an MPEG-U widget with ISO container, all files contained in the current folder are added to the widget package", GF_ARG_STRING, 0, parse_mpegu, 0, ARG_IS_FUN),
    1194             :         {0}
    1195             : };
    1196             : 
    1197           4 : void PrintMetaUsage()
    1198             : {
    1199             :         u32 i=0;
    1200           4 :         gf_sys_format_help(helpout, help_flags, "# Meta and HEIF Options\n"
    1201             :         "IsoMedia files can be used as generic meta-data containers, for examples storing XML information and sample images for a movie. The resulting file may not always contain a movie as is the case with some HEIF files or MPEG-21 files.\n"
    1202             :         "  \n"
    1203             :         "These information can be stored at the file root level, as is the case for HEIF/IFF and MPEG-21 file formats, or at the movie or track level for a regular movie."
    1204             :         "  \n  \n");
    1205          56 :         while (m4b_meta_args[i].name) {
    1206          48 :                 GF_GPACArg *arg = (GF_GPACArg *) &m4b_meta_args[i];
    1207          48 :                 i++;
    1208          48 :                 gf_sys_print_arg(helpout, help_flags, arg, "mp4box-extract");
    1209             :         }
    1210           4 : }
    1211             : 
    1212             : MP4BoxArg m4b_swf_args[] =
    1213             : {
    1214             :         MP4BOX_ARG("global", "all SWF defines are placed in first scene replace rather than when needed", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_STATIC_DICT, ARG_BIT_MASK),
    1215             :         MP4BOX_ARG("no-ctrl", "use a single stream for movie control and dictionary (this will disable ActionScript)", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_SPLIT_TIMELINE, ARG_BIT_MASK_REM),
    1216             :         MP4BOX_ARG("no-text", "remove all SWF text", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_NO_TEXT, ARG_BIT_MASK),
    1217             :         MP4BOX_ARG("no-font", "remove all embedded SWF Fonts (local playback host fonts used)", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_NO_FONT, ARG_BIT_MASK),
    1218             :         MP4BOX_ARG("no-line", "remove all lines from SWF shapes", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_NO_LINE, ARG_BIT_MASK),
    1219             :         MP4BOX_ARG("no-grad", "remove all gradients from swf shapes", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_NO_GRADIENT, ARG_BIT_MASK),
    1220             :         MP4BOX_ARG("quad", "use quadratic bezier curves instead of cubic ones", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_QUAD_CURVE, ARG_BIT_MASK),
    1221             :         MP4BOX_ARG("xlp", "support for lines transparency and scalability", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_SCALABLE_LINE, ARG_BIT_MASK),
    1222             :         MP4BOX_ARG("ic2d", "use indexed curve 2D hardcoded proto", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_USE_IC2D, ARG_BIT_MASK),
    1223             :         MP4BOX_ARG("same-app", "appearance nodes are reused", GF_ARG_BOOL, 0, &swf_flags, GF_SM_SWF_REUSE_APPEARANCE, ARG_BIT_MASK),
    1224             :         MP4BOX_ARG("flatten", "complementary angle below which 2 lines are merged, value `0` means no flattening", GF_ARG_DOUBLE, 0, &swf_flatten_angle, 0, 0),
    1225             :         {0}
    1226             : };
    1227             : 
    1228           4 : void PrintSWFUsage()
    1229             : {
    1230             :         u32 i=0;
    1231           4 :         gf_sys_format_help(helpout, help_flags, "# SWF Importer Options\n"
    1232             :                 "\n"
    1233             :                 "MP4Box can import simple Macromedia Flash files (\".SWF\")\n"
    1234             :                 "You can specify a SWF input file with \'-bt\', \'-xmt\' and \'-mp4\' options\n"
    1235             :                 "  \n"
    1236             :                 "Options:\n"
    1237             :         );
    1238          52 :         while (m4b_swf_args[i].name) {
    1239          44 :                 GF_GPACArg *arg = (GF_GPACArg *) &m4b_swf_args[i];
    1240          44 :                 i++;
    1241          44 :                 gf_sys_print_arg(helpout, help_flags, arg, "mp4box-extract");
    1242             :         }
    1243           4 : }
    1244             : 
    1245             : MP4BoxArg m4b_liveenc_args[] =
    1246             : {
    1247             :         MP4BOX_ARG("live", "enable live BIFS/LASeR encoder", GF_ARG_BOOL, 0, &live_scene, 0, 0),
    1248             :         GF_DEF_ARG("dst", NULL, "destination IP", NULL, NULL, GF_ARG_STRING, 0),
    1249             :         GF_DEF_ARG("port", NULL, "destination port", "7000", NULL, GF_ARG_INT, 0),
    1250             :         GF_DEF_ARG("mtu", NULL, "path MTU for RTP packets", "1450", NULL, GF_ARG_INT, 0),
    1251             :         GF_DEF_ARG("ifce", NULL, "IP address of the physical interface to use", NULL, NULL, GF_ARG_STRING, 0),
    1252             :         GF_DEF_ARG("ttl", NULL, "time to live for multicast packets", "1", NULL, GF_ARG_INT, 0),
    1253             :         GF_DEF_ARG("sdp", NULL, "output SDP file", "session.sdp", NULL, GF_ARG_STRING, 0),
    1254             :         GF_DEF_ARG("dims", NULL, "turn on DIMS mode for SVG input", NULL, NULL, GF_ARG_BOOL, 0),
    1255             :         GF_DEF_ARG("no-rap", NULL, "disable RAP sending and carousel generation", NULL, NULL, GF_ARG_BOOL, 0),
    1256             :         GF_DEF_ARG("src", NULL, "source of scene updates", NULL, NULL, GF_ARG_STRING, 0),
    1257             :         GF_DEF_ARG("rap", NULL, "duration in ms of base carousel; you can specify the RAP period of a single ESID (not in DIMS) using `ESID=X:time`", NULL, NULL, GF_ARG_INT, 0),
    1258             :         {0}
    1259             : };
    1260             : 
    1261           4 : void PrintLiveUsage()
    1262             : {
    1263             :         u32 i=0;
    1264           4 :         gf_sys_format_help(helpout, help_flags, "# Live Scene Encoder Options\n"
    1265             :                 "The options shall be specified as òpt_name=opt_val.\n"
    1266             :                 "Options:\n"
    1267             :                 "\n"
    1268             :         );
    1269          52 :         while (m4b_liveenc_args[i].name) {
    1270          44 :                 GF_GPACArg *arg = (GF_GPACArg *) &m4b_liveenc_args[i];
    1271          44 :                 i++;
    1272          44 :                 gf_sys_print_arg(helpout, help_flags, arg, "mp4box-extract");
    1273             :         }
    1274             : 
    1275           4 :         gf_sys_format_help(helpout, help_flags, "  \n"
    1276             :                 "Runtime options:\n"
    1277             :                 "- q: quits\n"
    1278             :                 "- u: inputs some commands to be sent\n"
    1279             :                 "- U: same as u but signals the updates as critical\n"
    1280             :                 "- e: inputs some commands to be sent without being aggregated\n"
    1281             :                 "- E: same as e but signals the updates as critical\n"
    1282             :                 "- f: forces RAP sending\n"
    1283             :                 "- F: forces RAP regeneration and sending\n"
    1284             :                 "- p: dumps current scene\n"
    1285             :         );
    1286           4 : }
    1287             : 
    1288           1 : void PrintCoreUsage()
    1289             : {
    1290           1 :         gf_sys_format_help(helpout, help_flags, "# libgpac core options\n");
    1291           1 :         gf_sys_print_core_help(helpout, 0, GF_ARGMODE_ALL, 0);
    1292           1 : }
    1293             : 
    1294           3 : void PrintTags()
    1295             : {
    1296             :         u32 i = 0;
    1297             : 
    1298           3 :         gf_sys_format_help(helpout, help_flags, "# Tagging support\n"
    1299             :         "Tags are specified as a colon-separated list `tag_name=tag_value[:tag2=val2]`\n"
    1300             :         "Setting a tag with no value or value `NULL` removes the tag.\n"
    1301             :         "Special tag value `clear` (or `reset`) removes all tags.\n"
    1302             :         "Unsupported tags can be added using their four character code as a tag name, and string value will be assumed.\n"
    1303             :         "If the tag name length is 3, the prefix 0xA9 is used to create the four character code.\n"
    1304             :         "  \n"
    1305             :         "Tags can also be loaded from a text file using `-itags filename`. The file must be in UTF8 with:\n"
    1306             :         "- lines starting with `tag_name=value` specify the start of a tag\n"
    1307             :         "- other lines specify the remainder of the last declared tag\n"
    1308             :         "  \n"
    1309             :         "If tag name starts with `WM/`, the tag is added to `Xtra` box (WMA tag, string only).\n"
    1310             :         "  \n"
    1311             :         "Supported tag names, values, types, aliases:\n"
    1312             :         );
    1313             : 
    1314         189 :         while (1) {
    1315         192 :                 s32 type = gf_itags_get_type(i);
    1316         192 :                 if (type<0) break;
    1317         189 :                 const char *name = gf_itags_get_name(i);
    1318         189 :                 u32 itag = gf_itags_get_itag(i);
    1319         189 :                 gf_sys_format_help(helpout, help_flags | GF_PRINTARG_HIGHLIGHT_FIRST , "%s", name);
    1320         189 :                 gf_sys_format_help(helpout, help_flags, " (%s) ", gf_4cc_to_str(itag) );
    1321         189 :                 switch (type) {
    1322         150 :                 case GF_ITAG_STR:
    1323         150 :                         gf_sys_format_help(helpout, help_flags, "string"); break;
    1324          18 :                 case GF_ITAG_INT8:
    1325             :                 case GF_ITAG_INT16:
    1326             :                 case GF_ITAG_INT32:
    1327             :                 case GF_ITAG_INT64:
    1328          18 :                         gf_sys_format_help(helpout, help_flags, "integer"); break;
    1329           6 :                 case GF_ITAG_FRAC6:
    1330             :                 case GF_ITAG_FRAC8:
    1331           6 :                         gf_sys_format_help(helpout, help_flags, "fraction (syntax: `A/B` or `A`, B will be 0)"); break;
    1332           9 :                 case GF_ITAG_BOOL:
    1333           9 :                         gf_sys_format_help(helpout, help_flags, "bool (`yes` or `no`)"); break;
    1334           3 :                 case GF_ITAG_ID3_GENRE:
    1335           3 :                         gf_sys_format_help(helpout, help_flags, "string (ID3 genre tag)"); break;
    1336           3 :                 case GF_ITAG_FILE:
    1337           3 :                         gf_sys_format_help(helpout, help_flags, "file path"); break;
    1338             :                 }
    1339         189 :                 name = gf_itags_get_alt_name(i);
    1340         189 :                 if (name) {
    1341          75 :                         gf_sys_format_help(helpout, help_flags, " (`alias` %s)", name);
    1342             :                 }
    1343             : 
    1344         189 :                 gf_sys_format_help(helpout, help_flags, "\n");
    1345         189 :                 i++;
    1346             :         }
    1347           3 : }
    1348             : 
    1349           2 : void PrintCICP()
    1350             : {
    1351             :         u32 i;
    1352           2 :         gf_sys_format_help(helpout, help_flags, "# Video CICP (ISO/IEC 23091-2) Constants\n");
    1353           2 :         gf_sys_format_help(helpout, help_flags, "CICP Color Primaries:\n");
    1354          48 :         for (i=0; i<GF_CICP_PRIM_LAST; i++) {
    1355          46 :                 const char *name = gf_cicp_color_primaries_name(i);
    1356          46 :                 if (!name || !strcmp(name, "unknwon")) continue;
    1357          28 :                 gf_sys_format_help(helpout, help_flags, " - `%s` (value %d)\n", name, i);
    1358             :         }
    1359           2 :         gf_sys_format_help(helpout, help_flags, "  \nCICP Color Transfer Characteristics:\n");
    1360          40 :         for (i=0; i<GF_CICP_TRANSFER_LAST; i++) {
    1361          38 :                 const char *name = gf_cicp_color_transfer_name(i);
    1362          38 :                 if (!name) continue;
    1363          38 :                 gf_sys_format_help(helpout, help_flags, " - `%s` (value %d)\n", name, i);
    1364             :         }
    1365           2 :         gf_sys_format_help(helpout, help_flags, "  \nCICP Color Matrix Coefficients:\n");
    1366          26 :         for (i=0; i<GF_CICP_MX_LAST; i++) {
    1367          24 :                 const char *name = gf_cicp_color_matrix_name(i);
    1368          24 :                 if (!name) continue;
    1369          24 :                 gf_sys_format_help(helpout, help_flags, " - `%s` (value %d)\n", name, i);
    1370             :         }
    1371           2 : }
    1372             : 
    1373             : MP4BoxArg m4b_usage_args[] =
    1374             : {
    1375             :         MP4BOX_ARG("h", "print help\n"
    1376             :                 "- general: general options help\n"
    1377             :                 "- hint: hinting options help\n"
    1378             :                 "- dash: DASH segmenter help\n"
    1379             :                 "- split: split options help\n"
    1380             :                 "- import: import options help\n"
    1381             :                 "- encode: scene descrription encoding options help\n"
    1382             :                 "- meta: meta (HEIF, MPEG-21) handling options help\n"
    1383             :                 "- extract: extraction options help\n"
    1384             :                 "- dump: dump options help\n"
    1385             :                 "- swf: Flash (SWF) options help\n"
    1386             :                 "- crypt: ISMA E&A options help\n"
    1387             :                 "- format: supported formats help\n"
    1388             :                 "- live: BIFS streamer help\n"
    1389             :                 "- core: libgpac core options\n"
    1390             :                 "- all: print all the above help screens\n"
    1391             :                 "- opts: print all options\n"
    1392             :                 "- tags: print supported iTunes tags\n"
    1393             :                 "- cicp: print various CICP code points\n"
    1394             :                 "- VAL: search for option named `VAL` (without `-` or `--`) in MP4Box, libgpac core and all filters\n"
    1395             :                 , GF_ARG_STRING, 0, parse_help, 0, ARG_IS_FUN | ARG_EMPTY | ARG_PUSH_SYSARGS),
    1396             :         MP4BOX_ARG("hx", "look for given string in all possible options"
    1397             :                 , GF_ARG_STRING, 0, parse_help, 1, ARG_IS_FUN),
    1398             :         MP4BOX_ARG("nodes", "list supported MPEG4 nodes", GF_ARG_BOOL, 0, PrintBuiltInNodes, 0, ARG_IS_FUN),
    1399             :         MP4BOX_ARG("nodex", "list supported MPEG4 nodes and print nodes", GF_ARG_BOOL, 0, PrintBuiltInNodes, 1, ARG_IS_FUN),
    1400             :         MP4BOX_ARG("node", "get given MPEG4 node syntax and QP infolist", GF_ARG_STRING, 0, PrintNode, 0, ARG_IS_FUN),
    1401             :         MP4BOX_ARG("xnodes", "list supported X3D nodes", GF_ARG_BOOL, 0, PrintBuiltInNodes, 2, ARG_IS_FUN),
    1402             :         MP4BOX_ARG("xnodex", "list supported X3D nodes and print nodes", GF_ARG_BOOL, 0, PrintBuiltInNodes, 3, ARG_IS_FUN),
    1403             :         MP4BOX_ARG("xnode", "get given X3D node syntax", GF_ARG_STRING, 0, PrintNode, 1, ARG_IS_FUN),
    1404             :         MP4BOX_ARG("snodes", "list supported SVG nodes", GF_ARG_BOOL, 0, PrintBuiltInNodes, 4, ARG_IS_FUN),
    1405             :         MP4BOX_ARG("languages", "list supported ISO 639 languages", GF_ARG_BOOL, 0, PrintLanguages, 0, ARG_IS_FUN),
    1406             :         MP4BOX_ARG("boxes", "list all supported ISOBMF boxes and their syntax", GF_ARG_BOOL, 0, PrintBuiltInBoxes, 0, ARG_IS_FUN),
    1407             :         MP4BOX_ARG("boxcov", "perform coverage of box IO coode", GF_ARG_BOOL, GF_ARG_HINT_HIDE, PrintBuiltInBoxes, 1, ARG_IS_FUN|ARG_PUSH_SYSARGS),
    1408             :         MP4BOX_ARG("fstat", "print filter session statistics (import/export/encrypt/decrypt/dashing)", GF_ARG_BOOL, 0, &fs_dump_flags, 1, ARG_BIT_MASK),
    1409             :         MP4BOX_ARG("fgraph", "print filter session graph (import/export/encrypt/decrypt/dashing)", GF_ARG_BOOL, 0, &fs_dump_flags, 2, ARG_BIT_MASK),
    1410             :         MP4BOX_ARG("v", "verbose mode", GF_ARG_BOOL, 0, &verbose, 0, ARG_INT_INC),
    1411             :         MP4BOX_ARG("version", "get build version", GF_ARG_BOOL, 0, print_version, 0, ARG_IS_FUN),
    1412             :         MP4BOX_ARG("genmd", "generate MD doc", GF_ARG_BOOL, GF_ARG_HINT_HIDE, parse_gendoc, 0, ARG_IS_FUN),
    1413             :         MP4BOX_ARG("genman", "generate man doc", GF_ARG_BOOL, GF_ARG_HINT_HIDE, parse_gendoc, 1, ARG_IS_FUN),
    1414             :         MP4BOX_ARG_S("--", "INPUT", "escape option if INPUT starts with `-` character", 0, NULL, 0, 0),
    1415             :         {0}
    1416             : };
    1417             : 
    1418           3 : void PrintUsage()
    1419             : {
    1420             :         u32 i=0;
    1421           3 :         gf_sys_format_help(helpout, help_flags, "MP4Box [option] input [option]\n"
    1422             :                 "  \n"
    1423             :                 "# General Options:\n"
    1424             :         );
    1425          63 :         while (m4b_usage_args[i].name) {
    1426          57 :                 GF_GPACArg *arg = (GF_GPACArg *) &m4b_usage_args[i];
    1427          57 :                 i++;
    1428          57 :                 gf_sys_print_arg(helpout, help_flags, arg, "mp4box-general");
    1429             :         }
    1430           3 : }
    1431             : 
    1432             : /*
    1433             :  *              END OF ARGS PARSING AND HELP
    1434             :  */
    1435             : 
    1436             : 
    1437             : enum
    1438             : {
    1439             :         SEARCH_ARG_EXACT,
    1440             :         SEARCH_ARG_CLOSE,
    1441             :         SEARCH_DESC,
    1442             : };
    1443             : 
    1444        1336 : static Bool strstr_nocase(const char *text, const char *subtext, u32 subtext_len)
    1445             : {
    1446        1336 :         if (!*text || !subtext || !subtext_len)
    1447             :                 return GF_FALSE;
    1448             : 
    1449      112202 :         while (*text) {
    1450      110871 :                 if (tolower(*text) == *subtext) {
    1451        1914 :                         if (!strnicmp(text, subtext, subtext_len))
    1452             :                                 return GF_TRUE;
    1453             : 
    1454             :                 }
    1455      110866 :                 text++;
    1456             :         }
    1457             :         return GF_FALSE;
    1458             : }
    1459             : 
    1460          45 : static u32 PrintHelpForArgs(char *arg_name, MP4BoxArg *args, GF_GPACArg *_args, u32 search_type)
    1461             : {
    1462             :         u32 res=0;
    1463             :         u32 i=0;
    1464          45 :         u32 alen = (u32) strlen(arg_name);
    1465             : 
    1466             :         while (1) {
    1467             :                 u32 flags=0;
    1468             :                 GF_GPACArg *arg;
    1469             :                 GF_GPACArg an_arg;
    1470             :                 Bool do_match = GF_FALSE;
    1471        1518 :                 if (args) {
    1472        1245 :                         if (!args[i].name)
    1473             :                                 break;
    1474             :                         arg = (GF_GPACArg *) &args[i];
    1475             :                 } else {
    1476         273 :                         if (!_args[i].name)
    1477             :                                 break;
    1478             :                         arg = &_args[i];
    1479             :                 }
    1480             : 
    1481        1473 :                 if (args == m4b_imp_fileopt_args) {
    1482             :                         flags = GF_PRINTARG_COLON;
    1483         297 :                         if (!strncmp(arg_name, arg->name, alen) && ((arg->name[alen]==0) || (arg->name[alen]=='=')))
    1484             :                                 do_match = GF_TRUE;
    1485             :                 }
    1486        1176 :                 else if (!strcmp(arg_name, arg->name))
    1487             :                         do_match = GF_TRUE;
    1488        1176 :                 else if ((alen < (u32) strlen(arg->name)) && (arg->name[alen]==' ') && !strncmp(arg_name, arg->name, alen))
    1489             :                         do_match = GF_TRUE;
    1490             : 
    1491        1473 :                 if (arg_name[0] == '@')
    1492             :                         do_match = GF_TRUE;
    1493             : 
    1494        1473 :                 if ((search_type==SEARCH_ARG_EXACT) && !do_match) {
    1495           0 :                         i++;
    1496        1462 :                         continue;
    1497             :                 }
    1498        1473 :                 if ((search_type==SEARCH_ARG_CLOSE) && !gf_sys_word_match(arg_name, arg->name)) {
    1499         972 :                         i++;
    1500         972 :                         continue;
    1501             :                 }
    1502         501 :                 if ((search_type==SEARCH_DESC) && !strstr_nocase(arg->description, arg_name, alen)) {
    1503         490 :                         i++;
    1504         490 :                         continue;
    1505             :                 }
    1506             : 
    1507          11 :                 an_arg = *arg;
    1508          11 :                 if (search_type!=SEARCH_ARG_EXACT) {
    1509          11 :                         an_arg.description = NULL;
    1510          11 :                         an_arg.type = GF_ARG_BOOL;
    1511             :                 }
    1512          11 :                 gf_sys_print_arg(helpout, flags, (GF_GPACArg *) &an_arg, "");
    1513          11 :                 res++;
    1514          11 :                 i++;
    1515             :         }
    1516          45 :         return res;
    1517             : }
    1518           3 : static Bool PrintHelpArg(char *arg_name, u32 search_type, GF_FilterSession *fs)
    1519             : {
    1520             :         Bool first=GF_TRUE;
    1521             :         GF_GPACArg an_arg;
    1522             :         u32 i, count;
    1523             :         u32 res = 0;
    1524           3 :         u32 alen = (u32) strlen(arg_name);
    1525           3 :         res += PrintHelpForArgs(arg_name, m4b_gen_args, NULL, search_type);
    1526           3 :         res += PrintHelpForArgs(arg_name, m4b_split_args, NULL, search_type);
    1527           3 :         res += PrintHelpForArgs(arg_name, m4b_dash_args, NULL, search_type);
    1528           3 :         res += PrintHelpForArgs(arg_name, m4b_imp_args, NULL, search_type);
    1529           3 :         res += PrintHelpForArgs(arg_name, m4b_imp_fileopt_args, NULL, search_type);
    1530           3 :         res += PrintHelpForArgs(arg_name, m4b_senc_args, NULL, search_type);
    1531           3 :         res += PrintHelpForArgs(arg_name, m4b_crypt_args, NULL, search_type);
    1532           3 :         res += PrintHelpForArgs(arg_name, m4b_hint_args, NULL, search_type);
    1533           3 :         res += PrintHelpForArgs(arg_name, m4b_extr_args, NULL, search_type);
    1534           3 :         res += PrintHelpForArgs(arg_name, m4b_dump_args, NULL, search_type);
    1535           3 :         res += PrintHelpForArgs(arg_name, m4b_meta_args, NULL, search_type);
    1536           3 :         res += PrintHelpForArgs(arg_name, m4b_swf_args, NULL, search_type);
    1537           3 :         res += PrintHelpForArgs(arg_name, m4b_liveenc_args, NULL, search_type);
    1538           3 :         res += PrintHelpForArgs(arg_name, m4b_usage_args, NULL, search_type);
    1539           3 :         res += PrintHelpForArgs(arg_name, NULL, (GF_GPACArg *) gf_sys_get_options(), search_type);
    1540             : 
    1541           3 :         if (!fs) return res;
    1542             : 
    1543             :         memset(&an_arg, 0, sizeof(GF_GPACArg));
    1544           3 :         count = gf_fs_filters_registers_count(fs);
    1545         315 :         for (i=0; i<count; i++) {
    1546             :                 u32 j=0;
    1547         312 :                 const GF_FilterRegister *reg = gf_fs_get_filter_register(fs, i);
    1548             : 
    1549        3159 :                 while (reg->args) {
    1550             :                         u32 len;
    1551        2808 :                         const GF_FilterArgs *arg = &reg->args[j];
    1552        2808 :                         if (!arg || !arg->arg_name) break;
    1553        2535 :                         j++;
    1554        2535 :                         if ((search_type==SEARCH_ARG_EXACT) && strcmp(arg->arg_name, arg_name)) continue;
    1555             : 
    1556        2535 :                         if ((search_type==SEARCH_ARG_CLOSE) && !gf_sys_word_match(arg->arg_name, arg_name)) continue;
    1557             : 
    1558         867 :                         if (search_type==SEARCH_DESC) {
    1559         845 :                                 if (!strstr_nocase(arg->arg_desc, arg_name, alen)) continue;
    1560             :                         }
    1561             : 
    1562          26 :                         an_arg.name = arg->arg_name;
    1563          26 :                         if (search_type==SEARCH_ARG_EXACT) {
    1564           0 :                                 an_arg.description = arg->arg_desc;
    1565           0 :                                 switch (arg->arg_type) {
    1566           0 :                                 case GF_PROP_BOOL:
    1567           0 :                                         an_arg.type = GF_ARG_BOOL;
    1568           0 :                                         break;
    1569           0 :                                 case GF_PROP_UINT:
    1570             :                                 case GF_PROP_SINT:
    1571           0 :                                         an_arg.type = GF_ARG_INT;
    1572           0 :                                         break;
    1573           0 :                                 case GF_PROP_DOUBLE:
    1574           0 :                                         an_arg.type = GF_ARG_DOUBLE;
    1575           0 :                                         break;
    1576           0 :                                 case GF_PROP_STRING_LIST:
    1577             :                                 case GF_PROP_UINT_LIST:
    1578             :                                 case GF_PROP_SINT_LIST:
    1579             :                                 case GF_PROP_VEC2I_LIST:
    1580           0 :                                         an_arg.type = GF_ARG_STRINGS;
    1581           0 :                                         break;
    1582           0 :                                 case GF_PROP_4CC:
    1583           0 :                                         an_arg.type = GF_ARG_4CC;
    1584           0 :                                         break;
    1585           0 :                                 case GF_PROP_4CC_LIST:
    1586           0 :                                         an_arg.type = GF_ARG_4CCS;
    1587           0 :                                         break;
    1588           0 :                                 default:
    1589           0 :                                         an_arg.type = GF_ARG_STRING;
    1590           0 :                                         break;
    1591             :                                 }
    1592           0 :                                 if (first) {
    1593             :                                         first = GF_FALSE;
    1594           0 :                                         gf_sys_format_help(helpout, 0, "\nGlobal filter session arguments. Syntax is `--arg` or `--arg=VAL`. `[F]` indicates filter name. See `gpac -h` and `gpac -h F` for more info.\n");
    1595             :                                 }
    1596           0 :                                 fprintf(helpout, "[%s]", reg->name);
    1597           0 :                                 len = (u32)strlen(reg->name);
    1598           0 :                                 while (len<10) {
    1599           0 :                                         len++;
    1600           0 :                                         fprintf(helpout, " ");
    1601             :                                 }
    1602           0 :                                 fprintf(helpout, " ");
    1603             :                         }
    1604             : 
    1605          26 :                         gf_sys_print_arg(helpout, GF_PRINTARG_ADD_DASH, &an_arg, "TEST");
    1606          26 :                         res++;
    1607             :                 }
    1608             :         }
    1609           3 :         if (res) return GF_TRUE;
    1610           0 :         return GF_FALSE;
    1611             : }
    1612             : 
    1613           3 : static void PrintHelp(char *arg_name, Bool search_desc, Bool no_match)
    1614             : {
    1615             :         GF_FilterSession *fs;
    1616             :         Bool res;
    1617             : 
    1618           3 :         fs = gf_fs_new_defaults(0);
    1619             : 
    1620           3 :         if (arg_name[0]=='-')
    1621           2 :                 arg_name++;
    1622             : 
    1623           3 :         if (search_desc) {
    1624           1 :                 char *_arg_name = gf_strdup(arg_name);
    1625           1 :                 strlwr(_arg_name);
    1626           1 :                 GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("Possible options mentionning `%s`:\n", arg_name));
    1627           1 :                 PrintHelpArg(_arg_name, SEARCH_DESC, fs);
    1628           1 :                 gf_free(_arg_name);
    1629             :         } else {
    1630           2 :                 res = no_match ? GF_FALSE : PrintHelpArg(arg_name, SEARCH_ARG_EXACT, fs);
    1631           0 :                 if (!res) {
    1632           2 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_APP, ("Option -%s unknown, please check usage.\n", arg_name));
    1633           2 :                         GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("Possible options are:\n"));
    1634             : 
    1635           2 :                         PrintHelpArg(arg_name, SEARCH_ARG_CLOSE, fs);
    1636             :                 }
    1637             :         }
    1638           3 :         if (fs)
    1639           3 :                 gf_fs_del(fs);
    1640           3 : }
    1641             : 
    1642             : 
    1643           0 : u32 parse_sdp_ext(char *arg_val, u32 param)
    1644             : {
    1645             :         char *id;
    1646           0 :         sdp_lines = gf_realloc(sdp_lines, sizeof(SDPLine) * (nb_sdp_ex + 1));
    1647           0 :         if (!sdp_lines) return 2;
    1648           0 :         id = strchr(arg_val, ':');
    1649           0 :         if (id) {
    1650           0 :                 id[0] = 0;
    1651           0 :                 if (sscanf(arg_val, "%u", &sdp_lines[0].trackID) == 1) {
    1652           0 :                         id[0] = ':';
    1653           0 :                         sdp_lines[nb_sdp_ex].line = id + 1;
    1654             :                 }
    1655             :                 else {
    1656           0 :                         id[0] = ':';
    1657           0 :                         sdp_lines[nb_sdp_ex].line = arg_val;
    1658           0 :                         sdp_lines[nb_sdp_ex].trackID = 0;
    1659             :                 }
    1660             :         }
    1661             :         else {
    1662           0 :                 sdp_lines[nb_sdp_ex].line = arg_val;
    1663           0 :                 sdp_lines[nb_sdp_ex].trackID = 0;
    1664             :         }
    1665           0 :         open_edit = GF_TRUE;
    1666           0 :         nb_sdp_ex++;
    1667           0 :         return GF_FALSE;
    1668             : }
    1669             : 
    1670             : 
    1671             : #ifndef GPAC_DISABLE_ISOM_WRITE
    1672         122 : static u32 parse_meta_args(char *opts, MetaActionType act_type)
    1673             : {
    1674             :         MetaAction *meta;
    1675             : 
    1676         122 :         metas = gf_realloc(metas, sizeof(MetaAction) * (nb_meta_act + 1));
    1677         122 :         if (!metas) return 2;
    1678         122 :         meta = &metas[nb_meta_act];
    1679         122 :         nb_meta_act ++;
    1680             : 
    1681             :         memset(meta, 0, sizeof(MetaAction));
    1682         122 :         meta->act_type = act_type;
    1683         122 :         meta->trackID = 0;
    1684         122 :         meta->root_meta = 1;
    1685         122 :         open_edit = GF_TRUE;
    1686             : 
    1687         122 :         if (!opts) return 2;
    1688             : 
    1689         122 :         if (act_type == META_ACTION_ADD_IMAGE_ITEM)
    1690          94 :                 has_add_image = GF_TRUE;
    1691             : 
    1692         218 :         while (1) {
    1693             :                 char *next;
    1694             :                 char *szSlot;
    1695         340 :                 if (!opts || !opts[0]) return 0;
    1696         340 :                 if (opts[0]==':') opts += 1;
    1697             : 
    1698             :                 szSlot = opts;
    1699         340 :                 next = gf_url_colon_suffix(opts);
    1700         340 :                 if (next) next[0] = 0;
    1701             : 
    1702         340 :                 if (!strnicmp(szSlot, "tk=", 3)) {
    1703           1 :                         sscanf(szSlot, "tk=%u", &meta->trackID);
    1704           1 :                         meta->root_meta = 0;
    1705             :                 }
    1706         339 :                 else if (!strnicmp(szSlot, "id=", 3)) {
    1707         114 :                         meta->item_id = atoi(szSlot+3);
    1708             :                 }
    1709         282 :                 else if (!strnicmp(szSlot, "type=", 5)) {
    1710           0 :                         meta->item_type = GF_4CC(szSlot[5], szSlot[6], szSlot[7], szSlot[8]);
    1711             :                 }
    1712             :                 //"ref" (without '=') is for data reference, "ref=" is for item references
    1713         282 :                 else if (!strnicmp(szSlot, "ref=", 4)) {
    1714             :                         char type[5];
    1715             :                         MetaRef *ref;
    1716          37 :                         if (!meta->item_refs) {
    1717           8 :                                 meta->item_refs = gf_list_new();
    1718           8 :                                 if (!meta->item_refs) return 2;
    1719             :                         }
    1720          37 :                         GF_SAFEALLOC(ref, MetaRef);
    1721          37 :                         if (!ref) return 2;
    1722          37 :                         sscanf(szSlot, "ref=%4s,%u", type, &(ref->ref_item_id));
    1723          37 :                         ref->ref_type = GF_4CC(type[0], type[1], type[2], type[3]);
    1724          37 :                         gf_list_add(meta->item_refs, ref);
    1725             :                 }
    1726         245 :                 else if (!strnicmp(szSlot, "name=", 5)) {
    1727           2 :                         meta->szName = gf_strdup(szSlot+5);
    1728             :                 }
    1729         243 :                 else if (!strnicmp(szSlot, "path=", 5)) {
    1730           5 :                         meta->szPath = gf_strdup(szSlot+5);
    1731             :                 }
    1732         238 :                 else if (!strnicmp(szSlot, "mime=", 5)) {
    1733           4 :                         meta->item_type = GF_META_ITEM_TYPE_MIME;
    1734           4 :                         meta->mime_type = gf_strdup(szSlot+5);
    1735             :                 }
    1736         234 :                 else if (!strnicmp(szSlot, "encoding=", 9)) {
    1737           0 :                         meta->enc_type = gf_strdup(szSlot+9);
    1738             :                 }
    1739         234 :                 else if (!strnicmp(szSlot, "image-size=", 11)) {
    1740           7 :                         if (!meta->image_props) {
    1741           3 :                                 GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties);
    1742           3 :                                 if (!meta->image_props) return 2;
    1743             :                         }
    1744           7 :                         sscanf(szSlot+11, "%dx%d", &meta->image_props->width, &meta->image_props->height);
    1745             :                 }
    1746         227 :                 else if (!strnicmp(szSlot, "image-grid-size=", 16)) {
    1747           7 :                         if (!meta->image_props) {
    1748           0 :                                 GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties);
    1749             :                         }
    1750           7 :                         sscanf(szSlot+16, "%dx%d", &meta->image_props->num_grid_rows, &meta->image_props->num_grid_columns);
    1751             :                 }
    1752         220 :                 else if (!strnicmp(szSlot, "image-pasp=", 11)) {
    1753           0 :                         if (!meta->image_props) {
    1754           0 :                                 GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties);
    1755           0 :                                 if (!meta->image_props) return 2;
    1756             :                         }
    1757           0 :                         sscanf(szSlot+11, "%dx%d", &meta->image_props->hSpacing, &meta->image_props->vSpacing);
    1758             :                 }
    1759         220 :                 else if (!strnicmp(szSlot, "image-rloc=", 11)) {
    1760           0 :                         if (!meta->image_props) {
    1761           0 :                                 GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties);
    1762           0 :                                 if (!meta->image_props) return 2;
    1763             :                         }
    1764           0 :                         sscanf(szSlot+11, "%dx%d", &meta->image_props->hOffset, &meta->image_props->vOffset);
    1765             :                 }
    1766         220 :                 else if (!strnicmp(szSlot, "rotation=", 9)) {
    1767          12 :                         if (!meta->image_props) {
    1768           9 :                                 GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties);
    1769           9 :                                 if (!meta->image_props) return 2;
    1770             :                         }
    1771          24 :                         meta->image_props->angle = atoi(szSlot+9);
    1772             :                 }
    1773         208 :                 else if (!strnicmp(szSlot, "mirror-axis=", 12)) {
    1774           9 :                         if (!meta->image_props) {
    1775           5 :                                 GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties);
    1776           5 :                                 if (!meta->image_props) return 2;
    1777             :                         }
    1778           9 :                         meta->image_props->mirror = (!strnicmp(szSlot+12, "vertical", 8) ? 1 : 2);
    1779             :                 }
    1780         199 :                 else if (!strnicmp(szSlot, "clap=", 5)) {
    1781          10 :                         if (!meta->image_props) {
    1782           6 :                                 GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties);
    1783           6 :                                 if (!meta->image_props) return 2;
    1784             :                         }
    1785          10 :                         sscanf(szSlot + 5, "%d,%d,%d,%d,%d,%d,%d,%d", &meta->image_props->clap_wnum, &meta->image_props->clap_wden,
    1786             :                                            &meta->image_props->clap_hnum, &meta->image_props->clap_hden,
    1787             :                                            &meta->image_props->clap_honum, &meta->image_props->clap_hoden,
    1788          10 :                                            &meta->image_props->clap_vonum, &meta->image_props->clap_voden);
    1789             :                 }
    1790         189 :                 else if (!stricmp(szSlot, "hidden")) {
    1791           2 :                         if (!meta->image_props) {
    1792           1 :                                 GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties);
    1793           1 :                                 if (!meta->image_props) return 2;
    1794             :                         }
    1795           2 :                         meta->image_props->hidden = GF_TRUE;
    1796             :                 }
    1797         187 :                 else if (!stricmp(szSlot, "alpha")) {
    1798           1 :                         if (!meta->image_props) {
    1799           1 :                                 GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties);
    1800           1 :                                 if (!meta->image_props) return 2;
    1801             :                         }
    1802           1 :                         meta->image_props->alpha = GF_TRUE;
    1803             :                 }
    1804             :                 //"ref" (without '=') is for data reference, "ref=" is for item references
    1805         186 :                 else if (!stricmp(szSlot, "ref")) {
    1806           1 :                         if (!meta->image_props) {
    1807           1 :                                 GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties);
    1808           1 :                                 if (!meta->image_props) return 2;
    1809             :                         }
    1810           1 :                         meta->image_props->use_reference = GF_TRUE;
    1811             :                 }
    1812         185 :                 else if (!strnicmp(szSlot, "time=", 5)) {
    1813          27 :                         Float s=0, e=0, step=0;
    1814          27 :                         if (!meta->image_props) {
    1815          27 :                                 GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties);
    1816          27 :                                 if (!meta->image_props) return 2;
    1817             :                         }
    1818          27 :                         if (sscanf(szSlot+5, "%f-%f/%f", &s, &e, &step)==3) {
    1819           1 :                                 meta->image_props->time = s;
    1820           1 :                                 meta->image_props->end_time = e;
    1821           1 :                                 meta->image_props->step_time = step;
    1822          26 :                         } else if (sscanf(szSlot+5, "%f-%f", &s, &e)==2) {
    1823           3 :                                 meta->image_props->time = s;
    1824           3 :                                 meta->image_props->end_time = e;
    1825          23 :                         } else if (sscanf(szSlot+5, "%f/%f", &s, &step)==2) {
    1826           1 :                                 meta->image_props->time = s;
    1827           1 :                                 meta->image_props->step_time = step;
    1828          22 :                         } else if (sscanf(szSlot+5, "%f", &s)==1) {
    1829          22 :                                 meta->image_props->time = s;
    1830             :                         }
    1831             :                 }
    1832         158 :                 else if (!strnicmp(szSlot, "samp=", 5)) {
    1833           5 :                         if (!meta->image_props) {
    1834           4 :                                 GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties);
    1835           4 :                                 if (!meta->image_props) return 2;
    1836             :                         }
    1837          10 :                         meta->image_props->sample_num = atoi(szSlot+5);
    1838           5 :                         meta->root_meta = 1;
    1839             :                 }
    1840         153 :                 else if (!strnicmp(szSlot, "group=", 6)) {
    1841             :                         char type[5];
    1842           0 :                         sscanf(szSlot, "group=%4s,%u", type, &meta->group_id);
    1843           0 :                         meta->group_type = GF_4CC(type[0], type[1], type[2], type[3]);
    1844             :                 }
    1845         153 :                 else if (!stricmp(szSlot, "split_tiles")) {
    1846           1 :                         if (!meta->image_props) {
    1847           1 :                                 GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties);
    1848           1 :                                 if (!meta->image_props) return 2;
    1849             :                         }
    1850           1 :                         meta->image_props->tile_mode = TILE_ITEM_ALL_BASE;
    1851             :                 }
    1852         152 :                 else if (!stricmp(szSlot, "dref")) {
    1853           0 :                         meta->use_dref = 1;
    1854             :                 }
    1855         152 :                 else if (!stricmp(szSlot, "primary")) {
    1856          28 :                         meta->primary = 1;
    1857             :                 }
    1858         124 :                 else if (!stricmp(szSlot, "binary")) {
    1859           0 :                         if (meta->act_type==META_ACTION_SET_XML) meta->act_type=META_ACTION_SET_BINARY_XML;
    1860             :                 }
    1861         124 :                 else if (!strnicmp(szSlot, "icc_path=", 9)) {
    1862           0 :                         if (!meta->image_props) {
    1863           0 :                                 GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties);
    1864           0 :                                 if (!meta->image_props) return 2;
    1865             :                         }
    1866           0 :                         strcpy(meta->image_props->iccPath, szSlot+9);
    1867             :                 }
    1868         124 :                 else if (!stricmp(szSlot, "agrid") || !strnicmp(szSlot, "agrid=", 6)) {
    1869           2 :                         if (!meta->image_props) {
    1870           2 :                                 GF_SAFEALLOC(meta->image_props, GF_ImageItemProperties);
    1871           2 :                                 if (!meta->image_props) return 2;
    1872             :                         }
    1873           2 :                         meta->image_props->auto_grid = GF_TRUE;
    1874           2 :                         if (!strnicmp(szSlot, "agrid=", 6))
    1875           2 :                                 meta->image_props->auto_grid_ratio = atof(szSlot+6);
    1876             :                 }
    1877         122 :                 else if (!strchr(szSlot, '=')) {
    1878         117 :                         switch (meta->act_type) {
    1879           4 :                         case META_ACTION_SET_TYPE:
    1880           4 :                                 if (!stricmp(szSlot, "null") || !stricmp(szSlot, "0")) meta->meta_4cc = 0;
    1881           4 :                                 else meta->meta_4cc = GF_4CC(szSlot[0], szSlot[1], szSlot[2], szSlot[3]);
    1882             :                                 break;
    1883          97 :                         case META_ACTION_ADD_ITEM:
    1884             :                         case META_ACTION_ADD_IMAGE_ITEM:
    1885             :                         case META_ACTION_SET_XML:
    1886             :                         case META_ACTION_DUMP_XML:
    1887          97 :                                 if (!strncmp(szSlot, "dopt", 4) || !strncmp(szSlot, "sopt", 4) || !strncmp(szSlot, "@", 1)) {
    1888           1 :                                         if (next) next[0]=':';
    1889             :                                         next=NULL;
    1890             :                                 }
    1891             :                                 //cat as -add arg
    1892          97 :                                 gf_dynstrcat(&meta->szPath, szSlot, ":");
    1893          97 :                                 if (!meta->szPath) return 2;
    1894             :                                 break;
    1895             :                         case META_ACTION_REM_ITEM:
    1896             :                         case META_ACTION_SET_PRIMARY_ITEM:
    1897             :                         case META_ACTION_DUMP_ITEM:
    1898           9 :                                 meta->item_id = atoi(szSlot);
    1899           9 :                                 break;
    1900             :                         default:
    1901             :                                 break;
    1902             :                         }
    1903           5 :                 }
    1904         340 :                 if (!next) break;
    1905         218 :                 opts += strlen(szSlot);
    1906         218 :                 next[0] = ':';
    1907             :         }
    1908             :         return 0;
    1909             : }
    1910             : #endif //GPAC_DISABLE_ISOM_WRITE
    1911             : 
    1912             : 
    1913             : #ifndef GPAC_DISABLE_ISOM_WRITE
    1914           4 : static Bool parse_tsel_args(char *opts, TSELActionType act)
    1915             : {
    1916             :         GF_ISOTrackID refTrackID = 0;
    1917             :         Bool has_switch_id;
    1918             :         u32 switch_id = 0;
    1919             :         u32 criteria[30];
    1920             :         u32 nb_criteria = 0;
    1921             :         TSELAction *tsel_act;
    1922             :         char szSlot[1024];
    1923             : 
    1924             :         has_switch_id = 0;
    1925             : 
    1926           4 :         if (!opts) return 0;
    1927          10 :         while (1) {
    1928             :                 char *next;
    1929          14 :                 if (!opts || !opts[0]) return 0;
    1930          10 :                 if (opts[0]==':') opts += 1;
    1931             :                 strcpy(szSlot, opts);
    1932          10 :                 next = gf_url_colon_suffix(szSlot);
    1933          10 :                 if (next) next[0] = 0;
    1934             : 
    1935             : 
    1936          10 :                 if (!strnicmp(szSlot, "refTrack=", 9)) refTrackID = atoi(szSlot+9);
    1937          10 :                 else if (!strnicmp(szSlot, "switchID=", 9)) {
    1938           2 :                         if (atoi(szSlot+9)<0) {
    1939             :                                 switch_id = 0;
    1940             :                                 has_switch_id = 0;
    1941             :                         } else {
    1942           2 :                                 switch_id = atoi(szSlot+9);
    1943             :                                 has_switch_id = 1;
    1944             :                         }
    1945             :                 }
    1946           8 :                 else if (!strnicmp(szSlot, "switchID", 8)) {
    1947             :                         switch_id = 0;
    1948             :                         has_switch_id = 1;
    1949             :                 }
    1950           8 :                 else if (!strnicmp(szSlot, "criteria=", 9)) {
    1951             :                         u32 j=9;
    1952             :                         nb_criteria = 0;
    1953           4 :                         while (j+3<strlen(szSlot)) {
    1954           2 :                                 criteria[nb_criteria] = GF_4CC(szSlot[j], szSlot[j+1], szSlot[j+2], szSlot[j+3]);
    1955           2 :                                 j+=5;
    1956           2 :                                 nb_criteria++;
    1957             :                         }
    1958             :                 }
    1959           6 :                 else if (!strnicmp(szSlot, "trackID=", 8) || !strchr(szSlot, '=') ) {
    1960           6 :                         tsel_acts = gf_realloc(tsel_acts, sizeof(TSELAction) * (nb_tsel_acts + 1));
    1961           6 :                         if (!tsel_acts) return 2;
    1962             : 
    1963           6 :                         tsel_act = &tsel_acts[nb_tsel_acts];
    1964           6 :                         nb_tsel_acts++;
    1965             : 
    1966             :                         memset(tsel_act, 0, sizeof(TSELAction));
    1967           6 :                         tsel_act->act_type = act;
    1968          12 :                         tsel_act->trackID = strchr(szSlot, '=') ? atoi(szSlot+8) : atoi(szSlot);
    1969           6 :                         tsel_act->refTrackID = refTrackID;
    1970           6 :                         tsel_act->switchGroupID = switch_id;
    1971           6 :                         tsel_act->is_switchGroup = has_switch_id;
    1972           6 :                         tsel_act->nb_criteria = nb_criteria;
    1973           6 :                         memcpy(tsel_act->criteria, criteria, sizeof(u32)*nb_criteria);
    1974             : 
    1975           6 :                         if (!refTrackID)
    1976             :                                 refTrackID = tsel_act->trackID;
    1977             : 
    1978           6 :                         open_edit = GF_TRUE;
    1979             :                 }
    1980          10 :                 opts += strlen(szSlot);
    1981             :         }
    1982             :         return 0;
    1983             : }
    1984             : #endif // GPAC_DISABLE_ISOM_WRITE
    1985             : 
    1986             : 
    1987         209 : GF_DashSegmenterInput *set_dash_input(GF_DashSegmenterInput *dash_inputs, char *name, u32 *nb_dash_inputs)
    1988             : {
    1989             :         GF_DashSegmenterInput *di;
    1990             :         Bool skip_rep_id = GF_FALSE;
    1991         209 :         char *other_opts = NULL;
    1992         209 :         char *sep = gf_url_colon_suffix(name);
    1993             : 
    1994         209 :         dash_inputs = gf_realloc(dash_inputs, sizeof(GF_DashSegmenterInput) * (*nb_dash_inputs + 1) );
    1995         209 :         memset(&dash_inputs[*nb_dash_inputs], 0, sizeof(GF_DashSegmenterInput) );
    1996         209 :         di = &dash_inputs[*nb_dash_inputs];
    1997         209 :         (*nb_dash_inputs)++;
    1998             : 
    1999         209 :         if (sep) {
    2000             :                 char *opts, *first_opt;
    2001             :                 first_opt = sep;
    2002          48 :                 opts = sep+1;
    2003         114 :                 while (opts) {
    2004          66 :                         sep = gf_url_colon_suffix(opts);
    2005          66 :                         if (sep && !strncmp(sep, "://", 3) && strncmp(sep, ":@", 2)) sep = gf_url_colon_suffix(sep+3);
    2006          66 :                         if (sep) sep[0] = 0;
    2007             : 
    2008          66 :                         if (!strnicmp(opts, "id=", 3)) {
    2009          11 :                                 if (!stricmp(opts+3, "NULL"))
    2010             :                                         skip_rep_id = GF_TRUE;
    2011             :                                 else
    2012          11 :                                         di->representationID = gf_strdup(opts+3);
    2013             :                                 /*we allow the same repID to be set to force muxed representations*/
    2014             :                         }
    2015          55 :                         else if (!strnicmp(opts, "dur=", 4)) gf_parse_lfrac(opts+4, &di->media_duration);
    2016          36 :                         else if (!strnicmp(opts, "period=", 7)) di->periodID = gf_strdup(opts+7);
    2017          29 :                         else if (!strnicmp(opts, "BaseURL=", 8)) {
    2018           1 :                                 di->baseURL = (char **)gf_realloc(di->baseURL, (di->nb_baseURL+1)*sizeof(char *));
    2019           1 :                                 di->baseURL[di->nb_baseURL] = gf_strdup(opts+8);
    2020           1 :                                 di->nb_baseURL++;
    2021          40 :                         } else if (!strnicmp(opts, "bandwidth=", 10)) di->bandwidth = atoi(opts+10);
    2022          16 :                         else if (!strnicmp(opts, "role=", 5)) {
    2023           0 :                                 di->roles = gf_realloc(di->roles, sizeof (char *) * (di->nb_roles+1));
    2024           0 :                                 di->roles[di->nb_roles] = gf_strdup(opts+5);
    2025           0 :                                 di->nb_roles++;
    2026          16 :                         } else if (!strnicmp(opts, "desc", 4)) {
    2027             :                                 u32 *nb_descs=NULL;
    2028             :                                 char ***descs=NULL;
    2029             :                                 u32 opt_offset=0;
    2030             :                                 u32 len;
    2031          10 :                                 if (!strnicmp(opts, "desc_p=", 7)) {
    2032           3 :                                         nb_descs = &di->nb_p_descs;
    2033           3 :                                         descs = &di->p_descs;
    2034             :                                         opt_offset = 7;
    2035           7 :                                 } else if (!strnicmp(opts, "desc_as=", 8)) {
    2036           6 :                                         nb_descs = &di->nb_as_descs;
    2037           6 :                                         descs = &di->as_descs;
    2038             :                                         opt_offset = 8;
    2039           1 :                                 } else if (!strnicmp(opts, "desc_as_c=", 8)) {
    2040           0 :                                         nb_descs = &di->nb_as_c_descs;
    2041           0 :                                         descs = &di->as_c_descs;
    2042             :                                         opt_offset = 10;
    2043           1 :                                 } else if (!strnicmp(opts, "desc_rep=", 8)) {
    2044           1 :                                         nb_descs = &di->nb_rep_descs;
    2045           1 :                                         descs = &di->rep_descs;
    2046             :                                         opt_offset = 9;
    2047             :                                 }
    2048          10 :                                 if (opt_offset) {
    2049          10 :                                         (*nb_descs)++;
    2050          10 :                                         opts += opt_offset;
    2051          10 :                                         len = (u32) strlen(opts);
    2052          10 :                                         (*descs) = (char **)gf_realloc((*descs), (*nb_descs)*sizeof(char *));
    2053          10 :                                         (*descs)[(*nb_descs)-1] = (char *)gf_malloc((len+1)*sizeof(char));
    2054          10 :                                         memcpy((*descs)[(*nb_descs)-1], opts, len);
    2055          10 :                                         (*descs)[(*nb_descs)-1][len] = 0;
    2056             :                                 }
    2057             : 
    2058             :                         }
    2059           6 :                         else if (!strnicmp(opts, "xlink=", 6)) di->xlink = gf_strdup(opts+6);
    2060           5 :                         else if (!strnicmp(opts, "sscale", 6)) di->sscale = GF_TRUE;
    2061           3 :                         else if (!strnicmp(opts, "pdur=", 5)) gf_parse_frac(opts+5, &di->period_duration);
    2062           2 :                         else if (!strnicmp(opts, "period_duration=", 16)) gf_parse_frac(opts+16, &di->period_duration);
    2063           2 :                         else if (!strnicmp(opts, "ddur=", 5)) gf_parse_frac(opts+5, &di->dash_duration);
    2064           2 :                         else if (!strnicmp(opts, "duration=", 9)) gf_parse_frac(opts+9, &di->dash_duration);
    2065           2 :                         else if (!strnicmp(opts, "asID=", 5)) di->asID = atoi(opts+5);
    2066           2 :                         else if (!strnicmp(opts, "sn=", 3)) di->startNumber = atoi(opts+3);
    2067           2 :                         else if (!strnicmp(opts, "tpl=", 4)) di->seg_template = gf_strdup(opts+4);
    2068           2 :                         else if (!strnicmp(opts, "hls=", 4)) di->hls_pl = gf_strdup(opts+4);
    2069           2 :                         else if (!strnicmp(opts, "trackID=", 8)) di->track_id = atoi(opts+8);
    2070           2 :                         else if (!strnicmp(opts, "@", 1)) {
    2071           2 :                                 Bool old_syntax = (opts[1]=='@') ? GF_TRUE : GF_FALSE;
    2072           2 :                                 if (sep) sep[0] = ':';
    2073           2 :                                 di->filter_chain = gf_strdup(opts + (old_syntax ? 2 : 1) );
    2074             :                                 sep = NULL;
    2075           2 :                                 if (!old_syntax && (strstr(di->filter_chain, "@@")!=NULL)) {
    2076             :                                         skip_rep_id = GF_TRUE;
    2077             :                                 }
    2078             :                         } else {
    2079           0 :                                 gf_dynstrcat(&other_opts, opts, ":");
    2080             :                         }
    2081             : 
    2082          64 :                         if (!sep) break;
    2083          18 :                         sep[0] = ':';
    2084          18 :                         opts = sep+1;
    2085             :                 }
    2086          48 :                 first_opt[0] = '\0';
    2087             :         }
    2088         209 :         di->file_name = name;
    2089         209 :         di->source_opts = other_opts;
    2090             : 
    2091         209 :         if (!skip_rep_id && !di->representationID) {
    2092             :                 char szRep[100];
    2093         197 :                 sprintf(szRep, "%d", *nb_dash_inputs);
    2094         197 :                 di->representationID = gf_strdup(szRep);
    2095             :         }
    2096             : 
    2097         209 :         return dash_inputs;
    2098             : }
    2099             : 
    2100         165 : static Bool create_new_track_action(char *arg_val, u32 act_type, u32 dump_type)
    2101             : {
    2102             :         TrackAction *tka;
    2103             :         char *param = arg_val;
    2104         165 :         tracks = (TrackAction *)gf_realloc(tracks, sizeof(TrackAction) * (nb_track_act+1));
    2105         165 :         if (!tracks) return GF_FALSE;
    2106             : 
    2107         165 :         tka = & tracks[nb_track_act];
    2108         165 :         nb_track_act++;
    2109             : 
    2110             :         memset(tka, 0, sizeof(TrackAction) );
    2111         165 :         tka->act_type = act_type;
    2112         165 :         tka->dump_type = dump_type;
    2113         165 :         if (act_type != TRAC_ACTION_RAW_EXTRACT) {
    2114         100 :                 open_edit = GF_TRUE;
    2115         100 :                 do_save = GF_TRUE;
    2116             :         }
    2117             : 
    2118         165 :         if ((act_type==TRAC_ACTION_SET_ID) || (act_type==TRAC_ACTION_SWAP_ID)) {
    2119           2 :                 if (sscanf(param, "%d:%u", &tka->trackID, &tka->newTrackID) != 2) {
    2120           0 :                         M4_LOG(GF_LOG_ERROR, ("Bad format for -set-track-id - expecting \"id1:id2\" got \"%s\"\n", param));
    2121             :                         return GF_FALSE;
    2122             :                 }
    2123             :                 return GF_TRUE;
    2124             :         }
    2125         163 :         if (act_type==TRAC_ACTION_SET_PAR) {
    2126             :                 char *ext;
    2127          12 :                 ext = strchr(param, '=');
    2128          12 :                 if (!ext) {
    2129           0 :                         M4_LOG(GF_LOG_ERROR, ("Bad format for track par - expecting tkID=none or tkID=PAR_NUM:PAR_DEN got %s\n", param));
    2130             :                         return GF_FALSE;
    2131             :                 }
    2132          12 :                 ext[0] = 0;
    2133          12 :                 tka->trackID = atoi(param);
    2134          12 :                 ext[0] = '=';
    2135             : 
    2136          12 :                 if (!stricmp(ext+1, "none"))
    2137           3 :                         tka->par_num = tka->par_den = 0;
    2138           9 :                 else if (!stricmp(ext+1, "auto")) {
    2139           3 :                         tka->par_num = tka->par_den = -1;
    2140           3 :                         tka->force_par = 1;
    2141             :                 }
    2142           6 :                 else if (!stricmp(ext+1, "force")) {
    2143           0 :                         tka->par_num = tka->par_den = 1;
    2144           0 :                         tka->force_par = 1;
    2145             :                 }
    2146             :                 else {
    2147           6 :                         if (ext[1]=='w') {
    2148           3 :                                 tka->rewrite_bs = 1;
    2149             :                                 ext++;
    2150             :                         }
    2151           6 :                         if (sscanf(ext+1, "%d:%d", &tka->par_num, &tka->par_den) != 2) {
    2152           0 :                                 M4_LOG(GF_LOG_ERROR, ("Bad format for track par - expecting tkID=PAR_NUM:PAR_DEN got %s\n", param));
    2153             :                                 return GF_FALSE;
    2154             :                         }
    2155             :                 }
    2156             :                 return GF_TRUE;
    2157             :         }
    2158         151 :         if (act_type==TRAC_ACTION_SET_CLAP) {
    2159           2 :                 char *ext = strchr(param, '=');
    2160           2 :                 if (!ext) {
    2161           0 :                         M4_LOG(GF_LOG_ERROR, ("Bad format for track clap - expecting tkID=none or tkID=Wn,Wd,Hn,Hd,HOn,HOd,VOn,VOd got %s\n", param));
    2162             :                         return GF_FALSE;
    2163             :                 }
    2164           2 :                 ext[0] = 0;
    2165           2 :                 tka->trackID = atoi(param);
    2166           2 :                 ext[0] = '=';
    2167           2 :                 if (stricmp(ext + 1, "none")) {
    2168           2 :                         if (sscanf(ext + 1, "%d,%d,%d,%d,%d,%d,%d,%d", &tka->clap_wnum, &tka->clap_wden, &tka->clap_hnum, &tka->clap_hden, &tka->clap_honum, &tka->clap_hoden, &tka->clap_vonum, &tka->clap_voden) != 8) {
    2169             : 
    2170           0 :                                 M4_LOG(GF_LOG_ERROR, ("Bad format for track clap - expecting tkID=none or tkID=Wn,Wd,Hn,Hd,HOn,HOd,VOn,VOd got %s\n", param));
    2171             :                                 return GF_FALSE;
    2172             :                         }
    2173             :                 }
    2174             :                 return GF_TRUE;
    2175             :         }
    2176             : 
    2177         149 :         if (act_type==TRAC_ACTION_SET_MX) {
    2178           0 :                 char *ext = strchr(param, '=');
    2179           0 :                 if (!ext) {
    2180           0 :                         M4_LOG(GF_LOG_ERROR, ("Bad format for track matrix - expecting ID=none or ID=M1:M2:M3:M4:M5:M6:M7:M8:M9 got %s\n", param));
    2181             :                         return GF_FALSE;
    2182             :                 }
    2183           0 :                 ext[0] = 0;
    2184           0 :                 tka->trackID = atoi(param);
    2185           0 :                 ext[0] = '=';
    2186           0 :                 if (!stricmp(ext + 1, "none")) {
    2187           0 :                         memset(tka->mx, 0, sizeof(s32)*9);
    2188           0 :                         tka->mx[0] = tka->mx[4] = tka->mx[8] = 1;
    2189             :                 } else {
    2190             :                         s32 res;
    2191           0 :                         if (strstr(ext+1, "0x")) {
    2192           0 :                                 res = sscanf(ext + 1, "0x%d:0x%d:0x%d:0x%d:0x%d:0x%d:0x%d:0x%d:0x%d", &tka->mx[0], &tka->mx[1], &tka->mx[2], &tka->mx[3], &tka->mx[4], &tka->mx[5], &tka->mx[6], &tka->mx[7], &tka->mx[8]);
    2193             :                         } else {
    2194           0 :                                 res = sscanf(ext + 1, "%d:%d:%d:%d:%d:%d:%d:%d:%d", &tka->mx[0], &tka->mx[1], &tka->mx[2], &tka->mx[3], &tka->mx[4], &tka->mx[5], &tka->mx[6], &tka->mx[7], &tka->mx[8]);
    2195             :                         }
    2196           0 :                         if (res != 9) {
    2197           0 :                                 M4_LOG(GF_LOG_ERROR, ("Bad format for track matrix - expecting ID=none or ID=M1:M2:M3:M4:M5:M6:M7:M8:M9 got %s\n", param));
    2198             :                                 return GF_FALSE;
    2199             :                         }
    2200             :                 }
    2201             :                 return GF_TRUE;
    2202             :         }
    2203         149 :         if (act_type==TRAC_ACTION_SET_EDITS) {
    2204           1 :                 char *ext = strchr(param, '=');
    2205           1 :                 if (!ext) {
    2206           0 :                         M4_LOG(GF_LOG_ERROR, ("Bad format for track edits - expecting ID=EDITS got %s\n", param));
    2207             :                         return GF_FALSE;
    2208             :                 }
    2209           1 :                 ext[0] = 0;
    2210           1 :                 tka->trackID = atoi(param);
    2211           1 :                 ext[0] = '=';
    2212           1 :                 tka->string = gf_strdup(ext+1);
    2213           1 :                 return GF_TRUE;
    2214             :         }
    2215         148 :         if (act_type==TRAC_ACTION_SET_LANGUAGE) {
    2216          11 :                 char *ext = strchr(param, '=');
    2217          11 :                 if (!strnicmp(param, "all=", 4)) {
    2218           4 :                         strncpy(tka->lang, param + 4, 10-1);
    2219             :                 }
    2220           7 :                 else if (!ext) {
    2221           3 :                         strncpy(tka->lang, param, 10-1);
    2222             :                 } else {
    2223           4 :                         strncpy(tka->lang, ext + 1, 10-1);
    2224           4 :                         ext[0] = 0;
    2225           4 :                         tka->trackID = atoi(param);
    2226           4 :                         ext[0] = '=';
    2227             :                 }
    2228             :                 return GF_TRUE;
    2229             :         }
    2230         137 :         if ((act_type==TRAC_ACTION_SET_KIND) || (act_type==TRAC_ACTION_REM_KIND)) {
    2231             :                 char *ext;
    2232             :                 char *scheme_start = NULL;
    2233             : 
    2234             :                 //extract trackID
    2235          53 :                 if (!strnicmp(param, "all=", 4)) {
    2236          20 :                         scheme_start = param + 4;
    2237             :                 } else {
    2238          33 :                         ext = strchr(param, '=');
    2239          33 :                         if (ext) {
    2240          21 :                                 ext[0] = 0;
    2241          21 :                                 if (sscanf(param, "%d", &tka->trackID) == 1) {
    2242          12 :                                         scheme_start = ext + 1;
    2243             :                                 } else {
    2244             :                                         scheme_start = param;
    2245             :                                 }
    2246          21 :                                 ext[0] = '=';
    2247             :                         } else {
    2248             :                                 scheme_start = param;
    2249             :                         }
    2250             :                 }
    2251             : 
    2252             :                 //extract scheme and value - if not, remove kind
    2253          53 :                 if (!scheme_start || !scheme_start[0]) {
    2254           0 :                         M4_LOG(GF_LOG_ERROR, ("Missing kind scheme - expecting ID=schemeURI=value got %s\n", param));
    2255             :                         return GF_FALSE;
    2256             :                 } else {
    2257          53 :                         ext = strchr(scheme_start, '=');
    2258          53 :                         if (!ext) {
    2259          33 :                                 tka->kind_scheme = gf_strdup(scheme_start);
    2260             :                         } else {
    2261          20 :                                 ext[0] = 0;
    2262          20 :                                 tka->kind_scheme = gf_strdup(scheme_start);
    2263          20 :                                 ext[0] = '=';
    2264          20 :                                 tka->kind_value = gf_strdup(ext + 1);
    2265             :                         }
    2266             :                 }
    2267             :                 return GF_TRUE;
    2268             :         }
    2269          84 :         if (act_type==TRAC_ACTION_SET_DELAY) {
    2270           1 :                 char *ext = strchr(param, '=');
    2271           1 :                 if (!ext) {
    2272           0 :                         M4_LOG(GF_LOG_ERROR, ("Bad format for track delay - expecting tkID=DLAY got %s\n", param));
    2273             :                         return GF_FALSE;
    2274             :                 }
    2275           1 :                 ext[0] = 0;
    2276           1 :                 tka->trackID = atoi(param);
    2277           1 :                 ext[0] = '=';
    2278           1 :                 if (sscanf(ext+1, "%d/%u", &tka->delay.num, &tka->delay.den) != 2) {
    2279           1 :                         tka->delay.num = atoi(ext + 1);
    2280           1 :                         tka->delay.den = 1000;
    2281             :                 }
    2282             :                 return GF_TRUE;
    2283             :         }
    2284          83 :         if (act_type==TRAC_ACTION_REFERENCE) {
    2285           1 :                 char *ext = strchr(param, '=');
    2286           1 :                 if (!ext) ext = strchr(param, ':');
    2287           1 :                 if (!ext) {
    2288           0 :                         M4_LOG(GF_LOG_ERROR, ("Bad format for track reference - expecting tkID:XXXX:refID got %s\n", param));
    2289             :                         return GF_FALSE;
    2290             :                 }
    2291           1 :                 ext[0] = 0;
    2292           1 :                 tka->trackID = atoi(param);
    2293           1 :                 ext[0] = '=';
    2294             : 
    2295           1 :                 char *ext2 = strchr(ext, ':');
    2296           1 :                 if (!ext2) {
    2297           0 :                         M4_LOG(GF_LOG_ERROR, ("Bad format for track reference - expecting tkID:XXXX:refID got %s\n", param));
    2298             :                         return GF_FALSE;
    2299             :                 }
    2300           1 :                 ext2[0] = 0;
    2301           1 :                 strncpy(tka->lang, ext+1, 9);
    2302           1 :                 ext2[0] = ':';
    2303           2 :                 tka->newTrackID = (s32) atoi(ext2 + 1);
    2304           1 :                 return GF_TRUE;
    2305             :         }
    2306          82 :         if (act_type==TRAC_ACTION_SET_HANDLER_NAME) {
    2307           1 :                 char *ext = strchr(param, '=');
    2308           1 :                 if (!ext) {
    2309           0 :                         M4_LOG(GF_LOG_ERROR, ("Bad format for track name - expecting tkID=name got %s\n", param));
    2310             :                         return GF_FALSE;
    2311             :                 }
    2312           1 :                 ext[0] = 0;
    2313           1 :                 tka->trackID = atoi(param);
    2314           1 :                 ext[0] = '=';
    2315           1 :                 tka->hdl_name = ext + 1;
    2316           1 :                 return GF_TRUE;
    2317             :         }
    2318          81 :         if (act_type==TRAC_ACTION_SET_KMS_URI) {
    2319           5 :                 char *ext = strchr(param, '=');
    2320             : 
    2321           5 :                 if (!strnicmp(param, "all=", 4)) {
    2322           0 :                         tka->kms = param + 4;
    2323           5 :                 } else if (!ext) {
    2324           5 :                         tka->kms = param;
    2325             :                 } else {
    2326           0 :                         tka->kms = ext + 1;
    2327           0 :                         ext[0] = 0;
    2328           0 :                         tka->trackID = atoi(param);
    2329           0 :                         ext[0] = '=';
    2330             :                 }
    2331             :                 return GF_TRUE;
    2332             :         }
    2333          76 :         if ((act_type==TRAC_ACTION_SET_TIME) || (act_type==TRAC_ACTION_SET_MEDIA_TIME)) {
    2334             :                 struct tm time;
    2335           1 :                 char *ext = strchr(arg_val, '=');
    2336           1 :                 if (ext) {
    2337           0 :                         ext[0] = 0;
    2338           0 :                         tka->trackID = atoi(arg_val);
    2339           0 :                         ext[0] = '=';
    2340           0 :                         arg_val = ext+1;
    2341             :                 }
    2342             :                 memset(&time, 0, sizeof(struct tm));
    2343           1 :                 sscanf(arg_val, "%d/%d/%d-%d:%d:%d", &time.tm_mday, &time.tm_mon, &time.tm_year, &time.tm_hour, &time.tm_min, &time.tm_sec);
    2344           1 :                 time.tm_isdst = 0;
    2345           1 :                 time.tm_year -= 1900;
    2346           1 :                 time.tm_mon -= 1;
    2347           1 :                 tka->time = 2082758400;
    2348           1 :                 tka->time += mktime(&time);
    2349             :                 return GF_TRUE;
    2350             :         }
    2351             : 
    2352         171 :         while (param) {
    2353          96 :                 param = gf_url_colon_suffix(param);
    2354          96 :                 if (param) {
    2355          21 :                         *param = 0;
    2356          21 :                         param++;
    2357             : #ifndef GPAC_DISABLE_MEDIA_EXPORT
    2358          21 :                         if (!strncmp("vttnomerge", param, 10)) {
    2359           0 :                                 tka->dump_type |= GF_EXPORT_WEBVTT_NOMERGE;
    2360          21 :                         } else if (!strncmp("layer", param, 5)) {
    2361           0 :                                 tka->dump_type |= GF_EXPORT_SVC_LAYER;
    2362          21 :                         } else if (!strncmp("full", param, 4)) {
    2363           1 :                                 tka->dump_type |= GF_EXPORT_NHML_FULL;
    2364          20 :                         } else if (!strncmp("embedded", param, 8)) {
    2365           0 :                                 tka->dump_type |= GF_EXPORT_WEBVTT_META_EMBEDDED;
    2366          20 :                         } else if (!strncmp("output=", param, 7)) {
    2367           1 :                                 tka->out_name = gf_strdup(param+7);
    2368          19 :                         } else if (!strncmp("src=", param, 4)) {
    2369           3 :                                 tka->src_name = gf_strdup(param+4);
    2370          16 :                         } else if (!strncmp("str=", param, 4)) {
    2371           1 :                                 tka->string = gf_strdup(param+4);
    2372          15 :                         } else if (!strncmp("box=", param, 4)) {
    2373           1 :                                 tka->src_name = gf_strdup(param+4);
    2374           1 :                                 tka->sample_num = 1;
    2375          14 :                         } else if (!strncmp("type=", param, 4)) {
    2376           5 :                                 tka->udta_type = GF_4CC(param[5], param[6], param[7], param[8]);
    2377           9 :                         } else if (tka->dump_type == GF_EXPORT_RAW_SAMPLES) {
    2378           1 :                                 tka->sample_num = atoi(param);
    2379             :                         }
    2380             : #endif
    2381             :                 }
    2382             :         }
    2383          75 :         if (arg_val) {
    2384          75 :                 if (!strcmp(arg_val, "*")) {
    2385           0 :                         tka->trackID = (u32) -1;
    2386             :                 } else {
    2387          75 :                         if (act_type==TRAC_ACTION_RAW_EXTRACT) {
    2388          65 :                                 if (!strncmp(arg_val, "video", 5)) {
    2389           0 :                                         arg_val += 5;
    2390           0 :                                         tka->dump_track_type = 1;
    2391             :                                 }
    2392          65 :                                 else if (!strncmp(arg_val, "audio", 5)) {
    2393           0 :                                         arg_val += 5;
    2394           0 :                                         tka->dump_track_type = 2;
    2395             :                                 }
    2396             :                         }
    2397          75 :                         if (arg_val[0])
    2398          75 :                                 tka->trackID = atoi(arg_val);
    2399             :                 }
    2400             :         }
    2401             :         return GF_TRUE;
    2402             : }
    2403             : 
    2404          65 : u32 parse_track_dump(char *arg, u32 dump_type)
    2405             : {
    2406          65 :         if (!create_new_track_action(arg, TRAC_ACTION_RAW_EXTRACT, dump_type))
    2407             :                 return 2;
    2408          65 :         track_dump_type = dump_type;
    2409          65 :         return 0;
    2410             : }
    2411          98 : u32 parse_track_action(char *arg, u32 act_type)
    2412             : {
    2413         100 :         if (!create_new_track_action(arg, act_type, 0)) {
    2414             :                 return 2;
    2415             :         }
    2416          98 :         return 0;
    2417             : }
    2418             : 
    2419           2 : u32 parse_comp_box(char *arg_val, u32 opt)
    2420             : {
    2421           2 :         compress_top_boxes = arg_val;
    2422           2 :         size_top_box = opt;
    2423           2 :         return 0;
    2424             : }
    2425          21 : u32 parse_dnal(char *arg_val, u32 opt)
    2426             : {
    2427          21 :         dump_nal = atoi(arg_val);
    2428          21 :         dump_nal_type = opt;
    2429          21 :         return 0;
    2430             : }
    2431           5 : u32 parse_dsap(char *arg_val, u32 opt)
    2432             : {
    2433           5 :         dump_saps = atoi(arg_val);
    2434           5 :         dump_saps_mode = opt;
    2435           5 :         return 0;
    2436             : }
    2437             : 
    2438           3 : u32 parse_bs_switch(char *arg_val, u32 opt)
    2439             : {
    2440           3 :         if (!stricmp(arg_val, "no") || !stricmp(arg_val, "off")) bitstream_switching_mode = GF_DASH_BSMODE_NONE;
    2441           1 :         else if (!stricmp(arg_val, "merge"))  bitstream_switching_mode = GF_DASH_BSMODE_MERGED;
    2442           1 :         else if (!stricmp(arg_val, "multi"))  bitstream_switching_mode = GF_DASH_BSMODE_MULTIPLE_ENTRIES;
    2443           1 :         else if (!stricmp(arg_val, "single"))  bitstream_switching_mode = GF_DASH_BSMODE_SINGLE;
    2444           0 :         else if (!stricmp(arg_val, "inband"))  bitstream_switching_mode = GF_DASH_BSMODE_INBAND;
    2445             :         else {
    2446           0 :                 M4_LOG(GF_LOG_ERROR, ("Unrecognized bitstream switching mode \"%s\" - please check usage\n", arg_val));
    2447             :                 return 2;
    2448             :         }
    2449             :         return 0;
    2450             : }
    2451             : 
    2452           0 : u32 parse_cp_loc(char *arg_val, u32 opt)
    2453             : {
    2454           0 :         if (!strcmp(arg_val, "both")) cp_location_mode = GF_DASH_CPMODE_BOTH;
    2455           0 :         else if (!strcmp(arg_val, "as")) cp_location_mode = GF_DASH_CPMODE_ADAPTATION_SET;
    2456           0 :         else if (!strcmp(arg_val, "rep")) cp_location_mode = GF_DASH_CPMODE_REPRESENTATION;
    2457             :         else {
    2458           0 :                 M4_LOG(GF_LOG_ERROR, ("Unrecognized ContentProtection loction mode \"%s\" - please check usage\n", arg_val));
    2459             :                 return 2;
    2460             :         }
    2461             :         return 0;
    2462             : }
    2463             : 
    2464           0 : u32 parse_pssh(char *arg_val, u32 opt)
    2465             : {
    2466           0 :         if (!strcmp(arg_val, "f")) pssh_mode = GF_DASH_PSSH_MOOF;
    2467           0 :         else if (!strcmp(arg_val, "v")) pssh_mode = GF_DASH_PSSH_MOOV;
    2468           0 :         else if (!strcmp(arg_val, "m")) pssh_mode = GF_DASH_PSSH_MPD;
    2469           0 :         else if (!strcmp(arg_val, "mf") || !strcmp(arg_val, "fm")) pssh_mode = GF_DASH_PSSH_MOOF_MPD;
    2470           0 :         else if (!strcmp(arg_val, "mv") || !strcmp(arg_val, "vm")) pssh_mode = GF_DASH_PSSH_MOOV_MPD;
    2471           0 :         else pssh_mode = GF_DASH_PSSH_MOOV;
    2472           0 :         return 0;
    2473             : }
    2474           0 : u32 parse_sdtp(char *arg_val, u32 opt)
    2475             : {
    2476           0 :         if (!stricmp(arg_val, "both")) sdtp_in_traf = 2;
    2477           0 :         else if (!stricmp(arg_val, "sdtp")) sdtp_in_traf = 1;
    2478           0 :         else sdtp_in_traf = 0;
    2479           0 :         return 0;
    2480             : }
    2481             : 
    2482          20 : u32 parse_rap_ref(char *arg_val, u32 opt)
    2483             : {
    2484          20 :         if (arg_val) {
    2485           2 :                 if (sscanf(arg_val, "%d", &trackID) == 1) {
    2486           2 :                         parse_track_action(arg_val, opt ? TRAC_ACTION_REM_NON_REFS : TRAC_ACTION_REM_NON_RAP);
    2487             :                 }
    2488             :         }
    2489          20 :         hint_flags |= GP_RTP_PCK_SIGNAL_RAP;
    2490          20 :         seg_at_rap = 1;
    2491          20 :         return 0;
    2492             : }
    2493          15 : u32 parse_store_mode(char *arg_val, u32 opt)
    2494             : {
    2495          15 :         do_save = GF_TRUE;
    2496          15 :         if ((opt == 0) || (opt == 1)) {
    2497           6 :                 interleaving_time = atof(arg_val) / 1000;
    2498           6 :                 if (!interleaving_time) do_flat = 2;
    2499           6 :                 open_edit = GF_TRUE;
    2500           6 :                 no_inplace = GF_TRUE;
    2501           6 :                 if (opt==1) old_interleave = 1;
    2502           9 :         } else if (opt==2) {
    2503           8 :                 interleaving_time = atof(arg_val);
    2504           8 :                 do_frag = GF_TRUE;
    2505             :         } else {
    2506           1 :                 force_new = 2;
    2507           1 :                 interleaving_time = 0.5;
    2508           1 :                 do_flat = 1;
    2509             :         }
    2510          15 :         return 0;
    2511             : }
    2512           1 : u32 parse_base_url(char *arg_val, u32 opt)
    2513             : {
    2514           1 :         mpd_base_urls = gf_realloc(mpd_base_urls, (nb_mpd_base_urls + 1)*sizeof(char**));
    2515           1 :         if (!mpd_base_urls) return 2;
    2516           1 :         mpd_base_urls[nb_mpd_base_urls] = arg_val;
    2517           1 :         nb_mpd_base_urls++;
    2518           1 :         return 0;
    2519             : }
    2520           0 : u32 parse_multi_rtp(char *arg_val, u32 opt)
    2521             : {
    2522           0 :         hint_flags |= GP_RTP_PCK_USE_MULTI;
    2523           0 :         if (arg_val)
    2524           0 :                 max_ptime = atoi(arg_val);
    2525           0 :         return 0;
    2526             : }
    2527             : 
    2528             : 
    2529           7 : u32 parse_senc_param(char *arg_val, u32 opt)
    2530             : {
    2531           7 :         switch (opt) {
    2532           3 :         case 0: //-sync
    2533           3 :                 smenc_opts.flags |= GF_SM_ENCODE_RAP_INBAND;
    2534           3 :                 smenc_opts.rap_freq = atoi(arg_val);
    2535           3 :                 break;
    2536           3 :         case 1: //-shadow
    2537           3 :                 smenc_opts.flags &= ~GF_SM_ENCODE_RAP_INBAND;
    2538           3 :                 smenc_opts.flags |= GF_SM_ENCODE_RAP_SHADOW;
    2539           3 :                 smenc_opts.rap_freq = atoi(arg_val);
    2540           3 :                 break;
    2541           0 :         case 2: //-carousel
    2542           0 :                 smenc_opts.flags &= ~(GF_SM_ENCODE_RAP_INBAND | GF_SM_ENCODE_RAP_SHADOW);
    2543           0 :                 smenc_opts.rap_freq = atoi(arg_val);
    2544           0 :                 break;
    2545             :         case 3: //-auto-quant
    2546           0 :                 smenc_opts.resolution = atoi(arg_val);
    2547           0 :                 smenc_opts.auto_quant = 1;
    2548           0 :                 break;
    2549             :         case 4: //-global-quant
    2550           0 :                 smenc_opts.resolution = atoi(arg_val);
    2551           0 :                 smenc_opts.auto_quant = 2;
    2552           0 :                 break;
    2553           1 :         case 5: //-ctx-in or -inctx
    2554           1 :                 chunk_mode = GF_TRUE;
    2555           1 :                 input_ctx = arg_val;
    2556             :         }
    2557           7 :         return 0;
    2558             : }
    2559         222 : u32 parse_cryp(char *arg_val, u32 opt)
    2560             : {
    2561         222 :         open_edit = GF_TRUE;
    2562         222 :         if (!opt) {
    2563         115 :                 crypt = 1;
    2564         115 :                 drm_file = arg_val;
    2565             :                 open_edit = GF_TRUE;
    2566         115 :                 return 0;
    2567             :         }
    2568         107 :         crypt = 2;
    2569         107 :         if (arg_val && get_file_type_by_ext(arg_val) != 1) {
    2570         100 :                 drm_file = arg_val;
    2571         100 :                 return 0;
    2572             :         }
    2573             :         return 3;
    2574             : }
    2575             : 
    2576         155 : u32 parse_dash_profile(char *arg_val, u32 opt)
    2577             : {
    2578         155 :         if (!stricmp(arg_val, "live") || !stricmp(arg_val, "simple")) dash_profile = GF_DASH_PROFILE_LIVE;
    2579          21 :         else if (!stricmp(arg_val, "onDemand")) dash_profile = GF_DASH_PROFILE_ONDEMAND;
    2580          10 :         else if (!stricmp(arg_val, "hbbtv1.5:live") || !stricmp(arg_val, "hbbtv1.5.live"))
    2581           0 :                 dash_profile = GF_DASH_PROFILE_HBBTV_1_5_ISOBMF_LIVE;
    2582          10 :         else if (!stricmp(arg_val, "dashavc264:live") || !stricmp(arg_val, "dashavc264.live"))
    2583           3 :                 dash_profile = GF_DASH_PROFILE_AVC264_LIVE;
    2584           7 :         else if (!stricmp(arg_val, "dashavc264:onDemand") || !stricmp(arg_val, "dashavc264.onDemand"))
    2585           2 :                 dash_profile = GF_DASH_PROFILE_AVC264_ONDEMAND;
    2586           5 :         else if (!stricmp(arg_val, "dashif.ll")) dash_profile = GF_DASH_PROFILE_DASHIF_LL;
    2587           5 :         else if (!stricmp(arg_val, "main")) dash_profile = GF_DASH_PROFILE_MAIN;
    2588           0 :         else if (!stricmp(arg_val, "full")) dash_profile = GF_DASH_PROFILE_FULL;
    2589             :         else {
    2590           0 :                 M4_LOG(GF_LOG_ERROR, ("Unrecognized DASH profile \"%s\" - please check usage\n", arg_val));
    2591             :                 return 2;
    2592             :         }
    2593             :         return 0;
    2594             : }
    2595             : 
    2596           0 : u32 parse_fps(char *arg_val, u32 opt)
    2597             : {
    2598             :         u32 ticks, dts_inc;
    2599           0 :         if (!strcmp(arg_val, "auto")) {
    2600           0 :                 M4_LOG(GF_LOG_WARNING, ("Warning, fps=auto option is deprecated\n"));
    2601             :         }
    2602           0 :         else if ((sscanf(arg_val, "%u-%u", &ticks, &dts_inc)==2) || (sscanf(arg_val, "%u/%u", &ticks, &dts_inc)==2) ) {
    2603           0 :                 if (!dts_inc) dts_inc = 1;
    2604           0 :                 import_fps.num = ticks;
    2605           0 :                 import_fps.den = dts_inc;
    2606             :         } else {
    2607           0 :                 gf_parse_frac(arg_val, &import_fps);
    2608             :         }
    2609           0 :         return 0;
    2610             : }
    2611             : 
    2612           8 : u32 parse_split(char *arg_val, u32 opt)
    2613             : {
    2614           8 :         switch (opt) {
    2615             :         case 0://-split
    2616           2 :                 split_duration = atof(arg_val);
    2617           2 :                 if (split_duration < 0) split_duration = 0;
    2618           2 :                 split_size = 0;
    2619           2 :                 break;
    2620           0 :         case 1: //-split-rap, -splitr
    2621           0 :                 split_duration = -1;
    2622           0 :                 split_size = -1;
    2623           0 :                 break;
    2624             :         case 2: //-split-size, -splits
    2625           2 :                 split_size = (u32)atoi(arg_val);
    2626           2 :                 split_duration = 0;
    2627           2 :                 break;
    2628           4 :         case 3: //-split-chunk, -splitx
    2629             :         case 4: //-splitz
    2630             :         case 5: //-splitg
    2631             :         case 6: //-splitf
    2632           4 :                 adjust_split_end = opt-3;
    2633           4 :                 if (!strstr(arg_val, ":") && !strstr(arg_val, "-")) {
    2634           0 :                         M4_LOG(GF_LOG_ERROR, ("Chunk extraction usage: \"-split* start:end\" expressed in seconds\n"));
    2635             :                         return 2;
    2636             :                 }
    2637           4 :                 if (strstr(arg_val, "end")) {
    2638           0 :                         if (strstr(arg_val, "end-")) {
    2639           0 :                                 Double dur_end=0;
    2640           0 :                                 sscanf(arg_val, "%lf:end-%lf", &split_start, &dur_end);
    2641           0 :                                 split_duration = -2 - dur_end;
    2642             :                         } else {
    2643           0 :                                 sscanf(arg_val, "%lf:end", &split_start);
    2644           0 :                                 split_duration = -2;
    2645             :                         }
    2646             :                 } else {
    2647           4 :                         split_range_str = arg_val;
    2648             :                 }
    2649           4 :                 split_size = 0;
    2650           4 :                 break;
    2651             :         }
    2652             :         return 0;
    2653             : }
    2654             : 
    2655          69 : u32 parse_brand(char *b, u32 opt)
    2656             : {
    2657          69 :         open_edit = GF_TRUE;
    2658          69 :         switch (opt) {
    2659           2 :         case 0: //-brand
    2660           2 :                 major_brand = GF_4CC(b[0], b[1], b[2], b[3]);
    2661           2 :                 if (b[4] == ':') {
    2662           1 :                         if (!strncmp(b+5, "0x", 2))
    2663           0 :                                 sscanf(b+5, "0x%x", &minor_version);
    2664             :                         else
    2665           1 :                                 minor_version = atoi(b + 5);
    2666             :                 }
    2667             :                 break;
    2668          65 :         case 1: //-ab
    2669          65 :                 brand_add = (u32*)gf_realloc(brand_add, sizeof(u32) * (nb_alt_brand_add + 1));
    2670          65 :                 if (!brand_add) return 2;
    2671          65 :                 brand_add[nb_alt_brand_add] = GF_4CC(b[0], b[1], b[2], b[3]);
    2672          65 :                 nb_alt_brand_add++;
    2673          65 :                 break;
    2674           2 :         case 2: //-rb
    2675           2 :                 brand_rem = (u32*)gf_realloc(brand_rem, sizeof(u32) * (nb_alt_brand_rem + 1));
    2676           2 :                 if (!brand_rem) return 2;
    2677           2 :                 brand_rem[nb_alt_brand_rem] = GF_4CC(b[0], b[1], b[2], b[3]);
    2678           2 :                 nb_alt_brand_rem++;
    2679           2 :                 break;
    2680             :         }
    2681             :         return 0;
    2682             : }
    2683             : 
    2684           1 : u32 parse_mpegu(char *arg_val, u32 opt)
    2685             : {
    2686           1 :         pack_file = arg_val;
    2687           1 :         pack_wgt = GF_TRUE;
    2688           1 :         return 0;
    2689             : }
    2690             : 
    2691         251 : u32 parse_file_info(char *arg_val, u32 opt)
    2692             : {
    2693         251 :         print_info = opt ? 2 : 1;
    2694         251 :         if (arg_val) {
    2695         251 :                 if (sscanf(arg_val, "%u", &info_track_id) == 1) {
    2696             :                         char szTk[20];
    2697           4 :                         sprintf(szTk, "%u", info_track_id);
    2698           4 :                         if (strcmp(szTk, arg_val)) info_track_id = 0;
    2699             :                 }
    2700         251 :                 if (!info_track_id) return 3;
    2701             :         }
    2702             :         return 0;
    2703             : }
    2704           6 : u32 parse_boxpatch(char *arg_val, u32 opt)
    2705             : {
    2706           6 :         box_patch_filename = arg_val;
    2707           6 :         char *sep = strchr(box_patch_filename, '=');
    2708           6 :         if (sep) {
    2709           0 :                 sep[0] = 0;
    2710           0 :                 box_patch_trackID = atoi(box_patch_filename);
    2711           0 :                 sep[0] = '=';
    2712           0 :                 box_patch_filename = sep+1;
    2713             :         }
    2714           6 :         open_edit = GF_TRUE;
    2715           6 :         return 0;
    2716             : }
    2717           0 : u32 parse_compress(char *arg_val, u32 opt)
    2718             : {
    2719           0 :         compress_moov = opt ? 2 : 1;
    2720           0 :         open_edit = GF_TRUE;
    2721           0 :         return 0;
    2722             : }
    2723             : 
    2724             : 
    2725           2 : u32 parse_dump_udta(char *code, u32 opt)
    2726             : {
    2727             :         char *sep;
    2728           2 :         sep = strchr(code, ':');
    2729           2 :         if (sep) {
    2730           1 :                 sep[0] = 0;
    2731           1 :                 dump_udta_track = atoi(code);
    2732           1 :                 sep[0] = ':';
    2733           1 :                 code = sep + 1;
    2734             :         }
    2735             : 
    2736           2 :         if (strlen(code) == 4) {
    2737           2 :                 dump_udta_type = GF_4CC(code[0], code[1], code[2], code[3]);
    2738           0 :         } else if (strlen(code) == 8) {
    2739             :                 // hex representation on 8 chars
    2740             :                 u32 hex1, hex2, hex3, hex4;
    2741           0 :                 if (sscanf(code, "%02x%02x%02x%02x", &hex1, &hex2, &hex3, &hex4) != 4) {
    2742           0 :                         M4_LOG(GF_LOG_ERROR, ("udta code is either a 4CC or 8 hex chars for non-printable 4CC\n"));
    2743           0 :                         return 2;
    2744             :                 }
    2745           0 :                 dump_udta_type = GF_4CC(hex1, hex2, hex3, hex4);
    2746             :         } else {
    2747           0 :                 M4_LOG(GF_LOG_ERROR, ("udta code is either a 4CC or 8 hex chars for non-printable 4CC\n"));
    2748             :                 return 2;
    2749             :         }
    2750             :         return 0;
    2751             : }
    2752             : 
    2753          63 : u32 parse_dump_ts(char *arg_val, u32 opt)
    2754             : {
    2755          63 :         dump_timestamps = 1;
    2756          63 :         if (arg_val) {
    2757           0 :                 if (isdigit(arg_val[0])) {
    2758           0 :                         program_number = atoi(arg_val);
    2759             :                 } else {
    2760             :                         return 3;
    2761             :                 }
    2762             :         }
    2763             :         return 0;
    2764             : }
    2765             : 
    2766           8 : u32 parse_ttxt(char *arg_val, u32 opt)
    2767             : {
    2768           8 :         if (opt) //-srt
    2769           4 :                 dump_srt = GF_TRUE;
    2770             :         else
    2771           4 :                 dump_ttxt = GF_TRUE;
    2772             : 
    2773           8 :         import_subtitle = 1;
    2774           8 :         trackID = 0;
    2775             : 
    2776           8 :         if (arg_val && (!strcmp(arg_val, "*") || !strcmp(arg_val, "@") || !strcmp(arg_val, "all")) ) {
    2777           0 :                 trackID = (u32)-1;
    2778           8 :         } else if (arg_val) {
    2779           8 :                 if (sscanf(arg_val, "%u", &trackID) == 1) {
    2780             :                         char szTk[20];
    2781           4 :                         sprintf(szTk, "%d", trackID);
    2782           4 :                         if (strcmp(szTk, arg_val))
    2783           0 :                                 trackID = 0;
    2784             :                 }
    2785           8 :                 if (!trackID) return 3;
    2786             :         }
    2787             :         return 0;
    2788             : }
    2789             : 
    2790           8 : u32 parse_dashlive(char *arg, char *arg_val, u32 opt)
    2791             : {
    2792           8 :         dash_mode = opt ? GF_DASH_DYNAMIC_DEBUG : GF_DASH_DYNAMIC;
    2793           8 :         dash_live = 1;
    2794           8 :         if (arg[10] == '=') {
    2795           0 :                 dash_ctx_file = arg + 11;
    2796             :         }
    2797           8 :         dash_duration = atof(arg_val);
    2798           8 :         return 0;
    2799             : }
    2800             : 
    2801          19 : u32 parse_help(char *arg_val, u32 opt)
    2802             : {
    2803          19 :         if (!arg_val) PrintUsage();
    2804          16 :         else if (opt) PrintHelp(arg_val, GF_TRUE, GF_FALSE);
    2805          15 :         else if (!strcmp(arg_val, "general")) PrintGeneralUsage();
    2806          14 :         else if (!strcmp(arg_val, "extract")) PrintExtractUsage();
    2807          13 :         else if (!strcmp(arg_val, "split")) PrintSplitUsage();
    2808          13 :         else if (!strcmp(arg_val, "dash")) PrintDASHUsage();
    2809          12 :         else if (!strcmp(arg_val, "dump")) PrintDumpUsage();
    2810          11 :         else if (!strcmp(arg_val, "import")) PrintImportUsage();
    2811          10 :         else if (!strcmp(arg_val, "format")) {
    2812           1 :                 M4_LOG(GF_LOG_WARNING, ("deprecated, see [filters documentation](Filters)\n"));
    2813             :         }
    2814           9 :         else if (!strcmp(arg_val, "hint")) PrintHintUsage();
    2815           8 :         else if (!strcmp(arg_val, "encode")) PrintEncodeUsage();
    2816           7 :         else if (!strcmp(arg_val, "crypt")) PrintEncryptUsage();
    2817           6 :         else if (!strcmp(arg_val, "meta")) PrintMetaUsage();
    2818           5 :         else if (!strcmp(arg_val, "swf")) PrintSWFUsage();
    2819             : #if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG)
    2820           4 :         else if (!strcmp(arg_val, "rtp")) {
    2821           1 :                 M4_LOG(GF_LOG_WARNING, ("RTP streaming deprecated in MP4Box, use gpac application\n"));
    2822             :         }
    2823           3 :         else if (!strcmp(arg_val, "live")) PrintLiveUsage();
    2824             : #endif
    2825           2 :         else if (!strcmp(arg_val, "core")) PrintCoreUsage();
    2826           2 :         else if (!strcmp(arg_val, "tags")) PrintTags();
    2827           2 :         else if (!strcmp(arg_val, "cicp")) PrintCICP();
    2828           1 :         else if (!strcmp(arg_val, "all")) {
    2829           1 :                 PrintGeneralUsage();
    2830           1 :                 PrintExtractUsage();
    2831           1 :                 PrintDASHUsage();
    2832           1 :                 PrintSplitUsage();
    2833           1 :                 PrintDumpUsage();
    2834           1 :                 PrintImportUsage();
    2835           1 :                 PrintHintUsage();
    2836           1 :                 PrintEncodeUsage();
    2837           1 :                 PrintEncryptUsage();
    2838           1 :                 PrintMetaUsage();
    2839           1 :                 PrintSWFUsage();
    2840             : #if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG)
    2841           1 :                 PrintLiveUsage();
    2842             : #endif
    2843           1 :                 PrintCoreUsage();
    2844           1 :                 PrintTags();
    2845           1 :                 PrintCICP();
    2846           0 :         } else if (!strcmp(arg_val, "opts")) {
    2847           0 :                 PrintHelp("@", GF_FALSE, GF_FALSE);
    2848             :         } else {
    2849           0 :                 PrintHelp(arg_val, GF_FALSE, GF_FALSE);
    2850             :         }
    2851          19 :         return 1;
    2852             : }
    2853             : 
    2854           2 : u32 parse_gendoc(char *name, u32 opt)
    2855             : {
    2856             :         u32 i=0;
    2857             :         //gen MD
    2858           2 :         if (!opt) {
    2859           1 :                 help_flags = GF_PRINTARG_MD | GF_PRINTARG_IS_APP;
    2860           1 :                 helpout = gf_fopen("mp4box-gen-opts.md", "w");
    2861             : 
    2862             :                 fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » General");
    2863           1 :                 fprintf(helpout, "<!-- automatically generated - do not edit, patch gpac/applications/mp4box/main.c -->\n");
    2864           1 :                 fprintf(helpout, "# Syntax\n");
    2865           1 :                 gf_sys_format_help(helpout, help_flags, "MP4Box [option] input [option] [other_dash_inputs]\n"
    2866             :                         "  \n"
    2867             :                 );
    2868           1 :                 PrintGeneralUsage();
    2869           1 :                 PrintEncryptUsage();
    2870           1 :                 fprintf(helpout, "# Help Options\n");
    2871          20 :                 while (m4b_usage_args[i].name) {
    2872          19 :                         GF_GPACArg *g_arg = (GF_GPACArg *) &m4b_usage_args[i];
    2873          19 :                         i++;
    2874          19 :                         gf_sys_print_arg(helpout, help_flags, g_arg, "mp4box-general");
    2875             :                 }
    2876             : 
    2877           1 :                 gf_fclose(helpout);
    2878             : 
    2879           1 :                 helpout = gf_fopen("mp4box-import-opts.md", "w");
    2880             :                 fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » Media Import");
    2881           1 :                 fprintf(helpout, "<!-- automatically generated - do not edit, patch gpac/applications/mp4box/main.c -->\n");
    2882           1 :                 PrintImportUsage();
    2883           1 :                 gf_fclose(helpout);
    2884             : 
    2885           1 :                 helpout = gf_fopen("mp4box-dash-opts.md", "w");
    2886             :                 fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » Media DASH");
    2887           1 :                 fprintf(helpout, "<!-- automatically generated - do not edit, patch gpac/applications/mp4box/main.c -->\n");
    2888           1 :                 PrintDASHUsage();
    2889           1 :                 gf_fclose(helpout);
    2890             : 
    2891           1 :                 helpout = gf_fopen("mp4box-dump-opts.md", "w");
    2892             :                 fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » Media Dump and Export");
    2893           1 :                 fprintf(helpout, "<!-- automatically generated - do not edit, patch gpac/applications/mp4box/main.c -->\n");
    2894           1 :                 PrintExtractUsage();
    2895           1 :                 PrintDumpUsage();
    2896           1 :                 PrintSplitUsage();
    2897           1 :                 gf_fclose(helpout);
    2898             : 
    2899           1 :                 helpout = gf_fopen("mp4box-meta-opts.md", "w");
    2900             :                 fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » Meta and HEIF/IFF");
    2901           1 :                 fprintf(helpout, "<!-- automatically generated - do not edit, patch gpac/applications/mp4box/main.c -->\n");
    2902           1 :                 PrintMetaUsage();
    2903           1 :                 gf_fclose(helpout);
    2904             : 
    2905             : 
    2906           1 :                 helpout = gf_fopen("mp4box-scene-opts.md", "w");
    2907             :                 fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » Scene Description");
    2908           1 :                 fprintf(helpout, "<!-- automatically generated - do not edit, patch gpac/applications/mp4box/main.c -->\n");
    2909           1 :                 PrintEncodeUsage();
    2910             : #if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG)
    2911           1 :                 PrintLiveUsage();
    2912             : #endif
    2913           1 :                 PrintSWFUsage();
    2914           1 :                 gf_fclose(helpout);
    2915             : 
    2916           1 :                 helpout = gf_fopen("mp4box-other-opts.md", "w");
    2917             :                 fprintf(helpout, "[**HOME**](Home) » [**MP4Box**](MP4Box) » Other Features");
    2918           1 :                 fprintf(helpout, "<!-- automatically generated - do not edit, patch gpac/applications/mp4box/main.c -->\n");
    2919           1 :                 PrintHintUsage();
    2920           1 :                 PrintTags();
    2921           1 :                 gf_fclose(helpout);
    2922             :         }
    2923             :         //gen man
    2924             :         else {
    2925           1 :                 help_flags = GF_PRINTARG_MAN;
    2926           1 :                 helpout = gf_fopen("mp4box.1", "w");
    2927             : 
    2928             : 
    2929             :                 fprintf(helpout, ".TH MP4Box 1 2019 MP4Box GPAC\n");
    2930           1 :                 fprintf(helpout, ".\n.SH NAME\n.LP\nMP4Box \\- GPAC command-line media packager\n.SH SYNOPSIS\n.LP\n.B MP4Box\n.RI [options] \\ [file] \\ [options]\n.br\n.\n");
    2931             : 
    2932           1 :                 PrintGeneralUsage();
    2933           1 :                 PrintExtractUsage();
    2934           1 :                 PrintDASHUsage();
    2935           1 :                 PrintSplitUsage();
    2936           1 :                 PrintDumpUsage();
    2937           1 :                 PrintImportUsage();
    2938           1 :                 PrintHintUsage();
    2939           1 :                 PrintEncodeUsage();
    2940           1 :                 PrintEncryptUsage();
    2941           1 :                 PrintMetaUsage();
    2942           1 :                 PrintSWFUsage();
    2943           1 :                 PrintTags();
    2944             : #if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG)
    2945           1 :                 PrintLiveUsage();
    2946             : #endif
    2947             : 
    2948           1 :                 fprintf(helpout, ".SH EXAMPLES\n.TP\nBasic and advanced examples are available at https://wiki.gpac.io/MP4Box\n");
    2949           1 :                 fprintf(helpout, ".SH MORE\n.LP\nAuthors: GPAC developers, see git repo history (-log)\n"
    2950             :                 ".br\nFor bug reports, feature requests, more information and source code, visit https://github.com/gpac/gpac\n"
    2951             :                 ".br\nbuild: %s\n"
    2952             :                 ".br\nCopyright: %s\n.br\n"
    2953             :                 ".SH SEE ALSO\n"
    2954             :                 ".LP\ngpac(1), MP4Client(1)\n", gf_gpac_version(), gf_gpac_copyright());
    2955             : 
    2956           1 :                 gf_fclose(helpout);
    2957             :         }
    2958           2 :         return 1;
    2959             : }
    2960             : 
    2961             : static Bool arg_parse_res = 0;
    2962      242165 : u32 mp4box_parse_single_arg_class(int argc, char **argv, char *arg, u32 *arg_index, MP4BoxArg *arg_class)
    2963             : {
    2964             :         MP4BoxArg *arg_desc = NULL;
    2965             :         char *arg_val = NULL;
    2966             :         u32 i=0;
    2967     6063339 :         while (arg_class[i].name) {
    2968             :                 arg_desc = (MP4BoxArg *) &arg_class[i];
    2969     5592468 :                 i++;
    2970             : 
    2971             : #ifdef TEST_ARGS
    2972             :                 char *sep = strchr(arg_desc->name, ' ');
    2973             :                 if (sep) {
    2974             :                         M4_LOG(GF_LOG_ERROR, ("Invalid arg %s, space not allowed\n", arg_desc->name));
    2975             :                         exit(1);
    2976             :                 }
    2977             : #endif
    2978     5592468 :                 if (!strcmp(arg_desc->name, arg+1))
    2979             :                         break;
    2980     5579015 :                 if (arg_desc->altname && !strcmp(arg_desc->altname, arg+1))
    2981             :                         break;
    2982             : 
    2983     5579009 :                 if (arg_desc->parse_flags & ARG_IS_FUN2) {
    2984       41490 :                         if (!strncmp(arg_desc->name, arg+1, strlen(arg_desc->name) ))
    2985             :                                 break;
    2986             :                 }
    2987             :                 arg_desc = NULL;
    2988             :         }
    2989      242165 :         if (!arg_desc)
    2990             :                 return GF_FALSE;
    2991             : 
    2992       13459 :         if (arg_desc->parse_flags & ARG_OPEN_EDIT) open_edit = GF_TRUE;
    2993       13459 :         if (arg_desc->parse_flags & ARG_NEED_SAVE) do_save = GF_TRUE;
    2994       13459 :         if (arg_desc->parse_flags & ARG_NO_INPLACE) no_inplace = GF_TRUE;
    2995             : 
    2996       13459 :         if (arg_desc->type != GF_ARG_BOOL) {
    2997             :                 Bool has_next = GF_TRUE;
    2998        2638 :                 if (*arg_index + 1 == (u32) argc)
    2999             :                         has_next = GF_FALSE;
    3000        2635 :                 else if (argv[*arg_index + 1][0] == '-') {
    3001             :                         s32 v;
    3002          10 :                         if (sscanf(argv[*arg_index + 1], "%d", &v)!=1)
    3003             :                                 has_next = GF_FALSE;
    3004             :                 }
    3005           6 :                 if (!has_next && ! (arg_desc->parse_flags & ARG_EMPTY) ) {
    3006           0 :                         M4_LOG(GF_LOG_ERROR, ("Missing argument value for %s - please check usage\n", arg));
    3007           0 :                         arg_parse_res = 2;
    3008           0 :                         return GF_TRUE;
    3009             :                 }
    3010             : 
    3011        2638 :                 if (has_next && (arg_desc->parse_flags & ARG_EMPTY) && (arg_desc->type==GF_ARG_INT)) {
    3012             :                         s32 ival;
    3013          17 :                         if (sscanf(argv[*arg_index + 1], "%d", &ival) != 1) {
    3014             :                                 has_next = GF_FALSE;
    3015             :                                 arg_val = NULL;
    3016             :                         }
    3017             :                 }
    3018        2623 :                 if (has_next) {
    3019        2617 :                         has_next_arg = GF_TRUE;
    3020        2617 :                         *arg_index += 1;
    3021        2617 :                         arg_val = argv[*arg_index];
    3022             :                 }
    3023             :         }
    3024       13459 :         if (!arg_desc->arg_ptr) return GF_TRUE;
    3025             : 
    3026        8977 :         if (arg_desc->parse_flags & (ARG_IS_FUN|ARG_IS_FUN2) ) {
    3027             :                 u32 res;
    3028        1186 :                 if (arg_desc->parse_flags & ARG_PUSH_SYSARGS)
    3029          19 :                         gf_sys_set_args(argc, (const char**) argv);
    3030             : 
    3031        1186 :                 if (arg_desc->parse_flags & ARG_IS_FUN) {
    3032        1178 :                         parse_arg_fun fun = (parse_arg_fun) arg_desc->arg_ptr;
    3033        1178 :                         res = fun(arg_val, arg_desc->argv_val);
    3034             :                 } else {
    3035           8 :                         parse_arg_fun2 fun2 = (parse_arg_fun2) arg_desc->arg_ptr;
    3036           8 :                         res = fun2(arg, arg_val, arg_desc->argv_val);
    3037             :                 }
    3038             :                 //rewind, not our arg
    3039        1186 :                 if ((res==3) && argv) {
    3040         258 :                         *arg_index -= 1;
    3041             :                         res = 0;
    3042             :                 }
    3043        1186 :                 arg_parse_res = res;
    3044        1186 :                 return GF_TRUE;
    3045             :         }
    3046             : 
    3047        7791 :         if (arg_desc->parse_flags & ARG_INT_INC) {
    3048         502 :                 * (u32 *) arg_desc->arg_ptr += 1;
    3049         502 :                 return GF_TRUE;
    3050             :         }
    3051             : 
    3052        7289 :         if (arg_desc->type == GF_ARG_BOOL) {
    3053        6266 :                 if (!arg_desc->parse_flags) {
    3054        6101 :                         if (arg_desc->argv_val) {
    3055        2852 :                                 * (u32 *) arg_desc->arg_ptr = arg_desc->argv_val;
    3056             :                         } else {
    3057        3249 :                                 * (Bool *) arg_desc->arg_ptr = GF_TRUE;
    3058             :                         }
    3059         165 :                 } else if (arg_desc->parse_flags & ARG_BOOL_REV) {
    3060           0 :                         * (Bool *) arg_desc->arg_ptr = GF_FALSE;
    3061         165 :                 } else if (arg_desc->parse_flags & ARG_HAS_VALUE) {
    3062           7 :                         * (u32 *) arg_desc->arg_ptr = 0;
    3063         158 :                 } else if (arg_desc->parse_flags & ARG_BIT_MASK) {
    3064          10 :                         * (u32 *) arg_desc->arg_ptr |= arg_desc->argv_val;
    3065         148 :                 } else if (arg_desc->parse_flags & ARG_BIT_MASK_REM) {
    3066           2 :                         * (u32 *) arg_desc->arg_ptr &= ~arg_desc->argv_val;
    3067         146 :                 } else if (arg_desc->argv_val) {
    3068           8 :                         * (u32 *) arg_desc->arg_ptr = arg_desc->argv_val;
    3069             :                 } else {
    3070         138 :                         * (u32 *) arg_desc->arg_ptr = GF_TRUE;
    3071             :                 }
    3072             :                 return GF_TRUE;
    3073             :         }
    3074             : 
    3075        1023 :         if (arg_desc->type == GF_ARG_STRING) {
    3076         812 :                 if (arg_desc->parse_flags & ARG_IS_4CC) {
    3077           0 :                         u32 alen = arg_val ? (u32) strlen(arg_val) : 0;
    3078           0 :                         if ((alen<3) || (alen>4)) {
    3079           0 :                                 M4_LOG(GF_LOG_ERROR, ("Value for %s must be a 4CC, %s is not - please check usage\n", arg, arg_val));
    3080           0 :                                 arg_parse_res = 2;
    3081           0 :                                 return GF_TRUE;
    3082             :                         }
    3083           0 :                         * (u32 *) arg_desc->arg_ptr = GF_4CC(arg_val[0], arg_val[1], arg_val[2], arg_val[3]);
    3084           0 :                         return GF_TRUE;
    3085             :                 }
    3086             : 
    3087         812 :                 * (char **) arg_desc->arg_ptr = arg_val;
    3088         812 :                 return GF_TRUE;
    3089             :         }
    3090         211 :         if (!arg_val) {
    3091           0 :                 M4_LOG(GF_LOG_ERROR, ("Missing value for %s - please check usage\n", arg));
    3092           0 :                 arg_parse_res = 2;
    3093           0 :                 return GF_TRUE;
    3094             :         }
    3095             : 
    3096         211 :         if (arg_desc->type == GF_ARG_DOUBLE) {
    3097             :                 Double v = atof(arg_val);
    3098         192 :                 if (arg_desc->parse_flags & ARG_DIV_1000) {
    3099           0 :                         v /= 1000;
    3100             :                 }
    3101         192 :                 if ((arg_desc->parse_flags & ARG_NON_ZERO) && !v) {
    3102           0 :                         M4_LOG(GF_LOG_ERROR, ("Value for %s shall not be 0 - please check usage\n", arg));
    3103           0 :                         arg_parse_res = 2;
    3104           0 :                         return GF_TRUE;
    3105             :                 }
    3106         192 :                 * (Double *) arg_desc->arg_ptr = v;
    3107         192 :                 return GF_TRUE;
    3108             :         }
    3109             : 
    3110          19 :         if (arg_desc->type != GF_ARG_INT) {
    3111           0 :                 M4_LOG(GF_LOG_ERROR, ("Unsupported argument type for %s - please report to gpac devs\n", arg));
    3112           0 :                 arg_parse_res = 2;
    3113           0 :                 return GF_TRUE;
    3114             :         }
    3115          19 :         if (arg_desc->parse_flags & ARG_64BITS) {
    3116             :                 u64 v;
    3117           0 :                 sscanf(arg_val, LLU, &v);
    3118           0 :                 if (arg_desc->parse_flags & ARG_DIV_1000) {
    3119           0 :                         v /= 1000;
    3120             :                 }
    3121           0 :                 if ((arg_desc->parse_flags & ARG_NON_ZERO) && !v) {
    3122           0 :                         M4_LOG(GF_LOG_ERROR, ("Value for %s shall not be 0 - please check usage\n", arg));
    3123           0 :                         arg_parse_res = 2;
    3124           0 :                         return GF_TRUE;
    3125             :                 }
    3126           0 :                 * (u64 *) arg_desc->arg_ptr = v;
    3127             :         } else {
    3128          19 :                 u32 v = atoi(arg_val);
    3129          19 :                 if (arg_desc->parse_flags & ARG_DIV_1000) {
    3130           0 :                         v /= 1000;
    3131             :                 }
    3132          19 :                 if ((arg_desc->parse_flags & ARG_NON_ZERO) && !v) {
    3133           0 :                         M4_LOG(GF_LOG_ERROR, ("Value for %s shall not be 0 - please check usage\n", arg));
    3134           0 :                         arg_parse_res = 2;
    3135           0 :                         return GF_TRUE;
    3136             :                 }
    3137          19 :                 * (s32 *) arg_desc->arg_ptr = v;
    3138             :         }
    3139             :         return GF_TRUE;
    3140             : }
    3141             : 
    3142       26923 : Bool mp4box_parse_single_arg(int argc, char **argv, char *arg, u32 *arg_index)
    3143             : {
    3144       26923 :         if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_gen_args)) return GF_TRUE;
    3145       20930 :         if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_split_args)) return GF_TRUE;
    3146       20922 :         if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_dash_args)) return GF_TRUE;
    3147       20486 :         if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_imp_args)) return GF_TRUE;
    3148       19982 :         if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_senc_args)) return GF_TRUE;
    3149       19937 :         if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_crypt_args)) return GF_TRUE;
    3150       19710 :         if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_hint_args)) return GF_TRUE;
    3151       19607 :         if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_extr_args)) return GF_TRUE;
    3152       19537 :         if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_dump_args)) return GF_TRUE;
    3153       13630 :         if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_meta_args)) return GF_TRUE;
    3154       13506 :         if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_swf_args)) return GF_TRUE;
    3155       13498 :         if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_liveenc_args)) return GF_TRUE;
    3156       13497 :         if (mp4box_parse_single_arg_class(argc, argv, arg, arg_index, m4b_usage_args)) return GF_TRUE;
    3157             : 
    3158       13464 :         return GF_FALSE;
    3159             : }
    3160             : 
    3161             : 
    3162        4485 : u32 mp4box_parse_args(int argc, char **argv)
    3163             : {
    3164             :         u32 i;
    3165             :         /*parse our args*/
    3166       40334 :         for (i = 1; i < (u32)argc; i++) {
    3167       35887 :                 char *arg = argv[i];
    3168             :                 /*input file(s)*/
    3169       35887 :                 if ((arg[0] != '-') || !stricmp(arg, "--")) {
    3170             :                         char *arg_val = arg;
    3171        4477 :                         if (!stricmp(arg, "--")) {
    3172           0 :                                 if (i+1==(u32)argc) {
    3173           0 :                                         M4_LOG(GF_LOG_ERROR, ("Missing arg for `--` - please check usage\n"));
    3174             :                                         return 2;
    3175             :                                 }
    3176           0 :                                 has_next_arg = GF_TRUE;
    3177           0 :                                 arg_val = argv[i + 1];
    3178           0 :                                 i++;
    3179             :                         }
    3180        4477 :                         if (argc < 3) {
    3181           0 :                                 M4_LOG(GF_LOG_ERROR, ("Error - only one input file found as argument, please check usage\n"));
    3182             :                                 return 2;
    3183             :                         }
    3184        4477 :                         else if (inName) {
    3185          33 :                                 if (dash_duration) {
    3186          33 :                                         if (!nb_dash_inputs) {
    3187          27 :                                                 dash_inputs = set_dash_input(dash_inputs, inName, &nb_dash_inputs);
    3188             :                                         }
    3189          33 :                                         dash_inputs = set_dash_input(dash_inputs, arg_val, &nb_dash_inputs);
    3190             :                                 }
    3191             :                                 else {
    3192           0 :                                         M4_LOG(GF_LOG_ERROR, ("Error - 2 input names specified, please check usage\n"));
    3193             :                                         return 2;
    3194             :                                 }
    3195             :                         }
    3196             :                         else {
    3197        4444 :                                 inName = arg_val;
    3198             :                         }
    3199             :                 }
    3200             :                 //all deprecated options
    3201       31410 :                 else if (!stricmp(arg, "-grab-ts") || !stricmp(arg, "-atsc") || !stricmp(arg, "-rtp")) {
    3202           0 :                         M4_LOG(GF_LOG_ERROR, ("Deprecated fuctionnality `%s` - use gpac application\n", arg));
    3203             :                         return 2;
    3204             :                 }
    3205       31410 :                 else if (!stricmp(arg, "-write-buffer")) {
    3206           1 :                         M4_LOG(GF_LOG_WARNING, ("`%s` option deprecated, use `-bs-cache-size`", arg));
    3207           1 :                         gf_opts_set_key("temp", "bs-cache-size", argv[i + 1]);
    3208           1 :                         i++;
    3209             :                 }
    3210       31409 :                 else if (!stricmp(arg, "-pssh-moof")) {
    3211           0 :                         M4_LOG(GF_LOG_ERROR, ("`-pssh-moof` option deprecated , use `-pssh` option\n"));
    3212             :                         return 2;
    3213             :                 }
    3214       31409 :                 else if (!stricmp(arg, "-tag-list")) {
    3215           0 :                         M4_LOG(GF_LOG_ERROR, ("`-tag-list` option deprecated, use `-h tags`\n"));
    3216             :                         return 2;
    3217             :                 }
    3218       31409 :                 else if (!stricmp(arg, "-aviraw")) {
    3219           4 :                         M4_LOG(GF_LOG_ERROR, ("`-aviraw` option deprecated, use `-raw`\n"));
    3220             :                         return 2;
    3221             :                 }
    3222       31405 :                 else if (!stricmp(arg, "-avi")) {
    3223           1 :                         M4_LOG(GF_LOG_ERROR, ("`-avi` option deprecated, use `-mux`\n"));
    3224             :                         return 2;
    3225             :                 }
    3226       31404 :                 else if (!strncmp(arg, "-p=", 3)) {
    3227        4481 :                         continue;
    3228             :                 }
    3229             : 
    3230             :                 //parse argument
    3231       26923 :                 else if (mp4box_parse_single_arg(argc, argv, arg, &i)) {
    3232       13459 :                         if (arg_parse_res)
    3233          30 :                                 return mp4box_cleanup(arg_parse_res);
    3234             :                 }
    3235             :                 //not a MP4Box arg
    3236             :                 else {
    3237       13464 :                         u32 res = gf_sys_is_gpac_arg(arg);
    3238       13464 :                         if (res==0) {
    3239           2 :                                 PrintHelp(arg, GF_FALSE, GF_TRUE);
    3240           2 :                                 return 2;
    3241       13462 :                         } else if (res==2) {
    3242           1 :                                 i++;
    3243             :                         }
    3244             :                 }
    3245             :                 //live scene encoder does not use the unified parsing and should be moved as a scene encoder filter
    3246       31369 :                 if (live_scene) return 0;
    3247             :         }
    3248             :         return 0;
    3249             : }
    3250             : 
    3251             : /*
    3252             :         END OF OPTION PARSING CODE
    3253             : */
    3254             : 
    3255             : 
    3256             : 
    3257       12474 : void scene_coding_log(void *cbk, GF_LOG_Level log_level, GF_LOG_Tool log_tool, const char *fmt, va_list vlist)
    3258             : {
    3259             :         FILE *logs = cbk;
    3260       12474 :         if (log_tool != GF_LOG_CODING) return;
    3261             :         vfprintf(logs, fmt, vlist);
    3262       12453 :         fflush(logs);
    3263             : }
    3264             : 
    3265             : 
    3266             : #ifndef GPAC_DISABLE_ISOM_HINTING
    3267             : 
    3268             : /*
    3269             :                 MP4 File Hinting
    3270             : */
    3271             : 
    3272           5 : void SetupClockReferences(GF_ISOFile *file)
    3273             : {
    3274             :         u32 i, count, ocr_id;
    3275           5 :         count = gf_isom_get_track_count(file);
    3276           5 :         if (count==1) return;
    3277             :         ocr_id = 0;
    3278          15 :         for (i=0; i<count; i++) {
    3279          12 :                 if (!gf_isom_is_track_in_root_od(file, i+1)) continue;
    3280           2 :                 ocr_id = gf_isom_get_track_id(file, i+1);
    3281           2 :                 break;
    3282             :         }
    3283             :         /*doesn't look like MP4*/
    3284           5 :         if (!ocr_id) return;
    3285          10 :         for (i=0; i<count; i++) {
    3286           8 :                 GF_ESD *esd = gf_isom_get_esd(file, i+1, 1);
    3287           8 :                 if (esd) {
    3288           8 :                         esd->OCRESID = ocr_id;
    3289           8 :                         gf_isom_change_mpeg4_description(file, i+1, 1, esd);
    3290           8 :                         gf_odf_desc_del((GF_Descriptor *) esd);
    3291             :                 }
    3292             :         }
    3293             : }
    3294             : 
    3295             : /*base RTP payload type used (you can specify your own types if needed)*/
    3296             : #define BASE_PAYT               96
    3297             : 
    3298          56 : GF_Err HintFile(GF_ISOFile *file, u32 MTUSize, u32 max_ptime, u32 rtp_rate, u32 base_flags, Bool copy_data, Bool interleave, Bool regular_iod, Bool single_group, Bool hint_no_offset)
    3299             : {
    3300             :         GF_ESD *esd;
    3301             :         GF_InitialObjectDescriptor *iod;
    3302             :         u32 i, val, res, streamType;
    3303             :         u32 sl_mode, prev_ocr, single_ocr, nb_done, tot_bw, bw, flags, spec_type;
    3304             :         GF_Err e;
    3305             :         char szPayload[30];
    3306             :         GF_RTPHinter *hinter;
    3307             :         Bool copy, has_iod, single_av;
    3308             :         u8 init_payt = BASE_PAYT;
    3309             :         u32 mtype;
    3310             :         GF_SDP_IODProfile iod_mode = GF_SDP_IOD_NONE;
    3311             :         u32 media_group = 0;
    3312             :         u8 media_prio = 0;
    3313             : 
    3314             :         tot_bw = 0;
    3315             :         prev_ocr = 0;
    3316             :         single_ocr = 1;
    3317             : 
    3318             :         has_iod = 1;
    3319          56 :         iod = (GF_InitialObjectDescriptor *) gf_isom_get_root_od(file);
    3320          56 :         if (!iod) has_iod = 0;
    3321             :         else {
    3322          31 :                 if (!gf_list_count(iod->ESDescriptors)) has_iod = 0;
    3323          31 :                 gf_odf_desc_del((GF_Descriptor *) iod);
    3324             :         }
    3325             : 
    3326          56 :         spec_type = gf_isom_guess_specification(file);
    3327          56 :         single_av = single_group ? 1 : gf_isom_is_single_av(file);
    3328             : 
    3329             :         /*first make sure we use a systems track as base OCR*/
    3330         173 :         for (i=0; i<gf_isom_get_track_count(file); i++) {
    3331          66 :                 res = gf_isom_get_media_type(file, i+1);
    3332          66 :                 if ((res==GF_ISOM_MEDIA_SCENE) || (res==GF_ISOM_MEDIA_OD)) {
    3333           5 :                         if (gf_isom_is_track_in_root_od(file, i+1)) {
    3334           5 :                                 gf_isom_set_default_sync_track(file, i+1);
    3335           5 :                                 break;
    3336             :                         }
    3337             :                 }
    3338             :         }
    3339             : 
    3340             :         nb_done = 0;
    3341         210 :         for (i=0; i<gf_isom_get_track_count(file); i++) {
    3342             :                 sl_mode = base_flags;
    3343             :                 copy = copy_data;
    3344             :                 /*skip emty tracks (mainly MPEG-4 interaction streams...*/
    3345         155 :                 if (!gf_isom_get_sample_count(file, i+1)) continue;
    3346         151 :                 if (!gf_isom_is_track_enabled(file, i+1)) {
    3347           0 :                         M4_LOG(GF_LOG_INFO, ("Track ID %d disabled - skipping hint\n", gf_isom_get_track_id(file, i+1) ));
    3348           0 :                         continue;
    3349             :                 }
    3350             : 
    3351         151 :                 mtype = gf_isom_get_media_type(file, i+1);
    3352         151 :                 switch (mtype) {
    3353          32 :                 case GF_ISOM_MEDIA_VISUAL:
    3354          32 :                         if (single_av) {
    3355             :                                 media_group = 2;
    3356             :                                 media_prio = 2;
    3357             :                         }
    3358             :                         break;
    3359           0 :         case GF_ISOM_MEDIA_AUXV:
    3360           0 :             if (single_av) {
    3361             :                 media_group = 2;
    3362             :                 media_prio = 3;
    3363             :             }
    3364             :             break;
    3365           0 :         case GF_ISOM_MEDIA_PICT:
    3366           0 :             if (single_av) {
    3367             :                 media_group = 2;
    3368             :                 media_prio = 4;
    3369             :             }
    3370             :             break;
    3371          29 :                 case GF_ISOM_MEDIA_AUDIO:
    3372          29 :                         if (single_av) {
    3373             :                                 media_group = 2;
    3374             :                                 media_prio = 1;
    3375             :                         }
    3376             :                         break;
    3377          73 :                 case GF_ISOM_MEDIA_HINT:
    3378          73 :                         continue;
    3379          17 :                 default:
    3380             :                         /*no hinting of systems track on isma*/
    3381          17 :                         if (spec_type==GF_ISOM_BRAND_ISMA) continue;
    3382             :                 }
    3383          78 :                 mtype = gf_isom_get_media_subtype(file, i+1, 1);
    3384          78 :                 if ((mtype==GF_ISOM_SUBTYPE_MPEG4) || (mtype==GF_ISOM_SUBTYPE_MPEG4_CRYP) ) mtype = gf_isom_get_mpeg4_subtype(file, i+1, 1);
    3385             : 
    3386          78 :                 if (!single_av) {
    3387             :                         /*one media per group only (we should prompt user for group selection)*/
    3388          13 :                         media_group ++;
    3389             :                         media_prio = 1;
    3390             :                 }
    3391             : 
    3392             :                 streamType = 0;
    3393          78 :                 esd = gf_isom_get_esd(file, i+1, 1);
    3394          78 :                 if (esd && esd->decoderConfig) {
    3395          69 :                         streamType = esd->decoderConfig->streamType;
    3396          69 :                         if (!prev_ocr) {
    3397          47 :                                 prev_ocr = esd->OCRESID;
    3398          47 :                                 if (!esd->OCRESID) prev_ocr = esd->ESID;
    3399          22 :                         } else if (esd->OCRESID && prev_ocr != esd->OCRESID) {
    3400             :                                 single_ocr = 0;
    3401             :                         }
    3402             :                         /*OD MUST BE WITHOUT REFERENCES*/
    3403          69 :                         if (streamType==1) copy = 1;
    3404             :                 }
    3405          78 :                 gf_odf_desc_del((GF_Descriptor *) esd);
    3406             : 
    3407          78 :                 if (!regular_iod && gf_isom_is_track_in_root_od(file, i+1)) {
    3408             :                         /*single AU - check if base64 would fit in ESD (consider 33% overhead of base64), otherwise stream*/
    3409          10 :                         if (gf_isom_get_sample_count(file, i+1)==1) {
    3410           4 :                                 GF_ISOSample *samp = gf_isom_get_sample(file, i+1, 1, &val);
    3411           4 :                                 if (streamType && samp) {
    3412           4 :                                         res = gf_hinter_can_embbed_data(samp->data, samp->dataLength, streamType);
    3413             :                                 } else {
    3414             :                                         /*not a system track, we shall hint it*/
    3415             :                                         res = 0;
    3416             :                                 }
    3417           4 :                                 if (samp) gf_isom_sample_del(&samp);
    3418           4 :                                 if (res) continue;
    3419             :                         }
    3420             :                 }
    3421          74 :                 if (interleave) sl_mode |= GP_RTP_PCK_USE_INTERLEAVING;
    3422             : 
    3423          74 :                 hinter = gf_hinter_track_new(file, i+1, MTUSize, max_ptime, rtp_rate, sl_mode, init_payt, copy, media_group, media_prio, &e);
    3424             : 
    3425          74 :                 if (!hinter) {
    3426           1 :                         if (e) {
    3427           1 :                                 M4_LOG(nb_done ? GF_LOG_WARNING : GF_LOG_ERROR, ("Cannot create hinter (%s)\n", gf_error_to_string(e) ));
    3428           1 :                                 if (!nb_done) return e;
    3429             :                         }
    3430           0 :                         continue;
    3431             :                 }
    3432             : 
    3433          73 :                 if (hint_no_offset)
    3434           1 :                         gf_hinter_track_force_no_offsets(hinter);
    3435             : 
    3436          73 :                 bw = gf_hinter_track_get_bandwidth(hinter);
    3437          73 :                 tot_bw += bw;
    3438          73 :                 flags = gf_hinter_track_get_flags(hinter);
    3439             : 
    3440             :                 //set extraction mode for AVC/SVC
    3441          73 :                 gf_isom_set_nalu_extract_mode(file, i+1, GF_ISOM_NALU_EXTRACT_LAYER_ONLY);
    3442             : 
    3443          73 :                 gf_hinter_track_get_payload_name(hinter, szPayload);
    3444          73 :                 M4_LOG(GF_LOG_INFO, ("Hinting track ID %d - Type \"%s:%s\" (%s) - BW %d kbps\n", gf_isom_get_track_id(file, i+1), gf_4cc_to_str(mtype), gf_4cc_to_str(mtype), szPayload, bw));
    3445          73 :                 if (flags & GP_RTP_PCK_SYSTEMS_CAROUSEL) M4_LOG(GF_LOG_INFO, ("\tMPEG-4 Systems stream carousel enabled\n"));
    3446          73 :                 e = gf_hinter_track_process(hinter);
    3447             : 
    3448          73 :                 if (!e) e = gf_hinter_track_finalize(hinter, has_iod);
    3449          73 :                 gf_hinter_track_del(hinter);
    3450             : 
    3451          73 :                 if (e) {
    3452           0 :                         M4_LOG(GF_LOG_ERROR, ("Error while hinting (%s)\n", gf_error_to_string(e)));
    3453           0 :                         if (!nb_done) return e;
    3454             :                 }
    3455          73 :                 init_payt++;
    3456          73 :                 nb_done ++;
    3457             :         }
    3458             : 
    3459          55 :         if (has_iod) {
    3460             :                 iod_mode = GF_SDP_IOD_ISMA;
    3461           5 :                 if (regular_iod) iod_mode = GF_SDP_IOD_REGULAR;
    3462             :         } else {
    3463             :                 iod_mode = GF_SDP_IOD_NONE;
    3464             :         }
    3465          55 :         gf_hinter_finalize(file, iod_mode, tot_bw);
    3466             : 
    3467          55 :         if (!single_ocr)
    3468           0 :                 M4_LOG(GF_LOG_WARNING, ("Warning: at least 2 timelines found in the file\nThis may not be supported by servers/players\n\n"));
    3469             : 
    3470             :         return GF_OK;
    3471             : }
    3472             : 
    3473             : #endif /*GPAC_DISABLE_ISOM_HINTING*/
    3474             : 
    3475             : #if !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_AV_PARSERS)
    3476             : 
    3477          62 : static void check_media_profile(GF_ISOFile *file, u32 track)
    3478             : {
    3479             :         u8 PL;
    3480          62 :         GF_ESD *esd = gf_isom_get_esd(file, track, 1);
    3481          62 :         if (!esd) return;
    3482             : 
    3483          43 :         switch (esd->decoderConfig->streamType) {
    3484          42 :         case 0x04:
    3485          42 :                 PL = gf_isom_get_pl_indication(file, GF_ISOM_PL_VISUAL);
    3486          42 :                 if (esd->decoderConfig->objectTypeIndication==GF_CODECID_MPEG4_PART2) {
    3487             :                         GF_M4VDecSpecInfo vdsi;
    3488           0 :                         gf_m4v_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &vdsi);
    3489           0 :                         if (vdsi.VideoPL > PL) gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, vdsi.VideoPL);
    3490          42 :                 } else if ((esd->decoderConfig->objectTypeIndication==GF_CODECID_AVC) || (esd->decoderConfig->objectTypeIndication==GF_CODECID_SVC)) {
    3491           8 :                         gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, 0x15);
    3492          34 :                 } else if (!PL) {
    3493           5 :                         gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, 0xFE);
    3494             :                 }
    3495             :                 break;
    3496           1 :         case 0x05:
    3497           1 :                 PL = gf_isom_get_pl_indication(file, GF_ISOM_PL_AUDIO);
    3498           1 :                 switch (esd->decoderConfig->objectTypeIndication) {
    3499           1 :                 case GF_CODECID_AAC_MPEG2_MP:
    3500             :                 case GF_CODECID_AAC_MPEG2_LCP:
    3501             :                 case GF_CODECID_AAC_MPEG2_SSRP:
    3502             :                 case GF_CODECID_AAC_MPEG4:
    3503             :                 {
    3504             :                         GF_M4ADecSpecInfo adsi;
    3505           1 :                         gf_m4a_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &adsi);
    3506           1 :                         if (adsi.audioPL > PL) gf_isom_set_pl_indication(file, GF_ISOM_PL_AUDIO, adsi.audioPL);
    3507             :                 }
    3508           1 :                         break;
    3509           0 :                 default:
    3510           0 :                         if (!PL) gf_isom_set_pl_indication(file, GF_ISOM_PL_AUDIO, 0xFE);
    3511             :                 }
    3512             :                 break;
    3513             :         }
    3514          43 :         gf_odf_desc_del((GF_Descriptor *) esd);
    3515             : }
    3516         341 : void remove_systems_tracks(GF_ISOFile *file)
    3517             : {
    3518             :         u32 i, count;
    3519             : 
    3520         341 :         count = gf_isom_get_track_count(file);
    3521         341 :         if (count==1) return;
    3522             : 
    3523             :         /*force PL rewrite*/
    3524          14 :         gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, 0);
    3525          14 :         gf_isom_set_pl_indication(file, GF_ISOM_PL_AUDIO, 0);
    3526          14 :         gf_isom_set_pl_indication(file, GF_ISOM_PL_OD, 1);      /*the lib always remove IOD when no profiles are specified..*/
    3527             : 
    3528          88 :         for (i=0; i<gf_isom_get_track_count(file); i++) {
    3529          74 :                 switch (gf_isom_get_media_type(file, i+1)) {
    3530          62 :                 case GF_ISOM_MEDIA_VISUAL:
    3531             :         case GF_ISOM_MEDIA_AUXV:
    3532             :         case GF_ISOM_MEDIA_PICT:
    3533             :                 case GF_ISOM_MEDIA_AUDIO:
    3534             :                 case GF_ISOM_MEDIA_TEXT:
    3535             :                 case GF_ISOM_MEDIA_SUBT:
    3536          62 :                         gf_isom_remove_track_from_root_od(file, i+1);
    3537          62 :                         check_media_profile(file, i+1);
    3538          62 :                         break;
    3539             :                 /*only remove real systems tracks (eg, delaing with scene description & presentation)
    3540             :                 but keep meta & all unknown tracks*/
    3541           1 :                 case GF_ISOM_MEDIA_SCENE:
    3542           1 :                         switch (gf_isom_get_media_subtype(file, i+1, 1)) {
    3543           0 :                         case GF_ISOM_MEDIA_DIMS:
    3544           0 :                                 gf_isom_remove_track_from_root_od(file, i+1);
    3545           0 :                                 continue;
    3546             :                         default:
    3547             :                                 break;
    3548             :                         }
    3549           2 :                 case GF_ISOM_MEDIA_OD:
    3550             :                 case GF_ISOM_MEDIA_OCR:
    3551             :                 case GF_ISOM_MEDIA_MPEGJ:
    3552           2 :                         gf_isom_remove_track(file, i+1);
    3553           2 :                         i--;
    3554           2 :                         break;
    3555             :                 default:
    3556             :                         break;
    3557             :                 }
    3558             :         }
    3559             :         /*none required*/
    3560          14 :         if (!gf_isom_get_pl_indication(file, GF_ISOM_PL_AUDIO)) gf_isom_set_pl_indication(file, GF_ISOM_PL_AUDIO, 0xFF);
    3561          14 :         if (!gf_isom_get_pl_indication(file, GF_ISOM_PL_VISUAL)) gf_isom_set_pl_indication(file, GF_ISOM_PL_VISUAL, 0xFF);
    3562             : 
    3563          14 :         gf_isom_set_pl_indication(file, GF_ISOM_PL_OD, 0xFF);
    3564          14 :         gf_isom_set_pl_indication(file, GF_ISOM_PL_SCENE, 0xFF);
    3565          14 :         gf_isom_set_pl_indication(file, GF_ISOM_PL_GRAPHICS, 0xFF);
    3566          14 :         gf_isom_set_pl_indication(file, GF_ISOM_PL_INLINE, 0);
    3567             : }
    3568             : 
    3569             : #endif /*!defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_AV_PARSERS)*/
    3570             : 
    3571        1227 : GF_FileType get_file_type_by_ext(char *inName)
    3572             : {
    3573             :         GF_FileType type = GF_FILE_TYPE_NOT_SUPPORTED;
    3574        1227 :         char *ext = strrchr(inName, '.');
    3575        1227 :         if (ext) {
    3576             :                 char *sep;
    3577        1227 :                 if (!strcmp(ext, ".gz")) ext = strrchr(ext-1, '.');
    3578        1227 :                 ext+=1;
    3579        1227 :                 sep = strchr(ext, '.');
    3580        1227 :                 if (sep) sep[0] = 0;
    3581             : 
    3582        1227 :                 if (!stricmp(ext, "mp4") || !stricmp(ext, "3gp") || !stricmp(ext, "mov") || !stricmp(ext, "3g2") || !stricmp(ext, "3gs")) {
    3583             :                         type = GF_FILE_TYPE_ISO_MEDIA;
    3584         373 :                 } else if (!stricmp(ext, "bt") || !stricmp(ext, "wrl") || !stricmp(ext, "x3dv")) {
    3585             :                         type = GF_FILE_TYPE_BT_WRL_X3DV;
    3586         367 :                 } else if (!stricmp(ext, "xmt") || !stricmp(ext, "x3d")) {
    3587             :                         type = GF_FILE_TYPE_XMT_X3D;
    3588         365 :                 } else if (!stricmp(ext, "lsr") || !stricmp(ext, "saf")) {
    3589             :                         type = GF_FILE_TYPE_LSR_SAF;
    3590         363 :                 } else if (!stricmp(ext, "svg") || !stricmp(ext, "xsr") || !stricmp(ext, "xml")) {
    3591             :                         type = GF_FILE_TYPE_SVG;
    3592         225 :                 } else if (!stricmp(ext, "swf")) {
    3593             :                         type = GF_FILE_TYPE_SWF;
    3594         223 :                 } else if (!stricmp(ext, "jp2")) {
    3595           1 :                         if (sep) sep[0] = '.';
    3596             :                         return GF_FILE_TYPE_NOT_SUPPORTED;
    3597             :                 }
    3598             :                 else type = GF_FILE_TYPE_NOT_SUPPORTED;
    3599             : 
    3600        1226 :                 if (sep) sep[0] = '.';
    3601             :         }
    3602             : 
    3603             : 
    3604             :         /*try open file in read mode*/
    3605        1226 :         if (!type && gf_isom_probe_file(inName)) type = GF_FILE_TYPE_ISO_MEDIA;
    3606             :         return type;
    3607             : }
    3608             : 
    3609             : 
    3610             : #ifndef GPAC_DISABLE_CORE_TOOLS
    3611           1 : static GF_Err xml_bs_to_bin(char *inName, char *outName, u32 dump_std)
    3612             : {
    3613             :         GF_Err e;
    3614             :         GF_XMLNode *root;
    3615           1 :         u8 *data = NULL;
    3616             :         u32 data_size;
    3617             : 
    3618           1 :         GF_DOMParser *dom = gf_xml_dom_new();
    3619           1 :         e = gf_xml_dom_parse(dom, inName, NULL, NULL);
    3620           1 :         if (e) {
    3621           0 :                 gf_xml_dom_del(dom);
    3622           0 :                 M4_LOG(GF_LOG_ERROR, ("Failed to parse XML file: %s\n", gf_error_to_string(e)));
    3623             :                 return e;
    3624             :         }
    3625           1 :         root = gf_xml_dom_get_root_idx(dom, 0);
    3626           1 :         if (!root) {
    3627           0 :                 gf_xml_dom_del(dom);
    3628           0 :                 return GF_OK;
    3629             :         }
    3630             : 
    3631           1 :         e = gf_xml_parse_bit_sequence(root, inName, &data, &data_size);
    3632           1 :         gf_xml_dom_del(dom);
    3633             : 
    3634           1 :         if (e) {
    3635           0 :                 M4_LOG(GF_LOG_ERROR, ("Failed to parse binary sequence: %s\n", gf_error_to_string(e)));
    3636             :                 return e;
    3637             :         }
    3638             : 
    3639           1 :         if (dump_std) {
    3640           0 :                 gf_fwrite(data, data_size, stdout);
    3641             :         } else {
    3642             :                 FILE *t;
    3643             :                 char szFile[GF_MAX_PATH];
    3644           1 :                 if (outName) {
    3645             :                         strcpy(szFile, outName);
    3646             :                 } else {
    3647             :                         strcpy(szFile, inName);
    3648             :                         strcat(szFile, ".bin");
    3649             :                 }
    3650           1 :                 t = gf_fopen(szFile, "wb");
    3651           1 :                 if (!t) {
    3652           0 :                         M4_LOG(GF_LOG_ERROR, ("Failed to open file %s\n", szFile));
    3653             :                         e = GF_IO_ERR;
    3654             :                 } else {
    3655           1 :                         if (gf_fwrite(data, data_size, t) != data_size) {
    3656           0 :                                 M4_LOG(GF_LOG_ERROR, ("Failed to write output to file %s\n", szFile));
    3657             :                                 e = GF_IO_ERR;
    3658             :                         }
    3659           1 :                         gf_fclose(t);
    3660             :                 }
    3661             :         }
    3662           1 :         gf_free(data);
    3663           1 :         return e;
    3664             : }
    3665             : #endif /*GPAC_DISABLE_CORE_TOOLS*/
    3666             : 
    3667           1 : static u64 do_size_top_boxes(char *inName, char *compress_top_boxes, u32 mode)
    3668             : {
    3669             :         FILE *in;
    3670             :         u64 top_size = 0;
    3671             :         Bool do_all = GF_FALSE;
    3672             :         GF_BitStream *bs_in;
    3673           1 :         if (!compress_top_boxes) return GF_BAD_PARAM;
    3674           1 :         if (!strcmp(compress_top_boxes, "all") || !strcmp(compress_top_boxes, "*") || !strcmp(compress_top_boxes, "@"))
    3675             :                 do_all = GF_TRUE;
    3676             : 
    3677           1 :         in = gf_fopen(inName, "rb");
    3678           1 :         if (!in) return GF_URL_ERROR;
    3679           1 :         bs_in = gf_bs_from_file(in, GF_BITSTREAM_READ);
    3680          27 :         while (gf_bs_available(bs_in)) {
    3681             :                 const char *stype;
    3682             :                 u32 hdr_size = 8;
    3683          25 :                 u64 lsize = gf_bs_read_u32(bs_in);
    3684          25 :                 u32 type = gf_bs_read_u32(bs_in);
    3685             : 
    3686          25 :                 if (lsize==1) {
    3687           0 :                         lsize = gf_bs_read_u64(bs_in);
    3688             :                         hdr_size = 16;
    3689          25 :                 } else if (lsize==0) {
    3690           0 :                         lsize = gf_bs_available(bs_in) + 8;
    3691             :                 }
    3692          25 :                 stype = gf_4cc_to_str(type);
    3693          25 :                 if (do_all || strstr(compress_top_boxes, stype)) {
    3694             :                         //only count boxes
    3695          11 :                         if (mode==2) {
    3696           0 :                                 top_size += 1;
    3697             :                         } else {
    3698          11 :                                 top_size += lsize;
    3699             :                         }
    3700             :                 }
    3701          25 :                 gf_bs_skip_bytes(bs_in, lsize - hdr_size);
    3702             :         }
    3703           1 :         gf_bs_del(bs_in);
    3704           1 :         gf_fclose(in);
    3705           1 :         return top_size;
    3706             : 
    3707             : }
    3708             : 
    3709           1 : static GF_Err do_compress_top_boxes(char *inName, char *outName)
    3710             : {
    3711             :         FILE *in, *out;
    3712             :         u8 *buf;
    3713             :         u32 buf_alloc, comp_size;
    3714             :         s32 bytes_comp=0;
    3715             :         s32 bytes_uncomp=0;
    3716             :         GF_Err e = GF_OK;
    3717             :         u64 source_size, dst_size;
    3718             :         u32 orig_box_overhead;
    3719             :         u32 final_box_overhead;
    3720             :         u32 nb_added_box_bytes=0;
    3721             :         Bool has_mov = GF_FALSE;
    3722           1 :         Bool replace_all = !strcmp(compress_top_boxes, "*");
    3723             :         GF_BitStream *bs_in, *bs_out;
    3724             : 
    3725           1 :         if (!outName) {
    3726           0 :                 M4_LOG(GF_LOG_ERROR, ("Missing output file name\n"));
    3727             :                 return GF_BAD_PARAM;
    3728             :         }
    3729             : 
    3730           1 :         in = gf_fopen(inName, "rb");
    3731           1 :         if (!in) return GF_URL_ERROR;
    3732           1 :         out = gf_fopen(outName, "wb");
    3733           1 :         if (!out) return GF_IO_ERR;
    3734             : 
    3735             :         buf_alloc = 4096;
    3736           1 :         buf = gf_malloc(buf_alloc);
    3737             : 
    3738           1 :         bs_in = gf_bs_from_file(in, GF_BITSTREAM_READ);
    3739           1 :         source_size = gf_bs_get_size(bs_in);
    3740             : 
    3741           1 :         bs_out = gf_bs_from_file(out, GF_BITSTREAM_WRITE);
    3742             : 
    3743             :         orig_box_overhead = 0;
    3744             :         final_box_overhead = 0;
    3745          27 :         while (gf_bs_available(bs_in)) {
    3746          25 :                 u32 size = gf_bs_read_u32(bs_in);
    3747          25 :                 u32 type = gf_bs_read_u32(bs_in);
    3748          25 :                 const char *b4cc = gf_4cc_to_str(type);
    3749          25 :                 const u8 *replace = (const u8 *) strstr(compress_top_boxes, b4cc);
    3750          25 :                 if (!strcmp(b4cc, "moov")) has_mov = GF_TRUE;
    3751             : 
    3752          25 :                 if (!replace && !replace_all) {
    3753          14 :                         gf_bs_write_u32(bs_out, size);
    3754          14 :                         gf_bs_write_u32(bs_out, type);
    3755             : 
    3756          14 :                         size-=8;
    3757         103 :                         while (size) {
    3758             :                                 u32 nbytes = size;
    3759          75 :                                 if (nbytes>buf_alloc) nbytes=buf_alloc;
    3760          75 :                                 gf_bs_read_data(bs_in, buf, nbytes);
    3761          75 :                                 gf_bs_write_data(bs_out, buf, nbytes);
    3762          75 :                                 size-=nbytes;
    3763             :                         }
    3764          14 :                         continue;
    3765             :                 }
    3766          11 :                 orig_box_overhead += size;
    3767             : 
    3768          11 :                 size-=8;
    3769             : 
    3770          11 :                 if (size>buf_alloc) {
    3771             :                         buf_alloc = size;
    3772           0 :                         buf = gf_realloc(buf, buf_alloc);
    3773             :                 }
    3774          11 :                 gf_bs_read_data(bs_in, buf, size);
    3775             : 
    3776          11 :                 replace+=5;
    3777             : 
    3778          11 :                 comp_size = buf_alloc;
    3779             : 
    3780          11 :                 e = gf_gz_compress_payload(&buf, size, &comp_size);
    3781          11 :                 if (e) break;
    3782             : 
    3783          11 :                 if (comp_size>buf_alloc) {
    3784             :                         buf_alloc = comp_size;
    3785             :                 }
    3786          11 :                 bytes_uncomp += size;
    3787          11 :                 bytes_comp += comp_size;
    3788             : 
    3789             :                 //write size
    3790          11 :                 gf_bs_write_u32(bs_out, comp_size+8);
    3791             :                 //write type
    3792          11 :                 gf_bs_write_data(bs_out, replace, 4);
    3793             :                 //write data
    3794          11 :                 gf_bs_write_data(bs_out, buf, comp_size);
    3795             : 
    3796          11 :                 final_box_overhead += 8+comp_size;
    3797             :         }
    3798           1 :         dst_size = gf_bs_get_position(bs_out);
    3799             : 
    3800           1 :         if (buf) gf_free(buf);
    3801           1 :         gf_bs_del(bs_in);
    3802           1 :         gf_bs_del(bs_out);
    3803           1 :         gf_fclose(in);
    3804           1 :         gf_fclose(out);
    3805           1 :         if (e) {
    3806           0 :                 M4_LOG(GF_LOG_ERROR, ("Error compressing: %s\n", gf_error_to_string(e)));
    3807             :                 return e;
    3808             :         }
    3809             : 
    3810           1 :         if (has_mov) {
    3811             :                 u32 i, nb_tracks, nb_samples;
    3812             :                 GF_ISOFile *mov;
    3813             :                 Double rate, new_rate, duration;
    3814             : 
    3815           1 :                 mov = gf_isom_open(inName, GF_ISOM_OPEN_READ, NULL);
    3816           1 :                 duration = (Double) gf_isom_get_duration(mov);
    3817           1 :                 duration /= gf_isom_get_timescale(mov);
    3818             : 
    3819             :                 nb_samples = 0;
    3820           1 :                 nb_tracks = gf_isom_get_track_count(mov);
    3821           4 :                 for (i=0; i<nb_tracks; i++) {
    3822           2 :                         nb_samples += gf_isom_get_sample_count(mov, i+1);
    3823             :                 }
    3824           1 :                 gf_isom_close(mov);
    3825             : 
    3826           1 :                 rate = (Double) source_size;
    3827           1 :                 rate /= duration;
    3828           1 :                 rate /= 1000;
    3829             : 
    3830           1 :                 new_rate = (Double) dst_size;
    3831           1 :                 new_rate /= duration;
    3832           1 :                 new_rate /= 1000;
    3833             : 
    3834             : 
    3835           1 :                 fprintf(stderr, "Log format:\nname\torig\tcomp\tgain\tadded_bytes\torate\tcrate\tsamples\tduration\tobbps\tcbbps\n");
    3836           1 :                 fprintf(stdout, "%s\t%d\t%d\t%g\t%d\t%g\t%g\t%d\t%g\t%g\t%g\n", inName, bytes_uncomp, bytes_comp, ((Double)(bytes_uncomp-bytes_comp)*100)/bytes_uncomp, nb_added_box_bytes, rate, new_rate, nb_samples, duration, ((Double)orig_box_overhead)/nb_samples, ((Double)final_box_overhead)/nb_samples );
    3837             : 
    3838           1 :                 fprintf(stderr, "%s Compressing top-level boxes saved %d bytes out of %d (reduced by %g %%) additional bytes %d original rate %g kbps new rate %g kbps, orig %g box bytes/sample final %g bytes/sample\n", inName, bytes_uncomp-bytes_comp, bytes_uncomp, ((Double)(bytes_uncomp-bytes_comp)*100)/bytes_uncomp, nb_added_box_bytes, rate, new_rate, ((Double)orig_box_overhead)/nb_samples, ((Double)final_box_overhead)/nb_samples );
    3839             : 
    3840             :         } else {
    3841           0 :                 fprintf(stderr, "Log format:\nname\torig\tcomp\tgain\tadded_bytes\n");
    3842           0 :                 fprintf(stdout, "%s\t%d\t%d\t%g\t%d\n", inName, bytes_uncomp, bytes_comp, ((Double) (bytes_uncomp - bytes_comp)*100)/(bytes_uncomp), nb_added_box_bytes);
    3843             : 
    3844           0 :                 fprintf(stderr, "%s Compressing top-level boxes saved %d bytes out of %d (reduced by %g %%) additional bytes %d\n", inName, bytes_uncomp-bytes_comp, bytes_uncomp, ((Double)(bytes_uncomp-bytes_comp)*100)/bytes_uncomp, nb_added_box_bytes);
    3845             : 
    3846             :         }
    3847             :         return GF_OK;
    3848             : }
    3849             : 
    3850        2686 : static GF_Err hash_file(char *name, u32 dump_std)
    3851             : {
    3852             :         u32 i;
    3853             :         u8 hash[20];
    3854        2686 :         GF_Err e = gf_media_get_file_hash(name, hash);
    3855        2686 :         if (e) return e;
    3856        2676 :         if (dump_std==2) {
    3857        2676 :                 gf_fwrite(hash, 20, stdout);
    3858           0 :         } else if (dump_std==1) {
    3859           0 :                 for (i=0; i<20; i++) fprintf(stdout, "%02X", hash[i]);
    3860             :         }
    3861        2676 :         fprintf(stderr, "File hash (SHA-1): ");
    3862       56196 :         for (i=0; i<20; i++) fprintf(stderr, "%02X", hash[i]);
    3863        2676 :         fprintf(stderr, "\n");
    3864             : 
    3865        2676 :         return GF_OK;
    3866             : }
    3867             : 
    3868           0 : static u32 do_raw_cat()
    3869             : {
    3870             :         char chunk[4096];
    3871             :         FILE *fin, *fout;
    3872             :         s64 to_copy, done;
    3873           0 :         fin = gf_fopen(raw_cat, "rb");
    3874           0 :         if (!fin) return mp4box_cleanup(1);
    3875             : 
    3876           0 :         fout = gf_fopen(inName, "a+b");
    3877           0 :         if (!fout) {
    3878           0 :                 gf_fclose(fin);
    3879           0 :                 return mp4box_cleanup(1);
    3880             :         }
    3881           0 :         gf_fseek(fin, 0, SEEK_END);
    3882           0 :         to_copy = gf_ftell(fin);
    3883           0 :         gf_fseek(fin, 0, SEEK_SET);
    3884             :         done = 0;
    3885             :         while (1) {
    3886           0 :                 u32 nb_bytes = (u32) gf_fread(chunk, 4096, fin);
    3887           0 :                 gf_fwrite(chunk, nb_bytes, fout);
    3888           0 :                 done += nb_bytes;
    3889           0 :                 fprintf(stderr, "Appending file %s - %02.2f done\r", raw_cat, 100.0*done/to_copy);
    3890           0 :                 if (done >= to_copy) break;
    3891             :         }
    3892           0 :         gf_fclose(fin);
    3893           0 :         gf_fclose(fout);
    3894           0 :         return mp4box_cleanup(0);
    3895             : }
    3896             : 
    3897           0 : static u32 do_write_udp()
    3898             : {
    3899             :         GF_Err e;
    3900           0 :         GF_Socket *sock = gf_sk_new(GF_SOCK_TYPE_UDP);
    3901             :         u16 port = 2345;
    3902           0 :         char *sep = strrchr(udp_dest, ':');
    3903           0 :         if (sep) {
    3904           0 :                 sep[0] = 0;
    3905           0 :                 port = atoi(sep+1);
    3906             :         }
    3907           0 :         e = gf_sk_bind( sock, "127.0.0.1", 0, udp_dest, port, 0);
    3908           0 :         if (sep) sep[0] = ':';
    3909           0 :         if (e) {
    3910           0 :                 M4_LOG(GF_LOG_ERROR, ("Failed to bind socket to %s: %s\n", udp_dest, gf_error_to_string(e) ));
    3911             :         } else {
    3912           0 :                 e = gf_sk_send(sock, (u8 *) inName, (u32)strlen(inName));
    3913           0 :                 if (e)
    3914           0 :                         M4_LOG(GF_LOG_ERROR, ("Failed to send datagram: %s\n", gf_error_to_string(e) ));
    3915             :         }
    3916           0 :         gf_sk_del(sock);
    3917           0 :         return 0;
    3918             : }
    3919             : 
    3920             : #ifndef GPAC_DISABLE_MPD
    3921           3 : static u32 convert_mpd()
    3922             : {
    3923             :         GF_Err e;
    3924             :         Bool remote = GF_FALSE;
    3925             :         GF_MPD *mpd;
    3926           3 :         char *mpd_base_url = NULL;
    3927           3 :         if (!strnicmp(inName, "http://", 7) || !strnicmp(inName, "https://", 8)) {
    3928             : #if !defined(GPAC_DISABLE_CORE_TOOLS)
    3929           0 :                 e = gf_dm_wget(inName, "tmp_main.m3u8", 0, 0, &mpd_base_url);
    3930           0 :                 if (e != GF_OK) {
    3931           0 :                         M4_LOG(GF_LOG_ERROR, ("Cannot retrieve M3U8 (%s): %s\n", inName, gf_error_to_string(e)));
    3932           0 :                         if (mpd_base_url) gf_free(mpd_base_url);
    3933           0 :                         return mp4box_cleanup(1);
    3934             :                 }
    3935             :                 remote = GF_TRUE;
    3936             : #else
    3937             :                 gf_free(mpd_base_url);
    3938             :                 M4_LOG(GF_LOG_ERROR, ("HTTP Downloader disabled in this build\n"));
    3939             :                 return mp4box_cleanup(1);
    3940             : #endif
    3941             : 
    3942           0 :                 if (outName)
    3943             :                         strcpy(outfile, outName);
    3944             :                 else {
    3945           0 :                         const char *sep = gf_file_basename(inName);
    3946           0 :                         char *ext = gf_file_ext_start(sep);
    3947           0 :                         if (ext) ext[0] = 0;
    3948             :                         sprintf(outfile, "%s.mpd", sep);
    3949           0 :                         if (ext) ext[0] = '.';
    3950             :                 }
    3951             :         } else {
    3952           3 :                 if (outName)
    3953             :                         strcpy(outfile, outName);
    3954             :                 else {
    3955           0 :                         char *dst = strdup(inName);
    3956           0 :                         char *ext = strstr(dst, ".m3u8");
    3957           0 :                         if (ext) ext[0] = 0;
    3958             :                         sprintf(outfile, "%s.mpd", dst);
    3959           0 :                         gf_free(dst);
    3960             :                 }
    3961             :         }
    3962             : 
    3963           3 :         mpd = gf_mpd_new();
    3964           3 :         if (!mpd) {
    3965             :                 e = GF_OUT_OF_MEM;
    3966           0 :                 M4_LOG(GF_LOG_ERROR, ("[DASH] Error: MPD creation problem %s\n", gf_error_to_string(e)));
    3967           0 :                 mp4box_cleanup(1);
    3968             :         }
    3969           3 :         FILE *f = gf_fopen(remote ? "tmp_main.m3u8" : inName, "r");
    3970             :         u32 manif_type = 0;
    3971           3 :         if (f) {
    3972             :                 char szDATA[1000];
    3973             :                 s32 read;
    3974           3 :                 szDATA[999]=0;
    3975           3 :                 read = (s32) gf_fread(szDATA, 999, f);
    3976           3 :                 if (read<0) read = 0;
    3977           3 :                 szDATA[read]=0;
    3978           3 :                 gf_fclose(f);
    3979           3 :                 if (strstr(szDATA, "SmoothStreamingMedia"))
    3980             :                         manif_type = 2;
    3981           2 :                 else if (strstr(szDATA, "#EXTM3U"))
    3982             :                         manif_type = 1;
    3983             :         }
    3984             : 
    3985             :         if (manif_type==1) {
    3986           2 :                 e = gf_m3u8_to_mpd(remote ? "tmp_main.m3u8" : inName, mpd_base_url ? mpd_base_url : inName, outfile, 0, "video/mp2t", GF_TRUE, use_url_template, segment_timeline, NULL, mpd, GF_TRUE, GF_TRUE);
    3987           1 :         } else if (manif_type==2) {
    3988           1 :                 e = gf_mpd_smooth_to_mpd(remote ? "tmp_main.m3u8" : inName, mpd, mpd_base_url ? mpd_base_url : inName);
    3989             :         } else {
    3990             :                 e = GF_NOT_SUPPORTED;
    3991             :         }
    3992           3 :         if (!e)
    3993           3 :                 gf_mpd_write_file(mpd, outfile);
    3994             : 
    3995           3 :         if (mpd)
    3996           3 :                 gf_mpd_del(mpd);
    3997           3 :         if (mpd_base_url)
    3998           0 :                 gf_free(mpd_base_url);
    3999             : 
    4000           3 :         if (remote) {
    4001           0 :                 gf_file_delete("tmp_main.m3u8");
    4002             :         }
    4003           3 :         if (e != GF_OK) {
    4004           0 :                 M4_LOG(GF_LOG_ERROR, ("Error converting %s (%s) to MPD (%s): %s\n", (manif_type==1) ? "HLS" : "Smooth",  inName, outfile, gf_error_to_string(e)));
    4005           0 :                 return mp4box_cleanup(1);
    4006             :         } else {
    4007           3 :                 M4_LOG(GF_LOG_INFO, ("Done converting %s (%s) to MPD (%s)\n", (manif_type==1) ? "HLS" : "Smooth",  inName, outfile));
    4008           3 :                 return mp4box_cleanup(0);
    4009             :         }
    4010             : }
    4011             : #endif
    4012             : 
    4013           6 : static u32 do_import_sub()
    4014             : {
    4015             :         /* We import the subtitle file,
    4016             :            i.e. we parse it and store the content as samples of a 3GPP Timed Text track in an ISO file,
    4017             :            possibly for later export (e.g. when converting SRT to TTXT, ...) */
    4018             : #ifndef GPAC_DISABLE_MEDIA_IMPORT
    4019             :         GF_Err e;
    4020             :         GF_MediaImporter import;
    4021             :         /* Prepare the importer */
    4022           6 :         file = gf_isom_open("ttxt_convert", GF_ISOM_OPEN_WRITE, NULL);
    4023           6 :         if (timescale && file) gf_isom_set_timescale(file, timescale);
    4024             : 
    4025             :         memset(&import, 0, sizeof(GF_MediaImporter));
    4026           6 :         import.dest = file;
    4027           6 :         import.in_name = inName;
    4028             :         /* Start the import */
    4029           6 :         e = gf_media_import(&import);
    4030           6 :         if (e) {
    4031           0 :                 M4_LOG(GF_LOG_ERROR, ("Error importing %s: %s\n", inName, gf_error_to_string(e)));
    4032           0 :                 gf_isom_delete(file);
    4033           0 :                 gf_file_delete("ttxt_convert");
    4034           0 :                 return mp4box_cleanup(1);
    4035             :         }
    4036             :         /* Prepare the export */
    4037           6 :         strcpy(outfile, inName);
    4038           6 :         if (strchr(outfile, '.')) {
    4039          20 :                 while (outfile[strlen(outfile)-1] != '.') outfile[strlen(outfile)-1] = 0;
    4040           6 :                 outfile[strlen(outfile)-1] = 0;
    4041             :         }
    4042             : #ifndef GPAC_DISABLE_ISOM_DUMP
    4043             :         /* Start the export of the track #1, in the appropriate dump type, indicating it's a conversion */
    4044          24 :         dump_isom_timed_text(file, gf_isom_get_track_id(file, 1),
    4045          12 :                                                   dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE,
    4046             :                                                   GF_TRUE,
    4047          10 :                                                   (import_subtitle==2) ? GF_TEXTDUMPTYPE_SVG : (dump_srt ? GF_TEXTDUMPTYPE_SRT : GF_TEXTDUMPTYPE_TTXT));
    4048             : #endif
    4049             :         /* Clean the importer */
    4050           6 :         gf_isom_delete(file);
    4051           6 :         gf_file_delete("ttxt_convert");
    4052             :         if (e) {
    4053             :                 M4_LOG(GF_LOG_ERROR, ("Error converting %s: %s\n", inName, gf_error_to_string(e)));
    4054             :                 return mp4box_cleanup(1);
    4055             :         }
    4056           6 :         return mp4box_cleanup(0);
    4057             : #else
    4058             :         M4_LOG(GF_LOG_ERROR, ("Feature not supported\n"));
    4059             :         return mp4box_cleanup(1);
    4060             : #endif
    4061             : }
    4062             : 
    4063             : #if !defined(GPAC_DISABLE_MEDIA_IMPORT) && !defined(GPAC_DISABLE_ISOM_WRITE)
    4064         455 : static u32 do_add_cat(int argc, char **argv)
    4065             : {
    4066             :         GF_Err e;
    4067             :         u32 i, ipass, nb_pass = 1;
    4068         455 :         char *mux_args=NULL;
    4069             :         GF_FilterSession *fs = NULL;
    4070         455 :         if (nb_add) {
    4071             : 
    4072             :                 GF_ISOOpenMode open_mode = GF_ISOM_OPEN_EDIT;
    4073         446 :                 if (force_new) {
    4074         445 :                         open_mode = (do_flat || (force_new==2)) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT;
    4075             :                 } else {
    4076           1 :                         FILE *test = gf_fopen(inName, "rb");
    4077           1 :                         if (!test) {
    4078           1 :                                 open_mode = (do_flat) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT;
    4079           1 :                                 if (!outName) outName = inName;
    4080             :                         } else {
    4081           0 :                                 gf_fclose(test);
    4082           0 :                                 if (! gf_isom_probe_file(inName) ) {
    4083           0 :                                         open_mode = (do_flat) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT;
    4084           0 :                                         if (!outName) outName = inName;
    4085             :                                 }
    4086             :                         }
    4087             :                 }
    4088         446 :                 open_edit = do_flat ? GF_FALSE : GF_TRUE;
    4089         446 :                 file = gf_isom_open(inName, open_mode, NULL);
    4090         446 :                 if (!file) {
    4091           0 :                         M4_LOG(GF_LOG_ERROR, ("Cannot open destination file %s: %s\n", inName, gf_error_to_string(gf_isom_last_error(NULL)) ));
    4092           0 :                         return mp4box_cleanup(1);
    4093             :                 }
    4094             : 
    4095         446 :                 if (freeze_box_order)
    4096           4 :                         gf_isom_freeze_order(file);
    4097             : 
    4098         446 :                 if (do_flat) {
    4099           2 :                         if (major_brand)
    4100           0 :                                 gf_isom_set_brand_info(file, major_brand, minor_version);
    4101           0 :                         for (i=0; i<nb_alt_brand_add; i++) {
    4102           0 :                                 gf_isom_modify_alternate_brand(file, brand_add[i], GF_TRUE);
    4103           0 :                                 do_save = GF_TRUE;
    4104             :                         }
    4105             : 
    4106           2 :                         if (!major_brand && !nb_alt_brand_add && has_add_image) {
    4107           0 :                                 gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_MIF1, GF_TRUE);
    4108             :                         }
    4109             :                 }
    4110             :         }
    4111             : 
    4112         455 :         if (file && keep_utc && open_edit) {
    4113           0 :                 gf_isom_keep_utc_times(file, 1);
    4114             :         }
    4115             : 
    4116         455 :         if (do_flat && interleaving_time) {
    4117             :                 char szSubArg[100];
    4118           1 :                 gf_isom_set_storage_mode(file, GF_ISOM_STORE_FASTSTART);
    4119           1 :                 do_flat = 2;
    4120             :                 nb_pass = 2;
    4121           1 :                 fs = gf_fs_new_defaults(0);
    4122           1 :                 if (!fs) {
    4123           0 :                         M4_LOG(GF_LOG_ERROR, ("Error creating filter session\n"));
    4124           0 :                         gf_isom_delete(file);
    4125           0 :                         return mp4box_cleanup(1);
    4126             :                 }
    4127             : 
    4128             :                 //mux args
    4129           1 :                 gf_dynstrcat(&mux_args, "mp4mx:importer:store=fstart", ":");
    4130             : 
    4131           1 :                 sprintf(szSubArg, "file=%p", file);
    4132           1 :                 gf_dynstrcat(&mux_args, szSubArg, ":");
    4133           1 :                 sprintf(szSubArg, "cdur=%g", interleaving_time);
    4134           1 :                 gf_dynstrcat(&mux_args, szSubArg, ":");
    4135             :         }
    4136             : 
    4137         908 :         for (ipass=0; ipass<nb_pass; ipass++) {
    4138             :                 u32 tk_idx = 1;
    4139        8932 :                 for (i=0; i<(u32) argc; i++) {
    4140        4241 :                         char *margs=NULL;
    4141        4241 :                         if (!strcmp(argv[i], "-add")) {
    4142         488 :                                 char *src = argv[i+1];
    4143             : 
    4144         977 :                                 while (src) {
    4145             :                                         char *loc_src = src;
    4146             :                                         char *sep = NULL;
    4147           0 :                                         while (1) {
    4148             :                                                 char *opt_sep;
    4149         489 :                                                 sep = strchr(loc_src, '+');
    4150         489 :                                                 if (!sep) break;
    4151             : 
    4152           1 :                                                 sep[0] = 0;
    4153           1 :                                                 if (strstr(src, "://"))
    4154             :                                                         break;
    4155             : 
    4156           1 :                                                 opt_sep = gf_url_colon_suffix(src);
    4157           1 :                                                 if (opt_sep)
    4158           0 :                                                         opt_sep[0] = 0;
    4159           1 :                                                 if (gf_file_exists(src)) {
    4160           1 :                                                         if (opt_sep)
    4161           0 :                                                                 opt_sep[0] = ':';
    4162             :                                                         break;
    4163             :                                                 }
    4164           0 :                                                 if (opt_sep)
    4165           0 :                                                         opt_sep[0] = ':';
    4166             : 
    4167           0 :                                                 sep[0] = '+';
    4168           0 :                                                 loc_src = sep+1;
    4169             :                                         }
    4170             : 
    4171         489 :                                         e = import_file(file, src, import_flags, import_fps, agg_samples, fs, (fs && (ipass==0)) ? &margs : NULL, tk_idx);
    4172         489 :                                         tk_idx++;
    4173             : 
    4174         489 :                                         if (margs) {
    4175           0 :                                                 gf_dynstrcat(&mux_args, margs, ":");
    4176           0 :                                                 gf_free(margs);
    4177             :                                         }
    4178             : 
    4179         489 :                                         if (e) {
    4180           3 :                                                 M4_LOG(GF_LOG_ERROR, ("Error importing %s: %s\n", argv[i+1], gf_error_to_string(e)));
    4181           3 :                                                 gf_isom_delete(file);
    4182           3 :                                                 if (fs)
    4183           0 :                                                         gf_fs_del(fs);
    4184           6 :                                                 return mp4box_cleanup(1);
    4185             :                                         }
    4186         486 :                                         if (sep) {
    4187           1 :                                                 sep[0] = '+';
    4188           1 :                                                 src = sep+1;
    4189             :                                         } else {
    4190             :                                                 break;
    4191             :                                         }
    4192             :                                 }
    4193             :                                 i++;
    4194        3753 :                         } else if (!strcmp(argv[i], "-cat") || !strcmp(argv[i], "-catx") || !strcmp(argv[i], "-catpl")) {
    4195          16 :                                 if (nb_pass == 2) {
    4196           0 :                                         M4_LOG(GF_LOG_ERROR, ("Cannot cat files when using -newfs mode\n"));
    4197           0 :                                         return mp4box_cleanup(1);
    4198             :                                 }
    4199          16 :                                 if (!file) {
    4200             :                                         u8 open_mode = GF_ISOM_OPEN_EDIT;
    4201           9 :                                         if (force_new) {
    4202           6 :                                                 open_mode = (do_flat) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT;
    4203             :                                         } else {
    4204           3 :                                                 FILE *test = gf_fopen(inName, "rb");
    4205           3 :                                                 if (!test) {
    4206           0 :                                                         open_mode = (do_flat) ? GF_ISOM_OPEN_WRITE : GF_ISOM_WRITE_EDIT;
    4207           0 :                                                         if (!outName) outName = inName;
    4208             :                                                 }
    4209           3 :                                                 else gf_fclose(test);
    4210             :                                         }
    4211             : 
    4212           9 :                                         open_edit = GF_TRUE;
    4213           9 :                                         file = gf_isom_open(inName, open_mode, NULL);
    4214           9 :                                         if (!file) {
    4215           0 :                                                 M4_LOG(GF_LOG_ERROR, ("Cannot open destination file %s: %s\n", inName, gf_error_to_string(gf_isom_last_error(NULL)) ));
    4216           0 :                                                 return mp4box_cleanup(1);
    4217             :                                         }
    4218             :                                 }
    4219             : 
    4220          16 :                                 e = cat_isomedia_file(file, argv[i+1], import_flags, import_fps, agg_samples, force_cat, align_cat, !strcmp(argv[i], "-catx") ? GF_TRUE : GF_FALSE, !strcmp(argv[i], "-catpl") ? GF_TRUE : GF_FALSE);
    4221          16 :                                 if (e) {
    4222           0 :                                         M4_LOG(GF_LOG_ERROR, ("Error appending %s: %s\n", argv[i+1], gf_error_to_string(e)));
    4223           0 :                                         gf_isom_delete(file);
    4224           0 :                                         return mp4box_cleanup(1);
    4225             :                                 }
    4226             :                                 i++;
    4227             :                         }
    4228             :                 }
    4229         453 :                 if ((nb_pass == 2) && !ipass) {
    4230           1 :                         GF_Filter *mux_filter = gf_fs_load_filter(fs, mux_args, NULL);
    4231           1 :                         gf_free(mux_args);
    4232           1 :                         if (!mux_filter) {
    4233           0 :                                 M4_LOG(GF_LOG_ERROR, ("Error loadin isobmff mux filter\n"));
    4234           0 :                                 gf_isom_delete(file);
    4235           0 :                                 gf_fs_del(fs);
    4236           0 :                                 return mp4box_cleanup(1);
    4237             :                         }
    4238             : 
    4239           1 :                         e = gf_fs_run(fs);
    4240           1 :                         if (e==GF_EOS) e = GF_OK;
    4241             : 
    4242           0 :                         if (!e) e = gf_fs_get_last_connect_error(fs);
    4243           1 :                         if (!e) e = gf_fs_get_last_process_error(fs);
    4244             : 
    4245           1 :                         if (e) {
    4246           0 :                                 M4_LOG(GF_LOG_ERROR, ("Error importing sources: %s\n", gf_error_to_string(e)));
    4247           0 :                                 gf_isom_delete(file);
    4248           0 :                                 gf_fs_del(fs);
    4249           0 :                                 return mp4box_cleanup(1);
    4250             :                         }
    4251             :                 }
    4252             :         }
    4253         452 :         if (fs) {
    4254           1 :                 gf_fs_print_non_connected(fs);
    4255           1 :                 if (fs_dump_flags & 1) gf_fs_print_stats(fs);
    4256           1 :                 if (fs_dump_flags & 2) gf_fs_print_connections(fs);
    4257           1 :                 gf_fs_del(fs);
    4258             :         }
    4259             : 
    4260             :         /*unless explicitly asked, remove all systems tracks*/
    4261             : #ifndef GPAC_DISABLE_AV_PARSERS
    4262         452 :         if (!keep_sys_tracks) remove_systems_tracks(file);
    4263             : #endif
    4264         452 :         do_save = GF_TRUE;
    4265             : 
    4266         452 :         return 0;
    4267             : }
    4268             : #endif /*!GPAC_DISABLE_MEDIA_IMPORT && !GPAC_DISABLE_ISOM_WRITE*/
    4269             : 
    4270             : 
    4271             : #if !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_SCENE_ENCODER) && !defined(GPAC_DISABLE_MEDIA_IMPORT)
    4272          33 : static GF_Err do_scene_encode()
    4273             : {
    4274             :         GF_Err e;
    4275             :         FILE *logs = NULL;
    4276          33 :         if (do_scene_log) {
    4277             :                 char alogfile[GF_MAX_PATH];
    4278           4 :                 strcpy(alogfile, inName);
    4279           4 :                 if (strchr(alogfile, '.')) {
    4280           9 :                         while (alogfile[strlen(alogfile)-1] != '.') alogfile[strlen(alogfile)-1] = 0;
    4281           4 :                         alogfile[strlen(alogfile)-1] = 0;
    4282             :                 }
    4283             :                 strcat(alogfile, "_enc.logs");
    4284           4 :                 logs = gf_fopen(alogfile, "wt");
    4285             :         }
    4286          33 :         strcpy(outfile, outName ? outName : inName);
    4287          33 :         if (strchr(outfile, '.')) {
    4288          83 :                 while (outfile[strlen(outfile)-1] != '.') outfile[strlen(outfile)-1] = 0;
    4289          33 :                 outfile[strlen(outfile)-1] = 0;
    4290             :         }
    4291             :         strcat(outfile, ".mp4");
    4292          33 :         file = gf_isom_open(outfile, GF_ISOM_WRITE_EDIT, NULL);
    4293          33 :         smenc_opts.mediaSource = mediaSource ? mediaSource : outfile;
    4294          33 :         e = EncodeFile(inName, file, &smenc_opts, logs);
    4295          33 :         if (logs) gf_fclose(logs);
    4296          33 :         if (e) return e;
    4297          33 :         do_save = GF_TRUE;
    4298          33 :         if (do_saf) {
    4299           1 :                 do_save = GF_FALSE;
    4300           1 :                 open_edit = GF_FALSE;
    4301             :         }
    4302             :         return GF_OK;
    4303             : }
    4304             : #endif //!defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_SCENE_ENCODER) && !defined(GPAC_DISABLE_MEDIA_IMPORT)
    4305             : 
    4306             : 
    4307         176 : static GF_Err do_dash()
    4308             : {
    4309             :         GF_Err e;
    4310             :         u32 i;
    4311             :         Bool del_file = GF_FALSE;
    4312             :         char szMPD[GF_MAX_PATH], *sep;
    4313             :         char szStateFile[GF_MAX_PATH];
    4314             :         Bool dyn_state_file = GF_FALSE;
    4315             :         u32 do_abort = 0;
    4316         176 :         GF_DASHSegmenter *dasher=NULL;
    4317             : 
    4318         176 :         if (crypt) {
    4319           0 :                 M4_LOG(GF_LOG_ERROR, ("MP4Box cannot use -crypt and -dash in the same pass. Please encrypt your content first, or specify encryption filters on dash sources.\n"));
    4320             :                 return GF_BAD_PARAM;
    4321             :         }
    4322             : 
    4323         176 :         strcpy(outfile, outName ? outName : gf_url_get_resource_name(inName) );
    4324         176 :         sep = strrchr(outfile, '.');
    4325         176 :         if (sep) sep[0] = 0;
    4326         176 :         if (!outName) strcat(outfile, "_dash");
    4327             :         strcpy(szMPD, outfile);
    4328         176 :         if (outName && sep) {
    4329         176 :                 sep[0] = '.';
    4330             :                 strcat(szMPD, sep);
    4331             :         } else {
    4332             :                 strcat(szMPD, ".mpd");
    4333             :         }
    4334             : 
    4335         176 :         if ((dash_subduration>0) && (dash_duration > dash_subduration)) {
    4336           0 :                 M4_LOG(GF_LOG_WARNING, ("Warning: -subdur parameter (%g s) should be greater than segment duration (%g s), using segment duration instead\n", dash_subduration, dash_duration));
    4337           0 :                 dash_subduration = dash_duration;
    4338             :         }
    4339             : 
    4340         176 :         if (dash_mode && dash_live)
    4341           8 :                 M4_LOG(GF_LOG_INFO, ("Live DASH-ing - press 'q' to quit, 's' to save context and quit\n"));
    4342             : 
    4343         183 :         if (!dash_ctx_file && dash_live) {
    4344             :                 u32 r1;
    4345           7 :                 u64 add = (u64) (intptr_t) &dasher;
    4346           7 :                 add ^= gf_net_get_utc();
    4347           7 :                 r1 = (u32) add ^ (u32) (add/0xFFFFFFFF);
    4348           7 :                 r1 ^= gf_rand();
    4349           7 :                 sprintf(szStateFile, "%s/dasher_%X.xml", gf_get_default_cache_directory(), r1 );
    4350           7 :                 dash_ctx_file = szStateFile;
    4351             :                 dyn_state_file = GF_TRUE;
    4352         169 :         } else if (dash_ctx_file) {
    4353           7 :                 if (force_new)
    4354           0 :                         gf_file_delete(dash_ctx_file);
    4355             :         }
    4356             : 
    4357         176 :         if (dash_profile==GF_DASH_PROFILE_AUTO)
    4358          21 :                 dash_profile = dash_mode ? GF_DASH_PROFILE_LIVE : GF_DASH_PROFILE_FULL;
    4359             : 
    4360         176 :         if (!dash_mode) {
    4361         165 :                 time_shift_depth = 0;
    4362         165 :                 mpd_update_time = 0;
    4363          11 :         } else if ((dash_profile>=GF_DASH_PROFILE_MAIN) && !use_url_template && !mpd_update_time) {
    4364             :                 /*use a default MPD update of dash_duration sec*/
    4365           0 :                 mpd_update_time = (Double) (dash_subduration ? dash_subduration : dash_duration);
    4366           0 :                 M4_LOG(GF_LOG_INFO, ("Using default MPD refresh of %g seconds\n", mpd_update_time));
    4367             :         }
    4368             : 
    4369         176 :         if (file && do_save) {
    4370           0 :                 gf_isom_close(file);
    4371           0 :                 file = NULL;
    4372             :                 del_file = GF_TRUE;
    4373             :         }
    4374             : 
    4375             :         /*setup dash*/
    4376         176 :         dasher = gf_dasher_new(szMPD, dash_profile, NULL, dash_scale, dash_ctx_file);
    4377         176 :         if (!dasher) {
    4378           0 :                 return mp4box_cleanup(1);
    4379             :         }
    4380         176 :         e = gf_dasher_set_info(dasher, dash_title, cprt, dash_more_info, dash_source, NULL);
    4381         176 :         if (e) {
    4382           0 :                 M4_LOG(GF_LOG_ERROR, ("DASH Error: %s\n", gf_error_to_string(e)));
    4383           0 :                 gf_dasher_del(dasher);
    4384           0 :                 return e;
    4385             :         }
    4386             : 
    4387         176 :         gf_dasher_set_start_date(dasher, dash_start_date);
    4388         176 :         gf_dasher_set_location(dasher, dash_source);
    4389         177 :         for (i=0; i < nb_mpd_base_urls; i++) {
    4390           1 :                 e = gf_dasher_add_base_url(dasher, mpd_base_urls[i]);
    4391           1 :                 if (e) {
    4392           0 :                         M4_LOG(GF_LOG_ERROR, ("DASH Error: %s\n", gf_error_to_string(e)));
    4393           0 :                         gf_dasher_del(dasher);
    4394           0 :                         return e;
    4395             :                 }
    4396             :         }
    4397             : 
    4398         176 :         if (segment_timeline && !use_url_template) {
    4399           5 :                 M4_LOG(GF_LOG_WARNING, ("DASH Warning: using -segment-timeline with no -url-template. Forcing URL template.\n"));
    4400           5 :                 use_url_template = GF_TRUE;
    4401             :         }
    4402             : 
    4403         176 :         e = gf_dasher_enable_url_template(dasher, (Bool) use_url_template, seg_name, seg_ext, init_seg_ext);
    4404         176 :         if (!e) e = gf_dasher_enable_segment_timeline(dasher, segment_timeline);
    4405         176 :         if (!e) e = gf_dasher_enable_single_segment(dasher, single_segment);
    4406         176 :         if (!e) e = gf_dasher_enable_single_file(dasher, single_file);
    4407         176 :         if (!e) e = gf_dasher_set_switch_mode(dasher, bitstream_switching_mode);
    4408         176 :         if (!e) e = gf_dasher_set_durations(dasher, dash_duration, interleaving_time, dash_subduration);
    4409         176 :         if (!e) e = gf_dasher_enable_rap_splitting(dasher, seg_at_rap, frag_at_rap);
    4410         176 :         if (!e) e = gf_dasher_set_segment_marker(dasher, segment_marker);
    4411         176 :         if (!e) e = gf_dasher_enable_sidx(dasher, (subsegs_per_sidx>=0) ? 1 : 0, (u32) subsegs_per_sidx, daisy_chain_sidx, use_ssix);
    4412         176 :         if (!e) e = gf_dasher_set_dynamic_mode(dasher, dash_mode, mpd_update_time, time_shift_depth, mpd_live_duration);
    4413         176 :         if (!e) e = gf_dasher_set_min_buffer(dasher, min_buffer);
    4414         176 :         if (!e) e = gf_dasher_set_ast_offset(dasher, ast_offset_ms);
    4415         176 :         if (!e) e = gf_dasher_enable_memory_fragmenting(dasher, memory_frags);
    4416         176 :         if (!e) e = gf_dasher_set_initial_isobmf(dasher, initial_moof_sn, initial_tfdt);
    4417         176 :         if (!e) e = gf_dasher_configure_isobmf_default(dasher, no_fragments_defaults, pssh_mode, samplegroups_in_traf, single_traf_per_moof, tfdt_per_traf, mvex_after_traks, sdtp_in_traf);
    4418         176 :         if (!e) e = gf_dasher_enable_utc_ref(dasher, insert_utc);
    4419         176 :         if (!e) e = gf_dasher_enable_real_time(dasher, frag_real_time);
    4420         176 :         if (!e) e = gf_dasher_set_content_protection_location_mode(dasher, cp_location_mode);
    4421         176 :         if (!e) e = gf_dasher_set_profile_extension(dasher, dash_profile_extension);
    4422         176 :         if (!e) e = gf_dasher_enable_cached_inputs(dasher, no_cache);
    4423         176 :         if (!e) e = gf_dasher_enable_loop_inputs(dasher, ! no_loop);
    4424         176 :         if (!e) e = gf_dasher_set_split_mode(dasher, dash_split_mode);
    4425         176 :         if (!e) e = gf_dasher_set_last_segment_merge(dasher, merge_last_seg);
    4426         176 :         if (!e) e = gf_dasher_set_hls_clock(dasher, hls_clock);
    4427         176 :         if (!e && dash_cues) e = gf_dasher_set_cues(dasher, dash_cues, strict_cues);
    4428         176 :         if (!e) e = gf_dasher_print_session_info(dasher, fs_dump_flags);
    4429         176 :         if (!e)  e = gf_dasher_keep_source_utc(dasher, keep_utc);
    4430             : 
    4431         209 :         for (i=0; i < nb_dash_inputs; i++) {
    4432         209 :                 if (!e) e = gf_dasher_add_input(dasher, &dash_inputs[i]);
    4433             :         }
    4434         176 :         if (e) {
    4435           0 :                 M4_LOG(GF_LOG_ERROR, ("DASH Setup Error: %s\n", gf_error_to_string(e)));
    4436           0 :                 gf_dasher_del(dasher);
    4437           0 :                 return e;
    4438             :         }
    4439             : 
    4440         176 :         dash_cumulated_time=0;
    4441             : 
    4442             :         while (1) {
    4443         193 :                 if (run_for && (dash_cumulated_time >= run_for)) {
    4444           8 :                         M4_LOG(GF_LOG_INFO, ("Done running, computing static MPD\n"));
    4445             :                         do_abort = 3;
    4446             :                 }
    4447             : 
    4448         193 :                 dash_prev_time=gf_sys_clock();
    4449         193 :                 if (do_abort>=2) {
    4450           8 :                         e = gf_dasher_set_dynamic_mode(dasher, GF_DASH_DYNAMIC_LAST, 0, time_shift_depth, mpd_live_duration);
    4451             :                 }
    4452             : 
    4453         193 :                 if (!e) e = gf_dasher_process(dasher);
    4454         193 :                 if (!dash_live && (e==GF_EOS) ) {
    4455           0 :                         M4_LOG(GF_LOG_INFO, ("Nothing to dash, too early ...\n"));
    4456             :                         e = GF_OK;
    4457             :                 }
    4458             : 
    4459         193 :                 if (do_abort)
    4460             :                         break;
    4461             : 
    4462             :                 //this happens when reading file while writing them (local playback of the live session ...)
    4463         185 :                 if (dash_live && (e==GF_IO_ERR) ) {
    4464           0 :                         M4_LOG(GF_LOG_WARNING, ("Error dashing file (%s) but continuing ...\n", gf_error_to_string(e) ));
    4465             :                         e = GF_OK;
    4466             :                 }
    4467             : 
    4468         185 :                 if (e) break;
    4469             : 
    4470         183 :                 if (dash_live) {
    4471          17 :                         u64 ms_in_session=0;
    4472          17 :                         u32 slept = gf_sys_clock();
    4473          17 :                         u32 sleep_for = gf_dasher_next_update_time(dasher, &ms_in_session);
    4474          17 :                         M4_LOG(GF_LOG_INFO, ("Next generation scheduled in %u ms (DASH time "LLU" ms)\r", sleep_for, ms_in_session));
    4475          17 :                         if (run_for && (ms_in_session>=run_for)) {
    4476           7 :                                 dash_cumulated_time = 1+run_for;
    4477           7 :                                 continue;
    4478             :                         }
    4479             : 
    4480             :                         while (1) {
    4481       70429 :                                 if (gf_prompt_has_input()) {
    4482           0 :                                         char c = (char) gf_prompt_get_char();
    4483           0 :                                         if (c=='X') {
    4484             :                                                 do_abort = 1;
    4485             :                                                 break;
    4486             :                                         }
    4487           0 :                                         if (c=='q') {
    4488             :                                                 do_abort = 2;
    4489             :                                                 break;
    4490             :                                         }
    4491           0 :                                         if (c=='s') {
    4492             :                                                 do_abort = 3;
    4493             :                                                 break;
    4494             :                                         }
    4495             :                                 }
    4496             : 
    4497       70429 :                                 if (dash_mode == GF_DASH_DYNAMIC_DEBUG) {
    4498             :                                         break;
    4499             :                                 }
    4500       70429 :                                 if (!sleep_for) break;
    4501             : 
    4502       70429 :                                 gf_sleep(sleep_for/10);
    4503       70429 :                                 sleep_for = gf_dasher_next_update_time(dasher, NULL);
    4504       70429 :                                 if (sleep_for<=1) {
    4505          10 :                                         dash_now_time=gf_sys_clock();
    4506          10 :                                         dash_cumulated_time+=(dash_now_time-dash_prev_time);
    4507          10 :                                         M4_LOG(GF_LOG_INFO, ("Slept for %d ms before generation, dash cumulated time %d\n", dash_now_time - slept, dash_cumulated_time));
    4508             :                                         break;
    4509             :                                 }
    4510             :                         }
    4511             :                 } else {
    4512             :                         break;
    4513             :                 }
    4514             :         }
    4515             : 
    4516         176 :         gf_dasher_del(dasher);
    4517             : 
    4518         176 :         if (!run_for && dash_ctx_file && (do_abort==3) && (dyn_state_file) && !gf_sys_is_test_mode() ) {
    4519             :                 char szName[1024];
    4520           0 :                 M4_LOG(GF_LOG_INFO, ("Enter file name to save dash context:\n"));
    4521           0 :                 if (scanf("%1023s", szName) == 1) {
    4522           0 :                         gf_file_move(dash_ctx_file, szName);
    4523             :                 }
    4524             :         }
    4525         176 :         if (e) M4_LOG(GF_LOG_ERROR, ("Error DASHing file: %s\n", gf_error_to_string(e)));
    4526         176 :         if (file) gf_isom_delete(file);
    4527         176 :         if (del_file)
    4528           0 :                 gf_file_delete(inName);
    4529             : 
    4530             :         return e;
    4531             : }
    4532             : 
    4533             : 
    4534           0 : static GF_Err do_export_tracks_non_isobmf()
    4535             : {
    4536             :         u32 i;
    4537             : 
    4538             :         GF_MediaExporter mdump;
    4539             :         char szFile[GF_MAX_PATH+24];
    4540           0 :         for (i=0; i<nb_track_act; i++) {
    4541             :                 GF_Err e;
    4542           0 :                 TrackAction *tka = &tracks[i];
    4543           0 :                 if (tka->act_type != TRAC_ACTION_RAW_EXTRACT) continue;
    4544             :                 memset(&mdump, 0, sizeof(mdump));
    4545           0 :                 mdump.in_name = inName;
    4546           0 :                 mdump.flags = tka->dump_type;
    4547           0 :                 mdump.trackID = tka->trackID;
    4548           0 :                 mdump.track_type = tka->dump_track_type;
    4549           0 :                 mdump.sample_num = tka->sample_num;
    4550             : 
    4551           0 :                 if (dump_std) {
    4552           0 :                         mdump.out_name = "std";
    4553             :                 }
    4554           0 :                 else if (outName) {
    4555           0 :                         mdump.out_name = outName;
    4556           0 :                         mdump.flags |= GF_EXPORT_MERGE;
    4557           0 :                 } else if (nb_track_act>1) {
    4558             :                         sprintf(szFile, "%s_track%d", outfile, mdump.trackID);
    4559           0 :                         mdump.out_name = szFile;
    4560             :                 } else {
    4561           0 :                         mdump.out_name = outfile;
    4562             :                 }
    4563           0 :                 mdump.print_stats_graph = fs_dump_flags;
    4564           0 :                 e = gf_media_export(&mdump);
    4565           0 :                 if (e) return e;
    4566             :         }
    4567             :         return GF_OK;
    4568             : }
    4569             : 
    4570             : 
    4571           1 : static GF_Err do_dump_iod()
    4572             : {
    4573             :         GF_Err e = GF_OK;
    4574           1 :         GF_InitialObjectDescriptor *iod = (GF_InitialObjectDescriptor *)gf_isom_get_root_od(file);
    4575           1 :         if (!iod) {
    4576           0 :                 M4_LOG(GF_LOG_WARNING, ("File %s has no IOD\n", inName));
    4577             :         } else {
    4578             :                 char szName[GF_MAX_PATH+10];
    4579             :                 FILE *iodf;
    4580             :                 sprintf(szName, "%s.iod", outfile);
    4581           1 :                 iodf = gf_fopen(szName, "wb");
    4582           1 :                 if (!iodf) {
    4583           0 :                         M4_LOG(GF_LOG_ERROR, ("Cannot open destination %s\n", szName));
    4584             :                         e = GF_IO_ERR;
    4585             :                 } else {
    4586             :                         u8 *desc;
    4587             :                         u32 size;
    4588           1 :                         GF_BitStream *bs = gf_bs_from_file(iodf, GF_BITSTREAM_WRITE);
    4589           1 :                         if (gf_odf_desc_write((GF_Descriptor *)iod, &desc, &size)==GF_OK) {
    4590           1 :                                 gf_fwrite(desc, size, iodf);
    4591           1 :                                 gf_free(desc);
    4592             :                         } else {
    4593           0 :                                 M4_LOG(GF_LOG_ERROR, ("Error writing IOD %s\n", szName));
    4594             :                                 e = GF_IO_ERR;
    4595             :                         }
    4596           1 :                         gf_bs_del(bs);
    4597           1 :                         gf_fclose(iodf);
    4598             :                 }
    4599           1 :                 gf_odf_desc_del((GF_Descriptor*)iod);
    4600             :         }
    4601           1 :         return e;
    4602             : }
    4603             : 
    4604          63 : static GF_Err do_export_tracks()
    4605             : {
    4606             :         GF_Err e;
    4607             :         u32 i;
    4608             :         char szFile[GF_MAX_PATH+24];
    4609             :         GF_MediaExporter mdump;
    4610         126 :         for (i=0; i<nb_track_act; i++) {
    4611             :                 u32 j;
    4612          63 :                 TrackAction *tka = &tracks[i];
    4613          63 :                 if (tka->act_type != TRAC_ACTION_RAW_EXTRACT) continue;
    4614             :                 memset(&mdump, 0, sizeof(mdump));
    4615          63 :                 mdump.file = file;
    4616          63 :                 mdump.flags = tka->dump_type;
    4617          63 :                 mdump.trackID = tka->trackID;
    4618          63 :                 mdump.sample_num = tka->sample_num;
    4619          63 :                 if (tka->out_name) {
    4620           1 :                         mdump.out_name = tka->out_name;
    4621          62 :                 } else if (outName) {
    4622          34 :                         mdump.out_name = outName;
    4623          34 :                         mdump.flags |= GF_EXPORT_MERGE;
    4624             :                         /*don't infer extension on user-given filename*/
    4625          34 :                         mdump.flags |= GF_EXPORT_NO_FILE_EXT;
    4626          28 :                 } else if (mdump.trackID) {
    4627             :                         sprintf(szFile, "%s_track%d", outfile, mdump.trackID);
    4628          28 :                         mdump.out_name = szFile;
    4629             :                 } else {
    4630             :                         sprintf(szFile, "%s_export", outfile);
    4631           0 :                         mdump.out_name = szFile;
    4632             :                 }
    4633          63 :                 if (tka->trackID==(u32) -1) {
    4634           0 :                         for (j=0; j<gf_isom_get_track_count(file); j++) {
    4635           0 :                                 mdump.trackID = gf_isom_get_track_id(file, j+1);
    4636             :                                 sprintf(szFile, "%s_track%d", outfile, mdump.trackID);
    4637           0 :                                 mdump.out_name = szFile;
    4638           0 :                                 mdump.print_stats_graph = fs_dump_flags;
    4639           0 :                                 e = gf_media_export(&mdump);
    4640           0 :                                 if (e) return e;
    4641             :                         }
    4642             :                 } else {
    4643          63 :                         mdump.print_stats_graph = fs_dump_flags;
    4644          63 :                         e = gf_media_export(&mdump);
    4645          63 :                         if (e) return e;
    4646             :                 }
    4647             :         }
    4648             :         return GF_OK;
    4649             : }
    4650             : 
    4651        4177 : static GF_Err do_meta_act()
    4652             : {
    4653             :         u32 i;
    4654        4299 :         for (i=0; i<nb_meta_act; i++) {
    4655             :                 GF_Err e = GF_OK;
    4656             :                 u32 tk = 0;
    4657             : #ifndef GPAC_DISABLE_ISOM_WRITE
    4658             :                 Bool self_ref;
    4659             : #endif
    4660         122 :                 MetaAction *meta = &metas[i];
    4661             : 
    4662         122 :                 if (meta->trackID) tk = gf_isom_get_track_by_id(file, meta->trackID);
    4663             : 
    4664         122 :                 switch (meta->act_type) {
    4665             : #ifndef GPAC_DISABLE_ISOM_WRITE
    4666           4 :                 case META_ACTION_SET_TYPE:
    4667             :                         /*note: we don't handle file brand modification, this is an author stuff and cannot be guessed from meta type*/
    4668           4 :                         e = gf_isom_set_meta_type(file, meta->root_meta, tk, meta->meta_4cc);
    4669           4 :                         gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_ISO2, GF_TRUE);
    4670           4 :                         do_save = GF_TRUE;
    4671           4 :                         break;
    4672           4 :                 case META_ACTION_ADD_ITEM:
    4673           4 :                         self_ref = !stricmp(meta->szPath, "NULL") || !stricmp(meta->szPath, "this") || !stricmp(meta->szPath, "self");
    4674          16 :                         e = gf_isom_add_meta_item(file, meta->root_meta, tk, self_ref, self_ref ? NULL : meta->szPath,
    4675           4 :                                                   meta->szName,
    4676             :                                                   meta->item_id,
    4677             :                                                                           meta->item_type,
    4678           4 :                                                   meta->mime_type,
    4679           4 :                                                   meta->enc_type,
    4680           4 :                                                   meta->use_dref ? meta->szPath : NULL,  NULL,
    4681             :                                                   meta->image_props);
    4682           4 :                         if (meta->item_refs && gf_list_count(meta->item_refs)) {
    4683             :                                 u32 ref_i;
    4684           0 :                                 for (ref_i = 0; ref_i < gf_list_count(meta->item_refs); ref_i++) {
    4685           0 :                                         MetaRef *ref_entry = gf_list_get(meta->item_refs, ref_i);
    4686           0 :                                         e = gf_isom_meta_add_item_ref(file, meta->root_meta, tk, meta->item_id, ref_entry->ref_item_id, ref_entry->ref_type, NULL);
    4687             :                                 }
    4688             :                         }
    4689           4 :                         do_save = GF_TRUE;
    4690           4 :                         break;
    4691          94 :                 case META_ACTION_ADD_IMAGE_ITEM:
    4692             :                 {
    4693          94 :                         u32 old_tk_count = gf_isom_get_track_count(file);
    4694             :                         u32 src_tk_id = 1;
    4695          94 :                         GF_Fraction _frac = {0,0};
    4696          94 :                         GF_ISOFile *fsrc = file;
    4697             :                         self_ref = GF_FALSE;
    4698             : 
    4699             :                         tk = 0;
    4700          94 :                         if (meta->image_props && meta->image_props->auto_grid) {
    4701             :                                 e = GF_OK;
    4702             :                                 self_ref = GF_TRUE;
    4703          92 :                         } else if (!meta->szPath || (meta->image_props && meta->image_props->sample_num && meta->image_props->use_reference)) {
    4704             :                                 e = GF_OK;
    4705             :                                 self_ref = GF_TRUE;
    4706           2 :                                 src_tk_id = meta->trackID;
    4707             :                         } else if (meta->szPath) {
    4708          90 :                                 if (meta->image_props && gf_isom_probe_file(meta->szPath) && !meta->image_props->tile_mode) {
    4709          13 :                                         meta->image_props->src_file = gf_isom_open(meta->szPath, GF_ISOM_OPEN_READ, NULL);
    4710          13 :                                         e = gf_isom_last_error(meta->image_props->src_file);
    4711          13 :                                         fsrc = meta->image_props->src_file;
    4712             :                                 } else {
    4713          77 :                                         e = import_file(file, meta->szPath, 0, _frac, 0, NULL, NULL, 0);
    4714             :                                 }
    4715             :                         } else {
    4716             :                                 M4_LOG(GF_LOG_ERROR, ("Missing file name to import\n"));
    4717             :                                 e = GF_BAD_PARAM;
    4718             :                         }
    4719          94 :                         if (e == GF_OK) {
    4720          94 :                                 u32 meta_type = gf_isom_get_meta_type(file, meta->root_meta, tk);
    4721          94 :                                 if (!meta_type) {
    4722          51 :                                         e = gf_isom_set_meta_type(file, meta->root_meta, tk, GF_META_ITEM_TYPE_PICT);
    4723             :                                 } else {
    4724          43 :                                         if (meta_type != GF_META_ITEM_TYPE_PICT) {
    4725           0 :                                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Warning: file already has a root 'meta' box of type %s\n", gf_4cc_to_str(meta_type)));
    4726             :                                                 e = GF_BAD_PARAM;
    4727             :                                         }
    4728             :                                 }
    4729          94 :                                 if (e == GF_OK) {
    4730          94 :                                         if (!meta->item_id) {
    4731          54 :                                                 e = gf_isom_meta_get_next_item_id(file, meta->root_meta, tk, &meta->item_id);
    4732             :                                         }
    4733          94 :                                         if (e == GF_OK) {
    4734          94 :                                                 if (!src_tk_id) {
    4735             :                                                         u32 j;
    4736           1 :                                                         for (j=0; j<gf_isom_get_track_count(fsrc); j++) {
    4737           1 :                                                                 if (gf_isom_is_video_handler_type (gf_isom_get_media_type(fsrc, j+1))) {
    4738           1 :                                                                         src_tk_id = gf_isom_get_track_id(fsrc, j+1);
    4739           1 :                                                                         break;
    4740             :                                                                 }
    4741             :                                                         }
    4742             : 
    4743           1 :                                                         if (!src_tk_id) {
    4744           0 :                                                                 M4_LOG(GF_LOG_ERROR, ("No video track in file, cannot add image from track\n"));
    4745             :                                                                 e = GF_BAD_PARAM;
    4746           0 :                                                                 break;
    4747             :                                                         }
    4748             :                                                 }
    4749             : 
    4750          94 :                                                 e = gf_isom_iff_create_image_item_from_track(file, meta->root_meta, tk, src_tk_id, meta->szName, meta->item_id, meta->image_props, NULL);
    4751          94 :                                                 if (e == GF_OK && meta->primary) {
    4752          21 :                                                         e = gf_isom_set_meta_primary_item(file, meta->root_meta, tk, meta->item_id);
    4753             :                                                 }
    4754          94 :                                                 if (e == GF_OK && meta->item_refs && gf_list_count(meta->item_refs)) {
    4755             :                                                         u32 ref_i;
    4756           1 :                                                         for (ref_i = 0; ref_i < gf_list_count(meta->item_refs); ref_i++) {
    4757           1 :                                                                 MetaRef *ref_entry = gf_list_get(meta->item_refs, ref_i);
    4758           1 :                                                                 e = gf_isom_meta_add_item_ref(file, meta->root_meta, tk, meta->item_id, ref_entry->ref_item_id, ref_entry->ref_type, NULL);
    4759             :                                                         }
    4760             :                                                 }
    4761          94 :                                                 if (e == GF_OK && meta->group_type) {
    4762           0 :                                                         e = gf_isom_meta_add_item_group(file, meta->root_meta, tk, meta->item_id, meta->group_id, meta->group_type);
    4763             :                                                 }
    4764             :                                         }
    4765             :                                 }
    4766             :                         }
    4767          94 :                         if (meta->image_props && meta->image_props->src_file) {
    4768          13 :                                 gf_isom_delete(meta->image_props->src_file);
    4769          13 :                                 meta->image_props->src_file = NULL;
    4770          81 :                         } else if (!self_ref) {
    4771          77 :                                 gf_isom_remove_track(file, old_tk_count+1);
    4772          77 :                                 if (do_flat) {
    4773           0 :                                         M4_LOG(GF_LOG_ERROR, ("Warning: -flat storage cannot be used when using -add-image on external file\n"));
    4774             :                                         e = GF_NOT_SUPPORTED;
    4775             :                                 }
    4776             :                         }
    4777          94 :                         do_save = GF_TRUE;
    4778             :                 }
    4779          94 :                         break;
    4780           7 :                 case META_ACTION_ADD_IMAGE_GRID:
    4781             :                 {
    4782           7 :                         u32 meta_type = gf_isom_get_meta_type(file, meta->root_meta, tk);
    4783             :                         e = GF_OK;
    4784           7 :                         if (!meta_type) {
    4785           7 :                                 e = gf_isom_set_meta_type(file, meta->root_meta, tk, GF_META_ITEM_TYPE_PICT);
    4786             :                         } else {
    4787           0 :                                 if (meta_type != GF_META_ITEM_TYPE_PICT) {
    4788           0 :                                         GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("Warning: file already has a root 'meta' box of type %s\n", gf_4cc_to_str(meta_type)));
    4789             :                                         e = GF_BAD_PARAM;
    4790             :                                 }
    4791             :                         }
    4792           7 :                         if (e == GF_OK) {
    4793           7 :                                 if (!meta->item_id) {
    4794           0 :                                         e = gf_isom_meta_get_next_item_id(file, meta->root_meta, tk, &meta->item_id);
    4795             :                                 }
    4796           7 :                                 if (e == GF_OK) {
    4797          14 :                                         e = gf_isom_iff_create_image_grid_item(file, meta->root_meta, tk,
    4798           7 :                                                         meta->szName && strlen(meta->szName) ? meta->szName : NULL,
    4799             :                                                         meta->item_id,
    4800             :                                                         meta->image_props);
    4801           7 :                                         if (e == GF_OK && meta->primary) {
    4802           7 :                                                 e = gf_isom_set_meta_primary_item(file, meta->root_meta, tk, meta->item_id);
    4803             :                                         }
    4804           7 :                                         if (e == GF_OK && meta->item_refs && gf_list_count(meta->item_refs)) {
    4805             :                                                 u32 ref_i;
    4806          36 :                                                 for (ref_i = 0; ref_i < gf_list_count(meta->item_refs); ref_i++) {
    4807          36 :                                                         MetaRef *ref_entry = gf_list_get(meta->item_refs, ref_i);
    4808          36 :                                                         e = gf_isom_meta_add_item_ref(file, meta->root_meta, tk, meta->item_id, ref_entry->ref_item_id, ref_entry->ref_type, NULL);
    4809             :                                                 }
    4810             :                                         }
    4811             :                                 }
    4812             :                         }
    4813           7 :                         do_save = GF_TRUE;
    4814             :                 }
    4815           7 :                         break;
    4816           4 :                 case META_ACTION_REM_ITEM:
    4817           4 :                         e = gf_isom_remove_meta_item(file, meta->root_meta, tk, meta->item_id);
    4818           4 :                         do_save = GF_TRUE;
    4819           4 :                         break;
    4820           1 :                 case META_ACTION_SET_PRIMARY_ITEM:
    4821           1 :                         e = gf_isom_set_meta_primary_item(file, meta->root_meta, tk, meta->item_id);
    4822           1 :                         do_save = GF_TRUE;
    4823           1 :                         break;
    4824           1 :                 case META_ACTION_SET_XML:
    4825             :                 case META_ACTION_SET_BINARY_XML:
    4826           1 :                         e = gf_isom_set_meta_xml(file, meta->root_meta, tk, meta->szPath, NULL, 0, (meta->act_type==META_ACTION_SET_BINARY_XML) ? 1 : 0);
    4827           1 :                         do_save = GF_TRUE;
    4828           1 :                         break;
    4829           1 :                 case META_ACTION_REM_XML:
    4830           1 :                         if (gf_isom_get_meta_item_count(file, meta->root_meta, tk)) {
    4831           0 :                                 e = gf_isom_remove_meta_xml(file, meta->root_meta, tk);
    4832           0 :                                 do_save = GF_TRUE;
    4833             :                         } else {
    4834           1 :                                 M4_LOG(GF_LOG_WARNING, ("No meta box in input file\n"));
    4835             :                                 e = GF_OK;
    4836             :                         }
    4837             :                         break;
    4838           5 :                 case META_ACTION_DUMP_ITEM:
    4839           5 :                         if (gf_isom_get_meta_item_count(file, meta->root_meta, tk)) {
    4840           5 :                                 e = gf_isom_extract_meta_item(file, meta->root_meta, tk, meta->item_id, meta->szPath && strlen(meta->szPath) ? meta->szPath : NULL);
    4841             :                         } else {
    4842           0 :                                 M4_LOG(GF_LOG_WARNING, ("No meta box in input file\n"));
    4843             :                                 e = GF_OK;
    4844             :                         }
    4845             :                         break;
    4846             : #endif // GPAC_DISABLE_ISOM_WRITE
    4847             : 
    4848           1 :                 case META_ACTION_DUMP_XML:
    4849           1 :                         if (gf_isom_has_meta_xml(file, meta->root_meta, tk)) {
    4850           1 :                                 e = gf_isom_extract_meta_xml(file, meta->root_meta, tk, meta->szPath, NULL);
    4851             :                         } else {
    4852           0 :                                 M4_LOG(GF_LOG_WARNING, ("No meta box in input file\n"));
    4853             :                                 e = GF_OK;
    4854             :                         }
    4855             :                         break;
    4856             :                 default:
    4857             :                         break;
    4858             :                 }
    4859         122 :                 if (meta->item_refs) {
    4860          45 :                         while (gf_list_count(meta->item_refs)) {
    4861          37 :                                 gf_free(gf_list_pop_back(meta->item_refs));
    4862             :                         }
    4863           8 :                         gf_list_del(meta->item_refs);
    4864           8 :                         meta->item_refs = NULL;
    4865             :                 }
    4866         122 :                 if (meta->image_props) {
    4867          60 :                         gf_free(meta->image_props);
    4868          60 :                         meta->image_props = NULL;
    4869             :                 }
    4870         122 :                 if (e) return e;
    4871             :         }
    4872             :         return GF_OK;
    4873             : }
    4874             : 
    4875         971 : static GF_Err do_tsel_act()
    4876             : {
    4877             :         u32 i;
    4878             :         GF_Err e;
    4879         977 :         for (i=0; i<nb_tsel_acts; i++) {
    4880           6 :                 switch (tsel_acts[i].act_type) {
    4881           4 :                 case TSEL_ACTION_SET_PARAM:
    4882          22 :                         e = gf_isom_set_track_switch_parameter(file,
    4883           4 :                                                                gf_isom_get_track_by_id(file, tsel_acts[i].trackID),
    4884           6 :                                                                tsel_acts[i].refTrackID ? gf_isom_get_track_by_id(file, tsel_acts[i].refTrackID) : 0,
    4885           4 :                                                                tsel_acts[i].is_switchGroup ? 1 : 0,
    4886             :                                                                &tsel_acts[i].switchGroupID,
    4887           4 :                                                                tsel_acts[i].criteria, tsel_acts[i].nb_criteria);
    4888           4 :                         if (e == GF_BAD_PARAM) {
    4889             :                                 u32 alternateGroupID, nb_groups;
    4890           0 :                                 gf_isom_get_track_switch_group_count(file, gf_isom_get_track_by_id(file, tsel_acts[i].trackID), &alternateGroupID, &nb_groups);
    4891           0 :                                 if (alternateGroupID) {
    4892           0 :                                         M4_LOG(GF_LOG_ERROR, ("Error - for adding more tracks to group, using: -group-add -refTrack=ID1:[criteria:]trackID=ID2\n"));
    4893             :                                 } else {
    4894           0 :                                         M4_LOG(GF_LOG_ERROR, ("Error - for creating a new grouping information, using -group-add -trackID=ID1:[criteria:]trackID=ID2\n"));
    4895             :                                 }
    4896             :                         }
    4897           4 :                         if (e) return e;
    4898           4 :                         do_save = GF_TRUE;
    4899           4 :                         break;
    4900           1 :                 case TSEL_ACTION_REMOVE_TSEL:
    4901           1 :                         e = gf_isom_reset_track_switch_parameter(file, gf_isom_get_track_by_id(file, tsel_acts[i].trackID), 0);
    4902           1 :                         if (e) return e;
    4903           1 :                         do_save = GF_TRUE;
    4904           1 :                         break;
    4905           1 :                 case TSEL_ACTION_REMOVE_ALL_TSEL_IN_GROUP:
    4906           1 :                         e = gf_isom_reset_track_switch_parameter(file, gf_isom_get_track_by_id(file, tsel_acts[i].trackID), 1);
    4907           1 :                         if (e) return e;
    4908           1 :                         do_save = GF_TRUE;
    4909           1 :                         break;
    4910             :                 default:
    4911             :                         break;
    4912             :                 }
    4913             :         }
    4914             :         return GF_OK;
    4915             : }
    4916             : 
    4917           1 : static void do_ipod_conv()
    4918             : {
    4919             :         u32 i, ipod_major_brand = 0;
    4920           1 :         M4_LOG(GF_LOG_INFO, ("Setting up iTunes/iPod file\n"));
    4921             : 
    4922           3 :         for (i=0; i<gf_isom_get_track_count(file); i++) {
    4923           2 :                 u32 mType = gf_isom_get_media_type(file, i+1);
    4924           2 :                 switch (mType) {
    4925           1 :                 case GF_ISOM_MEDIA_VISUAL:
    4926             :                 case GF_ISOM_MEDIA_AUXV:
    4927             :                 case GF_ISOM_MEDIA_PICT:
    4928             :                         ipod_major_brand = GF_ISOM_BRAND_M4V;
    4929           1 :                         gf_isom_set_ipod_compatible(file, i+1);
    4930           1 :                         break;
    4931           1 :                 case GF_ISOM_MEDIA_AUDIO:
    4932           1 :                         if (!ipod_major_brand) ipod_major_brand = GF_ISOM_BRAND_M4A;
    4933           1 :                         else gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_M4A, GF_TRUE);
    4934             :                         break;
    4935           0 :                 case GF_ISOM_MEDIA_TEXT:
    4936             :                         /*this is a text track track*/
    4937           0 :                         if (gf_isom_get_media_subtype(file, i+1, 1) == GF_ISOM_SUBTYPE_TX3G) {
    4938             :                                 Bool is_chap = 0;
    4939             :                                 u32 j;
    4940           0 :                                 for (j=0; j<gf_isom_get_track_count(file); j++) {
    4941           0 :                                         s32 count = gf_isom_get_reference_count(file, j+1, GF_ISOM_REF_CHAP);
    4942           0 :                                         if (count>0) {
    4943             :                                                 u32 tk, k;
    4944           0 :                                                 for (k=0; k<(u32) count; k++) {
    4945           0 :                                                         gf_isom_get_reference(file, j+1, GF_ISOM_REF_CHAP, k+1, &tk);
    4946           0 :                                                         if (tk==i+1) {
    4947             :                                                                 is_chap = 1;
    4948             :                                                                 break;
    4949             :                                                         }
    4950             :                                                 }
    4951           0 :                                                 if (is_chap) break;
    4952             :                                         }
    4953           0 :                                         if (is_chap) break;
    4954             :                                 }
    4955             :                                 /*this is a subtitle track*/
    4956           0 :                                 if (!is_chap)
    4957           0 :                                         gf_isom_set_media_type(file, i+1, GF_ISOM_MEDIA_SUBT);
    4958             :                         }
    4959             :                         break;
    4960             :                 }
    4961             :         }
    4962           1 :         gf_isom_set_brand_info(file, ipod_major_brand, 1);
    4963           1 :         gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_MP42, GF_TRUE);
    4964           1 :         do_save = GF_TRUE;
    4965           1 : }
    4966             : 
    4967         971 : static GF_Err do_track_act()
    4968             : {
    4969             :         u32 j;
    4970        1070 :         for (j=0; j<nb_track_act; j++) {
    4971             :                 u32 i;
    4972             :                 GF_Err e = GF_OK;
    4973         100 :                 TrackAction *tka = &tracks[j];
    4974         100 :                 u32 track = tka->trackID ? gf_isom_get_track_by_id(file, tka->trackID) : 0;
    4975             : 
    4976         100 :                 timescale = gf_isom_get_timescale(file);
    4977         100 :                 switch (tka->act_type) {
    4978           1 :                 case TRAC_ACTION_REM_TRACK:
    4979           1 :                         e = gf_isom_remove_track(file, track);
    4980           1 :                         if (e) {
    4981           0 :                                 M4_LOG(GF_LOG_ERROR, ("Error Removing track ID %d: %s\n", tka->trackID, gf_error_to_string(e)));
    4982             :                         } else {
    4983           1 :                                 M4_LOG(GF_LOG_INFO, ("Removing track ID %d\n", tka->trackID));
    4984             :                         }
    4985           1 :                         do_save = GF_TRUE;
    4986           1 :                         break;
    4987             :                 case TRAC_ACTION_SET_LANGUAGE:
    4988          22 :                         for (i=0; i<gf_isom_get_track_count(file); i++) {
    4989          22 :                                 if (track && (track != i+1)) continue;
    4990          18 :                                 e = gf_isom_set_media_language(file, i+1, tka->lang);
    4991          18 :                                 if (e) return e;
    4992          18 :                                 do_save = GF_TRUE;
    4993             :                         }
    4994          11 :                         do_save = GF_TRUE;
    4995          11 :                         break;
    4996             :                 case TRAC_ACTION_SET_KIND:
    4997          62 :                         for (i=0; i<gf_isom_get_track_count(file); i++) {
    4998          62 :                                 if (track && (track != i+1)) continue;
    4999          56 :                                 e = gf_isom_add_track_kind(file, i+1, tka->kind_scheme, tka->kind_value);
    5000          56 :                                 if (e) return e;
    5001          56 :                                 do_save = GF_TRUE;
    5002             :                         }
    5003          31 :                         do_save = GF_TRUE;
    5004          31 :                         break;
    5005             :                 case TRAC_ACTION_REM_KIND:
    5006          44 :                         for (i=0; i<gf_isom_get_track_count(file); i++) {
    5007          44 :                                 if (track && (track != i+1)) continue;
    5008          38 :                                 e = gf_isom_remove_track_kind(file, i+1, tka->kind_scheme, tka->kind_value);
    5009          38 :                                 if (e) return e;
    5010          38 :                                 do_save = GF_TRUE;
    5011             :                         }
    5012          22 :                         do_save = GF_TRUE;
    5013          22 :                         break;
    5014           1 :                 case TRAC_ACTION_SET_DELAY:
    5015           1 :                         if (tka->delay.num && tka->delay.den) {
    5016             :                                 u64 tk_dur;
    5017             : 
    5018           1 :                                 e = gf_isom_remove_edits(file, track);
    5019           1 :                                 if (e) return e;
    5020           0 :                                 tk_dur = gf_isom_get_track_duration(file, track);
    5021           0 :                                 if (gf_isom_get_edits_count(file, track))
    5022           0 :                                         do_save = GF_TRUE;
    5023           0 :                                 if (tka->delay.num>0) {
    5024             :                                         //cast to u64, delay_ms * timescale can be quite big before / 1000
    5025           0 :                                         e = gf_isom_append_edit(file, track, ((u64) tka->delay.num) * timescale / tka->delay.den, 0, GF_ISOM_EDIT_EMPTY);
    5026           0 :                                         if (e) return e;
    5027           0 :                                         e = gf_isom_append_edit(file, track, tk_dur, 0, GF_ISOM_EDIT_NORMAL);
    5028           0 :                                         if (e) return e;
    5029           0 :                                         do_save = GF_TRUE;
    5030             :                                 } else {
    5031             :                                         //cast to u64, delay_ms * timescale can be quite big before / 1000
    5032           0 :                                         u64 to_skip = ((u64) -tka->delay.num) * timescale / tka->delay.den;
    5033           0 :                                         if (to_skip<tk_dur) {
    5034             :                                                 //cast to u64, delay_ms * timescale can be quite big before / 1000
    5035           0 :                                                 u64 media_time = ((u64) -tka->delay.num) * gf_isom_get_media_timescale(file, track) / tka->delay.den;
    5036           0 :                                                 e = gf_isom_append_edit(file, track, tk_dur-to_skip, media_time, GF_ISOM_EDIT_NORMAL);
    5037           0 :                                                 if (e) return e;
    5038           0 :                                                 do_save = GF_TRUE;
    5039             :                                         } else {
    5040           0 :                                                 M4_LOG(GF_LOG_WARNING, ("Warning: request negative delay longer than track duration - ignoring\n"));
    5041             :                                         }
    5042             :                                 }
    5043           0 :                         } else if (gf_isom_get_edits_count(file, track)) {
    5044           0 :                                 e = gf_isom_remove_edits(file, track);
    5045           0 :                                 if (e) return e;
    5046           0 :                                 do_save = GF_TRUE;
    5047             :                         }
    5048             :                         break;
    5049             :                 case TRAC_ACTION_SET_KMS_URI:
    5050           5 :                         for (i=0; i<gf_isom_get_track_count(file); i++) {
    5051           5 :                                 if (track && (track != i+1)) continue;
    5052           5 :                                 if (!gf_isom_is_media_encrypted(file, i+1, 1)) continue;
    5053           5 :                                 if (!gf_isom_is_ismacryp_media(file, i+1, 1)) continue;
    5054           5 :                                 e = gf_isom_change_ismacryp_protection(file, i+1, 1, NULL, (char *) tka->kms);
    5055           5 :                                 if (e) return e;
    5056           5 :                                 do_save = GF_TRUE;
    5057             :                         }
    5058             :                         break;
    5059           1 :                 case TRAC_ACTION_SET_ID:
    5060           1 :                         if (!tka->trackID && (gf_isom_get_track_count(file) == 1)) {
    5061           0 :                                 M4_LOG(GF_LOG_WARNING, ("Warning: track id is not specified, but file has only one track - assume that you want to change id for this track\n"));
    5062             :                                 track = 1;
    5063             :                         }
    5064           1 :                         if (track) {
    5065             :                                 u32 newTrack;
    5066           1 :                                 newTrack = gf_isom_get_track_by_id(file, tka->newTrackID);
    5067           1 :                                 if (newTrack != 0) {
    5068           0 :                                         M4_LOG(GF_LOG_WARNING, ("Cannot set track id with value %d because a track already exists - ignoring", tka->newTrackID));
    5069             :                                 } else {
    5070           1 :                                         e = gf_isom_set_track_id(file, track, tka->newTrackID);
    5071           1 :                                         if (e) return e;
    5072           1 :                                         do_save = GF_TRUE;
    5073             :                                 }
    5074             :                         } else {
    5075           0 :                                 M4_LOG(GF_LOG_WARNING, ("Error: Cannot change id for track %d because it does not exist - ignoring", tka->trackID));
    5076             :                         }
    5077             :                         break;
    5078           1 :                 case TRAC_ACTION_SWAP_ID:
    5079           1 :                         if (track) {
    5080             :                                 u32 tk1, tk2;
    5081           1 :                                 tk1 = gf_isom_get_track_by_id(file, tka->trackID);
    5082           1 :                                 tk2 = gf_isom_get_track_by_id(file, tka->newTrackID);
    5083           1 :                                 if (!tk1 || !tk2) {
    5084           0 :                                         M4_LOG(GF_LOG_WARNING, ("Error: Cannot swap track IDs because not existing - ignoring"));
    5085             :                                 } else {
    5086           1 :                                         e = gf_isom_set_track_id(file, tk2, 0);
    5087           1 :                                         if (e) return e;
    5088           1 :                                         e = gf_isom_set_track_id(file, tk1, tka->newTrackID);
    5089           1 :                                         if (e) return e;
    5090           1 :                                         e = gf_isom_set_track_id(file, tk2, tka->trackID);
    5091           1 :                                         if (e) return e;
    5092           1 :                                         do_save = GF_TRUE;
    5093             :                                 }
    5094             :                         } else {
    5095           0 :                                 M4_LOG(GF_LOG_WARNING, ("Error: Cannot change id for track %d because it does not exist - ignoring", tka->trackID));
    5096             :                         }
    5097             :                         break;
    5098          12 :                 case TRAC_ACTION_SET_PAR:
    5099          12 :                         e = gf_media_change_par(file, track, tka->par_num, tka->par_den, tka->force_par, tka->rewrite_bs);
    5100          12 :                         do_save = GF_TRUE;
    5101          12 :                         break;
    5102           2 :                 case TRAC_ACTION_SET_CLAP:
    5103           2 :                         e = gf_isom_set_clean_aperture(file, track, 1, tka->clap_wnum, tka->clap_wden, tka->clap_hnum, tka->clap_hden, tka->clap_honum, tka->clap_hoden, tka->clap_vonum, tka->clap_voden);
    5104           2 :                         do_save = GF_TRUE;
    5105           2 :                         break;
    5106           0 :                 case TRAC_ACTION_SET_MX:
    5107           0 :                         e = gf_isom_set_track_matrix(file, track, tka->mx);
    5108           0 :                         do_save = GF_TRUE;
    5109           0 :                         break;
    5110           1 :                 case TRAC_ACTION_SET_HANDLER_NAME:
    5111           1 :                         e = gf_isom_set_handler_name(file, track, tka->hdl_name);
    5112           1 :                         do_save = GF_TRUE;
    5113           1 :                         break;
    5114           1 :                 case TRAC_ACTION_ENABLE:
    5115           1 :                         if (!gf_isom_is_track_enabled(file, track)) {
    5116           1 :                                 e = gf_isom_set_track_enabled(file, track, GF_TRUE);
    5117           1 :                                 do_save = GF_TRUE;
    5118             :                         }
    5119             :                         break;
    5120           1 :                 case TRAC_ACTION_DISABLE:
    5121           1 :                         if (gf_isom_is_track_enabled(file, track)) {
    5122           1 :                                 e = gf_isom_set_track_enabled(file, track, GF_FALSE);
    5123           1 :                                 do_save = GF_TRUE;
    5124             :                         }
    5125             :                         break;
    5126           1 :                 case TRAC_ACTION_REFERENCE:
    5127           1 :                         e = gf_isom_set_track_reference(file, track, GF_4CC(tka->lang[0], tka->lang[1], tka->lang[2], tka->lang[3]), tka->newTrackID);
    5128           1 :                         do_save = GF_TRUE;
    5129           1 :                         break;
    5130           1 :                 case TRAC_ACTION_REM_NON_RAP:
    5131           1 :                         e = gf_media_remove_non_rap(file, track, GF_FALSE);
    5132           1 :                         do_save = GF_TRUE;
    5133           1 :                         break;
    5134           1 :                 case TRAC_ACTION_REM_NON_REFS:
    5135           1 :                         e = gf_media_remove_non_rap(file, track, GF_TRUE);
    5136           1 :                         do_save = GF_TRUE;
    5137           1 :                         break;
    5138           5 :                 case TRAC_ACTION_SET_UDTA:
    5139           5 :                         e = set_file_udta(file, track, tka->udta_type, tka->string ? tka->string : tka->src_name , tka->sample_num ? GF_TRUE : GF_FALSE, tka->string ? GF_TRUE : GF_FALSE);
    5140           5 :                         do_save = GF_TRUE;
    5141           5 :                         break;
    5142           1 :                 case TRAC_ACTION_SET_EDITS:
    5143           1 :                         e = apply_edits(file, track, tka->string);
    5144           1 :                         do_save = GF_TRUE;
    5145           1 :                         break;
    5146           1 :                 case TRAC_ACTION_SET_TIME:
    5147           1 :                         if (!tka->trackID) {
    5148           1 :                                 e = gf_isom_set_creation_time(file, tka->time, tka->time);
    5149           1 :                                 if (e) return e;
    5150           5 :                                 for (i=0; i<gf_isom_get_track_count(file); i++) {
    5151           4 :                                         e = gf_isom_set_track_creation_time(file, i+1, tka->time, tka->time);
    5152           4 :                                         if (e) return e;
    5153             :                                 }
    5154             :                         } else {
    5155           0 :                                 e = gf_isom_set_track_creation_time(file, track, tka->time, tka->time);
    5156             :                         }
    5157           1 :                         do_save = GF_TRUE;
    5158           1 :                         break;
    5159             :                 case TRAC_ACTION_SET_MEDIA_TIME:
    5160           0 :                         for (i=0; i<gf_isom_get_track_count(file); i++) {
    5161           0 :                                 if (track && (track != i+1)) continue;
    5162           0 :                                 e = gf_isom_set_media_creation_time(file, i+1, tka->time, tka->time);
    5163           0 :                                 if (e) return e;
    5164             :                         }
    5165           0 :                         do_save = GF_TRUE;
    5166           0 :                         break;
    5167             :                 default:
    5168             :                         break;
    5169             :                 }
    5170          99 :                 if (e) return e;
    5171             :         }
    5172             :         return GF_OK;
    5173             : }
    5174             : 
    5175           1 : static GF_Err do_itunes_tag()
    5176             : {
    5177             :         GF_Err e;
    5178           1 :         char *itunes_data = NULL;
    5179           1 :         char *tags = itunes_tags;
    5180             : 
    5181           1 :         if (gf_file_exists(itunes_tags)) {
    5182             :                 u32 len;
    5183           0 :                 e = gf_file_load_data(itunes_tags, (u8 **) &itunes_data, &len);
    5184           0 :                 if (e) return e;;
    5185           0 :                 tags = itunes_data;
    5186             :         }
    5187             : 
    5188           2 :         while (tags) {
    5189             :                 char *val;
    5190             :                 Bool clear = GF_FALSE;
    5191             :                 Bool is_wma = GF_FALSE;
    5192             :                 u32 tlen, tagtype=0, itag = 0;
    5193             :                 s32 tag_idx=-1;
    5194           2 :                 char *sep = itunes_data ? strchr(tags, '\n') : gf_url_colon_suffix(tags);
    5195           2 :                 while (sep) {
    5196           1 :                         char *eq = strchr(sep+1, '=');
    5197           1 :                         if (eq) eq[0] = 0;
    5198           1 :                         s32 next_tag_idx = gf_itags_find_by_name(sep+1);
    5199           1 :                         if ((next_tag_idx<0) && strlen(sep+1)==4)
    5200             :                                 next_tag_idx = 0;
    5201             : 
    5202           1 :                         if (eq) eq[0] = '=';
    5203           1 :                         if (next_tag_idx>=0) {
    5204           1 :                                 sep[0] = 0;
    5205           1 :                                 break;
    5206             :                         }
    5207           0 :                         sep = itunes_data ? strchr(sep+1, '\n') : gf_url_colon_suffix(sep+1);
    5208             :                 }
    5209           2 :                 val = strchr(tags, '=');
    5210           2 :                 if (val) val[0] = 0;
    5211           2 :                 if (!strcmp(tags, "clear") || !strcmp(tags, "reset")) {
    5212             :                         clear = GF_TRUE;
    5213           2 :                 } else if (!strncmp(tags, "WM/", 3) ) {
    5214             :                         is_wma = GF_TRUE;
    5215             :                 } else {
    5216           2 :                         tag_idx = gf_itags_find_by_name(tags);
    5217           2 :                         if (tag_idx<0) {
    5218           0 :                                 if (strlen(tags)==4) {
    5219           0 :                                         itag = GF_4CC(tags[0], tags[1], tags[2], tags[3]);
    5220             :                                         tagtype = GF_ITAG_STR;
    5221           0 :                                 } else if (strlen(tags)==3) {
    5222           0 :                                         itag = GF_4CC(0xA9, tags[0], tags[1], tags[2]);
    5223             :                                         tagtype = GF_ITAG_STR;
    5224             :                                 }
    5225             :                         }
    5226             :                 }
    5227           2 :                 if (val) {
    5228           2 :                         val[0] = '=';
    5229           2 :                         val++;
    5230             :                 }
    5231           2 :                 if (!itag && !clear && !is_wma) {
    5232           2 :                         if (tag_idx<0) {
    5233           0 :                                 M4_LOG(GF_LOG_WARNING, ("Invalid iTune tag name \"%s\" - ignoring\n", tags));
    5234           0 :                                 break;
    5235             :                         }
    5236           2 :                         itag = gf_itags_get_itag(tag_idx);
    5237           2 :                         tagtype = gf_itags_get_type(tag_idx);
    5238             :                 }
    5239           2 :                 if (!val || (val[0]==':') || !val[0] || !stricmp(val, "NULL") ) val = NULL;
    5240             : 
    5241           2 :                 tlen = val ? (u32) strlen(val) : 0;
    5242           2 :                 if (clear) {
    5243           0 :                         e = gf_isom_apple_set_tag(file, GF_ISOM_ITUNE_RESET, NULL, 0, 0, 0);
    5244             :                 }
    5245           2 :                 else if (is_wma) {
    5246           0 :                         if (val) val[-1] = 0;
    5247           0 :                         e = gf_isom_wma_set_tag(file, tags, val);
    5248           0 :                         if (val) val[-1] = '=';
    5249             :                 }
    5250           2 :                 else if (val && (tagtype==GF_ITAG_FILE)) {
    5251           1 :                         u32 flen = (u32) strlen(val);
    5252           1 :                         u8 *d=NULL;
    5253           1 :                         while (flen && val[flen-1]=='\n') flen--;
    5254           1 :                         val[flen] = 0;
    5255           1 :                         e = gf_file_load_data(val, (u8 **) &d, &tlen);
    5256           1 :                         val[flen] = '\n';
    5257             : 
    5258           1 :                         if (!e)
    5259           1 :                                 e = gf_isom_apple_set_tag(file, itag, d, tlen, 0, 0);
    5260             : 
    5261           1 :                         if (d) gf_free(d);
    5262             :                 } else {
    5263           1 :                         e = gf_isom_apple_set_tag(file, itag, (u8 *) val, tlen, 0, 0);
    5264             :                 }
    5265           2 :                 if (e) {
    5266           0 :                         M4_LOG(GF_LOG_ERROR, ("Error assigning tag %s: %s\n", tags, gf_error_to_string(e) ));
    5267             :                 }
    5268             : 
    5269           2 :                 do_save = GF_TRUE;
    5270             : 
    5271           2 :                 if (sep) {
    5272           1 :                         sep[0] = itunes_data ? '\n' : ':';
    5273           1 :                         tags = sep+1;
    5274             :                 } else {
    5275             :                         tags = NULL;
    5276             :                 }
    5277             :         }
    5278           1 :         if (itunes_data) gf_free(itunes_data);
    5279             :         return GF_OK;
    5280             : }
    5281             : 
    5282             : #if !defined(GPAC_DISABLE_ISOM_HINTING) && !defined(GPAC_DISABLE_SENG)
    5283         743 : static void set_sdp_ext()
    5284             : {
    5285             :         u32 i, j;
    5286         743 :         for (i=0; i<nb_sdp_ex; i++) {
    5287           0 :                 if (sdp_lines[i].trackID) {
    5288           0 :                         u32 track = gf_isom_get_track_by_id(file, sdp_lines[i].trackID);
    5289           0 :                         if (gf_isom_get_media_type(file, track)!=GF_ISOM_MEDIA_HINT) {
    5290             :                                 s32 ref_count;
    5291           0 :                                 u32 k, count = gf_isom_get_track_count(file);
    5292           0 :                                 for (j=0; j<count; j++) {
    5293           0 :                                         if (gf_isom_get_media_type(file, j+1)!=GF_ISOM_MEDIA_HINT) continue;
    5294           0 :                                         ref_count = gf_isom_get_reference_count(file, j+1, GF_ISOM_REF_HINT);
    5295           0 :                                         if (ref_count<0) continue;
    5296           0 :                                         for (k=0; k<(u32) ref_count; k++) {
    5297             :                                                 u32 refTk;
    5298           0 :                                                 if (gf_isom_get_reference(file, j+1, GF_ISOM_REF_HINT, k+1, &refTk)) continue;
    5299           0 :                                                 if (refTk==track) {
    5300             :                                                         track = j+1;
    5301             :                                                         j=count;
    5302           0 :                                                         break;
    5303             :                                                 }
    5304             :                                         }
    5305             :                                 }
    5306             :                         }
    5307           0 :                         gf_isom_sdp_add_track_line(file, track, sdp_lines[i].line);
    5308           0 :                         do_save = GF_TRUE;
    5309             :                 } else {
    5310           0 :                         gf_isom_sdp_add_line(file, sdp_lines[i].line);
    5311           0 :                         do_save = GF_TRUE;
    5312             :                 }
    5313             :         }
    5314         743 : }
    5315             : #endif /*!defined(GPAC_DISABLE_ISOM_HINTING) && !defined(GPAC_DISABLE_SENG)*/
    5316             : 
    5317           0 : static GF_Err do_remux_file()
    5318             : {
    5319             :         GF_MediaExporter mdump;
    5320             :         memset(&mdump, 0, sizeof(GF_MediaExporter));
    5321           0 :         mdump.in_name = inName;
    5322           0 :         mdump.out_name = mux_name;
    5323           0 :         mdump.flags = GF_EXPORT_REMUX;
    5324           0 :         mdump.print_stats_graph = fs_dump_flags;
    5325           0 :         return gf_media_export(&mdump);
    5326             : }
    5327             : 
    5328        4515 : static u32 mp4box_cleanup(u32 ret_code) {
    5329        4515 :         if (mpd_base_urls) {
    5330           1 :                 gf_free(mpd_base_urls);
    5331           1 :                 mpd_base_urls = NULL;
    5332             :         }
    5333        4515 :         if (sdp_lines) {
    5334           0 :                 gf_free(sdp_lines);
    5335           0 :                 sdp_lines = NULL;
    5336             :         }
    5337        4515 :         if (metas) {
    5338             :                 u32 i;
    5339         122 :                 for (i=0; i<nb_meta_act; i++) {
    5340         122 :                         if (metas[i].enc_type) gf_free(metas[i].enc_type);
    5341         122 :                         if (metas[i].mime_type) gf_free(metas[i].mime_type);
    5342         122 :                         if (metas[i].szName) gf_free(metas[i].szName);
    5343         122 :                         if (metas[i].szPath) gf_free(metas[i].szPath);
    5344             :                 }
    5345          75 :                 gf_free(metas);
    5346          75 :                 metas = NULL;
    5347             :         }
    5348        4515 :         if (tracks) {
    5349             :                 u32 i;
    5350         165 :                 for (i = 0; i<nb_track_act; i++) {
    5351         165 :                         if (tracks[i].out_name)
    5352           1 :                                 gf_free(tracks[i].out_name);
    5353         165 :                         if (tracks[i].src_name)
    5354           4 :                                 gf_free(tracks[i].src_name);
    5355         165 :                         if (tracks[i].string)
    5356           2 :                                 gf_free(tracks[i].string);
    5357         165 :                         if (tracks[i].kind_scheme)
    5358          53 :                                 gf_free(tracks[i].kind_scheme);
    5359         165 :                         if (tracks[i].kind_value)
    5360          20 :                                 gf_free(tracks[i].kind_value);
    5361             :                 }
    5362         165 :                 gf_free(tracks);
    5363         165 :                 tracks = NULL;
    5364             :         }
    5365        4515 :         if (tsel_acts) {
    5366           3 :                 gf_free(tsel_acts);
    5367           3 :                 tsel_acts = NULL;
    5368             :         }
    5369        4515 :         if (brand_add) {
    5370          44 :                 gf_free(brand_add);
    5371          44 :                 brand_add = NULL;
    5372             :         }
    5373        4515 :         if (brand_rem) {
    5374           2 :                 gf_free(brand_rem);
    5375           2 :                 brand_rem = NULL;
    5376             :         }
    5377        4515 :         if (dash_inputs) {
    5378             :                 u32 i, j;
    5379         209 :                 for (i = 0; i<nb_dash_inputs; i++) {
    5380         209 :                         GF_DashSegmenterInput *di = &dash_inputs[i];
    5381         209 :                         if (di->nb_baseURL) {
    5382           1 :                                 for (j = 0; j<di->nb_baseURL; j++) {
    5383           1 :                                         gf_free(di->baseURL[j]);
    5384             :                                 }
    5385           1 :                                 gf_free(di->baseURL);
    5386             :                         }
    5387         209 :                         if (di->rep_descs) {
    5388           1 :                                 for (j = 0; j<di->nb_rep_descs; j++) {
    5389           1 :                                         gf_free(di->rep_descs[j]);
    5390             :                                 }
    5391           1 :                                 gf_free(di->rep_descs);
    5392             :                         }
    5393         209 :                         if (di->as_descs) {
    5394           6 :                                 for (j = 0; j<di->nb_as_descs; j++) {
    5395           6 :                                         gf_free(di->as_descs[j]);
    5396             :                                 }
    5397           6 :                                 gf_free(di->as_descs);
    5398             :                         }
    5399         209 :                         if (di->as_c_descs) {
    5400           0 :                                 for (j = 0; j<di->nb_as_c_descs; j++) {
    5401           0 :                                         gf_free(di->as_c_descs[j]);
    5402             :                                 }
    5403           0 :                                 gf_free(di->as_c_descs);
    5404             :                         }
    5405         209 :                         if (di->p_descs) {
    5406           3 :                                 for (j = 0; j<di->nb_p_descs; j++) {
    5407           3 :                                         gf_free(di->p_descs[j]);
    5408             :                                 }
    5409           3 :                                 gf_free(di->p_descs);
    5410             :                         }
    5411         209 :                         if (di->representationID) gf_free(di->representationID);
    5412         209 :                         if (di->periodID) gf_free(di->periodID);
    5413         209 :                         if (di->xlink) gf_free(di->xlink);
    5414         209 :                         if (di->seg_template) gf_free(di->seg_template);
    5415         209 :                         if (di->hls_pl) gf_free(di->hls_pl);
    5416         209 :                         if (di->source_opts) gf_free(di->source_opts);
    5417         209 :                         if (di->filter_chain) gf_free(di->filter_chain);
    5418             : 
    5419         209 :                         if (di->roles) {
    5420           0 :                                 for (j = 0; j<di->nb_roles; j++) {
    5421           0 :                                         gf_free(di->roles[j]);
    5422             :                                 }
    5423           0 :                                 gf_free(di->roles);
    5424             :                         }
    5425             :                 }
    5426         176 :                 gf_free(dash_inputs);
    5427         176 :                 dash_inputs = NULL;
    5428             :         }
    5429        4515 :         if (logfile) gf_fclose(logfile);
    5430        4515 :         gf_sys_close();
    5431        4515 :         return ret_code;
    5432             : }
    5433             : 
    5434             : 
    5435             : 
    5436        4485 : int mp4boxMain(int argc, char **argv)
    5437             : {
    5438             :         u32 i, j;
    5439             :         const char *gpac_profile = "0";
    5440             :         GF_Err e = GF_OK;
    5441             : 
    5442             : #ifdef TEST_ARGS
    5443             :         i=0;
    5444             :         mp4box_parse_single_arg(argc, argv, "", &i);
    5445             : #endif
    5446             : 
    5447       17935 :         for (i = 1; i < (u32) argc ; i++) {
    5448       17932 :                 if (!strcmp(argv[i], "-mem-track") || !strcmp(argv[i], "-mem-track-stack")) {
    5449             : #ifdef GPAC_MEMORY_TRACKING
    5450        4482 :             mem_track = !strcmp(argv[i], "-mem-track-stack") ? GF_MemTrackerBackTrace : GF_MemTrackerSimple;
    5451             : #else
    5452             :                         M4_LOG(GF_LOG_WARNING, ("WARNING - GPAC not compiled with Memory Tracker - ignoring \"%s\"\n", argv[i]));
    5453             : #endif
    5454        4482 :                         break;
    5455             :                 }
    5456       13450 :                 else if (!strcmp(argv[i], "-p")) {
    5457           0 :                         if (i+1<(u32) argc)
    5458           0 :                                 gpac_profile = argv[i+1];
    5459             :                         else {
    5460           0 :                                 M4_LOG(GF_LOG_ERROR, ("Bad argument for -p, expecting profile name but no more args\n"));
    5461             :                                 return 1;
    5462             :                         }
    5463             :                 }
    5464       13450 :                 else if (!strncmp(argv[i], "-p=", 3))
    5465           0 :                         gpac_profile = argv[i]+3;
    5466             :         }
    5467             : 
    5468             : #ifdef _TWO_DIGIT_EXPONENT
    5469             :         _set_output_format(_TWO_DIGIT_EXPONENT);
    5470             : #endif
    5471             : 
    5472             :         /*init libgpac*/
    5473        4485 :         gf_sys_init(mem_track, gpac_profile);
    5474        4485 :         if (argc < 2) {
    5475           0 :                 M4_LOG(GF_LOG_ERROR, ("Not enough arguments - check usage with -h\n"));
    5476           0 :                 M4_LOG(GF_LOG_INFO, ("MP4Box - GPAC version %s\n"
    5477             :                 "%s\n", gf_gpac_version(), gf_gpac_copyright_cite() ));
    5478           0 :                 gf_sys_close();
    5479           0 :                 return 0;
    5480             :         }
    5481             : 
    5482        4485 :         helpout = stdout;
    5483             : 
    5484        4485 :         i = mp4box_parse_args(argc, argv);
    5485        4485 :         if (i) {
    5486          37 :                 return mp4box_cleanup(i - 1);
    5487             :         }
    5488             : #if !defined(GPAC_DISABLE_STREAMING) && !defined(GPAC_DISABLE_SENG)
    5489        4448 :         if (live_scene) {
    5490           1 :                 int ret = live_session(argc, argv);
    5491           1 :                 return mp4box_cleanup(ret);
    5492             :         }
    5493             : #endif
    5494             : 
    5495        4447 :         if (!dash_duration && interleaving_time && do_frag)
    5496           4 :                 interleaving_time /= 1000;
    5497             : 
    5498        4447 :         if (do_mpd_conv) inName = do_mpd_conv;
    5499             : 
    5500        4447 :         if (import_flags & GF_IMPORT_FORCE_MPEG4)
    5501           0 :                 hint_flags |= GP_RTP_PCK_FORCE_MPEG4;
    5502             : 
    5503        4447 :         if (!inName && dump_std)
    5504           0 :                 inName = "std";
    5505             : 
    5506        4447 :         if (!dash_duration && cprt)
    5507           1 :                 open_edit = GF_TRUE;
    5508             : 
    5509        4447 :         if (!inName) {
    5510           0 :                 if (has_next_arg) {
    5511           0 :                         M4_LOG(GF_LOG_ERROR, ("Broken argument specifier or file name missing - check usage with -h\n"));
    5512             :                 } else {
    5513           0 :                         PrintUsage();
    5514             :                 }
    5515           0 :                 return mp4box_cleanup(1);
    5516             :         }
    5517        4447 :         if (!strcmp(inName, "std")) dump_std = 2;
    5518        4447 :         if (!strcmp(inName, "stdb")) {
    5519           0 :                 inName = "std";
    5520           0 :                 dump_std = 1;
    5521             :         }
    5522             : 
    5523        4447 :         if (!interleaving_time) {
    5524             :                 /*by default use single fragment per dash segment*/
    5525        4434 :                 if (dash_duration)
    5526         172 :                         interleaving_time = dash_duration;
    5527        4262 :                 else if (!do_flat) {
    5528        4258 :                         interleaving_time = DEFAULT_INTERLEAVING_IN_SEC;
    5529             :                 }
    5530             :         }
    5531             : 
    5532        4447 :         if (dump_std)
    5533        2686 :                 outName = "std";
    5534             : 
    5535        4447 :         if (dump_std==2) {
    5536             : #ifdef WIN32
    5537             :                 if ( _setmode(_fileno(stdout), _O_BINARY) == -1 )
    5538             : #else
    5539        2686 :                 if ( freopen(NULL, "wb", stdout) == NULL)
    5540             : #endif
    5541             :                 {
    5542           0 :                         M4_LOG(GF_LOG_ERROR, ("Fatal error: cannot reopen stdout in binary mode.\n"));
    5543           0 :                         return mp4box_cleanup(1);
    5544             :                 }
    5545             :         }
    5546             : 
    5547        4447 :         GF_LOG_Level level = verbose ? GF_LOG_DEBUG : GF_LOG_INFO;
    5548        4447 :         gf_log_set_tool_level(GF_LOG_CONTAINER, level);
    5549        4447 :         gf_log_set_tool_level(GF_LOG_SCENE, level);
    5550        4447 :         gf_log_set_tool_level(GF_LOG_PARSER, level);
    5551        4447 :         gf_log_set_tool_level(GF_LOG_AUTHOR, level);
    5552        4447 :         gf_log_set_tool_level(GF_LOG_CODING, level);
    5553        4447 :         gf_log_set_tool_level(GF_LOG_DASH, level);
    5554             : #ifdef GPAC_MEMORY_TRACKING
    5555        4447 :         if (mem_track)
    5556        4445 :                 gf_log_set_tool_level(GF_LOG_MEMORY, level);
    5557             : #endif
    5558             : 
    5559        4447 :         e = gf_sys_set_args(argc, (const char **) argv);
    5560        4447 :         if (e) {
    5561           0 :                 M4_LOG(GF_LOG_ERROR, ("Error assigning libgpac arguments: %s\n", gf_error_to_string(e) ));
    5562           0 :                 return mp4box_cleanup(1);
    5563             :         }
    5564             : 
    5565        4447 :         if (raw_cat)
    5566           0 :                 return do_raw_cat();
    5567             : 
    5568        4447 :         if (compress_top_boxes) {
    5569           2 :                 if (size_top_box) {
    5570           1 :                         u64 top_size = do_size_top_boxes(inName, compress_top_boxes, size_top_box);
    5571           1 :                         fprintf(stdout, LLU"\n", top_size);
    5572           1 :                         return mp4box_cleanup(e ? 1 : 0);
    5573             :                 } else {
    5574           1 :                         e = do_compress_top_boxes(inName, outName);
    5575           1 :                         return mp4box_cleanup(e ? 1 : 0);
    5576             :                 }
    5577             :         }
    5578             : 
    5579        4445 :         if (do_mpd_rip) {
    5580           1 :                 e = rip_mpd(inName, outName);
    5581           1 :                 return mp4box_cleanup(e ? 1 : 0);
    5582             :         }
    5583             : 
    5584             : #ifndef GPAC_DISABLE_CORE_TOOLS
    5585        4444 :         if (do_wget != NULL) {
    5586           4 :                 e = gf_dm_wget(do_wget, inName, 0, 0, NULL);
    5587           4 :                 if (e != GF_OK) {
    5588           0 :                         M4_LOG(GF_LOG_ERROR, ("Cannot retrieve %s: %s\n", do_wget, gf_error_to_string(e) ));
    5589           0 :                         return mp4box_cleanup(1);
    5590             :                 }
    5591           4 :                 return mp4box_cleanup(0);
    5592             :         }
    5593             : #endif
    5594             : 
    5595        4440 :         if (udp_dest)
    5596           0 :                 return do_write_udp();
    5597             : 
    5598             : #ifndef GPAC_DISABLE_MPD
    5599        4440 :         if (do_mpd_conv)
    5600           3 :                 return convert_mpd();
    5601             : #endif
    5602             : 
    5603        4437 :         if (dash_duration && !nb_dash_inputs) {
    5604         149 :                 dash_inputs = set_dash_input(dash_inputs, inName, &nb_dash_inputs);
    5605             :         }
    5606             : 
    5607        4437 :         if (do_saf && !encode) {
    5608           1 :                 switch (get_file_type_by_ext(inName)) {
    5609           1 :                 case GF_FILE_TYPE_BT_WRL_X3DV:
    5610             :                 case GF_FILE_TYPE_XMT_X3D:
    5611             :                 case GF_FILE_TYPE_SVG:
    5612           1 :                         encode = GF_TRUE;
    5613           1 :                         break;
    5614             :                 case GF_FILE_TYPE_NOT_SUPPORTED:
    5615             :                 case GF_FILE_TYPE_ISO_MEDIA:
    5616             :                 case GF_FILE_TYPE_SWF:
    5617             :                 case GF_FILE_TYPE_LSR_SAF:
    5618             :                         break;
    5619             :                 }
    5620             :         }
    5621             : 
    5622             : #ifndef GPAC_DISABLE_SCENE_DUMP
    5623        4437 :         if (dump_mode == GF_SM_DUMP_SVG) {
    5624           3 :                 if (strstr(inName, ".srt") || strstr(inName, ".ttxt")) import_subtitle = 2;
    5625             :         }
    5626             : #endif
    5627             : 
    5628        4437 :         if (import_subtitle && !trackID)
    5629           6 :                 return do_import_sub();
    5630             : 
    5631             : 
    5632             : #if !defined(GPAC_DISABLE_MEDIA_IMPORT) && !defined(GPAC_DISABLE_ISOM_WRITE)
    5633        4431 :         if (nb_add || nb_cat) {
    5634         455 :                 u32 res = do_add_cat(argc, argv);
    5635         455 :                 if (res) return res;
    5636             :         }
    5637             : #endif /*!GPAC_DISABLE_MEDIA_IMPORT && !GPAC_DISABLE_ISOM_WRITE*/
    5638             : 
    5639             : #if !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_SCENE_ENCODER) && !defined(GPAC_DISABLE_MEDIA_IMPORT)
    5640        3976 :         else if (chunk_mode) {
    5641           1 :                 if (!inName) {
    5642           0 :                         M4_LOG(GF_LOG_ERROR, ("chunk encoding syntax: [-outctx outDump] -inctx inScene auFile\n"));
    5643           0 :                         return mp4box_cleanup(1);
    5644             :                 }
    5645           1 :                 e = EncodeFileChunk(inName, outName ? outName : inName, input_ctx, output_ctx);
    5646           1 :                 if (e) {
    5647           0 :                         M4_LOG(GF_LOG_ERROR, ("Error encoding chunk file %s\n", gf_error_to_string(e)));
    5648           0 :                         return mp4box_cleanup(1);
    5649             :                 }
    5650             :                 goto exit;
    5651             :         }
    5652             : #endif // !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_SCENE_ENCODER) && !defined(GPAC_DISABLE_MEDIA_IMPORT)
    5653             : 
    5654        3975 :         else if (encode) {
    5655             : #if !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_SCENE_ENCODER) && !defined(GPAC_DISABLE_MEDIA_IMPORT)
    5656          33 :                 e = do_scene_encode();
    5657          33 :                 if (e) goto err_exit;
    5658             : #endif //!defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_SCENE_ENCODER) && !defined(GPAC_DISABLE_MEDIA_IMPORT)
    5659             :         }
    5660             : 
    5661             : #ifndef GPAC_DISABLE_ISOM_WRITE
    5662        3942 :         else if (pack_file) {
    5663           2 :                 char *fileName = gf_url_colon_suffix(pack_file);
    5664           2 :                 if (fileName && ((fileName - pack_file)==4)) {
    5665           1 :                         fileName[0] = 0;
    5666           1 :                         file = package_file(fileName + 1, pack_file, pack_wgt);
    5667           1 :                         fileName[0] = ':';
    5668             :                 } else {
    5669           1 :                         file = package_file(pack_file, NULL, pack_wgt);
    5670           1 :                         if (!file) {
    5671           0 :                                 M4_LOG(GF_LOG_ERROR, ("Failed to package file\n"));
    5672           0 :                                 return mp4box_cleanup(1);
    5673             :                         }
    5674             :                 }
    5675           2 :                 if (!outName) outName = inName;
    5676           2 :                 do_save = GF_TRUE;
    5677           2 :                 open_edit = GF_TRUE;
    5678             :         }
    5679             : #endif //GPAC_DISABLE_ISOM_WRITE
    5680             : 
    5681        4427 :         if (dash_duration) {
    5682         176 :                 e = do_dash();
    5683         176 :                 if (e) return mp4box_cleanup(1);
    5684             :                 goto exit;
    5685             :         }
    5686             : 
    5687             :         //need to open input
    5688        4251 :         if (!file && !do_hash) {
    5689        1078 :                 FILE *st = gf_fopen(inName, "rb");
    5690             :                 Bool file_exists = 0;
    5691             :                 GF_ISOOpenMode omode;
    5692        1078 :                 if (st) {
    5693             :                         file_exists = 1;
    5694        1023 :                         gf_fclose(st);
    5695             :                 }
    5696        1078 :                 switch (get_file_type_by_ext(inName)) {
    5697         938 :                 case 1:
    5698         938 :                         omode =  (u8) (force_new ? GF_ISOM_WRITE_EDIT : (open_edit ? GF_ISOM_OPEN_EDIT : ( ((dump_isom>0) || print_info) ? GF_ISOM_OPEN_READ_DUMP : GF_ISOM_OPEN_READ) ) );
    5699             : 
    5700         938 :                         if (crypt) {
    5701             :                                 //keep fragment signaling in moov
    5702             :                                 omode = GF_ISOM_OPEN_READ;
    5703         210 :                                 if (use_init_seg)
    5704           3 :                                         file = gf_isom_open(use_init_seg, GF_ISOM_OPEN_READ, NULL);
    5705             :                         }
    5706         938 :                         if (!crypt && use_init_seg) {
    5707           2 :                                 file = gf_isom_open(use_init_seg, GF_ISOM_OPEN_READ_DUMP, NULL);
    5708           2 :                                 if (file) {
    5709           2 :                                         e = gf_isom_open_segment(file, inName, 0, 0, 0);
    5710           2 :                                         if (e==GF_ISOM_INCOMPLETE_FILE) {
    5711           0 :                                                 M4_LOG(GF_LOG_WARNING, ("Segment %s: %s\n", inName, gf_error_to_string(e) ));
    5712           2 :                                         } else if (e) {
    5713           0 :                                                 M4_LOG(GF_LOG_ERROR, ("Error opening segment %s: %s\n", inName, gf_error_to_string(e) ));
    5714           0 :                                                 gf_isom_delete(file);
    5715           0 :                                                 file = NULL;
    5716             :                                         }
    5717             :                                 }
    5718             :                         }
    5719         938 :                         if (!file)
    5720         933 :                                 file = gf_isom_open(inName, omode, NULL);
    5721             : 
    5722         938 :                         if (!file && (gf_isom_last_error(NULL) == GF_ISOM_INCOMPLETE_FILE) && !open_edit) {
    5723             :                                 u64 missing_bytes;
    5724           0 :                                 gf_isom_open_progressive(inName, 0, 0, GF_FALSE, &file, &missing_bytes);
    5725           0 :                                 if (missing_bytes)
    5726           0 :                                         M4_LOG(GF_LOG_ERROR, ("Truncated file - missing "LLD" bytes\n", missing_bytes));
    5727             :                         }
    5728             : 
    5729         938 :                         if (!file) {
    5730           2 :                                 if (open_edit && nb_meta_act) {
    5731           0 :                                         file = gf_isom_open(inName, GF_ISOM_WRITE_EDIT, NULL);
    5732           0 :                                         if (!outName && file) outName = inName;
    5733             :                                 }
    5734             : 
    5735           2 :                                 if (!file) {
    5736           2 :                                         M4_LOG(GF_LOG_ERROR, ("Error opening file %s: %s\n", inName, gf_error_to_string(gf_isom_last_error(NULL))));
    5737           2 :                                         return mp4box_cleanup(1);
    5738             :                                 }
    5739             :                         }
    5740         936 :                         if (freeze_box_order)
    5741           0 :                                 gf_isom_freeze_order(file);
    5742             :                         break;
    5743             :                 /*allowed for bt<->xmt*/
    5744             :                 case 2:
    5745             :                 case 3:
    5746             :                 /*allowed for svg->lsr**/
    5747             :                 case 4:
    5748             :                 /*allowed for swf->bt, swf->xmt, swf->svg*/
    5749             :                 case 5:
    5750             :                         break;
    5751             :                 /*used for .saf / .lsr dump*/
    5752           1 :                 case 6:
    5753             : #ifndef GPAC_DISABLE_SCENE_DUMP
    5754           1 :                         if ((dump_mode==GF_SM_DUMP_LASER) || (dump_mode==GF_SM_DUMP_SVG)) {
    5755             :                                 break;
    5756             :                         }
    5757             : #endif
    5758             : 
    5759             :                 default:
    5760         115 :                         if (!open_edit && file_exists && !gf_isom_probe_file(inName) && track_dump_type) {
    5761             :                         }
    5762             : #ifndef GPAC_DISABLE_ISOM_WRITE
    5763         115 :                         else if (!open_edit && file_exists /* && !gf_isom_probe_file(inName) */
    5764             : #ifndef GPAC_DISABLE_SCENE_DUMP
    5765          62 :                                  && dump_mode == GF_SM_DUMP_NONE
    5766             : #endif //GPAC_DISABLE_SCENE_DUMP
    5767             :                                 ) {
    5768             :                                 /*************************************************************************************************/
    5769             : #ifndef GPAC_DISABLE_MEDIA_IMPORT
    5770          62 :                                 if(dvbhdemux)
    5771             :                                 {
    5772             :                                         GF_MediaImporter import;
    5773           0 :                                         file = gf_isom_open("ttxt_convert", GF_ISOM_OPEN_WRITE, NULL);
    5774             :                                         memset(&import, 0, sizeof(GF_MediaImporter));
    5775           0 :                                         import.dest = file;
    5776           0 :                                         import.in_name = inName;
    5777           0 :                                         import.flags = GF_IMPORT_MPE_DEMUX;
    5778           0 :                                         e = gf_media_import(&import);
    5779           0 :                                         if (e) {
    5780           0 :                                                 M4_LOG(GF_LOG_ERROR, ("Error importing %s: %s\n", inName, gf_error_to_string(e)));
    5781           0 :                                                 gf_isom_delete(file);
    5782           0 :                                                 gf_file_delete("ttxt_convert");
    5783           0 :                                                 return mp4box_cleanup(1);
    5784             :                                         }
    5785             :                                 }
    5786             : #endif /*GPAC_DISABLE_MEDIA_IMPORT*/
    5787             : 
    5788          62 :                                 if (dump_m2ts) {
    5789             : #ifndef GPAC_DISABLE_MPEG2TS
    5790           1 :                                         dump_mpeg2_ts(inName, outName, program_number);
    5791             : #endif
    5792          61 :                                 } else if (dump_timestamps) {
    5793             : #ifndef GPAC_DISABLE_MPEG2TS
    5794           0 :                                         dump_mpeg2_ts(inName, outName, program_number);
    5795             : #endif
    5796             : #ifndef GPAC_DISABLE_CORE_TOOLS
    5797          61 :                                 } else if (do_bin_xml) {
    5798           0 :                                         xml_bs_to_bin(inName, outName, dump_std);
    5799             : #endif
    5800          61 :                                 } else if (do_hash) {
    5801           0 :                                         hash_file(inName, dump_std);
    5802          61 :                                 } else if (print_info) {
    5803             : #ifndef GPAC_DISABLE_MEDIA_IMPORT
    5804          61 :                                         convert_file_info(inName, info_track_id);
    5805             : #endif
    5806             :                                 } else {
    5807           0 :                                         if (mux_name) {
    5808           0 :                                                 e = do_remux_file();
    5809           0 :                                                 if (e) goto err_exit;
    5810           0 :                                                 if (file) gf_isom_delete(file);
    5811             :                                                 goto exit;
    5812             :                                         } else {
    5813           0 :                                                 M4_LOG(GF_LOG_ERROR, ("Input %s is not an MP4 file, operation not allowed\n", inName));
    5814           0 :                                                 return mp4box_cleanup(1);
    5815             :                                         }
    5816             :                                 }
    5817             :                                 goto exit;
    5818             :                         }
    5819             : #endif /*GPAC_DISABLE_ISOM_WRITE*/
    5820          53 :                         else if (open_edit) {
    5821          53 :                                 file = gf_isom_open(inName, GF_ISOM_WRITE_EDIT, NULL);
    5822          53 :                                 if (!outName && file) outName = inName;
    5823           0 :                         } else if (!file_exists) {
    5824           0 :                                 M4_LOG(GF_LOG_ERROR, ("Error %s file %s: %s\n", force_new ? "creating" : "opening", inName, gf_error_to_string(GF_URL_ERROR)));
    5825           0 :                                 return mp4box_cleanup(1);
    5826             :                         } else {
    5827           0 :                                 M4_LOG(GF_LOG_ERROR, ("Cannot open %s - extension not supported\n", inName));
    5828           0 :                                 return mp4box_cleanup(1);
    5829             :                         }
    5830             :                 }
    5831             :         }
    5832             : 
    5833        4187 :         if (high_dynamc_range_filename) {
    5834           1 :                 e = parse_high_dynamc_range_xml_desc(file, high_dynamc_range_filename);
    5835           1 :                 if (e) goto err_exit;
    5836             :         }
    5837             : 
    5838        4187 :         if (file && keep_utc) {
    5839           0 :                 gf_isom_keep_utc_times(file, 1);
    5840             :         }
    5841             : 
    5842        4187 :         if ( gf_strlcpy(outfile, outName ? outName : inName, sizeof(outfile)) >= sizeof(outfile) ) {
    5843           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Filename too long (limit is %d)\n", GF_MAX_PATH));
    5844           0 :                 return mp4box_cleanup(1);
    5845             :         }
    5846             : 
    5847        4187 :         char *szExt = gf_file_ext_start(outfile);
    5848        4187 :         if (szExt) {
    5849             :                 /*turn on 3GP saving*/
    5850        1499 :                 if (!stricmp(szExt, ".3gp") || !stricmp(szExt, ".3gpp") || !stricmp(szExt, ".3g2"))
    5851           0 :                         conv_type = GF_ISOM_CONV_TYPE_3GPP;
    5852        1499 :                 else if (!stricmp(szExt, ".m4a") || !stricmp(szExt, ".m4v"))
    5853           0 :                         conv_type = GF_ISOM_CONV_TYPE_IPOD;
    5854        1499 :                 else if (!stricmp(szExt, ".psp"))
    5855           0 :                         conv_type = GF_ISOM_CONV_TYPE_PSP;
    5856        1499 :                 else if (!stricmp(szExt, ".mov") || !stricmp(szExt, ".qt"))
    5857           3 :                         conv_type = GF_ISOM_CONV_TYPE_MOV;
    5858             : 
    5859             :                 //remove extension from outfile
    5860        1499 :                 *szExt = 0;
    5861             :         }
    5862             : 
    5863             : #ifndef GPAC_DISABLE_MEDIA_EXPORT
    5864        4187 :         if (!open_edit && track_dump_type && !gf_isom_probe_file(inName)) {
    5865           0 :                 e = do_export_tracks_non_isobmf();
    5866           0 :                 if (e) goto err_exit;
    5867             :                 goto exit;
    5868             :         }
    5869        4187 :         if (mux_name) {
    5870           0 :                 e = do_remux_file();
    5871           0 :                 if (e) goto err_exit;
    5872           0 :                 if (file) gf_isom_delete(file);
    5873             :                 goto exit;
    5874             :         }
    5875             : 
    5876             : 
    5877             : 
    5878             : #endif /*GPAC_DISABLE_MEDIA_EXPORT*/
    5879             : 
    5880             : #ifndef GPAC_DISABLE_SCENE_DUMP
    5881        4187 :         if (dump_mode != GF_SM_DUMP_NONE) {
    5882          17 :                 e = dump_isom_scene(inName, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE, dump_mode, do_scene_log, no_odf_conf);
    5883          17 :                 if (e) goto err_exit;
    5884             :         }
    5885             : #endif
    5886             : 
    5887             : #ifndef GPAC_DISABLE_SCENE_STATS
    5888        4187 :         if (stat_level) dump_isom_scene_stats(inName, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE, stat_level);
    5889             : #endif
    5890             : 
    5891             : #ifndef GPAC_DISABLE_ISOM_HINTING
    5892        4187 :         if (!do_hint && print_sdp) dump_isom_sdp(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE);
    5893             : #endif
    5894        4187 :         if (get_nb_tracks) {
    5895           0 :                 fprintf(stdout, "%d\n", gf_isom_get_track_count(file));
    5896             :         }
    5897        4187 :         if (print_info) {
    5898         190 :                 if (!file) {
    5899           0 :                         M4_LOG(GF_LOG_ERROR, ("Cannot print info on a non ISOM file (%s)\n", inName));
    5900             :                 } else {
    5901         190 :                         if (info_track_id) DumpTrackInfo(file, info_track_id, 1, (print_info==2) ? GF_TRUE : GF_FALSE, GF_FALSE);
    5902         186 :                         else DumpMovieInfo(file);
    5903             :                 }
    5904             :         }
    5905             : #ifndef GPAC_DISABLE_ISOM_DUMP
    5906        4187 :         if (dump_isom) {
    5907         117 :                 e = dump_isom_xml(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE, (dump_isom==2) ? GF_TRUE : GF_FALSE, merge_vtt_cues, use_init_seg ? GF_TRUE : GF_FALSE, (dump_isom==3) ? GF_TRUE : GF_FALSE);
    5908         117 :                 if (e) goto err_exit;
    5909             :         }
    5910        4187 :         if (dump_cr) dump_isom_ismacryp(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE);
    5911        4187 :         if ((dump_ttxt || dump_srt) && trackID) {
    5912             : 
    5913           4 :                 if (trackID == (u32)-1) {
    5914           0 :                         for (j=0; j<gf_isom_get_track_count(file); j++) {
    5915           0 :                                 trackID = gf_isom_get_track_id(file, j+1);
    5916           0 :                                 dump_isom_timed_text(file, trackID, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE,
    5917           0 :                                                                         GF_FALSE, dump_srt ? GF_TEXTDUMPTYPE_SRT : GF_TEXTDUMPTYPE_TTXT);
    5918             :                         }
    5919             : 
    5920             :                 }
    5921             :                 else {
    5922           4 :                         dump_isom_timed_text(file, trackID, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE,
    5923           4 :                                                                 GF_FALSE, dump_srt ? GF_TEXTDUMPTYPE_SRT : GF_TEXTDUMPTYPE_TTXT);
    5924             :                 }
    5925             :         }
    5926             : 
    5927             : #ifndef GPAC_DISABLE_ISOM_HINTING
    5928        4187 :         if (dump_rtp) dump_isom_rtp(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE);
    5929             : #endif
    5930             : 
    5931             : #endif
    5932             : 
    5933        4187 :         if (dump_timestamps) dump_isom_timestamps(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE, dump_timestamps);
    5934        4187 :         if (dump_nal) dump_isom_nal(file, dump_nal, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE, dump_nal_type);
    5935        4187 :         if (dump_saps) dump_isom_saps(file, dump_saps, dump_saps_mode, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE);
    5936             : 
    5937        4187 :         if (do_hash) {
    5938        2686 :                 e = hash_file(inName, dump_std);
    5939        2686 :                 if (e) goto err_exit;
    5940             :         }
    5941             : #ifndef GPAC_DISABLE_CORE_TOOLS
    5942        4177 :         if (do_bin_xml) {
    5943           1 :                 e = xml_bs_to_bin(inName, outName, dump_std);
    5944           1 :                 if (e) goto err_exit;
    5945             :         }
    5946             : #endif
    5947             : 
    5948        4177 :         if (dump_cart) dump_isom_cover_art(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE);
    5949        4177 :         if (dump_chap) dump_isom_chapters(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE, dump_chap);
    5950        4177 :         if (dump_udta_type) dump_isom_udta(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE, dump_udta_type, dump_udta_track);
    5951             : 
    5952        4177 :         if (dump_iod) {
    5953           1 :                 e = do_dump_iod();
    5954           1 :                 if (e) goto err_exit;
    5955             :         }
    5956             : 
    5957             : #if !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_MEDIA_IMPORT)
    5958        4177 :         if (split_duration || split_size || split_range_str) {
    5959           8 :                 split_isomedia_file(file, split_duration, split_size, inName, interleaving_time, split_start, adjust_split_end, outName, seg_at_rap, split_range_str, fs_dump_flags);
    5960             : 
    5961             :                 /*never save file when splitting is desired*/
    5962           8 :                 open_edit = GF_FALSE;
    5963           8 :                 do_save = GF_FALSE;
    5964             :         }
    5965             : #endif // !defined(GPAC_DISABLE_ISOM_WRITE) && !defined(GPAC_DISABLE_MEDIA_IMPORT)
    5966             : 
    5967             : #ifndef GPAC_DISABLE_MEDIA_EXPORT
    5968        4177 :         if (track_dump_type) {
    5969          63 :                 e = do_export_tracks();
    5970          63 :                 if (e) goto err_exit;
    5971        4114 :         } else if (do_saf) {
    5972             :                 GF_MediaExporter mdump;
    5973             :                 memset(&mdump, 0, sizeof(mdump));
    5974           1 :                 mdump.file = file;
    5975           1 :                 mdump.flags = GF_EXPORT_SAF;
    5976           1 :                 mdump.out_name = outfile;
    5977           1 :                 mdump.print_stats_graph = fs_dump_flags;
    5978           1 :                 e = gf_media_export(&mdump);
    5979           1 :                 if (e) goto err_exit;
    5980             :         }
    5981             : #endif
    5982             : 
    5983        4177 :         e = do_meta_act();
    5984        4177 :         if (e) goto err_exit;
    5985             : 
    5986        4177 :         if (!open_edit && !do_save) {
    5987        3206 :                 if (file) gf_isom_delete(file);
    5988             :                 goto exit;
    5989             :         }
    5990             : 
    5991             : 
    5992             : #ifndef GPAC_DISABLE_ISOM_WRITE
    5993         971 :         if (clean_groups) {
    5994           1 :                 e = gf_isom_reset_switch_parameters(file);
    5995           1 :                 if (e) goto err_exit;
    5996           1 :                 do_save = GF_TRUE;
    5997             :         }
    5998             : 
    5999             : 
    6000         971 :         e = do_tsel_act();
    6001         971 :         if (e) goto err_exit;
    6002             : 
    6003         971 :         if (remove_sys_tracks) {
    6004             : #ifndef GPAC_DISABLE_AV_PARSERS
    6005           1 :                 remove_systems_tracks(file);
    6006             : #endif
    6007           1 :                 do_save = GF_TRUE;
    6008           1 :                 if (conv_type < GF_ISOM_CONV_TYPE_ISMA_EX) conv_type = 0;
    6009             :         }
    6010         971 :         if (remove_root_od) {
    6011           1 :                 gf_isom_remove_root_od(file);
    6012           1 :                 do_save = GF_TRUE;
    6013             :         }
    6014             : #ifndef GPAC_DISABLE_ISOM_HINTING
    6015         971 :         if (remove_hint) {
    6016          84 :                 for (i=0; i<gf_isom_get_track_count(file); i++) {
    6017          84 :                         if (gf_isom_get_media_type(file, i+1) == GF_ISOM_MEDIA_HINT) {
    6018          42 :                                 M4_LOG(GF_LOG_INFO, ("Removing hint track ID %d\n", gf_isom_get_track_id(file, i+1)));
    6019          42 :                                 gf_isom_remove_track(file, i+1);
    6020          42 :                                 i--;
    6021             :                         }
    6022             :                 }
    6023          41 :                 gf_isom_sdp_clean(file);
    6024          41 :                 do_save = GF_TRUE;
    6025             :         }
    6026             : #endif // GPAC_DISABLE_ISOM_HINTING
    6027             : 
    6028         971 :         if (timescale && (timescale != gf_isom_get_timescale(file))) {
    6029           1 :                 gf_isom_set_timescale(file, timescale);
    6030           1 :                 do_save = GF_TRUE;
    6031             :         }
    6032             : 
    6033         971 :         if (!encode) {
    6034         939 :                 if (!file) {
    6035           0 :                         M4_LOG(GF_LOG_INFO, ("Nothing to do - exiting\n"));
    6036             :                         goto exit;
    6037             :                 }
    6038         939 :                 if (outName) {
    6039             :                         strcpy(outfile, outName);
    6040             :                 } else {
    6041         562 :                         const char *tmp_dir = gf_opts_get_key("core", "tmp");
    6042         562 :                         char *rel_name = strrchr(inName, GF_PATH_SEPARATOR);
    6043             :                         if (!rel_name) rel_name = strrchr(inName, '/');
    6044             : 
    6045             :                         strcpy(outfile, "");
    6046         562 :                         if (tmp_dir) {
    6047             :                                 strcpy(outfile, tmp_dir);
    6048           0 :                                 if (!strchr("\\/", tmp_dir[strlen(tmp_dir)-1])) strcat(outfile, "/");
    6049             :                         }
    6050         562 :                         if (!pack_file) strcat(outfile, "out_");
    6051         562 :                         strcat(outfile, rel_name ? rel_name + 1 : inName);
    6052             : 
    6053         562 :                         if (pack_file) {
    6054             :                                 strcpy(outfile, rel_name ? rel_name + 1 : inName);
    6055           0 :                                 rel_name = strrchr(outfile, '.');
    6056           0 :                                 if (rel_name) rel_name[0] = 0;
    6057             :                                 strcat(outfile, ".m21");
    6058             :                         }
    6059             :                 }
    6060             : #ifndef GPAC_DISABLE_MEDIA_IMPORT
    6061         939 :                 if ((conv_type == GF_ISOM_CONV_TYPE_ISMA) || (conv_type == GF_ISOM_CONV_TYPE_ISMA_EX)) {
    6062           5 :                         M4_LOG(GF_LOG_INFO, ("Converting to ISMA Audio-Video MP4 file\n"));
    6063             :                         /*keep ESIDs when doing ISMACryp*/
    6064           5 :                         e = gf_media_make_isma(file, crypt ? 1 : 0, GF_FALSE, (conv_type==GF_ISOM_CONV_TYPE_ISMA_EX) ? 1 : 0);
    6065           5 :                         if (e) goto err_exit;
    6066           5 :                         do_save = GF_TRUE;
    6067             :                 }
    6068         939 :                 if (conv_type == GF_ISOM_CONV_TYPE_3GPP) {
    6069           1 :                         M4_LOG(GF_LOG_INFO, ("Converting to 3GP file\n"));
    6070           1 :                         e = gf_media_make_3gpp(file);
    6071           1 :                         if (e) goto err_exit;
    6072           1 :                         do_save = GF_TRUE;
    6073             :                 }
    6074         939 :                 if (conv_type == GF_ISOM_CONV_TYPE_PSP) {
    6075           1 :                         M4_LOG(GF_LOG_INFO, ("Converting to PSP file\n"));
    6076           1 :                         e = gf_media_make_psp(file);
    6077           1 :                         if (e) goto err_exit;
    6078           1 :                         do_save = GF_TRUE;
    6079             :                 }
    6080         939 :                 if (conv_type == GF_ISOM_CONV_TYPE_MOV) {
    6081           2 :                         e = gf_media_check_qt_prores(file);
    6082           2 :                         if (e) goto err_exit;
    6083           2 :                         do_save = GF_TRUE;
    6084           2 :                         if (interleaving_time) interleaving_time = 0.5;
    6085             :                 }
    6086             : #endif /*GPAC_DISABLE_MEDIA_IMPORT*/
    6087         939 :                 if (conv_type == GF_ISOM_CONV_TYPE_IPOD) {
    6088           1 :                         do_ipod_conv();
    6089             :                 }
    6090             : 
    6091          32 :         } else if (outName) {
    6092             :                 strcpy(outfile, outName);
    6093             :         }
    6094             : 
    6095         971 :         e = do_track_act();
    6096         971 :         if (e) goto err_exit;
    6097             : 
    6098         970 :         if (itunes_tags) {
    6099           1 :                 e = do_itunes_tag();
    6100           1 :                 if (e) goto err_exit;
    6101             :         }
    6102             : 
    6103         970 :         if (cprt) {
    6104           1 :                 e = gf_isom_set_copyright(file, "und", cprt);
    6105           1 :                 do_save = GF_TRUE;
    6106           1 :                 if (e) goto err_exit;
    6107             :         }
    6108         970 :         if (chap_file || chap_file_qt) {
    6109             : #ifndef GPAC_DISABLE_MEDIA_IMPORT
    6110             :                 Bool chap_qt = GF_FALSE;
    6111           0 :                 if (chap_file_qt) {
    6112           0 :                         chap_file = chap_file_qt;
    6113             :                         chap_qt = GF_TRUE;
    6114             :                 }
    6115           0 :                 e = gf_media_import_chapters(file, chap_file, import_fps, chap_qt);
    6116           0 :                 do_save = GF_TRUE;
    6117             : #else
    6118             :                 M4_LOG(GF_LOG_WARNING, ("Warning: GPAC compiled without Media Import, chapters can't be imported\n"));
    6119             :                 e = GF_NOT_SUPPORTED;
    6120             : #endif
    6121           0 :                 if (e) goto err_exit;
    6122             :         }
    6123             : 
    6124         970 :         if (major_brand) {
    6125           2 :                 gf_isom_set_brand_info(file, major_brand, minor_version);
    6126           2 :                 do_save = GF_TRUE;
    6127             :         }
    6128          65 :         for (i=0; i<nb_alt_brand_add; i++) {
    6129          65 :                 gf_isom_modify_alternate_brand(file, brand_add[i], GF_TRUE);
    6130          65 :                 do_save = GF_TRUE;
    6131             :         }
    6132           2 :         for (i=0; i<nb_alt_brand_rem; i++) {
    6133           2 :                 gf_isom_modify_alternate_brand(file, brand_rem[i], GF_FALSE);
    6134           2 :                 do_save = GF_TRUE;
    6135             :         }
    6136         970 :         if (box_patch_filename) {
    6137           6 :                 e = gf_isom_apply_box_patch(file, box_patch_trackID, box_patch_filename, GF_FALSE);
    6138           6 :                 if (e) {
    6139           0 :                         M4_LOG(GF_LOG_ERROR, ("Failed to apply box patch %s: %s\n", box_patch_filename, gf_error_to_string(e) ));
    6140             :                         goto err_exit;
    6141             :                 }
    6142           6 :                 do_save = GF_TRUE;
    6143             :         }
    6144             : 
    6145             : #ifndef GPAC_DISABLE_CRYPTO
    6146         970 :         if (crypt) {
    6147         222 :                 if (!drm_file && (crypt==1) ) {
    6148           0 :                         M4_LOG(GF_LOG_ERROR, ("Missing DRM file location - usage '-%s drm_file input_file\n", (crypt==1) ? "crypt" : "decrypt"));
    6149             :                         e = GF_BAD_PARAM;
    6150             :                         goto err_exit;
    6151             :                 }
    6152         222 :                 if (crypt == 1) {
    6153         115 :                         if (use_init_seg) {
    6154           2 :                                 e = gf_crypt_fragment(file, drm_file, outfile, inName, fs_dump_flags);
    6155             :                         } else {
    6156         113 :                                 e = gf_crypt_file(file, drm_file, outfile, interleaving_time, fs_dump_flags);
    6157             :                         }
    6158         107 :                 } else if (crypt ==2) {
    6159         107 :                         if (use_init_seg) {
    6160           1 :                                 e = gf_decrypt_fragment(file, drm_file, outfile, inName, fs_dump_flags);
    6161             :                         } else {
    6162         106 :                                 e = gf_decrypt_file(file, drm_file, outfile, interleaving_time, fs_dump_flags);
    6163             :                         }
    6164             :                 }
    6165         222 :                 if (e) goto err_exit;
    6166         222 :                 do_save = outName ? GF_FALSE : GF_TRUE;
    6167             : 
    6168         222 :                 if (!do_frag && !do_hint && !full_interleave && !force_co64) {
    6169             :                         char szName[GF_MAX_PATH];
    6170         222 :                         strcpy(szName, gf_isom_get_filename(file) );
    6171         222 :                         gf_isom_delete(file);
    6172         222 :                         file = NULL;
    6173         222 :                         if (!outName) {
    6174          12 :                                 e = gf_file_move(outfile, szName);
    6175          12 :                                 if (e) goto err_exit;
    6176             :                         }
    6177         222 :                         goto exit;
    6178             :                 }
    6179             :         }
    6180             : #endif /*GPAC_DISABLE_CRYPTO*/
    6181             : 
    6182             : #ifndef GPAC_DISABLE_ISOM_FRAGMENTS
    6183         748 :         if (do_frag) {
    6184           4 :                 if (!interleaving_time) interleaving_time = DEFAULT_INTERLEAVING_IN_SEC;
    6185           4 :                 if (do_hint) M4_LOG(GF_LOG_WARNING, ("Warning: cannot hint and fragment - ignoring hint\n"));
    6186           4 :                 M4_LOG(GF_LOG_INFO, ("Fragmenting file (%.3f seconds fragments)\n", interleaving_time));
    6187           4 :                 e = gf_media_fragment_file(file, outfile, interleaving_time, use_mfra);
    6188           4 :                 if (e) M4_LOG(GF_LOG_ERROR, ("Error while fragmenting file: %s\n", gf_error_to_string(e)));
    6189           4 :                 if (!e && !outName) {
    6190           1 :                         if (gf_file_exists(inName) && gf_file_delete(inName)) {
    6191           0 :                                 M4_LOG(GF_LOG_INFO, ("Error removing file %s\n", inName));
    6192             :                         }
    6193           1 :                         else if (gf_file_move(outfile, inName)) {
    6194           0 :                                 M4_LOG(GF_LOG_INFO, ("Error renaming file %s to %s\n", outfile, inName));
    6195             :                         }
    6196             :                 }
    6197           4 :                 if (e) goto err_exit;
    6198           4 :                 gf_isom_delete(file);
    6199           4 :                 goto exit;
    6200             :         }
    6201             : #endif
    6202             : 
    6203             : #ifndef GPAC_DISABLE_ISOM_HINTING
    6204         744 :         if (do_hint) {
    6205          56 :                 if (force_ocr) SetupClockReferences(file);
    6206          56 :                 MTUSize -= 12;
    6207          56 :                 e = HintFile(file, MTUSize, max_ptime, rtp_rate, hint_flags, HintCopy, hint_interleave, regular_iod, single_group, hint_no_offset);
    6208          56 :                 if (e) goto err_exit;
    6209          55 :                 do_save = GF_TRUE;
    6210          55 :                 if (print_sdp) dump_isom_sdp(file, dump_std ? NULL : (outName ? outName : outfile), outName ? GF_TRUE : GF_FALSE);
    6211             :         }
    6212             : #endif
    6213             : 
    6214             : #if !defined(GPAC_DISABLE_ISOM_HINTING) && !defined(GPAC_DISABLE_SENG)
    6215         743 :         set_sdp_ext();
    6216             : #endif /*!defined(GPAC_DISABLE_ISOM_HINTING) && !defined(GPAC_DISABLE_SENG)*/
    6217             : 
    6218         743 :         if (force_co64)
    6219           1 :                 gf_isom_force_64bit_chunk_offset(file, GF_TRUE);
    6220             : 
    6221         743 :         if (compress_moov)
    6222           0 :                 gf_isom_enable_compression(file, GF_ISOM_COMP_ALL, (compress_moov==2) ? GF_ISOM_COMP_WRAP_FTYPE : 0);
    6223             : 
    6224         743 :         if (no_inplace)
    6225           8 :                 gf_isom_disable_inplace_rewrite(file);
    6226             : 
    6227         743 :         if (moov_pading)
    6228           0 :                 gf_isom_set_inplace_padding(file, moov_pading);
    6229             : 
    6230         743 :         if (outName) {
    6231         175 :                 gf_isom_set_final_name(file, outfile);
    6232         568 :         } else if (!encode && !force_new && !gf_isom_is_inplace_rewrite(file)) {
    6233          47 :                 gf_isom_set_final_name(file, outfile);
    6234             :         }
    6235             : 
    6236         743 :         Bool is_inplace = gf_isom_is_inplace_rewrite(file);
    6237             : 
    6238             : 
    6239             :         /*full interleave (sample-based) if just hinted*/
    6240         743 :         if (full_interleave) {
    6241           1 :                 e = gf_isom_set_storage_mode(file, GF_ISOM_STORE_TIGHT);
    6242         742 :         } else if (do_flat) {
    6243           5 :                 e = gf_isom_set_storage_mode(file, (do_flat==1) ? GF_ISOM_STORE_FLAT : GF_ISOM_STORE_STREAMABLE);
    6244           5 :                 do_save = GF_TRUE;
    6245             :         }
    6246             :         //do not set storage mode unless inplace rewrite is disabled , either by user or due to operations on file
    6247         737 :         else if (!is_inplace) {
    6248         674 :                 e = gf_isom_make_interleave(file, interleaving_time);
    6249         674 :                 if (!e && old_interleave) e = gf_isom_set_storage_mode(file, GF_ISOM_STORE_INTERLEAVED);
    6250             :         }
    6251             : 
    6252         743 :         if (e) goto err_exit;
    6253             : 
    6254             : 
    6255         743 :         if (do_save) {
    6256             : 
    6257         736 :                 if (!gf_sys_is_quiet()) {
    6258           1 :                         if (outName) {
    6259           1 :                         } else if (encode || pack_file) {
    6260           0 :                                 M4_LOG(GF_LOG_INFO, ("Saving to %s: ", gf_isom_get_filename(file) ));
    6261             :                         } else {
    6262           1 :                                 M4_LOG(GF_LOG_INFO, ("Saving %s: ", inName));
    6263             :                         }
    6264           1 :                         if (is_inplace) {
    6265           0 :                                 M4_LOG(GF_LOG_INFO, ("In-place rewrite\n"));
    6266           1 :                         } else if (do_hint && full_interleave) {
    6267           0 :                                 M4_LOG(GF_LOG_INFO, ("Hinted file - Full Interleaving\n"));
    6268           1 :                         } else if (full_interleave) {
    6269           0 :                                 M4_LOG(GF_LOG_INFO, ("Full Interleaving\n"));
    6270           1 :                         } else if ((force_new==2) && interleaving_time) {
    6271           0 :                                 M4_LOG(GF_LOG_INFO, ("Fast-start interleaved storage\n"));
    6272           1 :                         } else if (do_flat || !interleaving_time) {
    6273           0 :                                 M4_LOG(GF_LOG_INFO, ("Flat storage\n"));
    6274             :                         } else {
    6275           1 :                                 M4_LOG(GF_LOG_INFO, ("%.3f secs Interleaving%s\n", interleaving_time, old_interleave ? " - no drift control" : ""));
    6276             :                         }
    6277             :                 }
    6278             : 
    6279         736 :                 e = gf_isom_close(file);
    6280         736 :                 file = NULL;
    6281             : 
    6282         736 :                 if (!e && !outName && !encode && !force_new && !pack_file && !is_inplace) {
    6283          47 :                         if (gf_file_exists(inName)) {
    6284          47 :                                 e = gf_file_delete(inName);
    6285          47 :                                 if (e) {
    6286           0 :                                         M4_LOG(GF_LOG_ERROR, ("Error removing file %s\n", inName));
    6287             :                                 }
    6288             :                         }
    6289             : 
    6290          47 :                         e = gf_file_move(outfile, inName);
    6291          47 :                         if (e) {
    6292           0 :                                 M4_LOG(GF_LOG_ERROR, ("Error renaming file %s to %s\n", outfile, inName));
    6293             :                         }
    6294             :                 }
    6295             :         } else {
    6296           7 :                 gf_isom_delete(file);
    6297             :         }
    6298             : 
    6299         743 :         if (e) {
    6300           0 :                 M4_LOG(GF_LOG_ERROR, ("Error: %s\n", gf_error_to_string(e)));
    6301             :                 goto err_exit;
    6302             :         }
    6303             :         goto exit;
    6304             : 
    6305             : #else
    6306             :         /*close libgpac*/
    6307             :         gf_isom_delete(file);
    6308             :         M4_LOG(GF_LOG_ERROR, ("Error: Read-only version of MP4Box.\n"));
    6309             :         return mp4box_cleanup(1);
    6310             : #endif //GPAC_DISABLE_ISOM_WRITE
    6311             : 
    6312             : 
    6313          24 : err_exit:
    6314             :         /*close libgpac*/
    6315          12 :         if (file) gf_isom_delete(file);
    6316          12 :         M4_LOG(GF_LOG_ERROR, ("\n\tError: %s\n", gf_error_to_string(e)));
    6317          12 :         return mp4box_cleanup(1);
    6318             : 
    6319        4412 : exit:
    6320        4412 :         mp4box_cleanup(0);
    6321             : 
    6322             : #ifdef GPAC_MEMORY_TRACKING
    6323        4412 :         if (mem_track && (gf_memory_size() || gf_file_handles_count() )) {
    6324           0 :                 gf_log_set_tool_level(GF_LOG_MEMORY, GF_LOG_INFO);
    6325           0 :                 gf_memory_print();
    6326           0 :                 return 2;
    6327             :         }
    6328             : #endif
    6329             :         return 0;
    6330             : }
    6331             : 
    6332             : 
    6333        4485 : GF_MAIN_FUNC(mp4boxMain)
    6334             : 
    6335             : 
    6336             : #endif /*GPAC_DISABLE_ISOM*/

Generated by: LCOV version 1.13