Merge remote-tracking branch 'qatar/master'
authorMichael Niedermayer <michaelni@gmx.at>
Sat, 10 Sep 2011 18:52:48 +0000 (20:52 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Sat, 10 Sep 2011 18:52:48 +0000 (20:52 +0200)
* qatar/master:
  Fixed segfault with wavpack decoder on corrupted decorrelation terms sub-blocks.
  avconv: move audio_channels to the options context.
  avconv: move *_disable to options context.
  avconv: remove -[vas]lang options.
  avconv: move codec tags to options context.
  cljr: init_get_bits size in bits instead of bytes
  indeo2: fail if input buffer too small
  indeo2: init_get_bits size in bits instead of bytes
  ffv1: Fixed size given to init_get_bits() in decoder.

Conflicts:
avconv.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
avconv.c
doc/avconv.texi
ffmpeg.c
libavcodec/cljr.c
libavcodec/indeo2.c
libavcodec/wavpack.c

diff --cc avconv.c
+++ b/avconv.c
@@@ -2966,9 -2820,7 +2937,9 @@@ static void add_input_streams(OptionsCo
  
          switch (dec->codec_type) {
          case AVMEDIA_TYPE_AUDIO:
 -            if (o->audio_disable)
 +            if(!ist->dec)
 +                ist->dec = avcodec_find_decoder(dec->codec_id);
-             if(audio_disable)
++            if(o->audio_disable)
                  st->discard= AVDISCARD_ALL;
              break;
          case AVMEDIA_TYPE_VIDEO:
          case AVMEDIA_TYPE_DATA:
              break;
          case AVMEDIA_TYPE_SUBTITLE:
 -            if (o->subtitle_disable)
 +            if(!ist->dec)
 +                ist->dec = avcodec_find_decoder(dec->codec_id);
-             if(subtitle_disable)
++            if(o->subtitle_disable)
                  st->discard = AVDISCARD_ALL;
              break;
          case AVMEDIA_TYPE_ATTACHMENT:
@@@ -4144,20 -3978,21 +4090,35 @@@ static int opt_data_frames(OptionsConte
      return parse_option(o, "frames:d", arg, options);
  }
  
 +static void log_callback_null(void* ptr, int level, const char* fmt, va_list vl)
 +{
 +}
 +
 +static int opt_passlogfile(const char *opt, const char *arg)
 +{
 +    pass_logfilename_prefix = arg;
 +#if CONFIG_LIBX264_ENCODER
 +    return opt_default("passlogfile", arg);
 +#else
 +    return 0;
 +#endif
 +}
 +
+ static int opt_video_tag(OptionsContext *o, const char *opt, const char *arg)
+ {
+     return parse_option(o, "tag:v", arg, options);
+ }
+ static int opt_audio_tag(OptionsContext *o, const char *opt, const char *arg)
+ {
+     return parse_option(o, "tag:a", arg, options);
+ }
+ static int opt_subtitle_tag(OptionsContext *o, const char *opt, const char *arg)
+ {
+     return parse_option(o, "tag:s", arg, options);
+ }
  #define OFFSET(x) offsetof(OptionsContext, x)
  static const OptionDef options[] = {
      /* main options */
      { "s", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_size}, "set frame size (WxH or abbreviation)", "size" },
      { "aspect", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_aspect_ratio}, "set aspect ratio (4:3, 16:9 or 1.3333, 1.7777)", "aspect" },
      { "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_frame_pix_fmt}, "set pixel format, 'list' as argument shows all the pixel formats supported", "format" },
-     { "vn", OPT_BOOL | OPT_VIDEO, {(void*)&video_disable}, "disable video" },
 +    { "bits_per_raw_sample", OPT_INT | HAS_ARG | OPT_VIDEO, {(void*)&frame_bits_per_raw_sample}, "set the number of bits per raw sample", "number" },
+     { "vn", OPT_BOOL | OPT_VIDEO | OPT_OFFSET, {.off = OFFSET(video_disable)}, "disable video" },
      { "vdt", OPT_INT | HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)&video_discard}, "discard threshold", "n" },
      { "qscale", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_qscale}, "use fixed video quantizer scale (VBR)", "q" },
      { "rc_override", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_video_rc_override_string}, "rate control override for specific intervals", "override" },
diff --cc doc/avconv.texi
Simple merge
diff --cc ffmpeg.c
+++ b/ffmpeg.c
@@@ -126,12 -139,12 +126,9 @@@ static float video_qscale = 0
  static uint16_t *intra_matrix = NULL;
  static uint16_t *inter_matrix = NULL;
  static const char *video_rc_override_string=NULL;
--static int video_disable = 0;
  static int video_discard = 0;
  static char *video_codec_name = NULL;
--static unsigned int video_codec_tag = 0;
--static char *video_language = NULL;
 -static int same_quality = 0;
 +static int same_quant = 0;
  static int do_deinterlace = 0;
  static int top_field_first = -1;
  static int me_threshold = 0;
@@@ -147,22 -160,29 +144,12 @@@ static int intra_only = 0
  static int audio_sample_rate = 0;
  #define QSCALE_NONE -99999
  static float audio_qscale = QSCALE_NONE;
--static int audio_disable = 0;
--static int audio_channels = 0;
  static char  *audio_codec_name = NULL;
--static unsigned int audio_codec_tag = 0;
--static char *audio_language = NULL;
--
--static int subtitle_disable = 0;
  static char *subtitle_codec_name = NULL;
--static char *subtitle_language = NULL;
--static unsigned int subtitle_codec_tag = 0;
  
--static int data_disable = 0;
  static char *data_codec_name = NULL;
