ffmpeg_opt.c
f5e66827
 /*
11a1033c
  * ffmpeg option parsing
f5e66827
  *
11a1033c
  * This file is part of FFmpeg.
f5e66827
  *
11a1033c
  * FFmpeg is free software; you can redistribute it and/or
f5e66827
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
11a1033c
  * FFmpeg is distributed in the hope that it will be useful,
f5e66827
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
11a1033c
  * License along with FFmpeg; if not, write to the Free Software
f5e66827
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include <stdint.h>
 
11a1033c
 #include "ffmpeg.h"
f5e66827
 #include "cmdutils.h"
 
 #include "libavformat/avformat.h"
 
 #include "libavcodec/avcodec.h"
 
 #include "libavfilter/avfilter.h"
 #include "libavfilter/avfiltergraph.h"
 
 #include "libavutil/audioconvert.h"
 #include "libavutil/avassert.h"
 #include "libavutil/avstring.h"
 #include "libavutil/avutil.h"
 #include "libavutil/intreadwrite.h"
 #include "libavutil/fifo.h"
 #include "libavutil/mathematics.h"
 #include "libavutil/opt.h"
 #include "libavutil/parseutils.h"
 #include "libavutil/pixdesc.h"
 #include "libavutil/pixfmt.h"
 
 #define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\
 {\
     int i, ret;\
     for (i = 0; i < o->nb_ ## name; i++) {\
         char *spec = o->name[i].specifier;\
         if ((ret = check_stream_specifier(fmtctx, st, spec)) > 0)\
             outvar = o->name[i].u.type;\
         else if (ret < 0)\
             exit_program(1);\
     }\
 }
 
bad953bc
 #define MATCH_PER_TYPE_OPT(name, type, outvar, fmtctx, mediatype)\
 {\
eb949544
     int i;\
bad953bc
     for (i = 0; i < o->nb_ ## name; i++) {\
         char *spec = o->name[i].specifier;\
a4271f3d
         if (!strcmp(spec, mediatype))\
bad953bc
             outvar = o->name[i].u.type;\
     }\
 }
f5e66827
 char *vstats_filename;
 
 float audio_drift_threshold = 0.1;
 float dts_delta_threshold   = 10;
11a1033c
 float dts_error_threshold   = 3600*30;
f5e66827
 
 int audio_volume      = 256;
 int audio_sync_method = 0;
 int video_sync_method = VSYNC_AUTO;
 int do_deinterlace    = 0;
 int do_benchmark      = 0;
11a1033c
 int do_benchmark_all  = 0;
f5e66827
 int do_hex_dump       = 0;
 int do_pkt_dump       = 0;
 int copy_ts           = 0;
11a1033c
 int copy_tb           = -1;
 int debug_ts          = 0;
f5e66827
 int exit_on_error     = 0;
 int print_stats       = 1;
 int qp_hist           = 0;
 int same_quant        = 0;
11a1033c
 int stdin_interaction = 1;
 int frame_bits_per_raw_sample = 0;
f5e66827
 
11a1033c
 
 static int intra_only         = 0;
f5e66827
 static int file_overwrite     = 0;
11a1033c
 static int no_file_overwrite  = 0;
f5e66827
 static int video_discard      = 0;
 static int intra_dc_precision = 8;
11a1033c
 static int do_psnr            = 0;
f5e66827
 static int input_sync;
 
11a1033c
 void reset_options(OptionsContext *o, int is_input)
f5e66827
 {
     const OptionDef *po = options;
11a1033c
     OptionsContext bak= *o;
f5e66827
     int i;
 
     /* all OPT_SPEC and OPT_STRING can be freed in generic way */
     while (po->name) {
         void *dst = (uint8_t*)o + po->u.off;
 
         if (po->flags & OPT_SPEC) {
             SpecifierOpt **so = dst;
             int i, *count = (int*)(so + 1);
             for (i = 0; i < *count; i++) {
                 av_freep(&(*so)[i].specifier);
                 if (po->flags & OPT_STRING)
                     av_freep(&(*so)[i].u.str);
             }
             av_freep(so);
             *count = 0;
         } else if (po->flags & OPT_OFFSET && po->flags & OPT_STRING)
             av_freep(dst);
         po++;
     }
 
     for (i = 0; i < o->nb_stream_maps; i++)
         av_freep(&o->stream_maps[i].linklabel);
     av_freep(&o->stream_maps);
11a1033c
     av_freep(&o->audio_channel_maps);
f5e66827
     av_freep(&o->streamid_map);
 
     memset(o, 0, sizeof(*o));
 
11a1033c
     if (is_input) {
         o->recording_time = bak.recording_time;
         if (o->recording_time != INT64_MAX)
             av_log(NULL, AV_LOG_WARNING,
                    "-t is not an input option, keeping it for the next output;"
                    " consider fixing your command line.\n");
     } else
f5e66827
     o->recording_time = INT64_MAX;
11a1033c
     o->mux_max_delay  = 0.7;
f5e66827
     o->limit_filesize = UINT64_MAX;
     o->chapters_input_file = INT_MAX;
 
     uninit_opts();
     init_opts();
 }
 
 
98298eb1
 static int opt_frame_crop(void *optctx, const char *opt, const char *arg)
f5e66827
 {
11a1033c
     av_log(NULL, AV_LOG_FATAL, "Option '%s' has been removed, use the crop filter instead\n", opt);
     return AVERROR(EINVAL);
 }
f5e66827
 
98298eb1
 static int opt_pad(void *optctx, const char *opt, const char *arg)
11a1033c
 {
     av_log(NULL, AV_LOG_FATAL, "Option '%s' has been removed, use the pad filter instead\n", opt);
     return -1;
 }
 
98298eb1
 static int opt_video_channel(void *optctx, const char *opt, const char *arg)
11a1033c
 {
     av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -channel.\n");
98298eb1
     return opt_default(optctx, "channel", arg);
f5e66827
     }
11a1033c
 
98298eb1
 static int opt_video_standard(void *optctx, const char *opt, const char *arg)
11a1033c
 {
     av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -standard.\n");
98298eb1
     return opt_default(optctx, "standard", arg);
f5e66827
 }
 
d3810c47
 static int opt_audio_codec(void *optctx, const char *opt, const char *arg)
f5e66827
 {
d3810c47
     OptionsContext *o = optctx;
f5e66827
     return parse_option(o, "codec:a", arg, options);
 }
 
d3810c47
 static int opt_video_codec(void *optctx, const char *opt, const char *arg)
f5e66827
 {
d3810c47
     OptionsContext *o = optctx;
f5e66827
     return parse_option(o, "codec:v", arg, options);
 }
 
d3810c47
 static int opt_subtitle_codec(void *optctx, const char *opt, const char *arg)
f5e66827
 {
d3810c47
     OptionsContext *o = optctx;
f5e66827
     return parse_option(o, "codec:s", arg, options);
 }
 
d3810c47
 static int opt_data_codec(void *optctx, const char *opt, const char *arg)
f5e66827
 {
d3810c47
     OptionsContext *o = optctx;
f5e66827
     return parse_option(o, "codec:d", arg, options);
 }
 
d3810c47
 static int opt_map(void *optctx, const char *opt, const char *arg)
f5e66827
 {
d3810c47
     OptionsContext *o = optctx;
f5e66827
     StreamMap *m = NULL;
     int i, negative = 0, file_idx;
11a1033c
     int sync_file_idx = -1, sync_stream_idx = 0;
f5e66827
     char *p, *sync;
     char *map;
 
     if (*arg == '-') {
         negative = 1;
         arg++;
     }
     map = av_strdup(arg);
 
     /* parse sync stream first, just pick first matching stream */
     if (sync = strchr(map, ',')) {
         *sync = 0;
         sync_file_idx = strtol(sync + 1, &sync, 0);
         if (sync_file_idx >= nb_input_files || sync_file_idx < 0) {
             av_log(NULL, AV_LOG_FATAL, "Invalid sync file index: %d.\n", sync_file_idx);
             exit_program(1);
         }
         if (*sync)
             sync++;
         for (i = 0; i < input_files[sync_file_idx]->nb_streams; i++)
             if (check_stream_specifier(input_files[sync_file_idx]->ctx,
                                        input_files[sync_file_idx]->ctx->streams[i], sync) == 1) {
                 sync_stream_idx = i;
                 break;
             }
         if (i == input_files[sync_file_idx]->nb_streams) {
             av_log(NULL, AV_LOG_FATAL, "Sync stream specification in map %s does not "
                                        "match any streams.\n", arg);
             exit_program(1);
         }
     }
 
 
     if (map[0] == '[') {
         /* this mapping refers to lavfi output */
         const char *c = map + 1;
         o->stream_maps = grow_array(o->stream_maps, sizeof(*o->stream_maps),
                                     &o->nb_stream_maps, o->nb_stream_maps + 1);
         m = &o->stream_maps[o->nb_stream_maps - 1];
         m->linklabel = av_get_token(&c, "]");
         if (!m->linklabel) {
             av_log(NULL, AV_LOG_ERROR, "Invalid output link label: %s.\n", map);
             exit_program(1);
         }
     } else {
         file_idx = strtol(map, &p, 0);
         if (file_idx >= nb_input_files || file_idx < 0) {
             av_log(NULL, AV_LOG_FATAL, "Invalid input file index: %d.\n", file_idx);
             exit_program(1);
         }
         if (negative)
             /* disable some already defined maps */
             for (i = 0; i < o->nb_stream_maps; i++) {
                 m = &o->stream_maps[i];
                 if (file_idx == m->file_index &&
                     check_stream_specifier(input_files[m->file_index]->ctx,
                                            input_files[m->file_index]->ctx->streams[m->stream_index],
                                            *p == ':' ? p + 1 : p) > 0)
                     m->disabled = 1;
             }
         else
             for (i = 0; i < input_files[file_idx]->nb_streams; i++) {
                 if (check_stream_specifier(input_files[file_idx]->ctx, input_files[file_idx]->ctx->streams[i],
                             *p == ':' ? p + 1 : p) <= 0)
                     continue;
                 o->stream_maps = grow_array(o->stream_maps, sizeof(*o->stream_maps),
                                             &o->nb_stream_maps, o->nb_stream_maps + 1);
                 m = &o->stream_maps[o->nb_stream_maps - 1];
 
                 m->file_index   = file_idx;
                 m->stream_index = i;
 
                 if (sync_file_idx >= 0) {
                     m->sync_file_index   = sync_file_idx;
                     m->sync_stream_index = sync_stream_idx;
                 } else {
                     m->sync_file_index   = file_idx;
                     m->sync_stream_index = i;
                 }
             }
     }
 
     if (!m) {
         av_log(NULL, AV_LOG_FATAL, "Stream map '%s' matches no streams.\n", arg);
         exit_program(1);
     }
 
     av_freep(&map);
     return 0;
 }
 
d3810c47
 static int opt_attach(void *optctx, const char *opt, const char *arg)
f5e66827
 {
d3810c47
     OptionsContext *o = optctx;
f5e66827
     o->attachments = grow_array(o->attachments, sizeof(*o->attachments),
                                 &o->nb_attachments, o->nb_attachments + 1);
     o->attachments[o->nb_attachments - 1] = arg;
     return 0;
 }
 
949938d1
 static int opt_map_channel(void *optctx, const char *opt, const char *arg)
11a1033c
 {
949938d1
     OptionsContext *o = optctx;
11a1033c
     int n;
     AVStream *st;
     AudioChannelMap *m;
 
     o->audio_channel_maps =
         grow_array(o->audio_channel_maps, sizeof(*o->audio_channel_maps),
                    &o->nb_audio_channel_maps, o->nb_audio_channel_maps + 1);
     m = &o->audio_channel_maps[o->nb_audio_channel_maps - 1];
 
     /* muted channel syntax */
     n = sscanf(arg, "%d:%d.%d", &m->channel_idx, &m->ofile_idx, &m->ostream_idx);
     if ((n == 1 || n == 3) && m->channel_idx == -1) {
         m->file_idx = m->stream_idx = -1;
         if (n == 1)
             m->ofile_idx = m->ostream_idx = -1;
         return 0;
     }
 
     /* normal syntax */
     n = sscanf(arg, "%d.%d.%d:%d.%d",
                &m->file_idx,  &m->stream_idx, &m->channel_idx,
                &m->ofile_idx, &m->ostream_idx);
 
     if (n != 3 && n != 5) {
         av_log(NULL, AV_LOG_FATAL, "Syntax error, mapchan usage: "
                "[file.stream.channel|-1][:syncfile:syncstream]\n");
         exit_program(1);
     }
 
     if (n != 5) // only file.stream.channel specified
         m->ofile_idx = m->ostream_idx = -1;
 
     /* check input */
     if (m->file_idx < 0 || m->file_idx >= nb_input_files) {
         av_log(NULL, AV_LOG_FATAL, "mapchan: invalid input file index: %d\n",
                m->file_idx);
         exit_program(1);
     }
     if (m->stream_idx < 0 ||
         m->stream_idx >= input_files[m->file_idx]->nb_streams) {
         av_log(NULL, AV_LOG_FATAL, "mapchan: invalid input file stream index #%d.%d\n",
                m->file_idx, m->stream_idx);
         exit_program(1);
     }
     st = input_files[m->file_idx]->ctx->streams[m->stream_idx];
     if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO) {
         av_log(NULL, AV_LOG_FATAL, "mapchan: stream #%d.%d is not an audio stream.\n",
                m->file_idx, m->stream_idx);
         exit_program(1);
     }
     if (m->channel_idx < 0 || m->channel_idx >= st->codec->channels) {
         av_log(NULL, AV_LOG_FATAL, "mapchan: invalid audio channel #%d.%d.%d\n",
                m->file_idx, m->stream_idx, m->channel_idx);
         exit_program(1);
     }
     return 0;
 }
 
