Merge remote-tracking branch 'qatar/master'
authorMichael Niedermayer <michaelni@gmx.at>
Mon, 5 Sep 2011 20:10:26 +0000 (22:10 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Mon, 5 Sep 2011 20:29:16 +0000 (22:29 +0200)
* qatar/master:
  ac3enc: Add channel coupling support for the fixed-point AC-3 encoder.
  ac3enc: scale floating-point coupling channel coefficients in scale_coefficients() rather than in apply_channel_coupling()
  ac3enc: fix encoding of stereo ac3 files when rematrixing is disabled.
  wavpack: fix wrong return value in wavpack_decode_block()
  avconv: fix parsing metadata specifiers.
  fate: use +frame+slice named constants instead of '3'
  mpeg12: propagate more real return values through chunk decode error return and fix some indentation
  wavpack: use context reset in appropriate places
  avconv: move mux_preload and mux_max_delay to options context
  avconv: move bitstream filters to options context.
  avconv: move rate_emu to options context.
  avconv: move max_frames to options context.
  avconv: move metadata to options context.
  avconv: move ts scale to options context.
  avconv: move chapter maps to options context.
  avconv: move metadata maps to options context.
  avconv: move codec_names to options context.

Conflicts:
avconv.c
tests/fate-run.sh

Merged-by: Michael Niedermayer <michaelni@gmx.at>
12 files changed:
1  2 
avconv.c
cmdutils.c
cmdutils.h
doc/avconv.texi
ffmpeg.c
libavcodec/ac3enc.c
libavcodec/ac3enc_fixed.c
libavcodec/ac3enc_float.c
libavcodec/mpeg12.c
libavcodec/wavpack.c
tests/fate-run.sh
tests/fate/h264.mak

diff --cc avconv.c
+++ b/avconv.c
@@@ -109,20 -97,6 +109,8 @@@ typedef struct MetadataMap 
  
  static const OptionDef options[];
  
- static AVDictionary *ts_scale;
- static AVDictionary *codec_names;
- /* first item specifies output metadata, second is input */
- static MetadataMap (*meta_data_maps)[2] = NULL;
- static int nb_meta_data_maps;
- static int metadata_global_autocopy   = 1;
- static int metadata_streams_autocopy  = 1;
- static int metadata_chapters_autocopy = 1;
- static int chapters_input_file = INT_MAX;
 +#define MAX_STREAMS 1024    /* arbitrary sanity check value */
 +
  /* indexed by output file stream index */
  static int *streamid_map = NULL;
  static int nb_streamid_map = 0;
@@@ -131,9 -105,7 +119,8 @@@ static int frame_width  = 0
  static int frame_height = 0;
  static float frame_aspect_ratio = 0;
  static enum PixelFormat frame_pix_fmt = PIX_FMT_NONE;
 +static int frame_bits_per_raw_sample = 0;
  static enum AVSampleFormat audio_sample_fmt = AV_SAMPLE_FMT_NONE;
- static int max_frames[4] = {INT_MAX, INT_MAX, INT_MAX, INT_MAX};
  static AVRational frame_rate;
  static float video_qscale = 0;
  static uint16_t *intra_matrix = NULL;
@@@ -3499,7 -3374,7 +3489,7 @@@ static int copy_chapters(InputFile *ifi
      return 0;
  }
  
- static int read_ffserver_streams(AVFormatContext *s, const char *filename)
 -static int read_avserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename)