--static unsigned int data_codec_tag = 0;
  
 -static float mux_preload= 0.5;
 -static float mux_max_delay= 0.7;
 -
 -static int64_t recording_time = INT64_MAX;
 -static int64_t start_time = 0;
 -static int64_t input_ts_offset = 0;
  static int file_overwrite = 0;
 -static AVDictionary *metadata;
  static int do_benchmark = 0;
  static int do_hex_dump = 0;
  static int do_pkt_dump = 0;
@@@ -313,103 -329,6 +300,112 @@@ static int         nb_input_streams = 0
  static InputFile   *input_files   = NULL;
  static int         nb_input_files   = 0;
  
 +static OutputStream *output_streams = NULL;
 +static int        nb_output_streams = 0;
 +static OutputFile   *output_files   = NULL;
 +static int        nb_output_files   = 0;
 +
 +typedef struct OptionsContext {
 +    /* input/output options */
 +    int64_t start_time;
 +    const char *format;
 +
 +    SpecifierOpt *codec_names;
 +    int        nb_codec_names;
++    SpecifierOpt *audio_channels;
++    int        nb_audio_channels;
 +
 +    /* input options */
 +    int64_t input_ts_offset;
 +    int rate_emu;
 +
 +    SpecifierOpt *ts_scale;
 +    int        nb_ts_scale;
 +
 +    /* output options */
 +    StreamMap *stream_maps;
 +    int     nb_stream_maps;
 +    /* first item specifies output metadata, second is input */
 +    MetadataMap (*meta_data_maps)[2];
 +    int nb_meta_data_maps;
 +    int metadata_global_manual;
 +    int metadata_streams_manual;
 +    int metadata_chapters_manual;
 +
 +    int chapters_input_file;
 +
 +    int64_t recording_time;
 +    uint64_t limit_filesize;
 +    float mux_preload;
 +    float mux_max_delay;
 +
++    int video_disable;
++    int audio_disable;
++    int subtitle_disable;
++    int data_disable;
++
 +    SpecifierOpt *metadata;
 +    int        nb_metadata;
 +    SpecifierOpt *max_frames;
 +    int        nb_max_frames;
 +    SpecifierOpt *bitstream_filters;
 +    int        nb_bitstream_filters;
++    SpecifierOpt *codec_tags;
++    int        nb_codec_tags;
 +} OptionsContext;
 +
 +#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);\
 +    }\
 +}
 +
 +static void reset_options(OptionsContext *o, int is_input)
 +{
 +    const OptionDef *po = options;
 +    OptionsContext bak= *o;
 +
 +    /* 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++;
 +    }
 +
 +    av_freep(&o->stream_maps);
 +    av_freep(&o->meta_data_maps);
 +
 +    memset(o, 0, sizeof(*o));
 +
 +    if(is_input) o->recording_time = bak.recording_time;
 +    else         o->recording_time = INT64_MAX;
 +    o->mux_preload    = 0.5;
 +    o->mux_max_delay  = 0.7;
 +    o->limit_filesize = UINT64_MAX;
 +    o->chapters_input_file = INT_MAX;
 +
 +    uninit_opts();
 +    init_opts();
 +}
 +
  #if CONFIG_AVFILTER
  
  static int configure_video_filters(InputStream *ist, OutputStream *ost)
@@@ -2803,12 -2894,12 +2799,6 @@@ static int opt_audio_rate(const char *o
      return 0;
  }
  
--static int opt_audio_channels(const char *opt, const char *arg)
--{
--    audio_channels = parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX);
--    return 0;
--}
--
  static int opt_video_channel(const char *opt, const char *arg)
  {
      av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -channel.\n");
  static int opt_video_standard(const char *opt, const char *arg)
  {
      av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -standard.\n");
 -    opt_default("standard", arg);
 -    return 0;
 -}
 -
 -static int opt_codec(int *pstream_copy, char **pcodec_name,
 -                      int codec_type, const char *arg)
 -{
 -    av_freep(pcodec_name);
 -    if (!strcmp(arg, "copy")) {
 -        *pstream_copy = 1;
 -    } else {
 -        *pcodec_name = av_strdup(arg);
 -    }
 -    return 0;
 +    return opt_default("standard", arg);
  }
  
 -static int opt_audio_codec(const char *opt, const char *arg)
 +static int opt_audio_codec(OptionsContext *o, const char *opt, const char *arg)
  {
 -    return opt_codec(&audio_stream_copy, &audio_codec_name, AVMEDIA_TYPE_AUDIO, arg);
 +    audio_codec_name = arg;
 +    return parse_option(o, "codec:a", arg, options);
  }
  
 -static int opt_video_codec(const char *opt, const char *arg)
 +static int opt_video_codec(OptionsContext *o, const char *opt, const char *arg)
  {
 -    return opt_codec(&video_stream_copy, &video_codec_name, AVMEDIA_TYPE_VIDEO, arg);
 +    video_codec_name = arg;
 +    return parse_option(o, "codec:v", arg, options);
  }
  
 -static int opt_subtitle_codec(const char *opt, const char *arg)
 +static int opt_subtitle_codec(OptionsContext *o, const char *opt, const char *arg)
  {
 -    return opt_codec(&subtitle_stream_copy, &subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, arg);
 +    subtitle_codec_name = arg;
 +    return parse_option(o, "codec:s", arg, options);
  }
  
 -static int opt_data_codec(const char *opt, const char *arg)
 +static int opt_data_codec(OptionsContext *o, const char *opt, const char *arg)
  {
 -    return opt_codec(&data_stream_copy, &data_codec_name, AVMEDIA_TYPE_DATA, arg);
 +    return parse_option(o, "codec:d", arg, options);
  }
  
--static int opt_codec_tag(const char *opt, const char *arg)
- {
-     char *tail;
-     uint32_t *codec_tag;
-     codec_tag = !strcmp(opt, "atag") ? &audio_codec_tag :
-                 !strcmp(opt, "vtag") ? &video_codec_tag :
-                 !strcmp(opt, "stag") ? &subtitle_codec_tag : NULL;
-     if (!codec_tag)
-         return -1;
-     *codec_tag = strtol(arg, &tail, 0);
-     if (!tail || *tail)
-         *codec_tag = AV_RL32(arg);
-     return 0;
- }
 +static int opt_map(OptionsContext *o, const char *opt, const char *arg)
  {
 -    char *tail;
 -    uint32_t *codec_tag;
 -
 -    codec_tag = !strcmp(opt, "atag") ? &audio_codec_tag :
 -                !strcmp(opt, "vtag") ? &video_codec_tag :
 -                !strcmp(opt, "stag") ? &subtitle_codec_tag : NULL;
 -    if (!codec_tag)
 -        return -1;
 -
 -    *codec_tag = strtol(arg, &tail, 0);
 -    if (!tail || *tail)
 -        *codec_tag = AV_RL32(arg);
 +    StreamMap *m = NULL;
 +    int i, negative = 0, file_idx;
 +    int sync_file_idx = -1, sync_stream_idx;
 +    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_ERROR, "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_ERROR, "Sync stream specification in map %s does not "
 +                                       "match any streams.\n", arg);
 +            exit_program(1);
 +        }
 +    }
  
 -    return 0;
 -}
  
 -static int opt_map(const char *opt, const char *arg)
 -{
 -    StreamMap *m;
 -    char *p;
 +    file_idx = strtol(map, &p, 0);
 +    if (file_idx >= nb_input_files || file_idx < 0) {
 +        av_log(NULL, AV_LOG_ERROR, "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 (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];
  
 -    stream_maps = grow_array(stream_maps, sizeof(*stream_maps), &nb_stream_maps, nb_stream_maps + 1);
 -    m = &stream_maps[nb_stream_maps-1];
 +            m->file_index   = file_idx;
 +            m->stream_index = i;
  
 -    m->file_index = strtol(arg, &p, 0);
 -    if (*p)
 -        p++;
 +            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;
 +            }
 +        }
  
 -    m->stream_index = strtol(p, &p, 0);
 -    if (*p) {
 -        p++;
 -        m->sync_file_index = strtol(p, &p, 0);
 -        if (*p)
 -            p++;
 -        m->sync_stream_index = strtol(p, &p, 0);
 -    } else {
 -        m->sync_file_index = m->file_index;
 -        m->sync_stream_index = m->stream_index;
 +    if (!m) {
 +        av_log(NULL, AV_LOG_ERROR, "Stream map '%s' matches no streams.\n", arg);
 +        exit_program(1);
      }
 +
 +    av_freep(&map);
      return 0;
  }
  
@@@ -3034,108 -3130,7 +3006,108 @@@ static enum CodecID find_codec_or_die(c
      return codec->id;
  }
  
 -static int opt_input_file(const char *opt, const char *filename)
 +static AVCodec *choose_codec(OptionsContext *o, AVFormatContext *s, AVStream *st, enum AVMediaType type)
 +{
 +    char *codec_name = NULL;
 +
 +    MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, st);
 +
 +    if (!codec_name) {
 +        if (s->oformat) {
 +            st->codec->codec_id = av_guess_codec(s->oformat, NULL, s->filename, NULL, type);
 +            return avcodec_find_encoder(st->codec->codec_id);
 +        }
 +    } else if (!strcmp(codec_name, "copy"))
 +        st->stream_copy = 1;
 +    else {
 +        st->codec->codec_id = find_codec_or_die(codec_name, type, s->iformat == NULL);
 +        return s->oformat ? avcodec_find_encoder_by_name(codec_name) :
 +                            avcodec_find_decoder_by_name(codec_name);
 +    }
 +
 +    return NULL;
 +}
 +
 +/**
 + * 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, rfps, rfps_base;
 +
 +    for (i = 0; i < ic->nb_streams; i++) {
 +        AVStream *st = ic->streams[i];
 +        AVCodecContext *dec = st->codec;
 +        InputStream *ist;
 +        double scale = 1.0;
 +
 +        dec->thread_count = thread_count;
 +
 +        input_streams = grow_array(input_streams, sizeof(*input_streams), &nb_input_streams, nb_input_streams + 1);
 +        ist = &input_streams[nb_input_streams - 1];
 +        ist->st = st;
 +        ist->file_index = nb_input_files;
 +        ist->discard = 1;
 +        ist->opts = filter_codec_opts(codec_opts, ist->st->codec->codec_id, ic, st);
 +
 +        MATCH_PER_STREAM_OPT(ts_scale, dbl, scale, ic, st);
 +        ist->ts_scale = scale;
 +
 +        ist->dec = choose_codec(o, ic, st, dec->codec_type);
 +        if (!ist->dec)
 +            ist->dec = avcodec_find_decoder(dec->codec_id);
 +
 +        switch (dec->codec_type) {
 +        case AVMEDIA_TYPE_AUDIO:
 +            if(!ist->dec)
 +                ist->dec = avcodec_find_decoder(dec->codec_id);
-             if(audio_disable)
++            if(o->audio_disable)
 +                st->discard= AVDISCARD_ALL;
 +            break;
 +        case AVMEDIA_TYPE_VIDEO:
 +            if(!ist->dec)
 +                ist->dec = avcodec_find_decoder(dec->codec_id);
 +            rfps      = ic->streams[i]->r_frame_rate.num;
 +            rfps_base = ic->streams[i]->r_frame_rate.den;
 +            if (dec->lowres) {
 +                dec->flags |= CODEC_FLAG_EMU_EDGE;
 +            }
 +            if(me_threshold)
 +                dec->debug |= FF_DEBUG_MV;
 +
 +            if (dec->time_base.den != rfps*dec->ticks_per_frame || dec->time_base.num != rfps_base) {
 +
 +                if (verbose >= 0)
 +                    fprintf(stderr,"\nSeems stream %d codec frame rate differs from container frame rate: %2.2f (%d/%d) -> %2.2f (%d/%d)\n",
 +                            i, (float)dec->time_base.den / dec->time_base.num, dec->time_base.den, dec->time_base.num,
 +
 +                    (float)rfps / rfps_base, rfps, rfps_base);
 +            }
 +
-             if(video_disable)
++            if (o->video_disable)
 +                st->discard= AVDISCARD_ALL;
 +            else if(video_discard)
 +                st->discard= video_discard;
 +            break;
 +        case AVMEDIA_TYPE_DATA:
 +            break;
 +        case AVMEDIA_TYPE_SUBTITLE:
 +            if(!ist->dec)
 +                ist->dec = avcodec_find_decoder(dec->codec_id);
-             if(subtitle_disable)
++            if(o->subtitle_disable)
 +                st->discard = AVDISCARD_ALL;
 +            break;
 +        case AVMEDIA_TYPE_ATTACHMENT:
 +        case AVMEDIA_TYPE_UNKNOWN:
 +            break;
 +        default:
 +            abort();
 +        }
 +    }
 +}
 +
 +static int opt_input_file(OptionsContext *o, const char *opt, const char *filename)
  {
      AVFormatContext *ic;
      AVInputFormat *file_iformat = NULL;
          snprintf(buf, sizeof(buf), "%d", audio_sample_rate);
          av_dict_set(&format_opts, "sample_rate", buf, 0);
      }
--    if (audio_channels) {
--        snprintf(buf, sizeof(buf), "%d", audio_channels);
++    if (o->nb_audio_channels) {
++        snprintf(buf, sizeof(buf), "%d", o->audio_channels[o->nb_audio_channels - 1].u.i);
          av_dict_set(&format_opts, "channels", buf, 0);
      }
      if (frame_rate.num) {
      frame_height = 0;
      frame_width  = 0;
      audio_sample_rate = 0;
--    audio_channels    = 0;
      audio_sample_fmt  = AV_SAMPLE_FMT_NONE;
 -    av_freep(&ts_scale);
 -    nb_ts_scale = 0;
  
      for (i = 0; i < orig_nb_streams; i++)
          av_dict_free(&opts[i]);
      return 0;
  }
  
 -static void check_inputs(int *has_video_ptr,
 -                         int *has_audio_ptr,
 -                         int *has_subtitle_ptr,
 -                         int *has_data_ptr)
 +static void parse_forced_key_frames(char *kf, OutputStream *ost,
 +                                    AVCodecContext *avctx)
  {
 -    int has_video, has_audio, has_subtitle, has_data, i, j;
 -    AVFormatContext *ic;
 +    char *p;
 +    int n = 1, i;
 +    int64_t t;
  
 -    has_video = 0;
 -    has_audio = 0;
 -    has_subtitle = 0;
 -    has_data = 0;
 +    for (p = kf; *p; p++)
 +        if (*p == ',')
 +            n++;
 +    ost->forced_kf_count = n;
 +    ost->forced_kf_pts = av_malloc(sizeof(*ost->forced_kf_pts) * n);
 +    if (!ost->forced_kf_pts) {
 +        av_log(NULL, AV_LOG_FATAL, "Could not allocate forced key frames array.\n");
 +        exit_program(1);
 +    }
 +    for (i = 0; i < n; i++) {
 +        p = i ? strchr(p, ',') + 1 : kf;
 +        t = parse_time_or_die("force_key_frames", p, 1);
 +        ost->forced_kf_pts[i] = av_rescale_q(t, AV_TIME_BASE_Q, avctx->time_base);
 +    }
 +}
  
 -    for(j=0;j<nb_input_files;j++) {
 -        ic = input_files[j].ctx;
 -        for(i=0;i<ic->nb_streams;i++) {
 -            AVCodecContext *enc = ic->streams[i]->codec;
 -            switch(enc->codec_type) {
 -            case AVMEDIA_TYPE_AUDIO:
 -                has_audio = 1;
 -                break;
 -            case AVMEDIA_TYPE_VIDEO:
 -                has_video = 1;
 -                break;
 -            case AVMEDIA_TYPE_SUBTITLE:
 -                has_subtitle = 1;
 -                break;
 -            case AVMEDIA_TYPE_DATA:
 -            case AVMEDIA_TYPE_ATTACHMENT:
 -            case AVMEDIA_TYPE_UNKNOWN:
 -                has_data = 1;
 -                break;
 -            default:
 -                abort();
 -            }
 +static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type)
 +{
 +    OutputStream *ost;
 +    AVStream *st = av_new_stream(oc, oc->nb_streams < nb_streamid_map ? streamid_map[oc->nb_streams] : 0);
 +    int idx      = oc->nb_streams - 1;
 +    int64_t max_frames = INT64_MAX;
-     char *bsf = NULL, *next;
++    char *bsf = NULL, *next, *codec_tag = NULL;
 +    AVBitStreamFilterContext *bsfc, *bsfc_prev = NULL;
 +
 +    if (!st) {
 +        av_log(NULL, AV_LOG_ERROR, "Could not alloc stream.\n");
 +        exit_program(1);
 +    }
 +
 +    output_streams = grow_array(output_streams, sizeof(*output_streams), &nb_output_streams,
 +                                nb_output_streams + 1);
 +    ost = &output_streams[nb_output_streams - 1];
 +    ost->file_index = nb_output_files;
 +    ost->index = idx;
 +    ost->st    = st;
 +    st->codec->codec_type = type;
 +    ost->enc = choose_codec(o, oc, st, type);
 +    if (ost->enc) {
 +        ost->opts  = filter_codec_opts(codec_opts, ost->enc->id, oc, st);
 +    }
 +
 +    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(max_frames, i64, max_frames, oc, st);
 +    ost->max_frames = max_frames;
 +
 +    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_ERROR, "Unknown bitstream filter %s\n", bsf);
 +            exit_program(1);
          }
 -    *has_video_ptr = has_video;
 -    *has_audio_ptr = has_audio;
 -    *has_subtitle_ptr = has_subtitle;
 -    *has_data_ptr = has_data;
 +        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;
+     }
++
 +    ost->sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
 +    return ost;
  }
  
 -static void new_video_stream(AVFormatContext *oc, int file_idx)
 +static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc)
  {
      AVStream *st;
      OutputStream *ost;
  
      video_enc = st->codec;
  
--    if(video_codec_tag)
--        video_enc->codec_tag= video_codec_tag;
--
      if(oc->oformat->flags & AVFMT_GLOBALHEADER) {
          video_enc->flags |= CODEC_FLAG_GLOBAL_HEADER;
      }
          if (forced_key_frames)
              parse_forced_key_frames(forced_key_frames, ost, video_enc);
      }
--    if (video_language) {
--        av_dict_set(&st->metadata, "language", video_language, 0);
--        av_freep(&video_language);
--    }
  
      /* reset some key parameters */
--    video_disable = 0;
 -    av_freep(&video_codec_name);
      av_freep(&forced_key_frames);
 -    video_stream_copy = 0;
      frame_pix_fmt = PIX_FMT_NONE;
 +    return ost;
  }
  
 -static void new_audio_stream(AVFormatContext *oc, int file_idx)
 +static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc)
  {
      AVStream *st;
      OutputStream *ost;
      audio_enc = st->codec;
      audio_enc->codec_type = AVMEDIA_TYPE_AUDIO;
  
--    if(audio_codec_tag)
--        audio_enc->codec_tag= audio_codec_tag;
--
      if (oc->oformat->flags & AVFMT_GLOBALHEADER) {
          audio_enc->flags |= CODEC_FLAG_GLOBAL_HEADER;
      }
              audio_enc->flags |= CODEC_FLAG_QSCALE;
              audio_enc->global_quality = FF_QP2LAMBDA * audio_qscale;
          }