f5e66827
 /**
  * Parse a metadata specifier in arg.
  * @param type metadata type is written here -- g(lobal)/s(tream)/c(hapter)/p(rogram)
  * @param index for type c/p, chapter/program index is written here
  * @param stream_spec for type s, the stream specifier is written here
  */
 static void parse_meta_type(char *arg, char *type, int *index, const char **stream_spec)
 {
     if (*arg) {
         *type = *arg;
         switch (*arg) {
         case 'g':
             break;
         case 's':
             if (*(++arg) && *arg != ':') {
                 av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", arg);
                 exit_program(1);
             }
             *stream_spec = *arg == ':' ? arg + 1 : "";
             break;
         case 'c':
         case 'p':
             if (*(++arg) == ':')
                 *index = strtol(++arg, NULL, 0);
             break;
         default:
             av_log(NULL, AV_LOG_FATAL, "Invalid metadata type %c.\n", *arg);
             exit_program(1);
         }
     } else
         *type = 'g';
 }
 
 static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFormatContext *ic, OptionsContext *o)
 {
     AVDictionary **meta_in = NULL;
11a1033c
     AVDictionary **meta_out = NULL;
f5e66827
     int i, ret = 0;
     char type_in, type_out;
     const char *istream_spec = NULL, *ostream_spec = NULL;
     int idx_in = 0, idx_out = 0;
 
     parse_meta_type(inspec,  &type_in,  &idx_in,  &istream_spec);
     parse_meta_type(outspec, &type_out, &idx_out, &ostream_spec);
 
11a1033c
     if (!ic) {
         if (type_out == 'g' || !*outspec)
             o->metadata_global_manual = 1;
         if (type_out == 's' || !*outspec)
             o->metadata_streams_manual = 1;
         if (type_out == 'c' || !*outspec)
             o->metadata_chapters_manual = 1;
         return 0;
     }
 
f5e66827
     if (type_in == 'g' || type_out == 'g')
         o->metadata_global_manual = 1;
     if (type_in == 's' || type_out == 's')
         o->metadata_streams_manual = 1;
     if (type_in == 'c' || type_out == 'c')
         o->metadata_chapters_manual = 1;
 
 #define METADATA_CHECK_INDEX(index, nb_elems, desc)\
     if ((index) < 0 || (index) >= (nb_elems)) {\
         av_log(NULL, AV_LOG_FATAL, "Invalid %s index %d while processing metadata maps.\n",\
                 (desc), (index));\
         exit_program(1);\
     }
 
 #define SET_DICT(type, meta, context, index)\
         switch (type) {\
         case 'g':\
             meta = &context->metadata;\
             break;\
         case 'c':\
             METADATA_CHECK_INDEX(index, context->nb_chapters, "chapter")\
             meta = &context->chapters[index]->metadata;\
             break;\
         case 'p':\
             METADATA_CHECK_INDEX(index, context->nb_programs, "program")\
             meta = &context->programs[index]->metadata;\
             break;\
         default: av_assert0(0);\
469f8b1d
         case 's':\
             break;\
f5e66827
         }\
 
     SET_DICT(type_in, meta_in, ic, idx_in);
     SET_DICT(type_out, meta_out, oc, idx_out);
 
     /* for input streams choose first matching stream */
     if (type_in == 's') {
         for (i = 0; i < ic->nb_streams; i++) {
             if ((ret = check_stream_specifier(ic, ic->streams[i], istream_spec)) > 0) {
                 meta_in = &ic->streams[i]->metadata;
                 break;
             } else if (ret < 0)
                 exit_program(1);
         }
         if (!meta_in) {
             av_log(NULL, AV_LOG_FATAL, "Stream specifier %s does not match  any streams.\n", istream_spec);
             exit_program(1);
         }
     }
 
     if (type_out == 's') {
         for (i = 0; i < oc->nb_streams; i++) {
             if ((ret = check_stream_specifier(oc, oc->streams[i], ostream_spec)) > 0) {
                 meta_out = &oc->streams[i]->metadata;
                 av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
             } else if (ret < 0)
                 exit_program(1);
         }
     } else
         av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
 
     return 0;
 }
 
949938d1
 static int opt_recording_timestamp(void *optctx, const char *opt, const char *arg)
11a1033c
 {
949938d1
     OptionsContext *o = optctx;
11a1033c
     char buf[128];
     int64_t recording_timestamp = parse_time_or_die(opt, arg, 0) / 1E6;
     struct tm time = *gmtime((time_t*)&recording_timestamp);
     strftime(buf, sizeof(buf), "creation_time=%FT%T%z", &time);
     parse_option(o, "metadata", buf, options);
 
     av_log(NULL, AV_LOG_WARNING, "%s is deprecated, set the 'creation_time' metadata "
                                  "tag instead.\n", opt);
     return 0;
 }
 
f5e66827
 static AVCodec *find_codec_or_die(const char *name, enum AVMediaType type, int encoder)
 {
db4766ad
     const AVCodecDescriptor *desc;
f5e66827
     const char *codec_string = encoder ? "encoder" : "decoder";
     AVCodec *codec;
 
     codec = encoder ?
         avcodec_find_encoder_by_name(name) :
         avcodec_find_decoder_by_name(name);
db4766ad
 
     if (!codec && (desc = avcodec_descriptor_get_by_name(name))) {
         codec = encoder ? avcodec_find_encoder(desc->id) :
                           avcodec_find_decoder(desc->id);
         if (codec)
             av_log(NULL, AV_LOG_VERBOSE, "Matched %s '%s' for codec '%s'.\n",
                    codec_string, codec->name, desc->name);
     }
 
f5e66827
     if (!codec) {
         av_log(NULL, AV_LOG_FATAL, "Unknown %s '%s'\n", codec_string, name);
         exit_program(1);
     }
     if (codec->type != type) {
         av_log(NULL, AV_LOG_FATAL, "Invalid %s type '%s'\n", codec_string, name);
         exit_program(1);
     }
     return codec;
 }
 
 static AVCodec *choose_decoder(OptionsContext *o, AVFormatContext *s, AVStream *st)
 {
     char *codec_name = NULL;
 
     MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, st);
     if (codec_name) {
         AVCodec *codec = find_codec_or_die(codec_name, st->codec->codec_type, 0);
         st->codec->codec_id = codec->id;
         return codec;
     } else
         return avcodec_find_decoder(st->codec->codec_id);
 }
 
 /**
  * Add all the streams from the given input file to the global
  * list of input streams.
  */
 static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
 {
     int i;
11a1033c
     char *next, *codec_tag = NULL;
f5e66827
 
     for (i = 0; i < ic->nb_streams; i++) {
         AVStream *st = ic->streams[i];
         AVCodecContext *dec = st->codec;
         InputStream *ist = av_mallocz(sizeof(*ist));
         char *framerate = NULL;
 
         if (!ist)
             exit_program(1);
 
         input_streams = grow_array(input_streams, sizeof(*input_streams), &nb_input_streams, nb_input_streams + 1);
         input_streams[nb_input_streams - 1] = ist;
 
         ist->st = st;
         ist->file_index = nb_input_files;
         ist->discard = 1;
         st->discard  = AVDISCARD_ALL;
11a1033c
         ist->opts = filter_codec_opts(codec_opts, ist->st->codec->codec_id, ic, st, choose_decoder(o, ic, st));
f5e66827
 
         ist->ts_scale = 1.0;
         MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st);
 
11a1033c
         MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, ic, st);
         if (codec_tag) {
             uint32_t tag = strtol(codec_tag, &next, 0);
             if (*next)
                 tag = AV_RL32(codec_tag);
             st->codec->codec_tag = tag;
         }
 
f5e66827
         ist->dec = choose_decoder(o, ic, st);
 
         switch (dec->codec_type) {
         case AVMEDIA_TYPE_VIDEO:
11a1033c
             if(!ist->dec)
                 ist->dec = avcodec_find_decoder(dec->codec_id);
             if (dec->lowres) {
                 dec->flags |= CODEC_FLAG_EMU_EDGE;
             }
 
f5e66827
             ist->resample_height  = dec->height;
             ist->resample_width   = dec->width;
             ist->resample_pix_fmt = dec->pix_fmt;
 
             MATCH_PER_STREAM_OPT(frame_rates, str, framerate, ic, st);
             if (framerate && av_parse_video_rate(&ist->framerate,
                                                  framerate) < 0) {
                 av_log(NULL, AV_LOG_ERROR, "Error parsing framerate %s.\n",
                        framerate);
                 exit_program(1);
             }
 
11a1033c
             ist->top_field_first = -1;
             MATCH_PER_STREAM_OPT(top_field_first, i, ist->top_field_first, ic, st);
 
f5e66827
             break;
         case AVMEDIA_TYPE_AUDIO:
             guess_input_channel_layout(ist);
 
             ist->resample_sample_fmt     = dec->sample_fmt;
             ist->resample_sample_rate    = dec->sample_rate;
             ist->resample_channels       = dec->channels;
             ist->resample_channel_layout = dec->channel_layout;
 
             break;
         case AVMEDIA_TYPE_DATA:
         case AVMEDIA_TYPE_SUBTITLE:
11a1033c
             if(!ist->dec)
                 ist->dec = avcodec_find_decoder(dec->codec_id);
0cad101e
             MATCH_PER_STREAM_OPT(fix_sub_duration, i, ist->fix_sub_duration, ic, st);
11a1033c
             break;
f5e66827
         case AVMEDIA_TYPE_ATTACHMENT:
         case AVMEDIA_TYPE_UNKNOWN:
             break;
         default:
             abort();
         }
     }
 }
 
 static void assert_file_overwrite(const char *filename)
 {
11a1033c
     if ((!file_overwrite || no_file_overwrite) &&
f5e66827
         (strchr(filename, ':') == NULL || filename[1] == ':' ||
          av_strstart(filename, "file:", NULL))) {
         if (avio_check(filename, 0) == 0) {
11a1033c
             if (stdin_interaction && (!no_file_overwrite || file_overwrite)) {
f5e66827
                 fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename);
                 fflush(stderr);
11a1033c
                 term_exit();
                 signal(SIGINT, SIG_DFL);
f5e66827
                 if (!read_yesno()) {
11a1033c
                     av_log(NULL, AV_LOG_FATAL, "Not overwriting - exiting\n");
f5e66827
                     exit_program(1);
                 }
11a1033c
                 term_init();
f5e66827
             }
             else {
11a1033c
                 av_log(NULL, AV_LOG_FATAL, "File '%s' already exists. Exiting.\n", filename);
f5e66827
                 exit_program(1);
             }
         }
     }
 }
 
 static void dump_attachment(AVStream *st, const char *filename)
 {
     int ret;
     AVIOContext *out = NULL;
     AVDictionaryEntry *e;
 
     if (!st->codec->extradata_size) {
         av_log(NULL, AV_LOG_WARNING, "No extradata to dump in stream #%d:%d.\n",
                nb_input_files - 1, st->index);
         return;
     }
     if (!*filename && (e = av_dict_get(st->metadata, "filename", NULL, 0)))
         filename = e->value;
     if (!*filename) {
         av_log(NULL, AV_LOG_FATAL, "No filename specified and no 'filename' tag"
                "in stream #%d:%d.\n", nb_input_files - 1, st->index);
         exit_program(1);
     }
 
     assert_file_overwrite(filename);
 
     if ((ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, &int_cb, NULL)) < 0) {
         av_log(NULL, AV_LOG_FATAL, "Could not open file %s for writing.\n",
                filename);
         exit_program(1);
     }
 
     avio_write(out, st->codec->extradata, st->codec->extradata_size);
     avio_flush(out);
     avio_close(out);
 }
 
d3810c47
 static int opt_input_file(void *optctx, const char *opt, const char *filename)
f5e66827
 {
d3810c47
     OptionsContext *o = optctx;
f5e66827
     AVFormatContext *ic;
     AVInputFormat *file_iformat = NULL;
     int err, i, ret;
     int64_t timestamp;
     uint8_t buf[128];
     AVDictionary **opts;
     int orig_nb_streams;                     // number of streams before avformat_find_stream_info
bad953bc
     char *   video_codec_name = NULL;
     char *   audio_codec_name = NULL;
     char *subtitle_codec_name = NULL;
f5e66827
 
     if (o->format) {
         if (!(file_iformat = av_find_input_format(o->format))) {
             av_log(NULL, AV_LOG_FATAL, "Unknown input format: '%s'\n", o->format);
             exit_program(1);
         }
     }
 
     if (!strcmp(filename, "-"))
         filename = "pipe:";
 
11a1033c
     stdin_interaction &= strncmp(filename, "pipe:", 5) &&
                          strcmp(filename, "/dev/stdin");
f5e66827
 
     /* get default parameters from command line */
     ic = avformat_alloc_context();
     if (!ic) {
         print_error(filename, AVERROR(ENOMEM));
         exit_program(1);
     }
     if (o->nb_audio_sample_rate) {
         snprintf(buf, sizeof(buf), "%d", o->audio_sample_rate[o->nb_audio_sample_rate - 1].u.i);
         av_dict_set(&format_opts, "sample_rate", buf, 0);
     }
     if (o->nb_audio_channels) {
         /* because we set audio_channels based on both the "ac" and
          * "channel_layout" options, we need to check that the specified
          * demuxer actually has the "channels" option before setting it */
         if (file_iformat && file_iformat->priv_class &&
             av_opt_find(&file_iformat->priv_class, "channels", NULL, 0,
                         AV_OPT_SEARCH_FAKE_OBJ)) {
             snprintf(buf, sizeof(buf), "%d",
                      o->audio_channels[o->nb_audio_channels - 1].u.i);
             av_dict_set(&format_opts, "channels", buf, 0);
         }
     }
     if (o->nb_frame_rates) {
         /* set the format-level framerate option;
          * this is important for video grabbers, e.g. x11 */
         if (file_iformat && file_iformat->priv_class &&
             av_opt_find(&file_iformat->priv_class, "framerate", NULL, 0,
                         AV_OPT_SEARCH_FAKE_OBJ)) {
             av_dict_set(&format_opts, "framerate",
                         o->frame_rates[o->nb_frame_rates - 1].u.str, 0);
         }
     }
     if (o->nb_frame_sizes) {
         av_dict_set(&format_opts, "video_size", o->frame_sizes[o->nb_frame_sizes - 1].u.str, 0);
     }
     if (o->nb_frame_pix_fmts)
         av_dict_set(&format_opts, "pixel_format", o->frame_pix_fmts[o->nb_frame_pix_fmts - 1].u.str, 0);
 
bad953bc
     MATCH_PER_TYPE_OPT(codec_names, str,    video_codec_name, ic, "v");
     MATCH_PER_TYPE_OPT(codec_names, str,    audio_codec_name, ic, "a");
     MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, ic, "s");
 