++static int read_ffserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename)
  {
      int i, err;
      AVFormatContext *ic = NULL;
@@@ -3555,9 -3445,9 +3545,9 @@@ static void opt_output_file(void *optct
  
      if (!strcmp(file_oformat->name, "ffm") &&
          av_strstart(filename, "http:", NULL)) {
 -        /* special case for files sent to avserver: we get the stream
 -           parameters from avserver */
 -        int err = read_avserver_streams(o, oc, filename);
 +        /* special case for files sent to ffserver: we get the stream
 +           parameters from ffserver */
-         int err = read_ffserver_streams(oc, filename);
++        int err = read_ffserver_streams(o, oc, filename);
          if (err < 0) {
              print_error(filename, err);
              exit_program(1);
          }
      }
  
-     oc->preload= (int)(mux_preload*AV_TIME_BASE);
-     oc->max_delay= (int)(mux_max_delay*AV_TIME_BASE);
+     oc->preload   = (int)(o->mux_preload   * AV_TIME_BASE);
+     oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE);
 -    oc->flags |= AVFMT_FLAG_NONBLOCK;
  
      /* copy chapters */
-     if (chapters_input_file >= nb_input_files) {
-         if (chapters_input_file == INT_MAX) {
+     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*/
-             chapters_input_file = -1;
+             o->chapters_input_file = -1;
              for (i = 0; i < nb_input_files; i++)
                  if (input_files[i].ctx->nb_chapters) {
-                     chapters_input_file = i;
+                     o->chapters_input_file = i;
                      break;
                  }
          } else {
@@@ -4101,41 -4017,21 +4121,35 @@@ static int opt_vstats(const char *opt, 
      return opt_vstats_file(opt, filename);
  }
  
- static int opt_bsf(const char *opt, const char *arg)
+ static int opt_video_frames(OptionsContext *o, const char *opt, const char *arg)
  {
-     AVBitStreamFilterContext *bsfc= av_bitstream_filter_init(arg); //FIXME split name and args for filter at '='
-     AVBitStreamFilterContext **bsfp;
-     if(!bsfc){
-         fprintf(stderr, "Unknown bitstream filter %s\n", arg);
-         exit_program(1);
-     }
-     bsfp= *opt == 'v' ? &video_bitstream_filters :
-           *opt == 'a' ? &audio_bitstream_filters :
-                         &subtitle_bitstream_filters;
-     while(*bsfp)
-         bsfp= &(*bsfp)->next;
+     return parse_option(o, "frames:v", arg, options);
+ }
  
-     *bsfp= bsfc;
+ static int opt_audio_frames(OptionsContext *o, const char *opt, const char *arg)
+ {
+     return parse_option(o, "frames:a", arg, options);
+ }
  
-     return 0;
+ static int opt_data_frames(OptionsContext *o, const char *opt, const char *arg)
+ {
+     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
 +}
 +
  #define OFFSET(x) offsetof(OptionsContext, x)
  static const OptionDef options[] = {
      /* main options */
diff --cc cmdutils.c
Simple merge
diff --cc cmdutils.h
Simple merge
diff --cc doc/avconv.texi
Simple merge
diff --cc ffmpeg.c
+++ b/ffmpeg.c
@@@ -107,21 -94,35 +107,9 @@@ typedef struct MetadataMap 
      int  index;     ///< stream/chapter/program number
  } MetadataMap;
  
 -typedef struct ChapterMap {
 -    int in_file;
 -    int out_file;
 -} ChapterMap;
 -
  static const OptionDef options[];
  
 -#define MAX_FILES 100
 -
 -static const char *last_asked_format = NULL;
 -static double *ts_scale;
 -static int  nb_ts_scale;
 -
 -static AVFormatContext *output_files[MAX_FILES];
 -static AVDictionary *output_opts[MAX_FILES];
 -static int nb_output_files = 0;
 -
 -static StreamMap *stream_maps = NULL;
 -static int nb_stream_maps;
 -
 -/* first item specifies output metadata, second is input */
 -static MetadataMap (*meta_data_maps)[2] = NULL;
 -static int nb_meta_data_maps;
 -static int metadata_global_autocopy   = 1;
 -static int metadata_streams_autocopy  = 1;
 -static int metadata_chapters_autocopy = 1;
 -
 -static ChapterMap *chapter_maps = NULL;
 -static int nb_chapter_maps;
 +#define MAX_STREAMS 1024    /* arbitrary sanity check value */
- static AVDictionary *ts_scale;
- static AVDictionary *codec_names;
- /* first item specifies output metadata, second is input */
- static MetadataMap (*meta_data_maps)[2] = NULL;
- static int nb_meta_data_maps;
- static int metadata_global_autocopy   = 1;
- static int metadata_streams_autocopy  = 1;
- static int metadata_chapters_autocopy = 1;
- static int chapters_input_file = INT_MAX;
  
  /* indexed by output file stream index */
  static int *streamid_map = NULL;
@@@ -131,9 -132,8 +119,8 @@@ static int frame_width  = 0
  static int frame_height = 0;
  static float frame_aspect_ratio = 0;
  static enum PixelFormat frame_pix_fmt = PIX_FMT_NONE;
 +static int frame_bits_per_raw_sample = 0;
  static enum AVSampleFormat audio_sample_fmt = AV_SAMPLE_FMT_NONE;
--static int max_frames[4] = {INT_MAX, INT_MAX, INT_MAX, INT_MAX};
  static AVRational frame_rate;
  static float video_qscale = 0;
  static uint16_t *intra_matrix = NULL;
@@@ -175,11 -175,14 +162,7 @@@ 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;
@@@ -197,8 -204,8 +180,6 @@@ static FILE *vstats_file
  static int opt_programid = 0;
  static int copy_initial_nonkeyframes = 0;
  
--static int rate_emu = 0;
--
  static int audio_volume = 256;
  
  static int exit_on_error = 0;
@@@ -223,41 -231,14 +204,37 @@@ static uint8_t *audio_out
  static unsigned int allocated_audio_out_size, allocated_audio_buf_size;
  
  static short *samples;
--
--static AVBitStreamFilterContext *video_bitstream_filters=NULL;
--static AVBitStreamFilterContext *audio_bitstream_filters=NULL;
--static AVBitStreamFilterContext *subtitle_bitstream_filters=NULL;
 +static uint8_t *input_tmp= NULL;
  
  #define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass"
  
 -struct InputStream;
 +typedef struct InputStream {
 +    int file_index;
 +    AVStream *st;
 +    int discard;             /* true if stream data should be discarded */
 +    int decoding_needed;     /* true if the packets must be decoded in 'raw_fifo' */
 +    AVCodec *dec;
 +
 +    int64_t       start;     /* time when read started */
 +    int64_t       next_pts;  /* synthetic pts for cases where pkt.pts
 +                                is not defined */
 +    int64_t       pts;       /* current pts */
 +    double ts_scale;
 +    int is_start;            /* is 1 at the start and after a discontinuity */
 +    int showed_multi_packet_warning;
 +    AVDictionary *opts;
 +} InputStream;
 +
 +typedef struct InputFile {
 +    AVFormatContext *ctx;
 +    int eof_reached;      /* true if eof reached */
 +    int ist_index;        /* index of first stream in ist_table */
 +    int buffer_size;      /* current total buffer size */
 +    int64_t ts_offset;
 +    int nb_streams;       /* number of stream that avconv is aware of; may be different
 +                             from ctx.nb_streams if new streams appear during av_read_frame() */
++    int rate_emu;
 +} InputFile;
  
  typedef struct OutputStream {
      int file_index;          /* file index */
      int64_t sync_opts;       /* output frame counter, could be changed to some true timestamp */ //FIXME look at frame_number
      AVBitStreamFilterContext *bitstream_filters;
      AVCodec *enc;
++    int64_t max_frames;
  
      /* video only */
      int video_resample;
@@@ -335,63 -329,6 +313,103 @@@ static int         nb_input_streams = 0
  static InputFile   *input_files   = NULL;
  static int         nb_input_files   = 0;
  
-     o->limit_filesize = UINT64_MAX;
 +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;
++
 +    /* 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;
++
++    SpecifierOpt *metadata;
++    int        nb_metadata;
++    SpecifierOpt *max_frames;
++    int        nb_max_frames;
++    SpecifierOpt *bitstream_filters;
++    int        nb_bitstream_filters;
 +} 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)
@@@ -616,12 -471,17 +634,10 @@@ void exit_program(int ret
          fclose(vstats_file);
      av_free(vstats_filename);
  
 -    av_free(streamid_map);
 -    av_free(stream_maps);
--    av_free(meta_data_maps);
--
      av_freep(&input_streams);
      av_freep(&input_files);
 -
 -    av_free(video_codec_name);
 -    av_free(audio_codec_name);
 -    av_free(subtitle_codec_name);
 -    av_free(data_codec_name);
 +    av_freep(&output_streams);
 +    av_freep(&output_files);
  
      uninit_opts();
      av_free(audio_buf);
@@@ -1236,7 -1149,7 +1252,7 @@@ static void do_video_out(AVFormatContex
      }else
          ost->sync_opts= lrintf(sync_ipts);
  
--    nb_frames= FFMIN(nb_frames, max_frames[AVMEDIA_TYPE_VIDEO] - ost->frame_number);
++    nb_frames = FFMIN(nb_frames, ost->max_frames - ost->frame_number);
      if (nb_frames <= 0)
          return;
  
@@@ -1766,7 -1630,7 +1782,7 @@@ static int output_packet(InputStream *i
          }
  
          /* frame rate emulation */
--        if (rate_emu) {
++        if (input_files[ist->file_index].rate_emu) {
              int64_t pts = av_rescale(ist->pts, 1000000, AV_TIME_BASE);
              int64_t now = av_gettime() - ist->start;
              if (pts > now)
@@@ -1936,60 -1856,212 +1952,64 @@@ static void print_sdp(OutputFile *outpu
      av_sdp_create(avc, n, sdp, sizeof(sdp));
      printf("SDP:\n%s\n", sdp);
      fflush(stdout);
 +    av_freep(&avc);
  }
  
 -static int copy_chapters(int infile, int outfile)
 +static int init_input_stream(int ist_index, OutputStream *output_streams, int nb_output_streams,
 +                             char *error, int error_len)
  {
 -    AVFormatContext *is = input_files[infile].ctx;
 -    AVFormatContext *os = output_files[outfile];
 -    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(start_time - input_files[infile].ts_offset,
 -                                      AV_TIME_BASE_Q, in_ch->time_base);
 -        int64_t rt       = (recording_time == INT64_MAX) ? INT64_MAX :
 -                           av_rescale_q(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 (metadata_chapters_autocopy)
 -            av_dict_copy(&out_ch->metadata, in_ch->metadata, 0);
 -
 -        os->nb_chapters++;
 -        os->chapters = av_realloc(os->chapters, sizeof(AVChapter)*os->nb_chapters);
 -        if (!os->chapters)
 -            return AVERROR(ENOMEM);
 -        os->chapters[os->nb_chapters - 1] = out_ch;
 +    InputStream *ist = &input_streams[ist_index];
 +    if (ist->decoding_needed) {
 +        AVCodec *codec = ist->dec;
 +        if (!codec) {
 +            snprintf(error, error_len, "Decoder (codec %s) not found for input stream #%d.%d",
 +                    avcodec_get_name(ist->st->codec->codec_id), ist->file_index, ist->st->index);
 +            return AVERROR(EINVAL);
 +        }
 +        if (avcodec_open2(ist->st->codec, codec, &ist->opts) < 0) {
 +            snprintf(error, error_len, "Error while opening decoder for input stream #%d.%d",
 +                    ist->file_index, ist->st->index);
 +            return AVERROR(EINVAL);
 +        }
 +        assert_codec_experimental(ist->st->codec, 0);
 +        assert_avoptions(ist->opts);
      }
 -    return 0;
 -}
  
 -static void parse_forced_key_frames(char *kf, OutputStream *ost,
 -                                    AVCodecContext *avctx)
 -{
 -    char *p;
 -    int n = 1, i;
 -    int64_t t;
 +    ist->pts = ist->st->avg_frame_rate.num ? - ist->st->codec->has_b_frames*AV_TIME_BASE / av_q2d(ist->st->avg_frame_rate) : 0;
 +    ist->next_pts = AV_NOPTS_VALUE;
 +    ist->is_start = 1;
  
 -    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);
 -    }
 +    return 0;
  }
  
 -/*
 - * The following code is the main loop of the file converter
 - */
 -static int transcode(AVFormatContext **output_files,
 -                     int nb_output_files,
 -                     InputFile *input_files,
 -                     int nb_input_files,
 -                     StreamMap *stream_maps, int nb_stream_maps)
 +static int transcode_init(OutputFile *output_files,
 +                          int nb_output_files,
 +                          InputFile *input_files,
 +                          int nb_input_files)
  {
-     int ret = 0, i;
 -    int ret = 0, i, j, k, n, nb_ostreams = 0;
 -    AVFormatContext *is, *os;
++    int ret = 0, i, j;
 +    AVFormatContext *os;
      AVCodecContext *codec, *icodec;
 -    OutputStream *ost, **ost_table = NULL;
 +    OutputStream *ost;
      InputStream *ist;
      char error[1024];
      int want_sdp = 1;
 -    uint8_t no_packet[MAX_FILES]={0};
 -    int no_packet_count=0;
  
--    if (rate_emu)
--        for (i = 0; i < nb_input_streams; i++)
--            input_streams[i].start = av_gettime();
++    /* init framerate emulation */
++    for (i = 0; i < nb_input_files; i++) {
++        InputFile *ifile = &input_files[i];
++        if (ifile->rate_emu)
++            for (j = 0; j < ifile->nb_streams; j++)
++                input_streams[j + ifile->ist_index].start = av_gettime();
++    }
  
      /* output stream init */
 -    nb_ostreams = 0;
      for(i=0;i<nb_output_files;i++) {
 -        os = output_files[i];
 +        os = output_files[i].ctx;
          if (!os->nb_streams && !(os->oformat->flags & AVFMT_NOSTREAMS)) {
 -            av_dump_format(output_files[i], i, output_files[i]->filename, 1);
 +            av_dump_format(os, i, os->filename, 1);
              fprintf(stderr, "Output file #%d does not contain any stream\n", i);
 -            ret = AVERROR(EINVAL);
 -            goto fail;
 -        }
 -        nb_ostreams += os->nb_streams;
 -    }
 -    if (nb_stream_maps > 0 && nb_stream_maps != nb_ostreams) {
 -        fprintf(stderr, "Number of stream maps must match number of output streams\n");
 -        ret = AVERROR(EINVAL);
 -        goto fail;
 -    }
 -
 -    /* Sanity check the mapping args -- do the input files & streams exist? */
 -    for(i=0;i<nb_stream_maps;i++) {
 -        int fi = stream_maps[i].file_index;
 -        int si = stream_maps[i].stream_index;
 -
 -        if (fi < 0 || fi > nb_input_files - 1 ||
 -            si < 0 || si > input_files[fi].ctx->nb_streams - 1) {
 -            fprintf(stderr,"Could not find input stream #%d.%d\n", fi, si);
 -            ret = AVERROR(EINVAL);
 -            goto fail;
 -        }
 -        fi = stream_maps[i].sync_file_index;
 -        si = stream_maps[i].sync_stream_index;
 -        if (fi < 0 || fi > nb_input_files - 1 ||
 -            si < 0 || si > input_files[fi].ctx->nb_streams - 1) {
 -            fprintf(stderr,"Could not find sync stream #%d.%d\n", fi, si);
 -            ret = AVERROR(EINVAL);
 -            goto fail;
 -        }
 -    }
 -
 -    ost_table = av_mallocz(sizeof(OutputStream *) * nb_ostreams);
 -    if (!ost_table)
 -        goto fail;
 -    n = 0;
 -    for(k=0;k<nb_output_files;k++) {
 -        os = output_files[k];
 -        for(i=0;i<os->nb_streams;i++,n++) {
 -            int found;
 -            ost = ost_table[n] = output_streams_for_file[k][i];
 -            if (nb_stream_maps > 0) {
 -                ost->source_index = input_files[stream_maps[n].file_index].ist_index +
 -                    stream_maps[n].stream_index;
 -
 -                /* Sanity check that the stream types match */
 -                if (input_streams[ost->source_index].st->codec->codec_type != ost->st->codec->codec_type) {
 -                    int i= ost->file_index;
 -                    av_dump_format(output_files[i], i, output_files[i]->filename, 1);
 -                    fprintf(stderr, "Codec type mismatch for mapping #%d.%d -> #%d.%d\n",
 -                        stream_maps[n].file_index, stream_maps[n].stream_index,
 -                        ost->file_index, ost->index);
 -                    exit_program(1);
 -                }
 -
 -            } else {
 -                int best_nb_frames=-1;
 -                /* get corresponding input stream index : we select the first one with the right type */
 -                found = 0;
 -                for (j = 0; j < nb_input_streams; j++) {
 -                    int skip=0;
 -                    ist = &input_streams[j];
 -                    if(opt_programid){
 -                        int pi,si;
 -                        AVFormatContext *f = input_files[ist->file_index].ctx;
 -                        skip=1;
 -                        for(pi=0; pi<f->nb_programs; pi++){
 -                            AVProgram *p= f->programs[pi];
 -                            if(p->id == opt_programid)
 -                                for(si=0; si<p->nb_stream_indexes; si++){
 -                                    if(f->streams[ p->stream_index[si] ] == ist->st)
 -                                        skip=0;
 -                                }
 -                        }
 -                    }
 -                    if (ist->discard && ist->st->discard != AVDISCARD_ALL && !skip &&
 -                        ist->st->codec->codec_type == ost->st->codec->codec_type) {
 -                        if(best_nb_frames < ist->st->codec_info_nb_frames){
 -                            best_nb_frames= ist->st->codec_info_nb_frames;
 -                            ost->source_index = j;
 -                            found = 1;
 -                        }
 -                    }
 -                }
 -
 -                if (!found) {
 -                    if(! opt_programid) {
 -                        /* try again and reuse existing stream */
 -                        for (j = 0; j < nb_input_streams; j++) {
 -                            ist = &input_streams[j];
 -                            if (   ist->st->codec->codec_type == ost->st->codec->codec_type
 -                                && ist->st->discard != AVDISCARD_ALL) {
 -                                ost->source_index = j;
 -                                found = 1;
 -                            }
 -                        }
 -                    }
 -                    if (!found) {
 -                        int i= ost->file_index;
 -                        av_dump_format(output_files[i], i, output_files[i]->filename, 1);
 -                        fprintf(stderr, "Could not find input stream matching output stream #%d.%d\n",
 -                                ost->file_index, ost->index);
 -                        exit_program(1);
 -                    }
 -                }
 -            }
 -            ist = &input_streams[ost->source_index];
 -            ist->discard = 0;
 -            ost->sync_ist = (nb_stream_maps > 0) ?
 -                &input_streams[input_files[stream_maps[n].sync_file_index].ist_index +
 -                         stream_maps[n].sync_stream_index] : ist;
 +            return AVERROR(EINVAL);
          }
      }
  
@@@ -2465,9 -2555,9 +2485,11 @@@ static int transcode(OutputFile *output
                      if(!input_sync) file_index = ist->file_index;
                  }
              }
--            if(ost->frame_number >= max_frames[ost->st->codec->codec_type]){
--                file_index= -1;
--                break;
++            if (ost->frame_number >= ost->max_frames) {
++                int j;
++                for (j = of->ost_index; j < of->ctx->nb_streams; j++)
++                    output_streams[j].is_past_recording_time = 1;
++                continue;
              }
          }
          /* if none, if is finished */
          if (pkt.pts != AV_NOPTS_VALUE)
              pkt.pts += av_rescale_q(input_files[ist->file_index].ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
  
--        if (ist->ts_scale) {
--            if(pkt.pts != AV_NOPTS_VALUE)
--                pkt.pts *= ist->ts_scale;
--            if(pkt.dts != AV_NOPTS_VALUE)
--                pkt.dts *= ist->ts_scale;
--        }
++        if(pkt.pts != AV_NOPTS_VALUE)
++            pkt.pts *= ist->ts_scale;
++        if(pkt.dts != AV_NOPTS_VALUE)
++            pkt.dts *= ist->ts_scale;
  
  //        fprintf(stderr, "next:%"PRId64" dts:%"PRId64" off:%"PRId64" %d\n", ist->next_pts, pkt.dts, input_files[ist->file_index].ts_offset, ist->st->codec->codec_type);
          if (pkt.dts != AV_NOPTS_VALUE && ist->next_pts != AV_NOPTS_VALUE
@@@ -2725,21 -2829,21 +2745,6 @@@ static int opt_frame_aspect_ratio(cons
      return 0;
  }
  
--static int opt_metadata(const char *opt, const char *arg)
--{
--    char *mid= strchr(arg, '=');
--
--    if(!mid){
--        fprintf(stderr, "Missing =\n");
--        exit_program(1);
--    }
--    *mid++= 0;
--
--    av_dict_set(&metadata, arg, mid, 0);
--
--    return 0;
--}
--
  static int opt_qscale(const char *opt, const char *arg)
  {
      video_qscale = parse_number_or_die(opt, arg, OPT_FLOAT, 0, 255);
@@@ -2805,38 -2910,40 +2810,30 @@@ static int opt_video_channel(const cha
  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_codec(const char *opt, const char *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)
  {
-     switch(opt[strlen(opt)-1]){
-     case 'a':    audio_codec_name = arg; break;
-     case 'v':    video_codec_name = arg; break;
-     case 's': subtitle_codec_name = arg; break;
-     }
-     return av_dict_set(&codec_names, opt, arg, 0);
 -    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_audio_codec(const char *opt, const char *arg)
 -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("codec:a", 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_video_codec(const char *opt, const char *arg)
 -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("codec:v", 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_subtitle_codec(const char *opt, const char *arg)
 -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("codec:s", arg);
- }
- static int opt_data_codec(const char *opt, const char *arg)
- {
-     return opt_codec("codec:d", 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)
@@@ -2939,10 -2990,11 +2936,10 @@@ static int opt_map(OptionsContext *o, c
      return 0;
  }
  
 -static void parse_meta_type(char *arg, char *type, int *index, char **endptr)
 +static void parse_meta_type(char *arg, char *type, int *index)
  {
-     if (*arg == ':') {
 -    *endptr = arg;
 -    if (*arg == ',') {
--        *type = *(++arg);
++    if (*arg) {
++        *type = *arg;
          switch (*arg) {
          case 'g':
              break;
          *type = 'g';
  }
  
--static int opt_map_metadata(const char *opt, const char *arg)
++static int opt_map_metadata(OptionsContext *o, const char *opt, const char *arg)
  {
      MetadataMap *m, *m1;
      char *p;
  
--    meta_data_maps = grow_array(meta_data_maps, sizeof(*meta_data_maps),
--                                &nb_meta_data_maps, nb_meta_data_maps + 1);
++    o->meta_data_maps = grow_array(o->meta_data_maps, sizeof(*o->meta_data_maps),
++                                   &o->nb_meta_data_maps, o->nb_meta_data_maps + 1);
  
-     m = &meta_data_maps[nb_meta_data_maps - 1][1];
 -    m = &meta_data_maps[nb_meta_data_maps - 1][0];
++    m = &o->meta_data_maps[o->nb_meta_data_maps - 1][1];
      m->file = strtol(arg, &p, 0);
-     parse_meta_type(p, &m->type, &m->index);
 -    parse_meta_type(p, &m->type, &m->index, &p);
 -    if (*p)
 -        p++;
++    parse_meta_type(*p ? p + 1 : p, &m->type, &m->index);
  
-     m1 = &meta_data_maps[nb_meta_data_maps - 1][0];
 -    m1 = &meta_data_maps[nb_meta_data_maps - 1][1];
 -    m1->file = strtol(p, &p, 0);
 -    parse_meta_type(p, &m1->type, &m1->index, &p);
++    m1 = &o->meta_data_maps[o->nb_meta_data_maps - 1][0];
 +    if (p = strchr(opt, ':'))
-         parse_meta_type(p, &m1->type, &m1->index);
++        parse_meta_type(p + 1, &m1->type, &m1->index);
 +    else
 +        m1->type = 'g';
  
      if (m->type == 'g' || m1->type == 'g')
--        metadata_global_autocopy = 0;
++        o->metadata_global_manual = 1;
      if (m->type == 's' || m1->type == 's')
--        metadata_streams_autocopy = 0;
++        o->metadata_streams_manual = 1;
      if (m->type == 'c' || m1->type == 'c')
--        metadata_chapters_autocopy = 0;
++        o->metadata_chapters_manual = 1;
  
      return 0;
  }
  
--static int opt_map_meta_data(const char *opt, const char *arg)
++static int opt_map_meta_data(OptionsContext *o, const char *opt, const char *arg)
  {
      fprintf(stderr, "-map_meta_data is deprecated and will be removed soon. "
                      "Use -map_metadata instead.\n");
--    return opt_map_metadata(opt, arg);
 -}
 -
 -static int opt_map_chapters(const char *opt, const char *arg)
 -{
 -    ChapterMap *c;
 -    char *p;
 -
 -    chapter_maps = grow_array(chapter_maps, sizeof(*chapter_maps), &nb_chapter_maps,
 -                              nb_chapter_maps + 1);
 -    c = &chapter_maps[nb_chapter_maps - 1];
 -    c->out_file = strtol(arg, &p, 0);
 -    if (*p)
 -        p++;
 -
 -    c->in_file = strtol(p, &p, 0);
 -    return 0;
--}
--
--static int opt_input_ts_scale(const char *opt, const char *arg)
--{
-     return av_dict_set(&ts_scale, opt, arg, 0);
 -    unsigned int stream;
 -    double scale;
 -    char *p;
 -
 -    stream = strtol(arg, &p, 0);
 -    if (*p)
 -        p++;
 -    scale= strtod(p, &p);
 -
 -    ts_scale = grow_array(ts_scale, sizeof(*ts_scale), &nb_ts_scale, stream + 1);
 -    ts_scale[stream] = scale;
 -    return 0;
 -}
 -
 -static int opt_recording_time(const char *opt, const char *arg)
 -{
 -    recording_time = parse_time_or_die(opt, arg, 1);
 -    return 0;
 -}
 -
 -static int opt_start_time(const char *opt, const char *arg)
 -{
 -    start_time = parse_time_or_die(opt, arg, 1);
 -    return 0;
++    return opt_map_metadata(o, opt, arg);
  }
  
--static int opt_recording_timestamp(const char *opt, const char *arg)
++static int opt_recording_timestamp(OptionsContext *o, const char *opt, const char *arg)
  {
      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);
--    opt_metadata("metadata", buf);
++    parse_option(o, "metadata", buf, options);
  
      av_log(NULL, AV_LOG_WARNING, "%s is deprecated, set the 'creation_time' metadata "
                                   "tag instead.\n", opt);
@@@ -3034,126 -3130,7 +3026,108 @@@ static enum CodecID find_codec_or_die(c
      return codec->id;
  }
  
- static AVCodec *choose_codec(AVFormatContext *s, AVStream *st, enum AVMediaType type, AVDictionary *codec_names)
 -static int opt_input_file(const char *opt, const char *filename)
++static AVCodec *choose_codec(OptionsContext *o, AVFormatContext *s, AVStream *st, enum AVMediaType type)
 +{
-     AVDictionaryEntry *e = NULL;
 +    char *codec_name = NULL;
-     int ret;
 +
-     while (e = av_dict_get(codec_names, "", e, AV_DICT_IGNORE_SUFFIX)) {
-         char *p = strchr(e->key, ':');
-         if ((ret = check_stream_specifier(s, st, p ? p + 1 : "")) > 0)
-             codec_name = e->value;
-         else if (ret < 0)
-             exit_program(1);
-     }
++    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(AVFormatContext *ic)
++static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
 +{
-     int i, rfps, rfps_base, ret;
++    int i, rfps, rfps_base;
 +
 +    for (i = 0; i < ic->nb_streams; i++) {
 +        AVStream *st = ic->streams[i];
 +        AVCodecContext *dec = st->codec;
-         AVDictionaryEntry *e = NULL;
 +        InputStream *ist;
-         char *scale = NULL;
++        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);
 +
-         while (e = av_dict_get(ts_scale, "", e, AV_DICT_IGNORE_SUFFIX)) {
-             char *p = strchr(e->key, ':');
-             if ((ret = check_stream_specifier(ic, st, p ? p + 1 : "")) > 0)
-                 scale = e->value;
-             else if (ret < 0)
-                 exit_program(1);
-         }
-         if (scale)
-             ist->ts_scale = strtod(scale, NULL);
++        MATCH_PER_STREAM_OPT(ts_scale, dbl, scale, ic, st);
++        ist->ts_scale = scale;
 +
-         ist->dec = choose_codec(ic, st, dec->codec_type, codec_names);
++        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)
 +                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)
 +                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)
 +                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;
          opt_programid=0;
      }
  
 -    if (loop_input) {
 -        av_log(NULL, AV_LOG_WARNING, "-loop_input is deprecated, use -loop 1\n");
 -        ic->loop_input = loop_input;
 -    }
 +    /* apply forced codec ids */
 +    for (i = 0; i < ic->nb_streams; i++)
-         choose_codec(ic, ic->streams[i], ic->streams[i]->codec->codec_type, codec_names);
++        choose_codec(o, ic, ic->streams[i], ic->streams[i]->codec->codec_type);
  
      /* Set AVCodecContext options for avformat_find_stream_info */
      opts = setup_find_stream_info_opts(ic, codec_opts);
      }
  
      /* update the current parameters so that they match the one of the input stream */
-     add_input_streams(ic);
 -    for(i=0;i<ic->nb_streams;i++) {
 -        AVStream *st = ic->streams[i];
 -        AVCodecContext *dec = st->codec;
 -        InputStream *ist;
 -
 -        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);
 -
 -        if (i < nb_ts_scale)
 -            ist->ts_scale = ts_scale[i];
 -
 -        switch (dec->codec_type) {
 -        case AVMEDIA_TYPE_AUDIO:
 -            ist->dec = avcodec_find_decoder_by_name(audio_codec_name);
 -            if(audio_disable)
 -                st->discard= AVDISCARD_ALL;
 -            break;
 -        case AVMEDIA_TYPE_VIDEO:
 -            ist->dec = avcodec_find_decoder_by_name(video_codec_name);
 -            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;
 -                dec->height >>= dec->lowres;
 -                dec->width  >>= dec->lowres;
 -            }
 -            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)
 -                st->discard= AVDISCARD_ALL;
 -            else if(video_discard)
 -                st->discard= video_discard;
 -            break;
 -        case AVMEDIA_TYPE_DATA:
 -            break;
 -        case AVMEDIA_TYPE_SUBTITLE:
 -            ist->dec = avcodec_find_decoder_by_name(subtitle_codec_name);
 -            if(subtitle_disable)
 -                st->discard = AVDISCARD_ALL;
 -            break;
 -        case AVMEDIA_TYPE_ATTACHMENT:
 -        case AVMEDIA_TYPE_UNKNOWN:
 -            break;
 -        default:
 -            abort();
 -        }
 -    }
++    add_input_streams(o, ic);
  
      /* dump the file content */
      if (verbose >= 0)
      audio_sample_rate = 0;
      audio_channels    = 0;
      audio_sample_fmt  = AV_SAMPLE_FMT_NONE;
-     av_dict_free(&ts_scale);
 -    av_freep(&ts_scale);
 -    nb_ts_scale = 0;
  
      for (i = 0; i < orig_nb_streams; i++)
          av_dict_free(&opts[i]);
      av_freep(&opts);
-     av_dict_free(&codec_names);
 -    av_freep(&video_codec_name);
 -    av_freep(&audio_codec_name);
 -    av_freep(&subtitle_codec_name);
 -    uninit_opts();
 -    init_opts();
 +
 +    reset_options(o, 1);
      return 0;
  }
  
 -static void check_inputs(int *has_video_ptr,
 -                         int *has_audio_ptr,
 -                         int *has_subtitle_ptr,
 -                         int *has_data_ptr)
 -{
 -    int has_video, has_audio, has_subtitle, has_data, i, j;
 -    AVFormatContext *ic;
 +static void parse_forced_key_frames(char *kf, OutputStream *ost,
 +                                    AVCodecContext *avctx)
 +{
 +    char *p;
 +    int n = 1, i;
 +    int64_t t;
 +
 +    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);
 +    }
 +}
 +
- static OutputStream *new_output_stream(AVFormatContext *oc, enum AVMediaType type)
++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;
++    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(oc, st, type, codec_names);
++    ost->enc = choose_codec(o, oc, st, type);
 +    if (ost->enc) {
 +        ost->opts  = filter_codec_opts(codec_opts, ost->enc->id, oc, st);
 +    }
  
 -    has_video = 0;
 -    has_audio = 0;
 -    has_subtitle = 0;
 -    has_data = 0;
 +    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
  
 -    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();
 -            }
++    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);
+         }
++        if (bsfc_prev)
++            bsfc_prev->next = bsfc;
++        else
++            ost->bitstream_filters = bsfc;
++
++        bsfc_prev = bsfc;
++        bsf       = next;
+     }
 -    *has_video_ptr = has_video;
 -    *has_audio_ptr = has_audio;
 -    *has_subtitle_ptr = has_subtitle;
 -    *has_data_ptr = has_data;
++
 +    ost->sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
 +    return ost;
  }
  
- static OutputStream *new_video_stream(AVFormatContext *oc)
 -static void new_video_stream(AVFormatContext *oc, int file_idx)
++static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc)
  {
      AVStream *st;
      OutputStream *ost;
      AVCodecContext *video_enc;
 -    enum CodecID codec_id = CODEC_ID_NONE;
 -    AVCodec *codec= NULL;
 -
 -    if(!video_stream_copy){
 -        if (video_codec_name) {
 -            codec_id = find_codec_or_die(video_codec_name, AVMEDIA_TYPE_VIDEO, 1);
 -            codec = avcodec_find_encoder_by_name(video_codec_name);
 -        } else {
 -            codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, AVMEDIA_TYPE_VIDEO);
 -            codec = avcodec_find_encoder(codec_id);
 -        }
 -    }
  
-     ost = new_output_stream(oc, AVMEDIA_TYPE_VIDEO);
 -    ost = new_output_stream(oc, file_idx, codec);
++    ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO);
      st  = ost->st;
 -    if (!video_stream_copy) {
 +    if (!st->stream_copy) {
          ost->frame_aspect_ratio = frame_aspect_ratio;
          frame_aspect_ratio = 0;
  #if CONFIG_AVFILTER
  #endif
      }
  
--    ost->bitstream_filters = video_bitstream_filters;
--    video_bitstream_filters= NULL;
--
      st->codec->thread_count= thread_count;
  
      video_enc = st->codec;
  
      /* 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 OutputStream *new_audio_stream(AVFormatContext *oc)
 -static void new_audio_stream(AVFormatContext *oc, int file_idx)
++static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc)
  {
      AVStream *st;
      OutputStream *ost;
 -    AVCodec *codec= NULL;
      AVCodecContext *audio_enc;
 -    enum CodecID codec_id = CODEC_ID_NONE;
  
-     ost = new_output_stream(oc, AVMEDIA_TYPE_AUDIO);
 -    if(!audio_stream_copy){
 -        if (audio_codec_name) {
 -            codec_id = find_codec_or_die(audio_codec_name, AVMEDIA_TYPE_AUDIO, 1);
 -            codec = avcodec_find_encoder_by_name(audio_codec_name);
 -        } else {
 -            codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, AVMEDIA_TYPE_AUDIO);
 -            codec = avcodec_find_encoder(codec_id);
 -        }
 -    }
 -    ost = new_output_stream(oc, file_idx, codec);
++    ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO);
      st  = ost->st;
  
--    ost->bitstream_filters = audio_bitstream_filters;
--    audio_bitstream_filters= NULL;
--
      st->codec->thread_count= thread_count;
  
      audio_enc = st->codec;
  
      /* reset some key parameters */
      audio_disable = 0;
 -    av_freep(&audio_codec_name);
 -    audio_stream_copy = 0;
 +
 +    return ost;
  }
  
- static OutputStream *new_data_stream(AVFormatContext *oc)
 -static void new_data_stream(AVFormatContext *oc, int file_idx)
++static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc)
  {
      AVStream *st;
      OutputStream *ost;
      AVCodecContext *data_enc;
  
-     ost = new_output_stream(oc, AVMEDIA_TYPE_DATA);
 -    ost = new_output_stream(oc, file_idx, NULL);
++    ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA);
      st  = ost->st;
      data_enc = st->codec;
 -    if (!data_stream_copy) {
 +    if (!st->stream_copy) {
          fprintf(stderr, "Data stream encoding not supported yet (only streamcopy)\n");
          exit_program(1);
      }
      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 OutputStream *new_subtitle_stream(AVFormatContext *oc)
 -static void new_subtitle_stream(AVFormatContext *oc, int file_idx)
++static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc)
  {
      AVStream *st;
      OutputStream *ost;
 -    AVCodec *codec=NULL;
      AVCodecContext *subtitle_enc;
 -    enum CodecID codec_id = CODEC_ID_NONE;
  
-     ost = new_output_stream(oc, AVMEDIA_TYPE_SUBTITLE);
 -    if(!subtitle_stream_copy){
 -        if (subtitle_codec_name) {
 -            codec_id = find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 1);
 -            codec = avcodec_find_encoder_by_name(subtitle_codec_name);
 -        } else {
 -            codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, AVMEDIA_TYPE_SUBTITLE);
 -            codec = avcodec_find_encoder(codec_id);
 -        }
 -    }
 -    ost = new_output_stream(oc, file_idx, codec);