--        if (audio_channels)
--            audio_enc->channels = audio_channels;
++        MATCH_PER_STREAM_OPT(audio_channels, i, audio_enc->channels, oc, st);
++
          if (audio_sample_fmt != AV_SAMPLE_FMT_NONE)
              audio_enc->sample_fmt = audio_sample_fmt;
          if (audio_sample_rate)
              audio_enc->sample_rate = audio_sample_rate;
      }
--    if (audio_language) {
--        av_dict_set(&st->metadata, "language", audio_language, 0);
--        av_freep(&audio_language);
--    }
-     /* reset some key parameters */
-     audio_disable = 0;
  
 -    /* reset some key parameters */
 -    audio_disable = 0;
 -    av_freep(&audio_codec_name);
 -    audio_stream_copy = 0;
 +    return ost;
  }
  
 -static void new_data_stream(AVFormatContext *oc, int file_idx)
 +static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc)
  {
      AVStream *st;
      OutputStream *ost;
          exit_program(1);
      }
  
 -    data_enc->codec_type = AVMEDIA_TYPE_DATA;
 -
--    if (data_codec_tag)
--        data_enc->codec_tag= data_codec_tag;
--
      if (oc->oformat->flags & AVFMT_GLOBALHEADER) {
          data_enc->flags |= CODEC_FLAG_GLOBAL_HEADER;
      }
 -    if (data_stream_copy) {
 -        st->stream_copy = 1;
 -    }
  