11a1033c
     ic->video_codec_id   = video_codec_name ?
         find_codec_or_die(video_codec_name   , AVMEDIA_TYPE_VIDEO   , 0)->id : AV_CODEC_ID_NONE;
     ic->audio_codec_id   = audio_codec_name ?
         find_codec_or_die(audio_codec_name   , AVMEDIA_TYPE_AUDIO   , 0)->id : AV_CODEC_ID_NONE;
     ic->subtitle_codec_id= subtitle_codec_name ?
         find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0)->id : AV_CODEC_ID_NONE;
f5e66827
     ic->flags |= AVFMT_FLAG_NONBLOCK;
     ic->interrupt_callback = int_cb;
 
11a1033c
     /* open the input file with generic avformat function */
f5e66827
     err = avformat_open_input(&ic, filename, file_iformat, &format_opts);
     if (err < 0) {
         print_error(filename, err);
         exit_program(1);
     }
     assert_avoptions(format_opts);
 
     /* apply forced codec ids */
     for (i = 0; i < ic->nb_streams; i++)
         choose_decoder(o, ic, ic->streams[i]);
 
     /* Set AVCodecContext options for avformat_find_stream_info */
     opts = setup_find_stream_info_opts(ic, codec_opts);
     orig_nb_streams = ic->nb_streams;
 
     /* If not enough info to get the stream parameters, we decode the
        first frames to get it. (used in mpeg case for example) */
     ret = avformat_find_stream_info(ic, opts);
     if (ret < 0) {
         av_log(NULL, AV_LOG_FATAL, "%s: could not find codec parameters\n", filename);
         avformat_close_input(&ic);
         exit_program(1);
     }
 
     timestamp = o->start_time;
     /* add the stream start time */
     if (ic->start_time != AV_NOPTS_VALUE)
         timestamp += ic->start_time;
 
     /* if seeking requested, we execute it */
     if (o->start_time != 0) {
         ret = av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
         if (ret < 0) {
             av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n",
                    filename, (double)timestamp / AV_TIME_BASE);
         }
     }
 
     /* update the current parameters so that they match the one of the input stream */
     add_input_streams(o, ic);
 
     /* dump the file content */
     av_dump_format(ic, nb_input_files, filename, 0);
 
     input_files = grow_array(input_files, sizeof(*input_files), &nb_input_files, nb_input_files + 1);
     if (!(input_files[nb_input_files - 1] = av_mallocz(sizeof(*input_files[0]))))
         exit_program(1);
 
     input_files[nb_input_files - 1]->ctx        = ic;
     input_files[nb_input_files - 1]->ist_index  = nb_input_streams - ic->nb_streams;
     input_files[nb_input_files - 1]->ts_offset  = o->input_ts_offset - (copy_ts ? 0 : timestamp);
     input_files[nb_input_files - 1]->nb_streams = ic->nb_streams;
     input_files[nb_input_files - 1]->rate_emu   = o->rate_emu;
 
     for (i = 0; i < o->nb_dump_attachment; i++) {
         int j;
 
         for (j = 0; j < ic->nb_streams; j++) {
             AVStream *st = ic->streams[j];
 
             if (check_stream_specifier(ic, st, o->dump_attachment[i].specifier) == 1)
                 dump_attachment(st, o->dump_attachment[i].u.str);
         }
     }
 
     for (i = 0; i < orig_nb_streams; i++)
         av_dict_free(&opts[i]);
     av_freep(&opts);
 
11a1033c
     reset_options(o, 1);
f5e66827
     return 0;
 }
 
 static uint8_t *get_line(AVIOContext *s)
 {
     AVIOContext *line;
     uint8_t *buf;
     char c;
 
     if (avio_open_dyn_buf(&line) < 0) {
         av_log(NULL, AV_LOG_FATAL, "Could not alloc buffer for reading preset.\n");
         exit_program(1);
     }
 
     while ((c = avio_r8(s)) && c != '\n')
         avio_w8(line, c);
     avio_w8(line, 0);
     avio_close_dyn_buf(line, &buf);
 
     return buf;
 }
 
 static int get_preset_file_2(const char *preset_name, const char *codec_name, AVIOContext **s)
 {
     int i, ret = 1;
     char filename[1000];
     const char *base[3] = { getenv("AVCONV_DATADIR"),
                             getenv("HOME"),
                             AVCONV_DATADIR,
                             };
 
     for (i = 0; i < FF_ARRAY_ELEMS(base) && ret; i++) {
         if (!base[i])
             continue;
         if (codec_name) {
             snprintf(filename, sizeof(filename), "%s%s/%s-%s.avpreset", base[i],
                      i != 1 ? "" : "/.avconv", codec_name, preset_name);
             ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);
         }
         if (ret) {
             snprintf(filename, sizeof(filename), "%s%s/%s.avpreset", base[i],
                      i != 1 ? "" : "/.avconv", preset_name);
             ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);
         }
     }
     return ret;
 }
 
 static void choose_encoder(OptionsContext *o, AVFormatContext *s, OutputStream *ost)
 {
     char *codec_name = NULL;
 
     MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, ost->st);
     if (!codec_name) {
         ost->st->codec->codec_id = av_guess_codec(s->oformat, NULL, s->filename,
                                                   NULL, ost->st->codec->codec_type);
         ost->enc = avcodec_find_encoder(ost->st->codec->codec_id);
     } else if (!strcmp(codec_name, "copy"))
         ost->stream_copy = 1;
     else {
         ost->enc = find_codec_or_die(codec_name, ost->st->codec->codec_type, 1);
         ost->st->codec->codec_id = ost->enc->id;
     }
 }
 
11a1033c
 static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type, int source_index)
f5e66827
 {
     OutputStream *ost;
     AVStream *st = avformat_new_stream(oc, NULL);
     int idx      = oc->nb_streams - 1, ret = 0;
     char *bsf = NULL, *next, *codec_tag = NULL;
     AVBitStreamFilterContext *bsfc, *bsfc_prev = NULL;
     double qscale = -1;
     char *buf = NULL, *arg = NULL, *preset = NULL;
     AVIOContext *s = NULL;
 
     if (!st) {
         av_log(NULL, AV_LOG_FATAL, "Could not alloc stream.\n");
         exit_program(1);
     }
 
     if (oc->nb_streams - 1 < o->nb_streamid_map)
         st->id = o->streamid_map[oc->nb_streams - 1];
 
     output_streams = grow_array(output_streams, sizeof(*output_streams), &nb_output_streams,
                                 nb_output_streams + 1);
     if (!(ost = av_mallocz(sizeof(*ost))))
         exit_program(1);
     output_streams[nb_output_streams - 1] = ost;
 
     ost->file_index = nb_output_files;
     ost->index      = idx;
     ost->st         = st;
     st->codec->codec_type = type;
     choose_encoder(o, oc, ost);
     if (ost->enc) {
         ost->opts  = filter_codec_opts(codec_opts, ost->enc->id, oc, st, ost->enc);
     }
 
     avcodec_get_context_defaults3(st->codec, ost->enc);
     st->codec->codec_type = type; // XXX hack, avcodec_get_context_defaults2() sets type to unknown for stream copy
 
     MATCH_PER_STREAM_OPT(presets, str, preset, oc, st);
     if (preset && (!(ret = get_preset_file_2(preset, ost->enc->name, &s)))) {
         do  {
             buf = get_line(s);
             if (!buf[0] || buf[0] == '#') {
                 av_free(buf);
                 continue;
             }
             if (!(arg = strchr(buf, '='))) {
                 av_log(NULL, AV_LOG_FATAL, "Invalid line found in the preset file.\n");
                 exit_program(1);
             }
             *arg++ = 0;
             av_dict_set(&ost->opts, buf, arg, AV_DICT_DONT_OVERWRITE);
             av_free(buf);
         } while (!s->eof_reached);
         avio_close(s);
     }
     if (ret) {
         av_log(NULL, AV_LOG_FATAL,
                "Preset %s specified for stream %d:%d, but could not be opened.\n",
                preset, ost->file_index, ost->index);
         exit_program(1);
     }
 
     ost->max_frames = INT64_MAX;
     MATCH_PER_STREAM_OPT(max_frames, i64, ost->max_frames, oc, st);
 
65f7aee6
     ost->copy_prior_start = -1;
     MATCH_PER_STREAM_OPT(copy_prior_start, i, ost->copy_prior_start, oc ,st);
 
f5e66827
     MATCH_PER_STREAM_OPT(bitstream_filters, str, bsf, oc, st);
     while (bsf) {
         if (next = strchr(bsf, ','))
             *next++ = 0;
         if (!(bsfc = av_bitstream_filter_init(bsf))) {
             av_log(NULL, AV_LOG_FATAL, "Unknown bitstream filter %s\n", bsf);
             exit_program(1);
         }
         if (bsfc_prev)
             bsfc_prev->next = bsfc;
         else
             ost->bitstream_filters = bsfc;
 
         bsfc_prev = bsfc;
         bsf       = next;
     }
 
     MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, oc, st);
     if (codec_tag) {
         uint32_t tag = strtol(codec_tag, &next, 0);
         if (*next)
             tag = AV_RL32(codec_tag);
         st->codec->codec_tag = tag;
     }
 
     MATCH_PER_STREAM_OPT(qscale, dbl, qscale, oc, st);
     if (qscale >= 0 || same_quant) {
         st->codec->flags |= CODEC_FLAG_QSCALE;
         st->codec->global_quality = FF_QP2LAMBDA * qscale;
     }
 
     if (oc->oformat->flags & AVFMT_GLOBALHEADER)
         st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
 
     av_opt_get_int(sws_opts, "sws_flags", 0, &ost->sws_flags);
11a1033c
     av_opt_get_int   (swr_opts, "dither_method", 0, &ost->swr_dither_method);
     av_opt_get_double(swr_opts, "dither_scale" , 0, &ost->swr_dither_scale);
 
     ost->source_index = source_index;
     if (source_index >= 0) {
         ost->sync_ist = input_streams[source_index];
         input_streams[source_index]->discard = 0;
         input_streams[source_index]->st->discard = AVDISCARD_NONE;
     }
f5e66827
 
     return ost;
 }
 
 static void parse_matrix_coeffs(uint16_t *dest, const char *str)
 {
     int i;
     const char *p = str;
     for (i = 0;; i++) {
         dest[i] = atoi(p);
         if (i == 63)
             break;
         p = strchr(p, ',');
         if (!p) {
             av_log(NULL, AV_LOG_FATAL, "Syntax error in matrix \"%s\" at coeff %d\n", str, i);
             exit_program(1);
         }
         p++;
     }
 }
 
11a1033c
 static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
f5e66827
 {
     AVStream *st;
     OutputStream *ost;
     AVCodecContext *video_enc;
11a1033c
     char *frame_rate = NULL;
f5e66827
 
11a1033c
     ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO, source_index);
f5e66827
     st  = ost->st;
     video_enc = st->codec;
 
11a1033c
     MATCH_PER_STREAM_OPT(frame_rates, str, frame_rate, oc, st);
     if (frame_rate && av_parse_video_rate(&ost->frame_rate, frame_rate) < 0) {
         av_log(NULL, AV_LOG_FATAL, "Invalid framerate value: %s\n", frame_rate);
         exit_program(1);
     }
 
