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