--    data_disable = 0;
 -    av_freep(&data_codec_name);
 -    data_stream_copy = 0;
 +    return ost;
  }
  
 -static void new_subtitle_stream(AVFormatContext *oc, int file_idx)
 +static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc)
  {
      AVStream *st;
      OutputStream *ost;
      st  = ost->st;
      subtitle_enc = st->codec;
  
 -    ost->bitstream_filters = subtitle_bitstream_filters;
 -    subtitle_bitstream_filters= NULL;
 -
      subtitle_enc->codec_type = AVMEDIA_TYPE_SUBTITLE;
  
--    if(subtitle_codec_tag)
--        subtitle_enc->codec_tag= subtitle_codec_tag;
--
      if (oc->oformat->flags & AVFMT_GLOBALHEADER) {
          subtitle_enc->flags |= CODEC_FLAG_GLOBAL_HEADER;
      }
 -    if (subtitle_stream_copy) {
 -        st->stream_copy = 1;
 -    } else {
 -        subtitle_enc->codec_id = codec_id;
 -    }
 -
 -    if (subtitle_language) {
 -        av_dict_set(&st->metadata, "language", subtitle_language, 0);
 -        av_freep(&subtitle_language);
 -    }
 -
 -    subtitle_disable = 0;
 -    av_freep(&subtitle_codec_name);
 -    subtitle_stream_copy = 0;
 -}
 -
 -static int opt_new_stream(const char *opt, const char *arg)
 -{
 -    AVFormatContext *oc;
 -    int file_idx = nb_output_files - 1;
 -    if (nb_output_files <= 0) {
 -        fprintf(stderr, "At least one output file must be specified\n");
 -        exit_program(1);
 -    }
 -    oc = output_files[file_idx];
  
-     if (subtitle_language) {
-         av_dict_set(&st->metadata, "language", subtitle_language, 0);
-         av_freep(&subtitle_language);
-     }
-     subtitle_disable = 0;
 -    if      (!strcmp(opt, "newvideo"   )) new_video_stream   (oc, file_idx);
 -    else if (!strcmp(opt, "newaudio"   )) new_audio_stream   (oc, file_idx);
 -    else if (!strcmp(opt, "newsubtitle")) new_subtitle_stream(oc, file_idx);
 -    else if (!strcmp(opt, "newdata"    )) new_data_stream    (oc, file_idx);
 -    else av_assert0(0);
 -    return 0;
 +    return ost;
  }
  
  /* arg format is "output-stream-index:streamid-value". */