++    ost = new_output_stream(o, oc, AVMEDIA_TYPE_SUBTITLE);
      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)
@@@ -3595,89 -3701,13 +3581,89 @@@ static int opt_streamid(const char *opt
      streamid_map[idx] = parse_number_or_die(opt, p, OPT_INT, 0, INT_MAX);
      return 0;
  }
- static int read_ffserver_streams(AVFormatContext *s, const char *filename)
- {
-     int i, err;
-     AVFormatContext *ic = NULL;
-     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;
-         codec = avcodec_find_encoder(ic->streams[i]->codec->codec_id);
-         ost   = new_output_stream(s, codec->type);
-         st    = ost->st;
-         // FIXME: a more elegant solution is needed
-         memcpy(st, ic->streams[i], sizeof(AVStream));
-         st->info = av_malloc(sizeof(*st->info));
-         memcpy(st->info, ic->streams[i]->info, sizeof(*st->info));
-         avcodec_copy_context(st->codec, ic->streams[i]->codec);
-         if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && !st->stream_copy)
-             choose_sample_fmt(st, codec);
-         else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && !st->stream_copy)
-             choose_pixel_fmt(st, codec);
-     }
-     av_close_input_file(ic);
-     return 0;
- }
  
- static int copy_chapters(InputFile *ifile, OutputFile *ofile)
++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 (metadata_chapters_autocopy)
++        if (copy_metadata)
 +            av_dict_copy(&out_ch->metadata, in_ch->metadata, 0);
 +
 +        os->nb_chapters++;
 +        os->chapters = av_realloc(os->chapters, sizeof(AVChapter)*os->nb_chapters);
 +        if (!os->chapters)
 +            return AVERROR(ENOMEM);
 +        os->chapters[os->nb_chapters - 1] = out_ch;
 +    }
 +    return 0;
 +}
 +