f5e66827
     if (!ost->stream_copy) {
         const char *p = NULL;
11a1033c
         char *frame_size = NULL;
f5e66827
         char *frame_aspect_ratio = NULL, *frame_pix_fmt = NULL;
         char *intra_matrix = NULL, *inter_matrix = NULL;
         const char *filters = "null";
038c0b1e
         int do_pass = 0;
f5e66827
         int i;
 
         MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
         if (frame_size && av_parse_video_size(&video_enc->width, &video_enc->height, frame_size) < 0) {
             av_log(NULL, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size);
             exit_program(1);
         }
 
         MATCH_PER_STREAM_OPT(frame_aspect_ratios, str, frame_aspect_ratio, oc, st);
11a1033c
         if (frame_aspect_ratio) {
             AVRational q;
             if (av_parse_ratio(&q, frame_aspect_ratio, 255, 0, NULL) < 0 ||
                 q.num <= 0 || q.den <= 0) {
                 av_log(NULL, AV_LOG_FATAL, "Invalid aspect ratio: %s\n", frame_aspect_ratio);
                 exit_program(1);
             }
             ost->frame_aspect_ratio = av_q2d(q);
         }
f5e66827
 
11a1033c
         video_enc->bits_per_raw_sample = frame_bits_per_raw_sample;
f5e66827
         MATCH_PER_STREAM_OPT(frame_pix_fmts, str, frame_pix_fmt, oc, st);
11a1033c
         if (frame_pix_fmt && *frame_pix_fmt == '+') {
             ost->keep_pix_fmt = 1;
             if (!*++frame_pix_fmt)
                 frame_pix_fmt = NULL;
         }
f5e66827
         if (frame_pix_fmt && (video_enc->pix_fmt = av_get_pix_fmt(frame_pix_fmt)) == PIX_FMT_NONE) {
             av_log(NULL, AV_LOG_FATAL, "Unknown pixel format requested: %s.\n", frame_pix_fmt);
             exit_program(1);
         }
         st->sample_aspect_ratio = video_enc->sample_aspect_ratio;
 
11a1033c
         if (intra_only)
             video_enc->gop_size = 0;
f5e66827
         MATCH_PER_STREAM_OPT(intra_matrices, str, intra_matrix, oc, st);
         if (intra_matrix) {
             if (!(video_enc->intra_matrix = av_mallocz(sizeof(*video_enc->intra_matrix) * 64))) {
                 av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for intra matrix.\n");
                 exit_program(1);
             }
             parse_matrix_coeffs(video_enc->intra_matrix, intra_matrix);
         }
         MATCH_PER_STREAM_OPT(inter_matrices, str, inter_matrix, oc, st);
         if (inter_matrix) {
             if (!(video_enc->inter_matrix = av_mallocz(sizeof(*video_enc->inter_matrix) * 64))) {
                 av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for inter matrix.\n");
                 exit_program(1);
             }
             parse_matrix_coeffs(video_enc->inter_matrix, inter_matrix);
         }
 
         MATCH_PER_STREAM_OPT(rc_overrides, str, p, oc, st);
         for (i = 0; p; i++) {
             int start, end, q;
             int e = sscanf(p, "%d,%d,%d", &start, &end, &q);
             if (e != 3) {
                 av_log(NULL, AV_LOG_FATAL, "error parsing rc_override\n");
                 exit_program(1);
             }
11a1033c
             /* FIXME realloc failure */
f5e66827
             video_enc->rc_override =
                 av_realloc(video_enc->rc_override,
                            sizeof(RcOverride) * (i + 1));
             video_enc->rc_override[i].start_frame = start;
             video_enc->rc_override[i].end_frame   = end;
             if (q > 0) {
                 video_enc->rc_override[i].qscale         = q;
                 video_enc->rc_override[i].quality_factor = 1.0;
             }
             else {
                 video_enc->rc_override[i].qscale         = 0;
                 video_enc->rc_override[i].quality_factor = -q/100.0;
             }
             p = strchr(p, '/');
             if (p) p++;
         }
         video_enc->rc_override_count = i;
         if (!video_enc->rc_initial_buffer_occupancy)
             video_enc->rc_initial_buffer_occupancy = video_enc->rc_buffer_size * 3 / 4;
         video_enc->intra_dc_precision = intra_dc_precision - 8;
 
11a1033c
         if (do_psnr)
             video_enc->flags|= CODEC_FLAG_PSNR;
 
f5e66827
         /* two pass mode */
038c0b1e
         MATCH_PER_STREAM_OPT(pass, i, do_pass, oc, st);
f5e66827
         if (do_pass) {
11a1033c
             if (do_pass & 1) {
f5e66827
                 video_enc->flags |= CODEC_FLAG_PASS1;
11a1033c
             }
             if (do_pass & 2) {
f5e66827
                 video_enc->flags |= CODEC_FLAG_PASS2;
             }
         }
 
bbcedade
         MATCH_PER_STREAM_OPT(passlogfiles, str, ost->logfile_prefix, oc, st);
         if (ost->logfile_prefix &&
             !(ost->logfile_prefix = av_strdup(ost->logfile_prefix)))
             exit_program(1);
 
f5e66827
         MATCH_PER_STREAM_OPT(forced_key_frames, str, ost->forced_keyframes, oc, st);
         if (ost->forced_keyframes)
             ost->forced_keyframes = av_strdup(ost->forced_keyframes);
 
         MATCH_PER_STREAM_OPT(force_fps, i, ost->force_fps, oc, st);
 
         ost->top_field_first = -1;
         MATCH_PER_STREAM_OPT(top_field_first, i, ost->top_field_first, oc, st);
 
         MATCH_PER_STREAM_OPT(filters, str, filters, oc, st);
         ost->avfilter = av_strdup(filters);
     } else {
         MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc ,st);
     }
 
     return ost;
 }
 
11a1033c
 static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
f5e66827
 {
11a1033c
     int n;
f5e66827
     AVStream *st;
     OutputStream *ost;
     AVCodecContext *audio_enc;
 
11a1033c
     ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO, source_index);
f5e66827
     st  = ost->st;
 
     audio_enc = st->codec;
     audio_enc->codec_type = AVMEDIA_TYPE_AUDIO;
 
     if (!ost->stream_copy) {
         char *sample_fmt = NULL;
         const char *filters = "anull";
 
         MATCH_PER_STREAM_OPT(audio_channels, i, audio_enc->channels, oc, st);
 
         MATCH_PER_STREAM_OPT(sample_fmts, str, sample_fmt, oc, st);
         if (sample_fmt &&
             (audio_enc->sample_fmt = av_get_sample_fmt(sample_fmt)) == AV_SAMPLE_FMT_NONE) {
             av_log(NULL, AV_LOG_FATAL, "Invalid sample format '%s'\n", sample_fmt);
             exit_program(1);
         }
 
         MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st);
 
         MATCH_PER_STREAM_OPT(filters, str, filters, oc, st);
11a1033c
 
         av_assert1(filters);
f5e66827
         ost->avfilter = av_strdup(filters);
11a1033c
 
         /* check for channel mapping for this audio stream */
         for (n = 0; n < o->nb_audio_channel_maps; n++) {
             AudioChannelMap *map = &o->audio_channel_maps[n];
             InputStream *ist = input_streams[ost->source_index];
             if ((map->channel_idx == -1 || (ist->file_index == map->file_idx && ist->st->index == map->stream_idx)) &&
                 (map->ofile_idx   == -1 || ost->file_index == map->ofile_idx) &&
                 (map->ostream_idx == -1 || ost->st->index  == map->ostream_idx)) {
                 if (ost->audio_channels_mapped < FF_ARRAY_ELEMS(ost->audio_channels_map))
                     ost->audio_channels_map[ost->audio_channels_mapped++] = map->channel_idx;
                 else
                     av_log(NULL, AV_LOG_FATAL, "Max channel mapping for output %d.%d reached\n",
                            ost->file_index, ost->st->index);
             }
         }
f5e66827
     }
 
     return ost;
 }
 
11a1033c
 static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
f5e66827
 {
     OutputStream *ost;
 
11a1033c
     ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA, source_index);
f5e66827
     if (!ost->stream_copy) {
         av_log(NULL, AV_LOG_FATAL, "Data stream encoding not supported yet (only streamcopy)\n");
         exit_program(1);
     }
 
     return ost;
 }
 
11a1033c
 static OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
f5e66827
 {
11a1033c
     OutputStream *ost = new_output_stream(o, oc, AVMEDIA_TYPE_ATTACHMENT, source_index);
f5e66827
     ost->stream_copy = 1;
     return ost;
 }
 
11a1033c
 static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
f5e66827
 {
     AVStream *st;
     OutputStream *ost;
     AVCodecContext *subtitle_enc;
 
11a1033c
     ost = new_output_stream(o, oc, AVMEDIA_TYPE_SUBTITLE, source_index);
f5e66827
     st  = ost->st;
     subtitle_enc = st->codec;
 
     subtitle_enc->codec_type = AVMEDIA_TYPE_SUBTITLE;
 
11a1033c
     MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc, st);
 
e4f4d99d
     if (!ost->stream_copy) {
         char *frame_size = NULL;
 
         MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
         if (frame_size && av_parse_video_size(&subtitle_enc->width, &subtitle_enc->height, frame_size) < 0) {
             av_log(NULL, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size);
             exit_program(1);
         }
     }
 
f5e66827
     return ost;
 }
 
 /* arg format is "output-stream-index:streamid-value". */
d3810c47
 static int opt_streamid(void *optctx, const char *opt, const char *arg)
f5e66827
 {
d3810c47
     OptionsContext *o = optctx;
f5e66827
     int idx;
     char *p;
     char idx_str[16];
 
     av_strlcpy(idx_str, arg, sizeof(idx_str));
     p = strchr(idx_str, ':');
     if (!p) {
         av_log(NULL, AV_LOG_FATAL,
                "Invalid value '%s' for option '%s', required syntax is 'index:value'\n",
                arg, opt);
         exit_program(1);
     }
     *p++ = '\0';
11a1033c
     idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, MAX_STREAMS-1);
f5e66827
     o->streamid_map = grow_array(o->streamid_map, sizeof(*o->streamid_map), &o->nb_streamid_map, idx+1);
     o->streamid_map[idx] = parse_number_or_die(opt, p, OPT_INT, 0, INT_MAX);
     return 0;
 }
 
 static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata)
 {
     AVFormatContext *is = ifile->ctx;
     AVFormatContext *os = ofile->ctx;
     int i;
 
     for (i = 0; i < is->nb_chapters; i++) {
         AVChapter *in_ch = is->chapters[i], *out_ch;
         int64_t ts_off   = av_rescale_q(ofile->start_time - ifile->ts_offset,
                                        AV_TIME_BASE_Q, in_ch->time_base);
         int64_t rt       = (ofile->recording_time == INT64_MAX) ? INT64_MAX :
                            av_rescale_q(ofile->recording_time, AV_TIME_BASE_Q, in_ch->time_base);
 
 
         if (in_ch->end < ts_off)
             continue;
         if (rt != INT64_MAX && in_ch->start > rt + ts_off)
             break;
 
         out_ch = av_mallocz(sizeof(AVChapter));
         if (!out_ch)
             return AVERROR(ENOMEM);
 
         out_ch->id        = in_ch->id;
         out_ch->time_base = in_ch->time_base;
         out_ch->start     = FFMAX(0,  in_ch->start - ts_off);
         out_ch->end       = FFMIN(rt, in_ch->end   - ts_off);
 
         if (copy_metadata)
             av_dict_copy(&out_ch->metadata, in_ch->metadata, 0);
 
         os->nb_chapters++;
11a1033c
         os->chapters = av_realloc_f(os->chapters, os->nb_chapters, sizeof(AVChapter));
f5e66827
         if (!os->chapters)
             return AVERROR(ENOMEM);
         os->chapters[os->nb_chapters - 1] = out_ch;
     }
     return 0;
 }
 
11a1033c
 static int read_ffserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename)
 {
     int i, err;
     AVFormatContext *ic = avformat_alloc_context();
 
     ic->interrupt_callback = int_cb;
     err = avformat_open_input(&ic, filename, NULL, NULL);
     if (err < 0)
         return err;
     /* copy stream format */
     for(i=0;i<ic->nb_streams;i++) {
         AVStream *st;
         OutputStream *ost;
         AVCodec *codec;
         AVCodecContext *avctx;
 
         codec = avcodec_find_encoder(ic->streams[i]->codec->codec_id);
         ost   = new_output_stream(o, s, codec->type, -1);
         st    = ost->st;
         avctx = st->codec;
         ost->enc = codec;
 
         // FIXME: a more elegant solution is needed
         memcpy(st, ic->streams[i], sizeof(AVStream));
         st->cur_dts = 0;
         st->info = av_malloc(sizeof(*st->info));
         memcpy(st->info, ic->streams[i]->info, sizeof(*st->info));
         st->codec= avctx;
         avcodec_copy_context(st->codec, ic->streams[i]->codec);
 
         if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && !ost->stream_copy)
             choose_sample_fmt(st, codec);
         else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && !ost->stream_copy)
             choose_pixel_fmt(st, codec, st->codec->pix_fmt);
     }
 
     avformat_close_input(&ic);
     return 0;
 }
 
f5e66827
 static void init_output_filter(OutputFilter *ofilter, OptionsContext *o,
                                AVFormatContext *oc)
 {
     OutputStream *ost;
 
     switch (avfilter_pad_get_type(ofilter->out_tmp->filter_ctx->output_pads,
                                   ofilter->out_tmp->pad_idx)) {
11a1033c
     case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc, -1); break;
     case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc, -1); break;