@@@ -3693,86 -3746,44 +3641,86 @@@ static void opt_output_file(void *optct
              print_error(filename, err);
              exit_program(1);
          }
-         if (!video_disable && oc->oformat->video_codec != CODEC_ID_NONE) {
 +    } else if (!o->nb_stream_maps) {
 +        /* pick the "best" stream of each type */
 +#define NEW_STREAM(type, index)\
 +        if (index >= 0) {\
 +            ost = new_ ## type ## _stream(o, oc);\
 +            ost->source_index = index;\
 +            ost->sync_ist     = &input_streams[index];\
 +            input_streams[index].discard = 0;\
 +        }
 +
 +        /* video: highest resolution */
-         if (!audio_disable && oc->oformat->audio_codec != CODEC_ID_NONE) {
++        if (!o->video_disable && oc->oformat->video_codec != CODEC_ID_NONE) {
 +            int area = 0, idx = -1;
 +            for (i = 0; i < nb_input_streams; i++) {
 +                ist = &input_streams[i];
 +                if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
 +                    ist->st->codec->width * ist->st->codec->height > area) {
 +                    area = ist->st->codec->width * ist->st->codec->height;
 +                    idx = i;
 +                }
 +            }
 +            NEW_STREAM(video, idx);
 +        }
 +
 +        /* audio: most channels */
-         if (!subtitle_disable && (oc->oformat->subtitle_codec != CODEC_ID_NONE || subtitle_codec_name)) {
++        if (!o->audio_disable && oc->oformat->audio_codec != 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;
 +                }
 +            }
 +            NEW_STREAM(audio, idx);
 +        }
 +
 +        /* subtitles: pick first */