++static int read_ffserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename)
++{
++    int i, err;
++    AVFormatContext *ic = NULL;
++
++    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;
++
++        codec = avcodec_find_encoder(ic->streams[i]->codec->codec_id);
++        ost   = new_output_stream(o, s, codec->type);
++        st    = ost->st;
++
++        // FIXME: a more elegant solution is needed
++        memcpy(st, ic->streams[i], sizeof(AVStream));
++        st->info = av_malloc(sizeof(*st->info));
++        memcpy(st->info, ic->streams[i]->info, sizeof(*st->info));
++        avcodec_copy_context(st->codec, ic->streams[i]->codec);
++
++        if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && !st->stream_copy)
++            choose_sample_fmt(st, codec);
++        else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && !st->stream_copy)
++            choose_pixel_fmt(st, codec);
++    }
++
++    av_close_input_file(ic);
++    return 0;
++}
++
  static void opt_output_file(void *optctx, const char *filename)
  {
 +    OptionsContext *o = optctx;
      AVFormatContext *oc;
 -    int err, use_video, use_audio, use_subtitle, use_data;
 -    int input_has_video, input_has_audio, input_has_subtitle, input_has_data;
 +    int i, err;
      AVOutputFormat *file_oformat;
 +    OutputStream *ost;
 +    InputStream  *ist;
  
      if (!strcmp(filename, "-"))
          filename = "pipe:";
  
      if (!strcmp(file_oformat->name, "ffm") &&
          av_strstart(filename, "http:", NULL)) {
 -        /* special case for files sent to avserver: we get the stream
 -           parameters from avserver */
 -        int err = read_avserver_streams(oc, filename);
 +        /* special case for files sent to ffserver: we get the stream
 +           parameters from ffserver */
-         int err = read_ffserver_streams(oc, filename);
++        int err = read_ffserver_streams(o, oc, filename);
          if (err < 0) {
              print_error(filename, err);
              exit_program(1);
          }
-             ost = new_ ## type ## _stream(oc);\
 +    } 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 (!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 (!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 (!subtitle_disable && oc->oformat->subtitle_codec != CODEC_ID_NONE) {
 +            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(oc);    break;
-             case AVMEDIA_TYPE_AUDIO:    ost = new_audio_stream(oc);    break;
-             case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream(oc); break;
-             case AVMEDIA_TYPE_DATA:     ost = new_data_stream(oc);     break;
++            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(&oc->metadata, metadata, 0);
-     av_dict_free(&metadata);
 -    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) {
          }
      }
  
--    oc->preload= (int)(mux_preload*AV_TIME_BASE);
--    oc->max_delay= (int)(mux_max_delay*AV_TIME_BASE);
++    oc->preload   = (int)(o->mux_preload   * AV_TIME_BASE);
++    oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE);
 +
      if (loop_output >= 0) {
          av_log(NULL, AV_LOG_WARNING, "-loop_output is deprecated, use -loop\n");
          oc->loop_output = loop_output;
      }
 -    oc->flags |= AVFMT_FLAG_NONBLOCK;
 +
 +    /* copy chapters */
-     if (chapters_input_file >= nb_input_files) {
-         if (chapters_input_file == INT_MAX) {
++    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*/
-             chapters_input_file = -1;
++            o->chapters_input_file = -1;
 +            for (i = 0; i < nb_input_files; i++)
 +                if (input_files[i].ctx->nb_chapters) {
-                     chapters_input_file = i;
++                    o->chapters_input_file = i;
 +                    break;
 +                }
 +        } else {
 +            av_log(NULL, AV_LOG_ERROR, "Invalid input file index %d in chapter mapping.\n",
-                    chapters_input_file);
++                   o->chapters_input_file);
 +            exit_program(1);
 +        }
 +    }
