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 = ®->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