++        if (!o->subtitle_disable && (oc->oformat->subtitle_codec != CODEC_ID_NONE || subtitle_codec_name)) {
 +            for (i = 0; i < nb_input_streams; i++)
 +                if (input_streams[i].st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
 +                    NEW_STREAM(subtitle, i);
 +                    break;
 +                }
 +        }
 +        /* do something with data? */
      } else {
 -        use_video = file_oformat->video_codec != CODEC_ID_NONE || video_stream_copy || video_codec_name;
 -        use_audio = file_oformat->audio_codec != CODEC_ID_NONE || audio_stream_copy || audio_codec_name;
 -        use_subtitle = file_oformat->subtitle_codec != CODEC_ID_NONE || subtitle_stream_copy || subtitle_codec_name;
 -        use_data = data_stream_copy ||  data_codec_name; /* XXX once generic data codec will be available add a ->data_codec reference and use it here */
 -
 -        /* disable if no corresponding type found */
 -        check_inputs(&input_has_video,
 -                     &input_has_audio,
 -                     &input_has_subtitle,
 -                     &input_has_data);
 -
 -        if (!input_has_video)
 -            use_video = 0;
 -        if (!input_has_audio)
 -            use_audio = 0;
 -        if (!input_has_subtitle)
 -            use_subtitle = 0;
 -        if (!input_has_data)
 -            use_data = 0;
 -
 -        /* manual disable */
 -        if (audio_disable)    use_audio    = 0;
 -        if (video_disable)    use_video    = 0;
 -        if (subtitle_disable) use_subtitle = 0;
 -        if (data_disable)     use_data     = 0;
 -
 -        if (use_video)    new_video_stream(oc, nb_output_files);
 -        if (use_audio)    new_audio_stream(oc, nb_output_files);
 -        if (use_subtitle) new_subtitle_stream(oc, nb_output_files);
 -        if (use_data)     new_data_stream(oc, nb_output_files);
 -
 -        av_dict_copy(&oc->metadata, metadata, 0);
 -        av_dict_free(&metadata);
 +        for (i = 0; i < o->nb_stream_maps; i++) {
 +            StreamMap *map = &o->stream_maps[i];
 +
 +            if (map->disabled)
 +                continue;
 +
 +            ist = &input_streams[input_files[map->file_index].ist_index + map->stream_index];
 +            switch (ist->st->codec->codec_type) {
 +            case AVMEDIA_TYPE_VIDEO:    ost = new_video_stream(o, oc);    break;
 +            case AVMEDIA_TYPE_AUDIO:    ost = new_audio_stream(o, oc);    break;
 +            case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream(o, oc); break;
 +            case AVMEDIA_TYPE_DATA:     ost = new_data_stream(o, oc);     break;
 +            default:
 +                av_log(NULL, AV_LOG_ERROR, "Cannot map stream #%d.%d - unsupported type.\n",
 +                       map->file_index, map->stream_index);
 +                exit_program(1);
 +            }
 +
 +            ost->source_index = input_files[map->file_index].ist_index + map->stream_index;
 +            ost->sync_ist = &input_streams[input_files[map->sync_file_index].ist_index +
 +                                           map->sync_stream_index];
 +            ist->discard = 0;
 +        }
      }
  
 -    av_dict_copy(&output_opts[nb_output_files], format_opts, 0);
 -    output_files[nb_output_files++] = oc;
 +    output_files = grow_array(output_files, sizeof(*output_files), &nb_output_files, nb_output_files + 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;
 +    output_files[nb_output_files - 1].start_time     = o->start_time;
 +    output_files[nb_output_files - 1].limit_filesize = o->limit_filesize;
 +    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) {
      frame_width   = 0;
      frame_height  = 0;
      audio_sample_rate = 0;
--    audio_channels    = 0;
      audio_sample_fmt  = AV_SAMPLE_FMT_NONE;
  
 +    av_freep(&streamid_map);
 +    nb_streamid_map = 0;
 +
      av_freep(&forced_key_frames);
 -    uninit_opts();
 -    init_opts();
 +    reset_options(o, 0);
  }
  
  /* same option as mencoder */