f5e66827
     default:
         av_log(NULL, AV_LOG_FATAL, "Only video and audio filters are supported "
                "currently.\n");
         exit_program(1);
     }
 
     ost->source_index = -1;
     ost->filter       = ofilter;
 
     ofilter->ost      = ost;
 
     if (ost->stream_copy) {
         av_log(NULL, AV_LOG_ERROR, "Streamcopy requested for output stream %d:%d, "
                "which is fed from a complex filtergraph. Filtering and streamcopy "
                "cannot be used together.\n", ost->file_index, ost->index);
         exit_program(1);
     }
 
     if (configure_output_filter(ofilter->graph, ofilter, ofilter->out_tmp) < 0) {
         av_log(NULL, AV_LOG_FATAL, "Error configuring filter.\n");
         exit_program(1);
     }
     avfilter_inout_free(&ofilter->out_tmp);
 }
 
 static int configure_complex_filters(void)
 {
     int i, ret = 0;
 
     for (i = 0; i < nb_filtergraphs; i++)
         if (!filtergraphs[i]->graph &&
             (ret = configure_filtergraph(filtergraphs[i])) < 0)
             return ret;
     return 0;
 }
 
 void opt_output_file(void *optctx, const char *filename)
 {
     OptionsContext *o = optctx;
     AVFormatContext *oc;
     int i, j, err;
     AVOutputFormat *file_oformat;
     OutputStream *ost;
     InputStream  *ist;
 
     if (configure_complex_filters() < 0) {
         av_log(NULL, AV_LOG_FATAL, "Error configuring filters.\n");
         exit_program(1);
     }
 
     if (!strcmp(filename, "-"))
         filename = "pipe:";
 
11a1033c
     err = avformat_alloc_output_context2(&oc, NULL, o->format, filename);
f5e66827
     if (!oc) {
11a1033c
         print_error(filename, err);
f5e66827
         exit_program(1);
     }
11a1033c
     file_oformat= oc->oformat;
f5e66827
     oc->interrupt_callback = int_cb;
 
     /* create streams for all unlabeled output pads */
     for (i = 0; i < nb_filtergraphs; i++) {
         FilterGraph *fg = filtergraphs[i];
         for (j = 0; j < fg->nb_outputs; j++) {
             OutputFilter *ofilter = fg->outputs[j];
 
             if (!ofilter->out_tmp || ofilter->out_tmp->name)
                 continue;
 
             switch (avfilter_pad_get_type(ofilter->out_tmp->filter_ctx->output_pads,
                                           ofilter->out_tmp->pad_idx)) {
             case AVMEDIA_TYPE_VIDEO:    o->video_disable    = 1; break;
             case AVMEDIA_TYPE_AUDIO:    o->audio_disable    = 1; break;
             case AVMEDIA_TYPE_SUBTITLE: o->subtitle_disable = 1; break;
             }
             init_output_filter(ofilter, o, oc);
         }
     }
 
11a1033c
     if (!strcmp(file_oformat->name, "ffm") &&
         av_strstart(filename, "http:", NULL)) {
         int j;
         /* special case for files sent to ffserver: we get the stream
            parameters from ffserver */
         int err = read_ffserver_streams(o, oc, filename);
         if (err < 0) {
             print_error(filename, err);
             exit_program(1);
         }
         for(j = nb_output_streams - oc->nb_streams; j < nb_output_streams; j++) {
             ost = output_streams[j];
             for (i = 0; i < nb_input_streams; i++) {
                 ist = input_streams[i];
                 if(ist->st->codec->codec_type == ost->st->codec->codec_type){
                     ost->sync_ist= ist;
                     ost->source_index= i;
                     if(ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO) ost->avfilter = av_strdup("anull");
                     if(ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) ost->avfilter = av_strdup("null");
                     ist->discard = 0;
                     ist->st->discard = AVDISCARD_NONE;
                     break;
                 }
             }
             if(!ost->sync_ist){
                 av_log(NULL, AV_LOG_FATAL, "Missing %s stream which is required by this ffm\n", av_get_media_type_string(ost->st->codec->codec_type));
                 exit_program(1);
             }
f5e66827
         }
11a1033c
     } else if (!o->nb_stream_maps) {
8ccb56ab
         char *subtitle_codec_name = NULL;
11a1033c
         /* pick the "best" stream of each type */
f5e66827
 
         /* video: highest resolution */
         if (!o->video_disable && oc->oformat->video_codec != AV_CODEC_ID_NONE) {
             int area = 0, idx = -1;
22d804b7
             int qcr = avformat_query_codec(oc->oformat, oc->oformat->video_codec, 0);
f5e66827
             for (i = 0; i < nb_input_streams; i++) {
a7b48395
                 int new_area;
f5e66827
                 ist = input_streams[i];
a7b48395
                 new_area = ist->st->codec->width * ist->st->codec->height;
de73ae6b
                 if((qcr!=MKTAG('A', 'P', 'I', 'C')) && (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
                     new_area = 1;
f5e66827
                 if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
a7b48395
                     new_area > area) {
22d804b7
                     if((qcr==MKTAG('A', 'P', 'I', 'C')) && !(ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
                         continue;
a7b48395
                     area = new_area;
f5e66827
                     idx = i;
                 }
             }
11a1033c
             if (idx >= 0)
                 new_video_stream(o, oc, idx);
f5e66827
         }
 
         /* audio: most channels */
         if (!o->audio_disable && oc->oformat->audio_codec != AV_CODEC_ID_NONE) {
             int channels = 0, idx = -1;
             for (i = 0; i < nb_input_streams; i++) {
                 ist = input_streams[i];
                 if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
                     ist->st->codec->channels > channels) {
                     channels = ist->st->codec->channels;
                     idx = i;
                 }
             }
11a1033c
             if (idx >= 0)
                 new_audio_stream(o, oc, idx);
f5e66827
         }
 
         /* subtitles: pick first */
8ccb56ab
         MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, oc, "s");
11a1033c
         if (!o->subtitle_disable && (oc->oformat->subtitle_codec != AV_CODEC_ID_NONE || subtitle_codec_name)) {
f5e66827
             for (i = 0; i < nb_input_streams; i++)
                 if (input_streams[i]->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
11a1033c
                     new_subtitle_stream(o, oc, i);
f5e66827
                     break;
                 }
         }
         /* do something with data? */
     } else {
         for (i = 0; i < o->nb_stream_maps; i++) {
             StreamMap *map = &o->stream_maps[i];
11a1033c
             int src_idx = input_files[map->file_index]->ist_index + map->stream_index;
f5e66827
 
             if (map->disabled)
                 continue;
 
             if (map->linklabel) {
                 FilterGraph *fg;
                 OutputFilter *ofilter = NULL;
                 int j, k;
 
                 for (j = 0; j < nb_filtergraphs; j++) {
                     fg = filtergraphs[j];
                     for (k = 0; k < fg->nb_outputs; k++) {
                         AVFilterInOut *out = fg->outputs[k]->out_tmp;
                         if (out && !strcmp(out->name, map->linklabel)) {
                             ofilter = fg->outputs[k];
                             goto loop_end;
                         }
                     }
                 }
 loop_end:
                 if (!ofilter) {
                     av_log(NULL, AV_LOG_FATAL, "Output with label '%s' does not exist "
                            "in any defined filter graph.\n", map->linklabel);
                     exit_program(1);
                 }
                 init_output_filter(ofilter, o, oc);
             } else {
                 ist = input_streams[input_files[map->file_index]->ist_index + map->stream_index];
11a1033c
                 if(o->subtitle_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE)
                     continue;
                 if(o->   audio_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
                     continue;
                 if(o->   video_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
                     continue;
                 if(o->    data_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_DATA)
                     continue;
 
f5e66827
                 switch (ist->st->codec->codec_type) {
11a1033c
                 case AVMEDIA_TYPE_VIDEO:      ost = new_video_stream     (o, oc, src_idx); break;
                 case AVMEDIA_TYPE_AUDIO:      ost = new_audio_stream     (o, oc, src_idx); break;
                 case AVMEDIA_TYPE_SUBTITLE:   ost = new_subtitle_stream  (o, oc, src_idx); break;
                 case AVMEDIA_TYPE_DATA:       ost = new_data_stream      (o, oc, src_idx); break;
                 case AVMEDIA_TYPE_ATTACHMENT: ost = new_attachment_stream(o, oc, src_idx); break;
f5e66827
                 default:
                     av_log(NULL, AV_LOG_FATAL, "Cannot map stream #%d:%d - unsupported type.\n",
                            map->file_index, map->stream_index);
                     exit_program(1);
                 }
             }
         }
     }
 
11a1033c
 
     for (i = nb_output_streams - oc->nb_streams; i < nb_output_streams; i++) { //for all streams of this output file
         AVDictionaryEntry *e;
         ost = output_streams[i];
 
         if (   ost->stream_copy
             && (e = av_dict_get(codec_opts, "flags", NULL, AV_DICT_IGNORE_SUFFIX))
             && (!e->key[5] || check_stream_specifier(oc, ost->st, e->key+6)))
             if (av_opt_set(ost->st->codec, "flags", e->value, 0) < 0)
                 exit_program(1);
     }
 
f5e66827
     /* handle attached files */
     for (i = 0; i < o->nb_attachments; i++) {
         AVIOContext *pb;
         uint8_t *attachment;
         const char *p;
         int64_t len;
 
         if ((err = avio_open2(&pb, o->attachments[i], AVIO_FLAG_READ, &int_cb, NULL)) < 0) {
             av_log(NULL, AV_LOG_FATAL, "Could not open attachment file %s.\n",
                    o->attachments[i]);
             exit_program(1);
         }
         if ((len = avio_size(pb)) <= 0) {
             av_log(NULL, AV_LOG_FATAL, "Could not get size of the attachment %s.\n",
                    o->attachments[i]);
             exit_program(1);
         }
         if (!(attachment = av_malloc(len))) {
             av_log(NULL, AV_LOG_FATAL, "Attachment %s too large to fit into memory.\n",
                    o->attachments[i]);
             exit_program(1);
         }
         avio_read(pb, attachment, len);
 
11a1033c
         ost = new_attachment_stream(o, oc, -1);
f5e66827
         ost->stream_copy               = 0;
         ost->attachment_filename       = o->attachments[i];
10ac4419
         ost->finished                  = 1;
f5e66827
         ost->st->codec->extradata      = attachment;
         ost->st->codec->extradata_size = len;
 
         p = strrchr(o->attachments[i], '/');
         av_dict_set(&ost->st->metadata, "filename", (p && *p) ? p + 1 : o->attachments[i], AV_DICT_DONT_OVERWRITE);
         avio_close(pb);
     }
 
     output_files = grow_array(output_files, sizeof(*output_files), &nb_output_files, nb_output_files + 1);
     if (!(output_files[nb_output_files - 1] = av_mallocz(sizeof(*output_files[0]))))
         exit_program(1);
 
     output_files[nb_output_files - 1]->ctx            = oc;
     output_files[nb_output_files - 1]->ost_index      = nb_output_streams - oc->nb_streams;
     output_files[nb_output_files - 1]->recording_time = o->recording_time;
     if (o->recording_time != INT64_MAX)
         oc->duration = o->recording_time;
     output_files[nb_output_files - 1]->start_time     = o->start_time;
     output_files[nb_output_files - 1]->limit_filesize = o->limit_filesize;
3c0df905
     output_files[nb_output_files - 1]->shortest       = o->shortest;
f5e66827
     av_dict_copy(&output_files[nb_output_files - 1]->opts, format_opts, 0);
 
     /* check filename in case of an image number is expected */
     if (oc->oformat->flags & AVFMT_NEEDNUMBER) {
         if (!av_filename_number_test(oc->filename)) {
             print_error(oc->filename, AVERROR(EINVAL));
             exit_program(1);
         }
     }
 
     if (!(oc->oformat->flags & AVFMT_NOFILE)) {
         /* test if it already exists to avoid losing precious files */
         assert_file_overwrite(filename);
 
         /* open the file */
         if ((err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE,
                               &oc->interrupt_callback,
                               &output_files[nb_output_files - 1]->opts)) < 0) {
             print_error(filename, err);
             exit_program(1);
         }
     }
 
     if (o->mux_preload) {
         uint8_t buf[64];
         snprintf(buf, sizeof(buf), "%d", (int)(o->mux_preload*AV_TIME_BASE));
         av_dict_set(&output_files[nb_output_files - 1]->opts, "preload", buf, 0);
     }
     oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE);
 
     /* copy metadata */
     for (i = 0; i < o->nb_metadata_map; i++) {
         char *p;
         int in_file_index = strtol(o->metadata_map[i].u.str, &p, 0);
 
         if (in_file_index >= nb_input_files) {
             av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d while processing metadata maps\n", in_file_index);
             exit_program(1);
         }
11a1033c
         copy_metadata(o->metadata_map[i].specifier, *p ? p + 1 : p, oc, in_file_index >= 0 ? input_files[in_file_index]->ctx : NULL, o);
f5e66827
     }
 
     /* copy chapters */
     if (o->chapters_input_file >= nb_input_files) {
         if (o->chapters_input_file == INT_MAX) {
             /* copy chapters from the first input file that has them*/
             o->chapters_input_file = -1;
             for (i = 0; i < nb_input_files; i++)
                 if (input_files[i]->ctx->nb_chapters) {
                     o->chapters_input_file = i;
                     break;
                 }
         } else {
             av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d in chapter mapping.\n",
                    o->chapters_input_file);
             exit_program(1);
         }
     }
     if (o->chapters_input_file >= 0)
         copy_chapters(input_files[o->chapters_input_file], output_files[nb_output_files - 1],
                       !o->metadata_chapters_manual);
 
     /* copy global metadata by default */
11a1033c
     if (!o->metadata_global_manual && nb_input_files){
f5e66827
         av_dict_copy(&oc->metadata, input_files[0]->ctx->metadata,
                      AV_DICT_DONT_OVERWRITE);
11a1033c
         if(o->recording_time != INT64_MAX)
             av_dict_set(&oc->metadata, "duration", NULL, 0);
         av_dict_set(&oc->metadata, "creation_time", NULL, 0);
     }
f5e66827
     if (!o->metadata_streams_manual)
         for (i = output_files[nb_output_files - 1]->ost_index; i < nb_output_streams; i++) {
             InputStream *ist;
             if (output_streams[i]->source_index < 0)         /* this is true e.g. for attached files */
                 continue;
             ist = input_streams[output_streams[i]->source_index];
             av_dict_copy(&output_streams[i]->st->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE);
         }
 
     /* process manually set metadata */
     for (i = 0; i < o->nb_metadata; i++) {
         AVDictionary **m;
         char type, *val;
         const char *stream_spec;
11a1033c
         int index = 0, j, ret = 0;
f5e66827
 
         val = strchr(o->metadata[i].u.str, '=');
         if (!val) {
             av_log(NULL, AV_LOG_FATAL, "No '=' character in metadata string %s.\n",
                    o->metadata[i].u.str);
             exit_program(1);
         }
         *val++ = 0;
 
         parse_meta_type(o->metadata[i].specifier, &type, &index, &stream_spec);
         if (type == 's') {
             for (j = 0; j < oc->nb_streams; j++) {
                 if ((ret = check_stream_specifier(oc, oc->streams[j], stream_spec)) > 0) {
                     av_dict_set(&oc->streams[j]->metadata, o->metadata[i].u.str, *val ? val : NULL, 0);
                 } else if (ret < 0)
                     exit_program(1);
             }
         }
         else {
             switch (type) {
             case 'g':
                 m = &oc->metadata;
                 break;
             case 'c':
                 if (index < 0 || index >= oc->nb_chapters) {
                     av_log(NULL, AV_LOG_FATAL, "Invalid chapter index %d in metadata specifier.\n", index);
                     exit_program(1);
                 }
                 m = &oc->chapters[index]->metadata;
                 break;
             default:
                 av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata[i].specifier);
                 exit_program(1);
             }
             av_dict_set(m, o->metadata[i].u.str, *val ? val : NULL, 0);
         }
     }
 
11a1033c
     reset_options(o, 0);
f5e66827
 }
 
d3810c47
 static int opt_target(void *optctx, const char *opt, const char *arg)