-     if (chapters_input_file >= 0)
-         copy_chapters(&input_files[chapters_input_file], &output_files[nb_output_files - 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 metadata */
-     for (i = 0; i < nb_meta_data_maps; i++) {
++    for (i = 0; i < o->nb_meta_data_maps; i++) {
 +        AVFormatContext *files[2];
 +        AVDictionary    **meta[2];
 +        int j;
 +
 +#define METADATA_CHECK_INDEX(index, nb_elems, desc)\
 +        if ((index) < 0 || (index) >= (nb_elems)) {\
 +            av_log(NULL, AV_LOG_ERROR, "Invalid %s index %d while processing metadata maps\n",\
 +                     (desc), (index));\
 +            exit_program(1);\
 +        }
 +
-         int in_file_index = meta_data_maps[i][1].file;
++        int in_file_index = o->meta_data_maps[i][1].file;
 +        if (in_file_index < 0)
 +            continue;
 +        METADATA_CHECK_INDEX(in_file_index, nb_input_files, "input file")
 +
 +        files[0] = oc;
 +        files[1] = input_files[in_file_index].ctx;
 +
 +        for (j = 0; j < 2; j++) {
-             MetadataMap *map = &meta_data_maps[i][j];
++            MetadataMap *map = &o->meta_data_maps[i][j];
 +
 +            switch (map->type) {
 +            case 'g':
 +                meta[j] = &files[j]->metadata;
 +                break;
 +            case 's':
 +                METADATA_CHECK_INDEX(map->index, files[j]->nb_streams, "stream")
 +                meta[j] = &files[j]->streams[map->index]->metadata;
 +                break;
 +            case 'c':
 +                METADATA_CHECK_INDEX(map->index, files[j]->nb_chapters, "chapter")
 +                meta[j] = &files[j]->chapters[map->index]->metadata;
 +                break;
 +            case 'p':
 +                METADATA_CHECK_INDEX(map->index, files[j]->nb_programs, "program")
 +                meta[j] = &files[j]->programs[map->index]->metadata;
 +                break;
 +            }
 +        }
 +
 +        av_dict_copy(meta[0], *meta[1], AV_DICT_DONT_OVERWRITE);
 +    }
 +
 +    /* copy global metadata by default */
-     if (metadata_global_autocopy && nb_input_files)
++    if (!o->metadata_global_manual && nb_input_files)
 +        av_dict_copy(&oc->metadata, input_files[0].ctx->metadata,
 +                     AV_DICT_DONT_OVERWRITE);
-     if (metadata_streams_autocopy)
++    if (!o->metadata_streams_manual)
 +        for (i = output_files[nb_output_files - 1].ost_index; i < nb_output_streams; i++) {
 +            InputStream *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;
++        int index = 0;
++
++        val = strchr(o->metadata[i].u.str, '=');
++        if (!val) {
++            av_log(NULL, AV_LOG_ERROR, "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);
++        switch (type) {
++        case 'g':
++            m = &oc->metadata;
++            break;
++        case 's':
++            if (index < 0 || index >= oc->nb_streams) {
++                av_log(NULL, AV_LOG_ERROR, "Invalid stream index %d in metadata specifier.\n", index);
++                exit_program(1);
++            }
++            m = &oc->streams[i]->metadata;
++            break;
++        case 'c':
++            if (index < 0 || index >= oc->nb_chapters) {
++                av_log(NULL, AV_LOG_ERROR, "Invalid chapter index %d in metadata specifier.\n", index);
++                exit_program(1);
++            }
++            m = &oc->chapters[i]->metadata;
++            break;
++        default:
++            av_log(NULL, AV_LOG_ERROR, "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);
++    }
      frame_rate    = (AVRational){0, 0};
      frame_width   = 0;
      frame_height  = 0;
      audio_sample_rate = 0;
      audio_channels    = 0;
      audio_sample_fmt  = AV_SAMPLE_FMT_NONE;
-     chapters_input_file = INT_MAX;
  
-     av_freep(&meta_data_maps);
-     nb_meta_data_maps = 0;
-     metadata_global_autocopy   = 1;
-     metadata_streams_autocopy  = 1;
-     metadata_chapters_autocopy = 1;
 +    av_freep(&streamid_map);
 +    nb_streamid_map = 0;
 +
-     av_dict_free(&codec_names);
      av_freep(&forced_key_frames);
 -    uninit_opts();
 -    init_opts();
 +    reset_options(o, 0);
  }
  
  /* same option as mencoder */
@@@ -4134,9 -4048,9 +4150,9 @@@ static int opt_target(OptionsContext *o
      }
  
      if(!strcmp(arg, "vcd")) {
-         opt_codec("c:v", "mpeg1video");
-         opt_codec("c:a", "mp2");
 -        opt_video_codec("vcodec", "mpeg1video");
 -        opt_audio_codec("vcodec", "mp2");
 -        opt_format("f", "vcd");
++        opt_video_codec(o, "c:v", "mpeg1video");
++        opt_audio_codec(o, "c:a", "mp2");
 +        parse_option(o, "f", "vcd", options);
  
          opt_frame_size("s", norm == PAL ? "352x288" : "352x240");
          opt_frame_rate("r", frame_rates[norm]);
             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. */
--        mux_preload= (36000+3*1200) / 90000.0; //0.44
++        o->mux_preload = (36000+3*1200) / 90000.0; //0.44
      } else if(!strcmp(arg, "svcd")) {
  
-         opt_codec("c:v", "mpeg2video");
-         opt_codec("c:a", "mp2");
 -        opt_video_codec("vcodec", "mpeg2video");
 -        opt_audio_codec("acodec", "mp2");
 -        opt_format("f", "svcd");
++        opt_video_codec(o, "c:v", "mpeg2video");
++        opt_audio_codec(o, "c:a", "mp2");
 +        parse_option(o, "f", "svcd", options);
  
          opt_frame_size("s", norm == PAL ? "480x576" : "480x480");
          opt_frame_rate("r", frame_rates[norm]);
  
      } else if(!strcmp(arg, "dvd")) {
  
-         opt_codec("c:v", "mpeg2video");
-         opt_codec("c:a", "ac3");
 -        opt_video_codec("vcodec", "mpeg2video");
 -        opt_audio_codec("vcodec", "ac3");
 -        opt_format("f", "dvd");
++        opt_video_codec(o, "c:v", "mpeg2video");
++        opt_audio_codec(o, "c:a", "ac3");
 +        parse_option(o, "f", "dvd", options);
  
          opt_frame_size("vcodec", norm == PAL ? "720x576" : "720x480");
          opt_frame_rate("r", frame_rates[norm]);
@@@ -4242,28 -4154,28 +4258,22 @@@ static int opt_vstats(const char *opt, 
      return opt_vstats_file(opt, filename);
  }
  
--static int opt_bsf(const char *opt, const char *arg)
++static int opt_video_frames(OptionsContext *o, const char *opt, const char *arg)
  {
--    AVBitStreamFilterContext *bsfc= av_bitstream_filter_init(arg); //FIXME split name and args for filter at '='
--    AVBitStreamFilterContext **bsfp;
--
--    if(!bsfc){
--        fprintf(stderr, "Unknown bitstream filter %s\n", arg);
--        exit_program(1);
--    }
--
--    bsfp= *opt == 'v' ? &video_bitstream_filters :
--          *opt == 'a' ? &audio_bitstream_filters :
--                        &subtitle_bitstream_filters;
--    while(*bsfp)
--        bsfp= &(*bsfp)->next;
++    return parse_option(o, "frames:v", arg, options);
++}
  
--    *bsfp= bsfc;
++static int opt_audio_frames(OptionsContext *o, const char *opt, const char *arg)
++{
++    return parse_option(o, "frames:a", arg, options);
++}
  
--    return 0;
++static int opt_data_frames(OptionsContext *o, const char *opt, const char *arg)
++{
++    return parse_option(o, "frames:d", arg, options);
  }
  
--static int opt_preset(const char *opt, const char *arg)
++static int opt_preset(OptionsContext *o, const char *opt, const char *arg)
  {
      FILE *f=NULL;
      char filename[1000], tmp[1000], tmp2[1000], line[1000];
              exit_program(1);
          }
          if(!strcmp(tmp, "acodec")){
--            opt_audio_codec(tmp, tmp2);
++            opt_audio_codec(o, tmp, tmp2);
          }else if(!strcmp(tmp, "vcodec")){
--            opt_video_codec(tmp, tmp2);
++            opt_video_codec(o, tmp, tmp2);
          }else if(!strcmp(tmp, "scodec")){
--            opt_subtitle_codec(tmp, tmp2);
++            opt_subtitle_codec(o, tmp, tmp2);
          }else if(!strcmp(tmp, "dcodec")){
--            opt_data_codec(tmp, tmp2);
++            opt_data_codec(o, tmp, tmp2);
          }else if(opt_default(tmp, tmp2) < 0){
              fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
              exit_program(1);
@@@ -4322,25 -4219,23 +4332,25 @@@ static int opt_passlogfile(const char *
  static const OptionDef options[] = {
      /* main options */
  #include "cmdutils_common_opts.h"
 -    { "f", HAS_ARG, {(void*)opt_format}, "force format", "fmt" },
 -    { "i", HAS_ARG, {(void*)opt_input_file}, "input file name", "filename" },
 +    { "f", HAS_ARG | OPT_STRING | OPT_OFFSET, {.off = OFFSET(format)}, "force format", "fmt" },
 +    { "i", HAS_ARG | OPT_FUNC2, {(void*)opt_input_file}, "input file name", "filename" },
      { "y", OPT_BOOL, {(void*)&file_overwrite}, "overwrite output files" },
-     { "c", HAS_ARG, {(void*)opt_codec}, "codec name", "codec" },
-     { "codec", HAS_ARG, {(void*)opt_codec}, "codec name", "codec" },
 -    { "map", HAS_ARG | OPT_EXPERT, {(void*)opt_map}, "set input stream mapping", "file.stream[:syncfile.syncstream]" },
 -    { "map_meta_data", HAS_ARG | OPT_EXPERT, {(void*)opt_map_meta_data}, "DEPRECATED set meta data information of outfile from infile",
++    { "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" },
 +    { "map", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map}, "set input stream mapping", "file.stream[:syncfile.syncstream]" },
-     { "map_meta_data", HAS_ARG | OPT_EXPERT, {(void*)opt_map_meta_data}, "DEPRECATED set meta data information of outfile from infile",
++    { "map_meta_data", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map_meta_data}, "DEPRECATED set meta data information of outfile from infile",
        "outfile[,metadata]:infile[,metadata]" },
--    { "map_metadata", HAS_ARG | OPT_EXPERT, {(void*)opt_map_metadata}, "set metadata information of outfile from infile",
++    { "map_metadata", HAS_ARG | OPT_EXPERT | OPT_FUNC2, {(void*)opt_map_metadata}, "set metadata information of outfile from infile",
        "outfile[,metadata]:infile[,metadata]" },
-     { "map_chapters",  OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&chapters_input_file},  "set chapters mapping", "input_file_index" },
 -    { "map_chapters",  HAS_ARG | OPT_EXPERT, {(void*)opt_map_chapters},  "set chapters mapping", "outfile:infile" },
 -    { "t", HAS_ARG, {(void*)opt_recording_time}, "record or transcode \"duration\" seconds of audio/video", "duration" },
 -    { "fs", HAS_ARG | OPT_INT64, {(void*)&limit_filesize}, "set the limit file size in bytes", "limit_size" }, //
 -    { "ss", HAS_ARG, {(void*)opt_start_time}, "set the start time offset", "time_off" },
 -    { "itsoffset", HAS_ARG, {(void*)opt_input_ts_offset}, "set the input ts offset", "time_off" },
 -    { "itsscale", HAS_ARG, {(void*)opt_input_ts_scale}, "set the input ts scale", "stream:scale" },
 -    { "timestamp", HAS_ARG, {(void*)opt_recording_timestamp}, "set the recording timestamp ('now' to set the current time)", "time" },
 -    { "metadata", HAS_ARG, {(void*)opt_metadata}, "add metadata", "string=string" },
 -    { "dframes", OPT_INT | HAS_ARG, {(void*)&max_frames[AVMEDIA_TYPE_DATA]}, "set the number of data frames to record", "number" },
++    { "map_chapters",  OPT_INT | HAS_ARG | 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" },
 +    { "itsoffset", HAS_ARG | OPT_TIME | OPT_OFFSET, {.off = OFFSET(input_ts_offset)}, "set the input ts offset", "time_off" },
-     { "itsscale", HAS_ARG, {(void*)opt_input_ts_scale}, "set the input ts scale", "scale" },
-     { "timestamp", HAS_ARG, {(void*)opt_recording_timestamp}, "set the recording timestamp ('now' to set the current time)", "time" },
-     { "metadata", HAS_ARG, {(void*)opt_metadata}, "add metadata", "string=string" },
-     { "dframes", OPT_INT | HAS_ARG, {(void*)&max_frames[AVMEDIA_TYPE_DATA]}, "set the number of data frames to record", "number" },
++    { "itsscale", HAS_ARG | OPT_DOUBLE | OPT_SPEC, {.off = OFFSET(ts_scale)}, "set the input ts scale", "scale" },
++    { "timestamp", HAS_ARG | OPT_FUNC2, {(void*)opt_recording_timestamp}, "set the recording timestamp ('now' to set the current time)", "time" },
++    { "metadata", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(metadata)}, "add metadata", "string=string" },
++    { "dframes", HAS_ARG | OPT_FUNC2, {(void*)opt_data_frames}, "set the number of data frames to record", "number" },
      { "benchmark", OPT_BOOL | OPT_EXPERT, {(void*)&do_benchmark},
        "add timings for benchmarking" },
      { "timelimit", HAS_ARG, {(void*)opt_timelimit}, "set max runtime in seconds", "limit" },
        "dump each input packet" },
      { "hex", OPT_BOOL | OPT_EXPERT, {(void*)&do_hex_dump},
        "when dumping packets, also dump the payload" },
--    { "re", OPT_BOOL | OPT_EXPERT, {(void*)&rate_emu}, "read input at native frame rate", "" },
++    { "re", OPT_BOOL | OPT_EXPERT | OPT_OFFSET, {.off = OFFSET(rate_emu)}, "read input at native frame rate", "" },
      { "loop_input", OPT_BOOL | OPT_EXPERT, {(void*)&loop_input}, "deprecated, use -loop" },
      { "loop_output", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&loop_output}, "deprecated, use -loop", "" },
 -    { "v", HAS_ARG, {(void*)opt_verbose}, "set ffmpeg verbosity level", "number" },
 -    { "target", HAS_ARG, {(void*)opt_target}, "specify target file type (\"vcd\", \"svcd\", \"dvd\", \"dv\", \"dv50\", \"pal-vcd\", \"ntsc-svcd\", ...)", "type" },
 +    { "v", HAS_ARG, {(void*)opt_verbose}, "set the verbosity level", "number" },
 +    { "target", HAS_ARG | OPT_FUNC2, {(void*)opt_target}, "specify target file type (\"vcd\", \"svcd\", \"dvd\", \"dv\", \"dv50\", \"pal-vcd\", \"ntsc-svcd\", ...)", "type" },
      { "threads",  HAS_ARG | OPT_EXPERT, {(void*)opt_thread_count}, "thread count", "count" },
      { "vsync", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&video_sync_method}, "video sync method", "" },
      { "async", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&audio_sync_method}, "audio sync method", "" },
      { "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" },
  
      /* 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" },
      { "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" },
--    { "vcodec", HAS_ARG | OPT_VIDEO, {(void*)opt_video_codec}, "force video codec ('copy' to copy stream)", "codec" },
 -    { "me_threshold", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_me_threshold}, "motion estimaton threshold",  "threshold" },
 -    { "sameq", OPT_BOOL | OPT_VIDEO, {(void*)&same_quality},
 -      "use same quantizer as source (implies VBR)" },
++    { "vcodec", HAS_ARG | OPT_VIDEO | OPT_FUNC2, {(void*)opt_video_codec}, "force video codec ('copy' to copy stream)", "codec" },
 +    { "me_threshold", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_me_threshold}, "motion estimation threshold",  "threshold" },
 +    { "sameq", OPT_BOOL | OPT_VIDEO, {(void*)&same_quant}, "use same quantizer as source (implies VBR)" },
 +    { "same_quant", OPT_BOOL | OPT_VIDEO, {(void*)&same_quant}, "use same quantizer as source (implies VBR)" },
      { "pass", HAS_ARG | OPT_VIDEO, {(void*)opt_pass}, "select the pass number (1 or 2)", "n" },
 -    { "passlogfile", HAS_ARG | OPT_STRING | OPT_VIDEO, {(void*)&pass_logfilename_prefix}, "select two pass log file name prefix", "prefix" },
 +    { "passlogfile", HAS_ARG | OPT_VIDEO, {(void*)&opt_passlogfile}, "select two pass log file name prefix", "prefix" },
      { "deinterlace", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&do_deinterlace},
        "deinterlace pictures" },
      { "psnr", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&do_psnr}, "calculate PSNR of compressed frames" },
      { "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" },
++    { "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" },
      { "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" },
++    { "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" },
  
      { "isync", OPT_BOOL | OPT_EXPERT | OPT_GRAB, {(void*)&input_sync}, "sync read on input", "" },
  
      /* muxer options */
--    { "muxdelay", OPT_FLOAT | HAS_ARG | OPT_EXPERT, {(void*)&mux_max_delay}, "set the maximum demux-decode delay", "seconds" },
--    { "muxpreload", OPT_FLOAT | HAS_ARG | OPT_EXPERT, {(void*)&mux_preload}, "set the initial demux-decode delay", "seconds" },
++    { "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" },
  
--    { "absf", HAS_ARG | OPT_AUDIO | OPT_EXPERT, {(void*)opt_bsf}, "", "bitstream_filter" },
--    { "vbsf", HAS_ARG | OPT_VIDEO | OPT_EXPERT, {(void*)opt_bsf}, "", "bitstream_filter" },
--    { "sbsf", HAS_ARG | OPT_SUBTITLE | OPT_EXPERT, {(void*)opt_bsf}, "", "bitstream_filter" },
++    { "bsf", HAS_ARG | OPT_STRING | OPT_SPEC, {.off = OFFSET(bitstream_filters)}, "A comma-separated list of bitstream filters", "bitstream_filters" },
  
--    { "apre", HAS_ARG | OPT_AUDIO | OPT_EXPERT, {(void*)opt_preset}, "set the audio options to the indicated preset", "preset" },
--    { "vpre", HAS_ARG | OPT_VIDEO | OPT_EXPERT, {(void*)opt_preset}, "set the video options to the indicated preset", "preset" },
--    { "spre", HAS_ARG | OPT_SUBTITLE | OPT_EXPERT, {(void*)opt_preset}, "set the subtitle options to the indicated preset", "preset" },
--    { "fpre", HAS_ARG | OPT_EXPERT, {(void*)opt_preset}, "set options from indicated preset file", "filename" },
++    { "apre", HAS_ARG | OPT_AUDIO | OPT_EXPERT| OPT_FUNC2, {(void*)opt_preset}, "set the audio options to the indicated preset", "preset" },
++    { "vpre", HAS_ARG | OPT_VIDEO | OPT_EXPERT| OPT_FUNC2, {(void*)opt_preset}, "set the video options to the indicated preset", "preset" },
++    { "spre", HAS_ARG | OPT_SUBTITLE | OPT_EXPERT| OPT_FUNC2, {(void*)opt_preset}, "set the subtitle options to the indicated preset", "preset" },
++    { "fpre", HAS_ARG | OPT_EXPERT| OPT_FUNC2, {(void*)opt_preset}, "set options from indicated preset file", "filename" },
      /* data codec support */
--    { "dcodec", HAS_ARG | OPT_DATA, {(void*)opt_data_codec}, "force data codec ('copy' to copy stream)", "codec" },
++    { "dcodec", HAS_ARG | OPT_DATA | OPT_FUNC2, {(void*)opt_data_codec}, "force data codec ('copy' to copy stream)", "codec" },
  
      { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {(void*)opt_default}, "generic catch all option", "" },
      { NULL, },
Simple merge
Simple merge
Simple merge
@@@ -2501,12 -2464,10 +2501,10 @@@ static int decode_chunks(AVCodecContex
                  }
                  if(!s2->current_picture_ptr){
                      av_log(avctx, AV_LOG_ERROR, "current_picture not initialized\n");
-                     if (avctx->error_recognition >= FF_ER_EXPLODE)
-                         return AVERROR_INVALIDDATA;
-                     return -1;
+                     return AVERROR_INVALIDDATA;
                  }
  
 -                if (avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU) {
 +                if (uses_vdpau(avctx)) {
                      s->slice_count++;
                      break;
                  }
Simple merge
@@@ -16,8 -16,7 +16,8 @@@ cmp=${6:-diff
  ref=${7:-"${base}/ref/fate/${test}"}
  fuzz=$8
  threads=${9:-1}
- thread_type=${10:-3}
+ thread_type=${10:-frame+slice}
 +tool=${11}
  
  outdir="tests/data/fate"
  outfile="${outdir}/${test}"
Simple merge