@@@ -4172,9 -4061,9 +4119,9 @@@ static int opt_target(OptionsContext *o
          opt_default("minrate", "1150000");
          opt_default("bufsize", "327680"); // 40*1024*8;
  
 -        opt_default("ab", "224000");
 +        opt_default("b:a", "224000");
          audio_sample_rate = 44100;
--        audio_channels = 2;
++        parse_option(o, "ac", "2", options);
  
          opt_default("packetsize", "2324");
          opt_default("muxrate", "1411200"); // 2352 * 75 * 8;
          opt_frame_rate("r", frame_rates[norm]);
  
          audio_sample_rate = 48000;
--        audio_channels = 2;
++        parse_option(o, "ac", "2", options);
  
      } else {
          fprintf(stderr, "Unknown target: %s\n", arg);
@@@ -4323,21 -4216,6 +4270,36 @@@ static int opt_preset(OptionsContext *o
      return 0;
  }
  
 +static void log_callback_null(void* ptr, int level, const char* fmt, va_list vl)
 +{
 +}
 +
 +static int opt_passlogfile(const char *opt, const char *arg)
 +{
 +    pass_logfilename_prefix = arg;
 +#if CONFIG_LIBX264_ENCODER
 +    return opt_default("passlogfile", arg);
 +#else
 +    return 0;
 +#endif
 +}
 +
++static int opt_video_tag(OptionsContext *o, const char *opt, const char *arg)
++{
++    return parse_option(o, "tag:v", arg, options);
++}
++
++static int opt_audio_tag(OptionsContext *o, const char *opt, const char *arg)
++{
++    return parse_option(o, "tag:a", arg, options);
++}
++
++static int opt_subtitle_tag(OptionsContext *o, const char *opt, const char *arg)
++{
++    return parse_option(o, "tag:s", arg, options);
++}
++
 +#define OFFSET(x) offsetof(OptionsContext, x)
  static const OptionDef options[] = {
      /* main options */
  #include "cmdutils_common_opts.h"
      { "programid", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&opt_programid}, "desired program number", "" },
      { "xerror", OPT_BOOL, {(void*)&exit_on_error}, "exit on error", "error" },
      { "copyinkf", OPT_BOOL | OPT_EXPERT, {(void*)&copy_initial_nonkeyframes}, "copy initial non-keyframes" },
 +    { "frames", OPT_INT64 | HAS_ARG | OPT_SPEC, {.off = OFFSET(max_frames)}, "set the number of frames to record", "number" },
++    { "tag",   OPT_STRING | HAS_ARG | OPT_SPEC, {.off = OFFSET(codec_tags)}, "force codec tag/fourcc", "fourcc/tag" },
  
      /* video options */
 -    { "vframes", OPT_INT | HAS_ARG | OPT_VIDEO, {(void*)&max_frames[AVMEDIA_TYPE_VIDEO]}, "set the number of video frames to record", "number" },
 +    { "vframes", HAS_ARG | OPT_VIDEO | OPT_FUNC2, {(void*)opt_video_frames}, "set the number of video frames to record", "number" },
      { "r", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_rate}, "set frame rate (Hz value, fraction or abbreviation)", "rate" },
      { "s", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_size}, "set frame size (WxH or abbreviation)", "size" },
      { "aspect", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_aspect_ratio}, "set aspect ratio (4:3, 16:9 or 1.3333, 1.7777)", "aspect" },
      { "padright", HAS_ARG | OPT_VIDEO, {(void*)opt_pad}, "Removed, use the pad filter instead", "size" },
      { "padcolor", HAS_ARG | OPT_VIDEO, {(void*)opt_pad}, "Removed, use the pad filter instead", "color" },
      { "intra", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&intra_only}, "use only intra frames"},
--    { "vn", OPT_BOOL | OPT_VIDEO, {(void*)&video_disable}, "disable video" },
++    { "vn", OPT_BOOL | OPT_VIDEO | OPT_OFFSET, {.off = OFFSET(video_disable)}, "disable video" },
      { "vdt", OPT_INT | HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)&video_discard}, "discard threshold", "n" },
      { "qscale", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_qscale}, "use fixed video quantizer scale (VBR)", "q" },
      { "rc_override", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_video_rc_override_string}, "rate control override for specific intervals", "override" },
      { "inter_matrix", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_inter_matrix}, "specify inter matrix coeffs", "matrix" },
      { "top", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_top_field_first}, "top=1/bottom=0/auto=-1 field first", "" },
      { "dc", OPT_INT | HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)&intra_dc_precision}, "intra_dc_precision", "precision" },
--    { "vtag", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_codec_tag}, "force video tag/fourcc", "fourcc/tag" },
 -    { "newvideo", OPT_VIDEO, {(void*)opt_new_stream}, "add a new video stream to the current output stream" },