f5e66827
 {
d3810c47
     OptionsContext *o = optctx;
f5e66827
     enum { PAL, NTSC, FILM, UNKNOWN } norm = UNKNOWN;
     static const char *const frame_rates[] = { "25", "30000/1001", "24000/1001" };
 
     if (!strncmp(arg, "pal-", 4)) {
         norm = PAL;
         arg += 4;
     } else if (!strncmp(arg, "ntsc-", 5)) {
         norm = NTSC;
         arg += 5;
     } else if (!strncmp(arg, "film-", 5)) {
         norm = FILM;
         arg += 5;
     } else {
         /* Try to determine PAL/NTSC by peeking in the input files */
         if (nb_input_files) {
             int i, j, fr;
             for (j = 0; j < nb_input_files; j++) {
                 for (i = 0; i < input_files[j]->nb_streams; i++) {
                     AVCodecContext *c = input_files[j]->ctx->streams[i]->codec;
                     if (c->codec_type != AVMEDIA_TYPE_VIDEO)
                         continue;
                     fr = c->time_base.den * 1000 / c->time_base.num;
                     if (fr == 25000) {
                         norm = PAL;
                         break;
                     } else if ((fr == 29970) || (fr == 23976)) {
                         norm = NTSC;
                         break;
                     }
                 }
                 if (norm != UNKNOWN)
                     break;
             }
         }
         if (norm != UNKNOWN)
             av_log(NULL, AV_LOG_INFO, "Assuming %s for target.\n", norm == PAL ? "PAL" : "NTSC");
     }
 
     if (norm == UNKNOWN) {
         av_log(NULL, AV_LOG_FATAL, "Could not determine norm (PAL/NTSC/NTSC-Film) for target.\n");
         av_log(NULL, AV_LOG_FATAL, "Please prefix target with \"pal-\", \"ntsc-\" or \"film-\",\n");
         av_log(NULL, AV_LOG_FATAL, "or set a framerate with \"-r xxx\".\n");
         exit_program(1);
     }
 
     if (!strcmp(arg, "vcd")) {
         opt_video_codec(o, "c:v", "mpeg1video");
         opt_audio_codec(o, "c:a", "mp2");
         parse_option(o, "f", "vcd", options);
 
         parse_option(o, "s", norm == PAL ? "352x288" : "352x240", options);
         parse_option(o, "r", frame_rates[norm], options);
11d957fb
         opt_default(NULL, "g", norm == PAL ? "15" : "18");
f5e66827
 
98298eb1
         opt_default(NULL, "b:v", "1150000");
11d957fb
         opt_default(NULL, "maxrate", "1150000");
         opt_default(NULL, "minrate", "1150000");
         opt_default(NULL, "bufsize", "327680"); // 40*1024*8;
f5e66827
 
11d957fb
         opt_default(NULL, "b:a", "224000");
f5e66827
         parse_option(o, "ar", "44100", options);
         parse_option(o, "ac", "2", options);
 
11d957fb
         opt_default(NULL, "packetsize", "2324");
         opt_default(NULL, "muxrate", "1411200"); // 2352 * 75 * 8;
f5e66827
 
         /* We have to offset the PTS, so that it is consistent with the SCR.
            SCR starts at 36000, but the first two packs contain only padding
            and the first pack from the other stream, respectively, may also have
            been written before.
            So the real data starts at SCR 36000+3*1200. */
         o->mux_preload = (36000 + 3 * 1200) / 90000.0; // 0.44
     } else if (!strcmp(arg, "svcd")) {
 
         opt_video_codec(o, "c:v", "mpeg2video");
         opt_audio_codec(o, "c:a", "mp2");
         parse_option(o, "f", "svcd", options);
 
         parse_option(o, "s", norm == PAL ? "480x576" : "480x480", options);
         parse_option(o, "r", frame_rates[norm], options);
11a1033c
         parse_option(o, "pix_fmt", "yuv420p", options);
11d957fb
         opt_default(NULL, "g", norm == PAL ? "15" : "18");
f5e66827
 
98298eb1
         opt_default(NULL, "b:v", "2040000");
11d957fb
         opt_default(NULL, "maxrate", "2516000");
         opt_default(NULL, "minrate", "0"); // 1145000;
         opt_default(NULL, "bufsize", "1835008"); // 224*1024*8;
98298eb1
         opt_default(NULL, "scan_offset", "1");
f5e66827
 
11d957fb
         opt_default(NULL, "b:a", "224000");
f5e66827
         parse_option(o, "ar", "44100", options);
 
11d957fb
         opt_default(NULL, "packetsize", "2324");
f5e66827
 
     } else if (!strcmp(arg, "dvd")) {
 
         opt_video_codec(o, "c:v", "mpeg2video");
         opt_audio_codec(o, "c:a", "ac3");
         parse_option(o, "f", "dvd", options);
 
         parse_option(o, "s", norm == PAL ? "720x576" : "720x480", options);
         parse_option(o, "r", frame_rates[norm], options);
11a1033c
         parse_option(o, "pix_fmt", "yuv420p", options);
11d957fb
         opt_default(NULL, "g", norm == PAL ? "15" : "18");
f5e66827
 
98298eb1
         opt_default(NULL, "b:v", "6000000");
11d957fb
         opt_default(NULL, "maxrate", "9000000");
         opt_default(NULL, "minrate", "0"); // 1500000;
         opt_default(NULL, "bufsize", "1835008"); // 224*1024*8;
f5e66827
 
11d957fb
         opt_default(NULL, "packetsize", "2048");  // from www.mpucoder.com: DVD sectors contain 2048 bytes of data, this is also the size of one pack.
         opt_default(NULL, "muxrate", "10080000"); // from mplex project: data_rate = 1260000. mux_rate = data_rate * 8
f5e66827
 
11d957fb
         opt_default(NULL, "b:a", "448000");
f5e66827
         parse_option(o, "ar", "48000", options);
 
     } else if (!strncmp(arg, "dv", 2)) {
 
         parse_option(o, "f", "dv", options);
 
         parse_option(o, "s", norm == PAL ? "720x576" : "720x480", options);
         parse_option(o, "pix_fmt", !strncmp(arg, "dv50", 4) ? "yuv422p" :
                           norm == PAL ? "yuv420p" : "yuv411p", options);
         parse_option(o, "r", frame_rates[norm], options);
 
         parse_option(o, "ar", "48000", options);
         parse_option(o, "ac", "2", options);
 
     } else {
         av_log(NULL, AV_LOG_ERROR, "Unknown target: %s\n", arg);
         return AVERROR(EINVAL);
     }
     return 0;
 }
 
11d957fb
 static int opt_vstats_file(void *optctx, const char *opt, const char *arg)
f5e66827
 {
     av_free (vstats_filename);
     vstats_filename = av_strdup (arg);
     return 0;
 }
 
11d957fb
 static int opt_vstats(void *optctx, const char *opt, const char *arg)
f5e66827
 {
     char filename[40];
     time_t today2 = time(NULL);
     struct tm *today = localtime(&today2);
 
     snprintf(filename, sizeof(filename), "vstats_%02d%02d%02d.log", today->tm_hour, today->tm_min,
              today->tm_sec);
11d957fb
     return opt_vstats_file(NULL, opt, filename);
f5e66827
 }
 
d3810c47
 static int opt_video_frames(void *optctx, const char *opt, const char *arg)
f5e66827
 {
d3810c47
     OptionsContext *o = optctx;
f5e66827
     return parse_option(o, "frames:v", arg, options);
 }
 
d3810c47
 static int opt_audio_frames(void *optctx, const char *opt, const char *arg)
f5e66827
 {
d3810c47
     OptionsContext *o = optctx;
f5e66827
     return parse_option(o, "frames:a", arg, options);
 }
 
d3810c47
 static int opt_data_frames(void *optctx, const char *opt, const char *arg)
f5e66827
 {
d3810c47
     OptionsContext *o = optctx;
f5e66827
     return parse_option(o, "frames:d", arg, options);
 }
 
949938d1
 static int opt_preset(void *optctx, const char *opt, const char *arg)
11a1033c
 {
949938d1
     OptionsContext *o = optctx;
11a1033c
     FILE *f=NULL;
     char filename[1000], line[1000], tmp_line[1000];
3db4c88a
     const char *codec_name = NULL;
 
     tmp_line[0] = *opt;
     tmp_line[1] = 0;
     MATCH_PER_TYPE_OPT(codec_names, str, codec_name, NULL, tmp_line);
11a1033c
 
     if (!(f = get_preset_file(filename, sizeof(filename), arg, *opt == 'f', codec_name))) {
         if(!strncmp(arg, "libx264-lossless", strlen("libx264-lossless"))){
             av_log(NULL, AV_LOG_FATAL, "Please use -preset <speed> -qp 0\n");
         }else
             av_log(NULL, AV_LOG_FATAL, "File for preset '%s' not found\n", arg);
         exit_program(1);
 }
 
     while (fgets(line, sizeof(line), f)) {
         char *key = tmp_line, *value, *endptr;
 
         if (strcspn(line, "#\n\r") == 0)
             continue;
         strcpy(tmp_line, line);
         if (!av_strtok(key,   "=",    &value) ||
             !av_strtok(value, "\r\n", &endptr)) {
             av_log(NULL, AV_LOG_FATAL, "%s: Invalid syntax: '%s'\n", filename, line);
             exit_program(1);
         }
         av_log(NULL, AV_LOG_DEBUG, "ffpreset[%s]: set '%s' = '%s'\n", filename, key, value);
 
         if      (!strcmp(key, "acodec")) opt_audio_codec   (o, key, value);
         else if (!strcmp(key, "vcodec")) opt_video_codec   (o, key, value);
         else if (!strcmp(key, "scodec")) opt_subtitle_codec(o, key, value);
         else if (!strcmp(key, "dcodec")) opt_data_codec    (o, key, value);
98298eb1
         else if (opt_default(NULL, key, value) < 0) {
11a1033c
             av_log(NULL, AV_LOG_FATAL, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n",
                    filename, line, key, value);
             exit_program(1);
         }
     }
 
     fclose(f);
 
     return 0;
 }
 
949938d1
 static int opt_old2new(void *optctx, const char *opt, const char *arg)
11a1033c
 {
949938d1
     OptionsContext *o = optctx;
11a1033c
     char *s = av_asprintf("%s:%c", opt + 1, *opt);
     int ret = parse_option(o, s, arg, options);
     av_free(s);
     return ret;
f5e66827
 }
 
949938d1
 static int opt_bitrate(void *optctx, const char *opt, const char *arg)
f5e66827
 {
949938d1
     OptionsContext *o = optctx;
11a1033c
     if(!strcmp(opt, "b")){
         av_log(NULL, AV_LOG_WARNING, "Please use -b:a or -b:v, -b is ambiguous\n");
         return parse_option(o, "b:v", arg, options);
     }
98298eb1
     return opt_default(optctx, opt, arg);
f5e66827
 }
 
949938d1
 static int opt_qscale(void *optctx, const char *opt, const char *arg)
f5e66827
 {
949938d1
     OptionsContext *o = optctx;
11a1033c
     char *s;
     int ret;
     if(!strcmp(opt, "qscale")){
         av_log(NULL, AV_LOG_WARNING, "Please use -q:a or -q:v, -qscale is ambiguous\n");
         return parse_option(o, "q:v", arg, options);
     }
     s = av_asprintf("q%s", opt + 6);
     ret = parse_option(o, s, arg, options);
     av_free(s);
     return ret;
 }
 
949938d1
 static int opt_profile(void *optctx, const char *opt, const char *arg)
11a1033c
 {
949938d1
     OptionsContext *o = optctx;
11a1033c
     if(!strcmp(opt, "profile")){
         av_log(NULL, AV_LOG_WARNING, "Please use -profile:a or -profile:v, -profile is ambiguous\n");
         return parse_option(o, "profile:v", arg, options);
     }
98298eb1
     return opt_default(optctx, opt, arg);
927022a7
 
f5e66827
 }
 
d3810c47
 static int opt_video_filters(void *optctx, const char *opt, const char *arg)
f5e66827
 {
d3810c47
     OptionsContext *o = optctx;
f5e66827
     return parse_option(o, "filter:v", arg, options);
 }
 
d3810c47
 static int opt_audio_filters(void *optctx, const char *opt, const char *arg)
f5e66827
 {
d3810c47
     OptionsContext *o = optctx;
f5e66827
     return parse_option(o, "filter:a", arg, options);
 }
 
11d957fb
 static int opt_vsync(void *optctx, const char *opt, const char *arg)
f5e66827
 {
     if      (!av_strcasecmp(arg, "cfr"))         video_sync_method = VSYNC_CFR;
     else if (!av_strcasecmp(arg, "vfr"))         video_sync_method = VSYNC_VFR;
     else if (!av_strcasecmp(arg, "passthrough")) video_sync_method = VSYNC_PASSTHROUGH;
11a1033c
     else if (!av_strcasecmp(arg, "drop"))        video_sync_method = VSYNC_DROP;
f5e66827
 
     if (video_sync_method == VSYNC_AUTO)
         video_sync_method = parse_number_or_die("vsync", arg, OPT_INT, VSYNC_AUTO, VSYNC_VFR);
     return 0;
 }
 
11d957fb
 static int opt_deinterlace(void *optctx, const char *opt, const char *arg)
f5e66827
 {
     av_log(NULL, AV_LOG_WARNING, "-%s is deprecated, use -filter:v yadif instead\n", opt);
     do_deinterlace = 1;
     return 0;
 }
 
949938d1
 static int opt_timecode(void *optctx, const char *opt, const char *arg)
f5e66827
 {
949938d1
     OptionsContext *o = optctx;
11a1033c
     char *tcr = av_asprintf("timecode=%s", arg);
     int ret = parse_option(o, "metadata:g", tcr, options);
     if (ret >= 0)
98298eb1
         ret = opt_default(optctx, "gop_timecode", arg);
11a1033c
     av_free(tcr);
     return ret;
f5e66827
 }
 
d3810c47
 static int opt_channel_layout(void *optctx, const char *opt, const char *arg)
f5e66827
 {
d3810c47
     OptionsContext *o = optctx;
f5e66827
     char layout_str[32];
     char *stream_str;
     char *ac_str;
     int ret, channels, ac_str_size;
     uint64_t layout;
 
     layout = av_get_channel_layout(arg);
     if (!layout) {
         av_log(NULL, AV_LOG_ERROR, "Unknown channel layout: %s\n", arg);
         return AVERROR(EINVAL);
     }
     snprintf(layout_str, sizeof(layout_str), "%"PRIu64, layout);
11d957fb
     ret = opt_default(NULL, opt, layout_str);
f5e66827
     if (ret < 0)
         return ret;
 
     /* set 'ac' option based on channel layout */
     channels = av_get_channel_layout_nb_channels(layout);
     snprintf(layout_str, sizeof(layout_str), "%d", channels);
     stream_str = strchr(opt, ':');
     ac_str_size = 3 + (stream_str ? strlen(stream_str) : 0);
     ac_str = av_mallocz(ac_str_size);
     if (!ac_str)
         return AVERROR(ENOMEM);
     av_strlcpy(ac_str, "ac", 3);
     if (stream_str)
         av_strlcat(ac_str, stream_str, ac_str_size);
     ret = parse_option(o, ac_str, layout_str, options);
     av_free(ac_str);
 
     return ret;
 }
 
d3810c47
 static int opt_audio_qscale(void *optctx, const char *opt, const char *arg)
f5e66827
 {
d3810c47
     OptionsContext *o = optctx;
f5e66827
     return parse_option(o, "q:a", arg, options);
 }
 
11d957fb
 static int opt_filter_complex(void *optctx, const char *opt, const char *arg)
f5e66827
 {
     filtergraphs = grow_array(filtergraphs, sizeof(*filtergraphs),
                               &nb_filtergraphs, nb_filtergraphs + 1);
     if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0]))))
         return AVERROR(ENOMEM);
     filtergraphs[nb_filtergraphs - 1]->index       = nb_filtergraphs - 1;
     filtergraphs[nb_filtergraphs - 1]->graph_desc = arg;
     return 0;
 }
 
a3ad68d3
 void show_help_default(const char *opt, const char *arg)
f5e66827
 {
f9fada27
     /* per-file options have at least one of those set */
11d957fb
     const int per_file = OPT_SPEC | OPT_OFFSET | OPT_PERFILE;
6e3857fa
     int show_advanced = 0, show_avoptions = 0;
 
     if (opt) {
         if (!strcmp(opt, "long"))
             show_advanced = 1;
         else if (!strcmp(opt, "full"))
             show_advanced = show_avoptions = 1;
         else
             av_log(NULL, AV_LOG_ERROR, "Unknown help option '%s'.\n", opt);
     }
a3ad68d3
 
f5e66827
     show_usage();
6e3857fa
 
     printf("Getting help:\n"
            "    -h      -- print basic options\n"
            "    -h long -- print more options\n"
            "    -h full -- print all options (including all format and codec specific options, very long)\n"
            "    See man %s for detailed description of the options.\n"
            "\n", program_name);
 
f8b1e665
     show_help_options(options, "Print help / information / capabilities:",
f9fada27
                       OPT_EXIT, 0, 0);
 
     show_help_options(options, "Global options (affect whole program "
                       "instead of just one file:",
                       0, per_file | OPT_EXIT | OPT_EXPERT, 0);
     if (show_advanced)
         show_help_options(options, "Advanced global options:", OPT_EXPERT,
                           per_file | OPT_EXIT, 0);
 
     show_help_options(options, "Per-file main options:", 0,
                       OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE |
                       OPT_EXIT, per_file);
6e3857fa
     if (show_advanced)
f9fada27
         show_help_options(options, "Advanced per-file options:",
                           OPT_EXPERT, OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE, per_file);
6e3857fa
 
dc4c24a3
     show_help_options(options, "Video options:",
f9fada27
                       OPT_VIDEO, OPT_EXPERT | OPT_AUDIO, 0);
6e3857fa
     if (show_advanced)
         show_help_options(options, "Advanced Video options:",
f9fada27
                           OPT_EXPERT | OPT_VIDEO, OPT_AUDIO, 0);
6e3857fa
 
dc4c24a3
     show_help_options(options, "Audio options:",
f9fada27
                       OPT_AUDIO, OPT_EXPERT | OPT_VIDEO, 0);
6e3857fa
     if (show_advanced)
         show_help_options(options, "Advanced Audio options:",
f9fada27
                           OPT_EXPERT | OPT_AUDIO, OPT_VIDEO, 0);
dc4c24a3
     show_help_options(options, "Subtitle options:",
f9fada27
                       OPT_SUBTITLE, 0, 0);
f5e66827
     printf("\n");
6e3857fa
 
     if (show_avoptions) {
         int flags = AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM;
         show_help_children(avcodec_get_class(), flags);
         show_help_children(avformat_get_class(), flags);
         show_help_children(sws_get_class(), flags);
bb3ed3ba
         show_help_children(swr_get_class(), AV_OPT_FLAG_AUDIO_PARAM);
         show_help_children(avfilter_get_class(), AV_OPT_FLAG_FILTERING_PARAM);
6e3857fa
     }
f5e66827
 }
 
 void show_usage(void)
 {
11a1033c
     av_log(NULL, AV_LOG_INFO, "Hyper fast Audio and Video encoder\n");
     av_log(NULL, AV_LOG_INFO, "usage: %s [options] [[infile options] -i infile]... {[outfile options] outfile}...\n", program_name);
     av_log(NULL, AV_LOG_INFO, "\n");
f5e66827
 }
 
 
98298eb1
 static int opt_progress(void *optctx, const char *opt, const char *arg)
11a1033c
 {
     AVIOContext *avio = NULL;
     int ret;
 
     if (!strcmp(arg, "-"))
         arg = "pipe:";
     ret = avio_open2(&avio, arg, AVIO_FLAG_WRITE, &int_cb, NULL);
     if (ret < 0) {
         av_log(0, AV_LOG_ERROR, "Failed to open progress URL \"%s\": %s\n",
                arg, av_err2str(ret));
         return ret;
     }
     progress_avio = avio;
     return 0;
 }
 
f5e66827
 #define OFFSET(x) offsetof(OptionsContext, x)
 const OptionDef options[] = {
     /* main options */
 #include "cmdutils_common_opts.h"
8fc83fb0
     { "f",              HAS_ARG | OPT_STRING | OPT_OFFSET,           { .off       = OFFSET(format) },
         "force format", "fmt" },
11d957fb
     { "i",              HAS_ARG | OPT_PERFILE,                       { .func_arg = opt_input_file },
8fc83fb0
         "input file name", "filename" },
     { "y",              OPT_BOOL,                                    {              &file_overwrite },
         "overwrite output files" },
c5af0680
     { "n",              OPT_BOOL,                                    {              &no_file_overwrite },
         "do not overwrite output files" },
8fc83fb0
     { "c",              HAS_ARG | OPT_STRING | OPT_SPEC,             { .off       = OFFSET(codec_names) },
         "codec name", "codec" },
     { "codec",          HAS_ARG | OPT_STRING | OPT_SPEC,             { .off       = OFFSET(codec_names) },
         "codec name", "codec" },
     { "pre",            HAS_ARG | OPT_STRING | OPT_SPEC,             { .off       = OFFSET(presets) },
         "preset name", "preset" },
11d957fb
     { "map",            HAS_ARG | OPT_EXPERT | OPT_PERFILE,          { .func_arg = opt_map },
8fc83fb0
         "set input stream mapping",
         "[-]input_file_id[:stream_specifier][,sync_file_id[:stream_specifier]]" },
98298eb1
     { "map_channel",    HAS_ARG | OPT_EXPERT | OPT_PERFILE,          { .func_arg = opt_map_channel },
c5af0680
         "map an audio channel from one stream to another", "file.stream.channel[:syncfile.syncstream]" },
8fc83fb0
     { "map_metadata",   HAS_ARG | OPT_STRING | OPT_SPEC,             { .off       = OFFSET(metadata_map) },
         "set metadata information of outfile from infile",
         "outfile[,metadata]:infile[,metadata]" },
     { "map_chapters",   HAS_ARG | OPT_INT | OPT_EXPERT | OPT_OFFSET, { .off = OFFSET(chapters_input_file) },
         "set chapters mapping", "input_file_index" },
     { "t",              HAS_ARG | OPT_TIME | OPT_OFFSET,             { .off = OFFSET(recording_time) },
         "record or transcode \"duration\" seconds of audio/video",
         "duration" },
     { "fs",             HAS_ARG | OPT_INT64 | OPT_OFFSET,            { .off = OFFSET(limit_filesize) },
         "set the limit file size in bytes", "limit_size" },
     { "ss",             HAS_ARG | OPT_TIME | OPT_OFFSET,             { .off = OFFSET(start_time) },
         "set the start time offset", "time_off" },
602b1898
     { "itsoffset",      HAS_ARG | OPT_TIME | OPT_OFFSET | OPT_EXPERT,{ .off = OFFSET(input_ts_offset) },
8fc83fb0
         "set the input ts offset", "time_off" },
602b1898
     { "itsscale",       HAS_ARG | OPT_DOUBLE | OPT_SPEC | OPT_EXPERT,{ .off = OFFSET(ts_scale) },
8fc83fb0
         "set the input ts scale", "scale" },
98298eb1
     { "timestamp",      HAS_ARG | OPT_PERFILE,                       { .func_arg = opt_recording_timestamp },
c5af0680
         "set the recording timestamp ('now' to set the current time)", "time" },
8fc83fb0
     { "metadata",       HAS_ARG | OPT_STRING | OPT_SPEC,             { .off = OFFSET(metadata) },
         "add metadata", "string=string" },
11d957fb
     { "dframes",        HAS_ARG | OPT_PERFILE | OPT_EXPERT,          { .func_arg = opt_data_frames },
8fc83fb0
         "set the number of data frames to record", "number" },
     { "benchmark",      OPT_BOOL | OPT_EXPERT,                       { &do_benchmark },
         "add timings for benchmarking" },
c5af0680
     { "benchmark_all",  OPT_BOOL | OPT_EXPERT,                       { &do_benchmark_all },
11a1033c
       "add timings for each task" },
c5af0680
     { "progress",       HAS_ARG | OPT_EXPERT,                        { .func_arg = opt_progress },
11a1033c
       "write program-readable progress information", "url" },
c5af0680
     { "stdin",          OPT_BOOL | OPT_EXPERT,                       { &stdin_interaction },
11a1033c
       "enable or disable interaction on standard input" },
602b1898
     { "timelimit",      HAS_ARG | OPT_EXPERT,                        { .func_arg = opt_timelimit },
8fc83fb0
         "set max runtime in seconds", "limit" },
     { "dump",           OPT_BOOL | OPT_EXPERT,                       { &do_pkt_dump },
         "dump each input packet" },
     { "hex",            OPT_BOOL | OPT_EXPERT,                       { &do_hex_dump },
         "when dumping packets, also dump the payload" },
     { "re",             OPT_BOOL | OPT_EXPERT | OPT_OFFSET,          { .off = OFFSET(rate_emu) },
         "read input at native frame rate", "" },
11d957fb
     { "target",         HAS_ARG | OPT_PERFILE,                       { .func_arg = opt_target },
8fc83fb0
         "specify target file type (\"vcd\", \"svcd\", \"dvd\","
         " \"dv\", \"dv50\", \"pal-vcd\", \"ntsc-svcd\", ...)", "type" },
     { "vsync",          HAS_ARG | OPT_EXPERT,                        { opt_vsync },
         "video sync method", "" },
     { "async",          HAS_ARG | OPT_INT | OPT_EXPERT,              { &audio_sync_method },
         "audio sync method", "" },
     { "adrift_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT,          { &audio_drift_threshold },
         "audio drift threshold", "threshold" },
     { "copyts",         OPT_BOOL | OPT_EXPERT,                       { &copy_ts },
         "copy timestamps" },
c5af0680
     { "copytb",         HAS_ARG | OPT_INT | OPT_EXPERT,              { &copy_tb },
         "copy input stream time base when stream copying", "mode" },
8fc83fb0
     { "shortest",       OPT_BOOL | OPT_EXPERT | OPT_OFFSET,          { .off = OFFSET(shortest) },
         "finish encoding within shortest input" },
     { "dts_delta_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT,       { &dts_delta_threshold },
         "timestamp discontinuity delta threshold", "threshold" },
c5af0680
     { "dts_error_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT,       { &dts_error_threshold },
         "timestamp error delta threshold", "threshold" },
602b1898
     { "xerror",         OPT_BOOL | OPT_EXPERT,                       { &exit_on_error },
8fc83fb0
         "exit on error", "error" },
     { "copyinkf",       OPT_BOOL | OPT_EXPERT | OPT_SPEC,            { .off = OFFSET(copy_initial_nonkeyframes) },
         "copy initial non-keyframes" },
65f7aee6
     { "copypriorss",    OPT_INT | HAS_ARG | OPT_EXPERT | OPT_SPEC,   { .off = OFFSET(copy_prior_start) },
         "copy or discard frames before start time" },
8fc83fb0
     { "frames",         OPT_INT64 | HAS_ARG | OPT_SPEC,              { .off = OFFSET(max_frames) },
         "set the number of frames to record", "number" },
602b1898
     { "tag",            OPT_STRING | HAS_ARG | OPT_SPEC | OPT_EXPERT,{ .off = OFFSET(codec_tags) },
8fc83fb0
         "force codec tag/fourcc", "fourcc/tag" },
     { "q",              HAS_ARG | OPT_EXPERT | OPT_DOUBLE | OPT_SPEC,{ .off = OFFSET(qscale) },
         "use fixed quality scale (VBR)", "q" },
98298eb1
     { "qscale",         HAS_ARG | OPT_EXPERT | OPT_PERFILE,          { .func_arg = opt_qscale },
8fc83fb0
         "use fixed quality scale (VBR)", "q" },
98298eb1
     { "profile",        HAS_ARG | OPT_EXPERT | OPT_PERFILE,          { .func_arg = opt_profile },
c5af0680
         "set profile", "profile" },
8fc83fb0
     { "filter",         HAS_ARG | OPT_STRING | OPT_SPEC,             { .off = OFFSET(filters) },
         "set stream filterchain", "filter_list" },
     { "filter_complex", HAS_ARG | OPT_EXPERT,                        { .func_arg = opt_filter_complex },
         "create a complex filtergraph", "graph_description" },
     { "stats",          OPT_BOOL,                                    { &print_stats },
         "print progress report during encoding", },
11d957fb
     { "attach",         HAS_ARG | OPT_PERFILE | OPT_EXPERT,          { .func_arg = opt_attach },
8fc83fb0
         "add an attachment to the output file", "filename" },
602b1898
     { "dump_attachment", HAS_ARG | OPT_STRING | OPT_SPEC |OPT_EXPERT,{ .off = OFFSET(dump_attachment) },
8fc83fb0
         "extract an attachment into a file", "filename" },
c5af0680
     { "debug_ts",       OPT_BOOL | OPT_EXPERT,                       { &debug_ts },
         "print timestamp debugging info" },
f5e66827
 
     /* video options */
11d957fb
     { "vframes",      OPT_VIDEO | HAS_ARG  | OPT_PERFILE,                        { .func_arg = opt_video_frames },
8fc83fb0
         "set the number of video frames to record", "number" },
     { "r",            OPT_VIDEO | HAS_ARG  | OPT_STRING | OPT_SPEC,              { .off = OFFSET(frame_rates) },
         "set frame rate (Hz value, fraction or abbreviation)", "rate" },
c5af0680
     { "s",            OPT_VIDEO | HAS_ARG | OPT_SUBTITLE | OPT_STRING | OPT_SPEC,{ .off = OFFSET(frame_sizes) },
8fc83fb0
         "set frame size (WxH or abbreviation)", "size" },
     { "aspect",       OPT_VIDEO | HAS_ARG  | OPT_STRING | OPT_SPEC,              { .off = OFFSET(frame_aspect_ratios) },
         "set aspect ratio (4:3, 16:9 or 1.3333, 1.7777)", "aspect" },
     { "pix_fmt",      OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_STRING | OPT_SPEC, { .off = OFFSET(frame_pix_fmts) },
         "set pixel format", "format" },
c5af0680
     { "bits_per_raw_sample", OPT_VIDEO | OPT_INT | HAS_ARG,                      { &frame_bits_per_raw_sample },
         "set the number of bits per raw sample", "number" },
     { "croptop",      OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_frame_crop },
         "Removed, use the crop filter instead", "size" },
     { "cropbottom",   OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_frame_crop },
         "Removed, use the crop filter instead", "size" },
     { "cropleft",     OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_frame_crop },
         "Removed, use the crop filter instead", "size" },
     { "cropright",    OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_frame_crop },
         "Removed, use the crop filter instead", "size" },
     { "padtop",       OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_pad },
         "Removed, use the pad filter instead", "size" },
     { "padbottom",    OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_pad },
         "Removed, use the pad filter instead", "size" },
     { "padleft",      OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_pad },
         "Removed, use the pad filter instead", "size" },
     { "padright",     OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_pad },
         "Removed, use the pad filter instead", "size" },
     { "padcolor",     OPT_VIDEO | HAS_ARG,                                       { .func_arg = opt_pad },
         "Removed, use the pad filter instead", "color" },
     { "intra",        OPT_VIDEO | OPT_BOOL | OPT_EXPERT,                         { &intra_only },
         "deprecated use -g 1" },