--    { "vlang", HAS_ARG | OPT_STRING | OPT_VIDEO, {(void *)&video_language}, "set the ISO 639 language code (3 letters) of the current video stream" , "code" },
++    { "vtag", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_FUNC2, {(void*)opt_video_tag}, "force video tag/fourcc", "fourcc/tag" },
      { "qphist", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, { (void *)&qp_hist }, "show QP histogram" },
      { "force_fps", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&force_fps}, "force the selected framerate, disable the best supported framerate selection" },
      { "streamid", HAS_ARG | OPT_EXPERT, {(void*)opt_streamid}, "set the value of an outfile streamid", "streamIndex:value" },
      { "force_key_frames", OPT_STRING | HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void *)&forced_key_frames}, "force key frames at specified timestamps", "timestamps" },
  
      /* audio options */
 -    { "aframes", OPT_INT | HAS_ARG | OPT_AUDIO, {(void*)&max_frames[AVMEDIA_TYPE_AUDIO]}, "set the number of audio frames to record", "number" },
 +    { "aframes", HAS_ARG | OPT_AUDIO | OPT_FUNC2, {(void*)opt_audio_frames}, "set the number of audio frames to record", "number" },
      { "aq", OPT_FLOAT | HAS_ARG | OPT_AUDIO, {(void*)&audio_qscale}, "set audio quality (codec-specific)", "quality", },
      { "ar", HAS_ARG | OPT_AUDIO, {(void*)opt_audio_rate}, "set audio sampling rate (in Hz)", "rate" },
--    { "ac", HAS_ARG | OPT_AUDIO, {(void*)opt_audio_channels}, "set number of audio channels", "channels" },
--    { "an", OPT_BOOL | OPT_AUDIO, {(void*)&audio_disable}, "disable audio" },
 -    { "acodec", HAS_ARG | OPT_AUDIO, {(void*)opt_audio_codec}, "force audio codec ('copy' to copy stream)", "codec" },
 -    { "atag", HAS_ARG | OPT_EXPERT | OPT_AUDIO, {(void*)opt_codec_tag}, "force audio tag/fourcc", "fourcc/tag" },
++    { "ac", HAS_ARG | OPT_AUDIO | OPT_INT | OPT_SPEC, {.off = OFFSET(audio_channels)}, "set number of audio channels", "channels" },
++    { "an", OPT_BOOL | OPT_AUDIO | OPT_OFFSET, {.off = OFFSET(audio_disable)}, "disable audio" },
 +    { "acodec", HAS_ARG | OPT_AUDIO | OPT_FUNC2, {(void*)opt_audio_codec}, "force audio codec ('copy' to copy stream)", "codec" },
-     { "atag", HAS_ARG | OPT_EXPERT | OPT_AUDIO, {(void*)opt_codec_tag}, "force audio tag/fourcc", "fourcc/tag" },
++    { "atag", HAS_ARG | OPT_EXPERT | OPT_AUDIO | OPT_FUNC2, {(void*)opt_audio_tag}, "force audio tag/fourcc", "fourcc/tag" },
      { "vol", OPT_INT | HAS_ARG | OPT_AUDIO, {(void*)&audio_volume}, "change audio volume (256=normal)" , "volume" }, //
 -    { "newaudio", OPT_AUDIO, {(void*)opt_new_stream}, "add a new audio stream to the current output stream" },
--    { "alang", HAS_ARG | OPT_STRING | OPT_AUDIO, {(void *)&audio_language}, "set the ISO 639 language code (3 letters) of the current audio stream" , "code" },
      { "sample_fmt", HAS_ARG | OPT_EXPERT | OPT_AUDIO, {(void*)opt_audio_sample_fmt}, "set sample format, 'list' as argument shows all the sample formats supported", "format" },
  
      /* subtitle options */
--    { "sn", OPT_BOOL | OPT_SUBTITLE, {(void*)&subtitle_disable}, "disable subtitle" },
 -    { "scodec", HAS_ARG | OPT_SUBTITLE, {(void*)opt_subtitle_codec}, "force subtitle codec ('copy' to copy stream)", "codec" },
 -    { "newsubtitle", OPT_SUBTITLE, {(void*)opt_new_stream}, "add a new subtitle stream to the current output stream" },
 -    { "slang", HAS_ARG | OPT_STRING | OPT_SUBTITLE, {(void *)&subtitle_language}, "set the ISO 639 language code (3 letters) of the current subtitle stream" , "code" },
 -    { "stag", HAS_ARG | OPT_EXPERT | OPT_SUBTITLE, {(void*)opt_codec_tag}, "force subtitle tag/fourcc", "fourcc/tag" },
++    { "sn", OPT_BOOL | OPT_SUBTITLE | OPT_OFFSET, {.off = OFFSET(subtitle_disable)}, "disable subtitle" },
 +    { "scodec", HAS_ARG | OPT_SUBTITLE | OPT_FUNC2, {(void*)opt_subtitle_codec}, "force subtitle codec ('copy' to copy stream)", "codec" },
-     { "slang", HAS_ARG | OPT_STRING | OPT_SUBTITLE, {(void *)&subtitle_language}, "set the ISO 639 language code (3 letters) of the current subtitle stream" , "code" },
-     { "stag", HAS_ARG | OPT_EXPERT | OPT_SUBTITLE, {(void*)opt_codec_tag}, "force subtitle tag/fourcc", "fourcc/tag" },
++    { "stag", HAS_ARG | OPT_EXPERT | OPT_SUBTITLE | OPT_FUNC2, {(void*)opt_subtitle_tag}, "force subtitle tag/fourcc", "fourcc/tag" },
  
      /* grab options */
      { "vc", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_GRAB, {(void*)opt_video_channel}, "deprecated, use -channel", "channel" },
Simple merge
Simple merge
Simple merge