8fc83fb0
     { "vn",           OPT_VIDEO | OPT_BOOL  | OPT_OFFSET,                        { .off = OFFSET(video_disable) },
         "disable video" },
     { "vdt",          OPT_VIDEO | OPT_INT | HAS_ARG | OPT_EXPERT ,               { &video_discard },
         "discard threshold", "n" },
     { "rc_override",  OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_STRING | OPT_SPEC, { .off = OFFSET(rc_overrides) },
         "rate control override for specific intervals", "override" },
11d957fb
     { "vcodec",       OPT_VIDEO | HAS_ARG  | OPT_PERFILE,                        { .func_arg = opt_video_codec },
8fc83fb0
         "force video codec ('copy' to copy stream)", "codec" },
bb3ed3ba
     { "sameq",        OPT_VIDEO | OPT_BOOL | OPT_EXPERT ,                        { &same_quant },
c5af0680
         "use same quantizer as source (implies VBR)" },
602b1898
     { "same_quant",   OPT_VIDEO | OPT_BOOL | OPT_EXPERT,                         { &same_quant },
8fc83fb0
         "use same quantizer as source (implies VBR)" },
98298eb1
     { "timecode",     OPT_VIDEO | HAS_ARG | OPT_PERFILE,                         { .func_arg = opt_timecode },
c5af0680
         "set initial TimeCode value.", "hh:mm:ss[:;.]ff" },
038c0b1e
     { "pass",         OPT_VIDEO | HAS_ARG | OPT_SPEC | OPT_INT,                  { .off = OFFSET(pass) },
98298eb1
         "select the pass number (1 to 3)", "n" },
bbcedade
     { "passlogfile",  OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_EXPERT | OPT_SPEC,  { .off = OFFSET(passlogfiles) },
8fc83fb0
         "select two pass log file name prefix", "prefix" },
     { "deinterlace",  OPT_VIDEO | OPT_EXPERT ,                                   { .func_arg = opt_deinterlace },
         "this option is deprecated, use the yadif filter instead" },
c5af0680
     { "psnr",         OPT_VIDEO | OPT_BOOL | OPT_EXPERT,                         { &do_psnr },
         "calculate PSNR of compressed frames" },
8fc83fb0
     { "vstats",       OPT_VIDEO | OPT_EXPERT ,                                   { &opt_vstats },
         "dump video coding statistics to file" },
     { "vstats_file",  OPT_VIDEO | HAS_ARG | OPT_EXPERT ,                         { opt_vstats_file },
         "dump video coding statistics to file", "file" },
11d957fb
     { "vf",           OPT_VIDEO | HAS_ARG  | OPT_PERFILE,                        { .func_arg = opt_video_filters },
8fc83fb0
         "video filters", "filter list" },
     { "intra_matrix", OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_STRING | OPT_SPEC, { .off = OFFSET(intra_matrices) },
         "specify intra matrix coeffs", "matrix" },
     { "inter_matrix", OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_STRING | OPT_SPEC, { .off = OFFSET(inter_matrices) },
         "specify inter matrix coeffs", "matrix" },
     { "top",          OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_INT| OPT_SPEC,     { .off = OFFSET(top_field_first) },
         "top=1/bottom=0/auto=-1 field first", "" },
     { "dc",           OPT_VIDEO | OPT_INT | HAS_ARG | OPT_EXPERT ,               { &intra_dc_precision },
         "intra_dc_precision", "precision" },
98298eb1
     { "vtag",         OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_PERFILE,           { .func_arg = opt_old2new },
8fc83fb0
         "force video tag/fourcc", "fourcc/tag" },
     { "qphist",       OPT_VIDEO | OPT_BOOL | OPT_EXPERT ,                        { &qp_hist },
         "show QP histogram" },
     { "force_fps",    OPT_VIDEO | OPT_BOOL | OPT_EXPERT  | OPT_SPEC,             { .off = OFFSET(force_fps) },
         "force the selected framerate, disable the best supported framerate selection" },
11d957fb
     { "streamid",     OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_PERFILE,            { .func_arg = opt_streamid },
8fc83fb0
         "set the value of an outfile streamid", "streamIndex:value" },
     { "force_key_frames", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT  | OPT_SPEC,
c5af0680
         { .off = OFFSET(forced_key_frames) },
         "force key frames at specified timestamps", "timestamps" },
98298eb1
     { "b",            OPT_VIDEO | HAS_ARG | OPT_PERFILE,                         { .func_arg = opt_bitrate },
c5af0680
         "video bitrate (please use -b:v)", "bitrate" },
f5e66827
 
     /* audio options */
11d957fb
     { "aframes",        OPT_AUDIO | HAS_ARG  | OPT_PERFILE,                        { .func_arg = opt_audio_frames },
8fc83fb0
         "set the number of audio frames to record", "number" },
11d957fb
     { "aq",             OPT_AUDIO | HAS_ARG  | OPT_PERFILE,                        { .func_arg = opt_audio_qscale },
8fc83fb0
         "set audio quality (codec-specific)", "quality", },
     { "ar",             OPT_AUDIO | HAS_ARG  | OPT_INT | OPT_SPEC,                 { .off = OFFSET(audio_sample_rate) },
         "set audio sampling rate (in Hz)", "rate" },
     { "ac",             OPT_AUDIO | HAS_ARG  | OPT_INT | OPT_SPEC,                 { .off = OFFSET(audio_channels) },
         "set number of audio channels", "channels" },
     { "an",             OPT_AUDIO | OPT_BOOL | OPT_OFFSET,                         { .off = OFFSET(audio_disable) },
         "disable audio" },
11d957fb
     { "acodec",         OPT_AUDIO | HAS_ARG  | OPT_PERFILE,                        { .func_arg = opt_audio_codec },
8fc83fb0
         "force audio codec ('copy' to copy stream)", "codec" },
98298eb1
     { "atag",           OPT_AUDIO | HAS_ARG  | OPT_EXPERT | OPT_PERFILE,           { .func_arg = opt_old2new },
8fc83fb0
         "force audio tag/fourcc", "fourcc/tag" },
     { "vol",            OPT_AUDIO | HAS_ARG  | OPT_INT,                            { &audio_volume },
         "change audio volume (256=normal)" , "volume" },
     { "sample_fmt",     OPT_AUDIO | HAS_ARG  | OPT_EXPERT | OPT_SPEC | OPT_STRING, { .off = OFFSET(sample_fmts) },
         "set sample format", "format" },
11d957fb
     { "channel_layout", OPT_AUDIO | HAS_ARG  | OPT_EXPERT | OPT_PERFILE,           { .func_arg = opt_channel_layout },
8fc83fb0
         "set channel layout", "layout" },
11d957fb
     { "af",             OPT_AUDIO | HAS_ARG  | OPT_PERFILE,                        { .func_arg = opt_audio_filters },
8fc83fb0
         "audio filters", "filter list" },
f5e66827
 
     /* subtitle options */
8fc83fb0
     { "sn",     OPT_SUBTITLE | OPT_BOOL | OPT_OFFSET, { .off = OFFSET(subtitle_disable) },
         "disable subtitle" },
11d957fb
     { "scodec", OPT_SUBTITLE | HAS_ARG  | OPT_PERFILE, { .func_arg = opt_subtitle_codec },
8fc83fb0
         "force subtitle codec ('copy' to copy stream)", "codec" },
98298eb1
     { "stag",   OPT_SUBTITLE | HAS_ARG  | OPT_EXPERT  | OPT_PERFILE, { .func_arg = opt_old2new }
8fc83fb0
         , "force subtitle tag/fourcc", "fourcc/tag" },
c5af0680
     { "fix_sub_duration", OPT_BOOL | OPT_EXPERT | OPT_SUBTITLE | OPT_SPEC, { .off = OFFSET(fix_sub_duration) },
         "fix subtitles duration" },
f5e66827
 
     /* grab options */
67a6dac7
     { "vc", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_video_channel },
c5af0680
         "deprecated, use -channel", "channel" },
67a6dac7
     { "tvstd", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_video_standard },
c5af0680
         "deprecated, use -standard", "standard" },
79600a83
     { "isync", OPT_BOOL | OPT_EXPERT, { &input_sync }, "this option is deprecated and does nothing", "" },
f5e66827
 
     /* muxer options */
8fc83fb0
     { "muxdelay",   OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET, { .off = OFFSET(mux_max_delay) },
         "set the maximum demux-decode delay", "seconds" },
     { "muxpreload", OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET, { .off = OFFSET(mux_preload) },
         "set the initial demux-decode delay", "seconds" },
f5e66827
 
602b1898
     { "bsf", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_EXPERT, { .off = OFFSET(bitstream_filters) },
8fc83fb0
         "A comma-separated list of bitstream filters", "bitstream_filters" },
98298eb1
     { "absf", HAS_ARG | OPT_AUDIO | OPT_EXPERT| OPT_PERFILE, { .func_arg = opt_old2new },
c5af0680
         "deprecated", "audio bitstream_filters" },
98298eb1
     { "vbsf", OPT_VIDEO | HAS_ARG | OPT_EXPERT| OPT_PERFILE, { .func_arg = opt_old2new },
c5af0680
         "deprecated", "video bitstream_filters" },
 
98298eb1
     { "apre", HAS_ARG | OPT_AUDIO | OPT_EXPERT| OPT_PERFILE,    { .func_arg = opt_preset },
c5af0680
         "set the audio options to the indicated preset", "preset" },
98298eb1
     { "vpre", OPT_VIDEO | HAS_ARG | OPT_EXPERT| OPT_PERFILE,    { .func_arg = opt_preset },
c5af0680
         "set the video options to the indicated preset", "preset" },
98298eb1
     { "spre", HAS_ARG | OPT_SUBTITLE | OPT_EXPERT| OPT_PERFILE, { .func_arg = opt_preset },
c5af0680
         "set the subtitle options to the indicated preset", "preset" },
98298eb1
     { "fpre", HAS_ARG | OPT_EXPERT| OPT_PERFILE,                { .func_arg = opt_preset },
c5af0680
         "set options from indicated preset file", "filename" },
f5e66827
     /* data codec support */
11d957fb
     { "dcodec", HAS_ARG | OPT_DATA | OPT_PERFILE | OPT_EXPERT, { .func_arg = opt_data_codec },
8fc83fb0
         "force data codec ('copy' to copy stream)", "codec" },
c5af0680
     { "dn", OPT_BOOL | OPT_VIDEO | OPT_OFFSET, { .off = OFFSET(data_disable) },
         "disable data" },
f5e66827
 
8fc83fb0
     { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { .func_arg = opt_default },
         "generic catch all option", "" },
f5e66827
     { NULL, },
 };