diff --git a/avconv.c b/avconv.c
index 3d7cf7562b9f6ac65daf573987ae5db361983752..f0ee2ba3b68ebb6b68a6b5a850c02c7a71b66e79 100644
--- a/avconv.c
+++ b/avconv.c
@@ -110,18 +110,6 @@ typedef struct MetadataMap {
 static const OptionDef options[];
 
 #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;
@@ -133,7 +121,6 @@ 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;
@@ -168,11 +155,7 @@ static unsigned int subtitle_codec_tag = 0;
 static int data_disable = 0;
 static unsigned int data_codec_tag = 0;
 
-static float mux_preload= 0.5;
-static float mux_max_delay= 0.7;
-
 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;
@@ -190,8 +173,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;
@@ -216,10 +197,6 @@ 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;
-
 #define DEFAULT_PASS_LOGFILENAME_PREFIX "av2pass"
 
 typedef struct InputStream {
@@ -247,6 +224,7 @@ typedef struct InputFile {
     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 {
@@ -263,6 +241,7 @@ typedef struct OutputStream {
     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;
@@ -334,17 +313,53 @@ typedef struct OptionsContext {
     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)
 {
     const OptionDef *po = options;
@@ -369,11 +384,15 @@ static void reset_options(OptionsContext *o)
     }
 
     av_freep(&o->stream_maps);
+    av_freep(&o->meta_data_maps);
 
     memset(o, 0, sizeof(*o));
 
+    o->mux_preload    = 0.5;
+    o->mux_max_delay  = 0.7;
     o->recording_time = INT64_MAX;
     o->limit_filesize = UINT64_MAX;
+    o->chapters_input_file = INT_MAX;
 
     uninit_opts();
     init_opts();
@@ -577,8 +596,6 @@ void exit_program(int ret)
         fclose(vstats_file);
     av_free(vstats_filename);
 
-    av_free(meta_data_maps);
-
     av_freep(&input_streams);
     av_freep(&input_files);
     av_freep(&output_streams);
@@ -1209,7 +1226,7 @@ static void do_video_out(AVFormatContext *s,
     }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;
 
@@ -1722,7 +1739,7 @@ static int output_packet(InputStream *ist, int ist_index,
         }
 
         /* 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)
@@ -1938,7 +1955,7 @@ static int transcode_init(OutputFile *output_files,
                           InputFile *input_files,
                           int nb_input_files)
 {
-    int ret = 0, i;
+    int ret = 0, i, j;
     AVFormatContext *os;
     AVCodecContext *codec, *icodec;
     OutputStream *ost;
@@ -1946,9 +1963,13 @@ static int transcode_init(OutputFile *output_files,
     char error[1024];
     int want_sdp = 1;
 
-    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 */
     for(i=0;i<nb_output_files;i++) {
@@ -2403,9 +2424,11 @@ static int transcode(OutputFile *output_files,
                     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 */
@@ -2456,12 +2479,10 @@ static int transcode(OutputFile *output_files,
         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
@@ -2649,21 +2670,6 @@ static int opt_frame_aspect_ratio(const char *opt, const char *arg)
     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);
@@ -2710,29 +2716,24 @@ static int opt_audio_channels(const char *opt, const char *arg)
     return 0;
 }
 
-static int opt_codec(const char *opt, const char *arg)
+static int opt_audio_codec(OptionsContext *o, const char *opt, const char *arg)
 {
-    return av_dict_set(&codec_names, opt, arg, 0);
+    return parse_option(o, "codec:a", arg, options);
 }
 
-static int opt_audio_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 parse_option(o, "codec:v", arg, options);
 }
 
-static int opt_video_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 parse_option(o, "codec:s", arg, options);
 }
 
-static int opt_subtitle_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 parse_option(o, "codec:d", arg, options);
 }
 
 static int opt_codec_tag(const char *opt, const char *arg)
@@ -2837,8 +2838,8 @@ static int opt_map(OptionsContext *o, const char *opt, const char *arg)
 
 static void parse_meta_type(char *arg, char *type, int *index)
 {
-    if (*arg == ':') {
-        *type = *(++arg);
+    if (*arg) {
+        *type = *arg;
         switch (*arg) {
         case 'g':
             break;
@@ -2856,39 +2857,34 @@ static void parse_meta_type(char *arg, char *type, int *index)
         *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 = &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 ? p + 1 : p, &m->type, &m->index);
 
-    m1 = &meta_data_maps[nb_meta_data_maps - 1][0];
+    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_input_ts_scale(const char *opt, const char *arg)
-{
-    return av_dict_set(&ts_scale, opt, arg, 0);
-}
-
 static enum CodecID find_codec_or_die(const char *name, enum AVMediaType type, int encoder)
 {
     const char *codec_string = encoder ? "encoder" : "decoder";
@@ -2910,20 +2906,11 @@ static enum CodecID find_codec_or_die(const char *name, enum AVMediaType type, i
     return codec->id;
 }
 
-static AVCodec *choose_codec(AVFormatContext *s, AVStream *st, enum AVMediaType type, AVDictionary *codec_names)
+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) {
@@ -2945,16 +2932,15 @@ static AVCodec *choose_codec(AVFormatContext *s, AVStream *st, enum AVMediaType
  * 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;
 
         input_streams = grow_array(input_streams, sizeof(*input_streams), &nb_input_streams, nb_input_streams + 1);
         ist = &input_streams[nb_input_streams - 1];
@@ -2963,18 +2949,10 @@ static void add_input_streams(AVFormatContext *ic)
         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, ':');
+        MATCH_PER_STREAM_OPT(ts_scale, dbl, scale, ic, st);
+        ist->ts_scale = scale;
 
-            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);
-
-        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);
 
@@ -3111,7 +3089,7 @@ static int opt_input_file(OptionsContext *o, const char *opt, const char *filena
 
     /* 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);
@@ -3141,7 +3119,7 @@ static int opt_input_file(OptionsContext *o, const char *opt, const char *filena
     }
 
     /* update the current parameters so that they match the one of the input stream */
-    add_input_streams(ic);
+    add_input_streams(o, ic);
 
     /* dump the file content */
     if (verbose >= 0)
@@ -3161,12 +3139,10 @@ static int opt_input_file(OptionsContext *o, const char *opt, const char *filena
     audio_sample_rate = 0;
     audio_channels    = 0;
     audio_sample_fmt  = AV_SAMPLE_FMT_NONE;
-    av_dict_free(&ts_scale);
 
     for (i = 0; i < orig_nb_streams; i++)
         av_dict_free(&opts[i]);
     av_freep(&opts);
-    av_dict_free(&codec_names);
 
     reset_options(o);
     return 0;
@@ -3195,11 +3171,14 @@ static void parse_forced_key_frames(char *kf, OutputStream *ost,
     }
 }
 
-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");
@@ -3213,7 +3192,7 @@ static OutputStream *new_output_stream(AVFormatContext *oc, enum AVMediaType typ
     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);
     }
@@ -3221,17 +3200,37 @@ static OutputStream *new_output_stream(AVFormatContext *oc, enum AVMediaType typ
     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);
+        }
+        if (bsfc_prev)
+            bsfc_prev->next = bsfc;
+        else
+            ost->bitstream_filters = bsfc;
+
+        bsfc_prev = bsfc;
+        bsf       = next;
+    }
+
     ost->sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
     return ost;
 }
 
-static OutputStream *new_video_stream(AVFormatContext *oc)
+static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc)
 {
     AVStream *st;
     OutputStream *ost;
     AVCodecContext *video_enc;
 
-    ost = new_output_stream(oc, AVMEDIA_TYPE_VIDEO);
+    ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO);
     st  = ost->st;
     if (!st->stream_copy) {
         ost->frame_aspect_ratio = frame_aspect_ratio;
@@ -3242,9 +3241,6 @@ static OutputStream *new_video_stream(AVFormatContext *oc)
 #endif
     }
 
-    ost->bitstream_filters = video_bitstream_filters;
-    video_bitstream_filters= NULL;
-
     video_enc = st->codec;
 
     if(video_codec_tag)
@@ -3337,18 +3333,15 @@ static OutputStream *new_video_stream(AVFormatContext *oc)
     return ost;
 }
 
-static OutputStream *new_audio_stream(AVFormatContext *oc)
+static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc)
 {
     AVStream *st;
     OutputStream *ost;
     AVCodecContext *audio_enc;
 
-    ost = new_output_stream(oc, AVMEDIA_TYPE_AUDIO);
+    ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO);
     st  = ost->st;
 
-    ost->bitstream_filters = audio_bitstream_filters;
-    audio_bitstream_filters= NULL;
-
     audio_enc = st->codec;
     audio_enc->codec_type = AVMEDIA_TYPE_AUDIO;
 
@@ -3381,13 +3374,13 @@ static OutputStream *new_audio_stream(AVFormatContext *oc)
     return ost;
 }
 
-static OutputStream *new_data_stream(AVFormatContext *oc)
+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(o, oc, AVMEDIA_TYPE_DATA);
     st  = ost->st;
     data_enc = st->codec;
     if (!st->stream_copy) {
@@ -3406,19 +3399,16 @@ static OutputStream *new_data_stream(AVFormatContext *oc)
     return ost;
 }
 
-static OutputStream *new_subtitle_stream(AVFormatContext *oc)
+static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc)
 {
     AVStream *st;
     OutputStream *ost;
     AVCodecContext *subtitle_enc;
 
-    ost = new_output_stream(oc, AVMEDIA_TYPE_SUBTITLE);
+    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)
@@ -3459,7 +3449,7 @@ static int opt_streamid(const char *opt, const char *arg)
     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;
@@ -3487,7 +3477,7 @@ static int copy_chapters(InputFile *ifile, OutputFile *ofile)
         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++;
@@ -3499,7 +3489,7 @@ static int copy_chapters(InputFile *ifile, OutputFile *ofile)
     return 0;
 }
 
-static int read_ffserver_streams(AVFormatContext *s, const char *filename)
+static int read_ffserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename)
 {
     int i, err;
     AVFormatContext *ic = NULL;
@@ -3514,7 +3504,7 @@ static int read_ffserver_streams(AVFormatContext *s, const char *filename)
         AVCodec *codec;
 
         codec = avcodec_find_encoder(ic->streams[i]->codec->codec_id);
-        ost   = new_output_stream(s, codec->type);
+        ost   = new_output_stream(o, s, codec->type);
         st    = ost->st;
 
         // FIXME: a more elegant solution is needed
@@ -3557,7 +3547,7 @@ static void opt_output_file(void *optctx, const char *filename)
         av_strstart(filename, "http:", NULL)) {
         /* 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);
@@ -3566,7 +3556,7 @@ static void opt_output_file(void *optctx, const char *filename)
         /* pick the "best" stream of each type */
 #define NEW_STREAM(type, index)\
         if (index >= 0) {\
-            ost = new_ ## type ## _stream(oc);\
+            ost = new_ ## type ## _stream(o, oc);\
             ost->source_index = index;\
             ost->sync_ist     = &input_streams[index];\
             input_streams[index].discard = 0;\
@@ -3618,10 +3608,10 @@ static void opt_output_file(void *optctx, const char *filename)
 
             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);
@@ -3635,10 +3625,6 @@ static void opt_output_file(void *optctx, const char *filename)
         }
     }
 
-    av_dict_copy(&oc->metadata, metadata, 0);
-    av_dict_free(&metadata);
-
-
     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;
@@ -3684,30 +3670,31 @@ static void opt_output_file(void *optctx, const char *filename)
         }
     }
 
-    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);
 
     /* 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;
@@ -3719,7 +3706,7 @@ static void opt_output_file(void *optctx, const char *filename)
             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")
@@ -3728,7 +3715,7 @@ static void opt_output_file(void *optctx, const char *filename)
         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':
@@ -3753,33 +3740,66 @@ static void opt_output_file(void *optctx, const char *filename)
     }
 
     /* 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);
     reset_options(o);
 }
@@ -3993,8 +4013,8 @@ static int opt_target(OptionsContext *o, const char *opt, const char *arg)
     }
 
     if(!strcmp(arg, "vcd")) {
-        opt_codec("c:v", "mpeg1video");
-        opt_codec("c:a", "mp2");
+        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");
@@ -4018,11 +4038,11 @@ static int opt_target(OptionsContext *o, const char *opt, const char *arg)
            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(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");
@@ -4044,8 +4064,8 @@ static int opt_target(OptionsContext *o, const char *opt, const char *arg)
 
     } else if(!strcmp(arg, "dvd")) {
 
-        opt_codec("c:v", "mpeg2video");
-        opt_codec("c:a", "ac3");
+        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");
@@ -4101,25 +4121,19 @@ static int opt_vstats(const char *opt, const char *arg)
     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)
@@ -4143,19 +4157,19 @@ static const OptionDef options[] = {
     { "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" },
+    { "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_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",  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" },
-    { "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" },
+    { "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" },
@@ -4163,7 +4177,7 @@ static const OptionDef options[] = {
       "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", "" },
     { "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" },
     { "vsync", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&video_sync_method}, "video sync method", "" },
@@ -4176,9 +4190,10 @@ static const OptionDef options[] = {
     { "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" },
@@ -4188,7 +4203,7 @@ static const OptionDef options[] = {
     { "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" },
+    { "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" },
     { "same_quant", OPT_BOOL | OPT_VIDEO, {(void*)&same_quant},
       "use same quantizer as source (implies VBR)" },
@@ -4214,12 +4229,12 @@ static const OptionDef options[] = {
     { "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" }, //
     { "alang", HAS_ARG | OPT_STRING | OPT_AUDIO, {(void *)&audio_language}, "set the ISO 639 language code (3 letters) of the current audio stream" , "code" },
@@ -4227,7 +4242,7 @@ static const OptionDef options[] = {
 
     /* 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" },
+    { "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" },
 
@@ -4235,15 +4250,13 @@ static const OptionDef options[] = {
     { "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" },
 
     /* 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, },
diff --git a/cmdutils.c b/cmdutils.c
index 478aeeb60c195a1400b175648e74b23acb18e693..c72c74737b8d0dc5207a091ea9aa59e0e4675636 100644
--- a/cmdutils.c
+++ b/cmdutils.c
@@ -259,6 +259,8 @@ unknown_opt:
         *(int64_t*)dst = parse_time_or_die(opt, arg, 1);
     } else if (po->flags & OPT_FLOAT) {
         *(float*)dst = parse_number_or_die(opt, arg, OPT_FLOAT, -INFINITY, INFINITY);
+    } else if (po->flags & OPT_DOUBLE) {
+        *(double*)dst = parse_number_or_die(opt, arg, OPT_DOUBLE, -INFINITY, INFINITY);
     } else if (po->u.func_arg) {
         int ret = po->flags & OPT_FUNC2 ? po->u.func2_arg(optctx, opt, arg) :
                                           po->u.func_arg(opt, arg);
diff --git a/cmdutils.h b/cmdutils.h
index a0d36865fb12dcaef554c3c557dace1bc12b875f..586cff6c5fa1c8a641e7eaece39472b200ee038d 100644
--- a/cmdutils.h
+++ b/cmdutils.h
@@ -119,6 +119,7 @@ typedef struct SpecifierOpt {
         int        i;
         int64_t  i64;
         float      f;
+        double   dbl;
     } u;
 } SpecifierOpt;
 
@@ -144,6 +145,7 @@ typedef struct {
                                    Implies OPT_OFFSET. Next element after the offset is
                                    an int containing element count in the array. */
 #define OPT_TIME  0x10000
+#define OPT_DOUBLE 0x20000
      union {
         void *dst_ptr;
         int (*func_arg)(const char *, const char *);
diff --git a/doc/avconv.texi b/doc/avconv.texi
index d25e61d640857edea29f07da0f4d382ea841a656..66389ee37eabdf11c3d2af7b28151b748cac261e 100644
--- a/doc/avconv.texi
+++ b/doc/avconv.texi
@@ -160,14 +160,26 @@ interpreted as UTC.
 If the year-month-day part is not specified it takes the current
 year-month-day.
 
-@item -metadata @var{key}=@var{value}
+@item -metadata[:metadata_specifier] @var{key}=@var{value}
 Set a metadata key/value pair.
 
+An optional @var{metadata_specifier} may be given to set metadata
+on streams or chapters. See @code{-map_metadata} documentation for
+details.
+
+This option overrides metadata set with @code{-map_metadata}. It is
+also possible to delete metadata by using an empty value.
+
 For example, for setting the title in the output file:
 @example
 avconv -i in.avi -metadata title="my title" out.flv
 @end example
 
+To set the language of the second stream:
+@example
+avconv -i INPUT -metadata:s:1 language=eng OUTPUT
+@end example
+
 @item -v @var{number}
 Set the logging verbosity level.
 
@@ -188,18 +200,21 @@ avconv -i myfile.avi -target vcd -bf 2 /tmp/vcd.mpg
 @end example
 
 @item -dframes @var{number}
-Set the number of data frames to record.
+Set the number of data frames to record. This is an alias for @code{-frames:d}.
 
 @item -slang @var{code}
 Set the ISO 639 language code (3 letters) of the current subtitle stream.
 
+@item -frames[:stream_specifier] @var{framecount}
+Stop writing to the stream after @var{framecount} frames.
+
 @end table
 
 @section Video Options
 
 @table @option
 @item -vframes @var{number}
-Set the number of video frames to record.
+Set the number of video frames to record. This is an alias for @code{-frames:v}.
 @item -r @var{fps}
 Set frame rate (Hz value, fraction or abbreviation), (default = 25).
 @item -s @var{size}
@@ -552,11 +567,6 @@ Intra_dc_precision.
 Force video tag/fourcc.
 @item -qphist
 Show QP histogram.
-@item -vbsf @var{bitstream_filter}
-Bitstream filters available are "dump_extra", "remove_extra", "noise", "h264_mp4toannexb", "imxdump", "mjpegadump", "mjpeg2jpeg".
-@example
-avconv -i h264.mp4 -c:v copy -vbsf h264_mp4toannexb -an out.h264
-@end example
 @item -force_key_frames @var{time}[,@var{time}...]
 Force key frames at the specified timestamps, more precisely at the first
 frames after each specified time.
@@ -569,7 +579,7 @@ The timestamps must be specified in ascending order.
 
 @table @option
 @item -aframes @var{number}
-Set the number of audio frames to record.
+Set the number of audio frames to record. This is an alias for @code{-frames:a}.
 @item -ar @var{freq}
 Set the audio sampling frequency. For output streams it is set by
 default to the frequency of the corresponding input stream. For input
@@ -617,8 +627,6 @@ Voice Over
 @item ka
 Karaoke
 @end table
-@item -absf @var{bitstream_filter}
-Bitstream filters available are "dump_extra", "remove_extra", "noise", "mp3comp", "mp3decomp".
 @end table
 
 @section Subtitle options:
@@ -630,11 +638,6 @@ Set the subtitle codec. This is an alias for @code{-codec:s}.
 Set the ISO 639 language code (3 letters) of the current subtitle stream.
 @item -sn
 Disable subtitle recording.
-@item -sbsf @var{bitstream_filter}
-Bitstream filters available are "mov2textsub", "text2movsub".
-@example
-avconv -i file.mov -an -vn -sbsf mov2textsub -c:s copy -f rawvideo sub.txt
-@end example
 @end table
 
 @section Audio/Video grab options
@@ -797,6 +800,17 @@ an output mpegts file:
 @example
 avconv -i infile -streamid 0:33 -streamid 1:36 out.ts
 @end example
+
+@item -bsf[:@var{stream_specifier}] @var{bitstream_filters}
+Set bitstream filters for matching streams. @var{bistream_filters} is
+a comma-separated list of bitstream filters. Use the @code{-bsfs} option
+to get the list of bitstream filters.
+@example
+avconv -i h264.mp4 -c:v copy -vbsf h264_mp4toannexb -an out.h264
+@end example
+@example
+avconv -i file.mov -an -vn -sbsf mov2textsub -c:s copy -f rawvideo sub.txt
+@end example
 @end table
 @c man end OPTIONS
 
diff --git a/ffmpeg.c b/ffmpeg.c
index 6aa3fa02bf3f93e262fe5cb997727dddbf61eaf5..129501ba18c3843337ed40057ebf136bfb76267f 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -110,18 +110,6 @@ typedef struct MetadataMap {
 static const OptionDef options[];
 
 #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;
@@ -133,7 +121,6 @@ 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 +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 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 +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,11 +204,6 @@ 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"
@@ -257,6 +233,7 @@ typedef struct InputFile {
     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 {
@@ -273,6 +250,7 @@ typedef struct OutputStream {
     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;
@@ -345,17 +323,53 @@ typedef struct OptionsContext {
     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;
@@ -381,12 +395,16 @@ static void reset_options(OptionsContext *o, int is_input)
     }
 
     av_freep(&o->stream_maps);
+    av_freep(&o->meta_data_maps);
 
     memset(o, 0, sizeof(*o));
 
-    o->limit_filesize = UINT64_MAX;
     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();
@@ -616,8 +634,6 @@ void exit_program(int ret)
         fclose(vstats_file);
     av_free(vstats_filename);
 
-    av_free(meta_data_maps);
-
     av_freep(&input_streams);
     av_freep(&input_files);
     av_freep(&output_streams);
@@ -1236,7 +1252,7 @@ static void do_video_out(AVFormatContext *s,
     }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 +1782,7 @@ static int output_packet(InputStream *ist, int ist_index,
         }
 
         /* 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)
@@ -1971,7 +1987,7 @@ static int transcode_init(OutputFile *output_files,
                           InputFile *input_files,
                           int nb_input_files)
 {
-    int ret = 0, i;
+    int ret = 0, i, j;
     AVFormatContext *os;
     AVCodecContext *codec, *icodec;
     OutputStream *ost;
@@ -1979,9 +1995,13 @@ static int transcode_init(OutputFile *output_files,
     char error[1024];
     int want_sdp = 1;
 
-    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 */
     for(i=0;i<nb_output_files;i++) {
@@ -2465,9 +2485,11 @@ static int transcode(OutputFile *output_files,
                     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 */
@@ -2518,12 +2540,10 @@ static int transcode(OutputFile *output_files,
         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 +2745,6 @@ static int opt_frame_aspect_ratio(const char *opt, const char *arg)
     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);
@@ -2808,35 +2813,27 @@ static int opt_video_standard(const char *opt, const char *arg)
     return opt_default("standard", arg);
 }
 
-static int opt_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);
+    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(OptionsContext *o, const char *opt, const char *arg)
 {
-    return opt_codec("codec:a", 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(OptionsContext *o, const char *opt, const char *arg)
 {
-    return opt_codec("codec:v", 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(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 parse_option(o, "codec:d", arg, options);
 }
 
 static int opt_codec_tag(const char *opt, const char *arg)
@@ -2941,8 +2938,8 @@ static int opt_map(OptionsContext *o, const char *opt, const char *arg)
 
 static void parse_meta_type(char *arg, char *type, int *index)
 {
-    if (*arg == ':') {
-        *type = *(++arg);
+    if (*arg) {
+        *type = *arg;
         switch (*arg) {
         case 'g':
             break;
@@ -2960,53 +2957,48 @@ static void parse_meta_type(char *arg, char *type, int *index)
         *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 = &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 ? p + 1 : p, &m->type, &m->index);
 
-    m1 = &meta_data_maps[nb_meta_data_maps - 1][0];
+    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_input_ts_scale(const char *opt, const char *arg)
-{
-    return av_dict_set(&ts_scale, opt, arg, 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,20 +3026,11 @@ static enum CodecID find_codec_or_die(const char *name, enum AVMediaType type, i
     return codec->id;
 }
 
-static AVCodec *choose_codec(AVFormatContext *s, AVStream *st, enum AVMediaType type, AVDictionary *codec_names)
+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) {
@@ -3069,16 +3052,15 @@ static AVCodec *choose_codec(AVFormatContext *s, AVStream *st, enum AVMediaType
  * 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;
 
@@ -3089,18 +3071,10 @@ static void add_input_streams(AVFormatContext *ic)
         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);
 
@@ -3242,7 +3216,7 @@ static int opt_input_file(OptionsContext *o, const char *opt, const char *filena
 
     /* 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);
@@ -3272,7 +3246,7 @@ static int opt_input_file(OptionsContext *o, const char *opt, const char *filena
     }
 
     /* update the current parameters so that they match the one of the input stream */
-    add_input_streams(ic);
+    add_input_streams(o, ic);
 
     /* dump the file content */
     if (verbose >= 0)
@@ -3292,12 +3266,10 @@ static int opt_input_file(OptionsContext *o, const char *opt, const char *filena
     audio_sample_rate = 0;
     audio_channels    = 0;
     audio_sample_fmt  = AV_SAMPLE_FMT_NONE;
-    av_dict_free(&ts_scale);
 
     for (i = 0; i < orig_nb_streams; i++)
         av_dict_free(&opts[i]);
     av_freep(&opts);
-    av_dict_free(&codec_names);
 
     reset_options(o, 1);
     return 0;
@@ -3326,11 +3298,14 @@ static void parse_forced_key_frames(char *kf, OutputStream *ost,
     }
 }
 
-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");
@@ -3344,7 +3319,7 @@ static OutputStream *new_output_stream(AVFormatContext *oc, enum AVMediaType typ
     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);
     }
@@ -3352,17 +3327,37 @@ static OutputStream *new_output_stream(AVFormatContext *oc, enum AVMediaType typ
     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);
+        }
+        if (bsfc_prev)
+            bsfc_prev->next = bsfc;
+        else
+            ost->bitstream_filters = bsfc;
+
+        bsfc_prev = bsfc;
+        bsf       = next;
+    }
+
     ost->sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
     return ost;
 }
 
-static OutputStream *new_video_stream(AVFormatContext *oc)
+static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc)
 {
     AVStream *st;
     OutputStream *ost;
     AVCodecContext *video_enc;
 
-    ost = new_output_stream(oc, AVMEDIA_TYPE_VIDEO);
+    ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO);
     st  = ost->st;
     if (!st->stream_copy) {
         ost->frame_aspect_ratio = frame_aspect_ratio;
@@ -3373,9 +3368,6 @@ static OutputStream *new_video_stream(AVFormatContext *oc)
 #endif
     }
 
-    ost->bitstream_filters = video_bitstream_filters;
-    video_bitstream_filters= NULL;
-
     st->codec->thread_count= thread_count;
 
     video_enc = st->codec;
@@ -3472,18 +3464,15 @@ static OutputStream *new_video_stream(AVFormatContext *oc)
     return ost;
 }
 
-static OutputStream *new_audio_stream(AVFormatContext *oc)
+static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc)
 {
     AVStream *st;
     OutputStream *ost;
     AVCodecContext *audio_enc;
 
-    ost = new_output_stream(oc, AVMEDIA_TYPE_AUDIO);
+    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;
@@ -3518,13 +3507,13 @@ static OutputStream *new_audio_stream(AVFormatContext *oc)
     return ost;
 }
 
-static OutputStream *new_data_stream(AVFormatContext *oc)
+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(o, oc, AVMEDIA_TYPE_DATA);
     st  = ost->st;
     data_enc = st->codec;
     if (!st->stream_copy) {
@@ -3543,19 +3532,16 @@ static OutputStream *new_data_stream(AVFormatContext *oc)
     return ost;
 }
 
-static OutputStream *new_subtitle_stream(AVFormatContext *oc)
+static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc)
 {
     AVStream *st;
     OutputStream *ost;
     AVCodecContext *subtitle_enc;
 
-    ost = new_output_stream(oc, AVMEDIA_TYPE_SUBTITLE);
+    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,42 +3581,8 @@ static int opt_streamid(const char *opt, const char *arg)
     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;
@@ -3658,7 +3610,7 @@ static int copy_chapters(InputFile *ifile, OutputFile *ofile)
         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++;
@@ -3670,6 +3622,40 @@ static int copy_chapters(InputFile *ifile, OutputFile *ofile)
     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;
@@ -3693,7 +3679,7 @@ static void opt_output_file(void *optctx, const char *filename)
         av_strstart(filename, "http:", NULL)) {
         /* 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);
@@ -3702,7 +3688,7 @@ static void opt_output_file(void *optctx, const char *filename)
         /* pick the "best" stream of each type */
 #define NEW_STREAM(type, index)\
         if (index >= 0) {\
-            ost = new_ ## type ## _stream(oc);\
+            ost = new_ ## type ## _stream(o, oc);\
             ost->source_index = index;\
             ost->sync_ist     = &input_streams[index];\
             input_streams[index].discard = 0;\
@@ -3754,10 +3740,10 @@ static void opt_output_file(void *optctx, const char *filename)
 
             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);
@@ -3771,10 +3757,6 @@ static void opt_output_file(void *optctx, const char *filename)
         }
     }
 
-    av_dict_copy(&oc->metadata, metadata, 0);
-    av_dict_free(&metadata);
-
-
     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;
@@ -3820,8 +3802,8 @@ static void opt_output_file(void *optctx, const char *filename)
         }
     }
 
-    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");
@@ -3829,26 +3811,27 @@ static void opt_output_file(void *optctx, const char *filename)
     }
 
     /* 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;
@@ -3860,7 +3843,7 @@ static void opt_output_file(void *optctx, const char *filename)
             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")
@@ -3869,7 +3852,7 @@ static void opt_output_file(void *optctx, const char *filename)
         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':
@@ -3894,33 +3877,66 @@ static void opt_output_file(void *optctx, const char *filename)
     }
 
     /* 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);
     reset_options(o, 0);
 }
@@ -4134,8 +4150,8 @@ static int opt_target(OptionsContext *o, const char *opt, const char *arg)
     }
 
     if(!strcmp(arg, "vcd")) {
-        opt_codec("c:v", "mpeg1video");
-        opt_codec("c:a", "mp2");
+        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");
@@ -4159,11 +4175,11 @@ static int opt_target(OptionsContext *o, const char *opt, const char *arg)
            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(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");
@@ -4185,8 +4201,8 @@ static int opt_target(OptionsContext *o, const char *opt, const char *arg)
 
     } else if(!strcmp(arg, "dvd")) {
 
-        opt_codec("c:v", "mpeg2video");
-        opt_codec("c:a", "ac3");
+        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");
@@ -4242,28 +4258,22 @@ static int opt_vstats(const char *opt, const char *arg)
     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];
@@ -4286,13 +4296,13 @@ static int opt_preset(const char *opt, const char *arg)
             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);
@@ -4325,22 +4335,22 @@ static const OptionDef options[] = {
     { "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" },
+    { "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",  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" },
@@ -4348,7 +4358,7 @@ static const OptionDef options[] = {
       "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 the verbosity level", "number" },
@@ -4364,9 +4374,10 @@ static const OptionDef options[] = {
     { "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" },
@@ -4386,7 +4397,7 @@ static const OptionDef options[] = {
     { "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" },
+    { "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)" },
@@ -4412,12 +4423,12 @@ static const OptionDef options[] = {
     { "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" }, //
     { "alang", HAS_ARG | OPT_STRING | OPT_AUDIO, {(void *)&audio_language}, "set the ISO 639 language code (3 letters) of the current audio stream" , "code" },
@@ -4425,7 +4436,7 @@ static const OptionDef options[] = {
 
     /* 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" },
+    { "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" },
 
@@ -4435,19 +4446,17 @@ static const OptionDef options[] = {
     { "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, },
diff --git a/libavcodec/ac3enc.c b/libavcodec/ac3enc.c
index 5bcbd726e62b8887a62c15621dcf85c79de81eae..44c16073a20f8ef9e69dcc83dc29dbd4b2aaf4d7 100644
--- a/libavcodec/ac3enc.c
+++ b/libavcodec/ac3enc.c
@@ -2167,7 +2167,7 @@ static av_cold int validate_options(AC3EncodeContext *s)
                              (s->channel_mode == AC3_CHMODE_STEREO);
 
     s->cpl_enabled = s->options.channel_coupling &&
-                     s->channel_mode >= AC3_CHMODE_STEREO && !s->fixed_point;
+                     s->channel_mode >= AC3_CHMODE_STEREO;
 
     return 0;
 }
diff --git a/libavcodec/ac3enc.h b/libavcodec/ac3enc.h
index 65e88c9e0141a6dd4da69516843cf362d25fd253..bf5ccea19fe927d667315a15fc78df59301ebfc8 100644
--- a/libavcodec/ac3enc.h
+++ b/libavcodec/ac3enc.h
@@ -52,6 +52,7 @@
 #define MAC_COEF(d,a,b) ((d)+=(a)*(b))
 #define COEF_MIN (-16777215.0/16777216.0)
 #define COEF_MAX ( 16777215.0/16777216.0)
+#define NEW_CPL_COORD_THRESHOLD 0.03
 typedef float SampleType;
 typedef float CoefType;
 typedef float CoefSumType;
@@ -60,6 +61,7 @@ typedef float CoefSumType;
 #define MAC_COEF(d,a,b) MAC64(d,a,b)
 #define COEF_MIN -16777215
 #define COEF_MAX  16777215
+#define NEW_CPL_COORD_THRESHOLD 503317
 typedef int16_t SampleType;
 typedef int32_t CoefType;
 typedef int64_t CoefSumType;
diff --git a/libavcodec/ac3enc_fixed.c b/libavcodec/ac3enc_fixed.c
index c2e51552bc7f5db94e15e772eff5d347f5994200..0c7f81b7d3542ef8556422367962c100457de383 100644
--- a/libavcodec/ac3enc_fixed.c
+++ b/libavcodec/ac3enc_fixed.c
@@ -29,6 +29,7 @@
 #define CONFIG_FFT_FLOAT 0
 #undef CONFIG_AC3ENC_FLOAT
 #include "ac3enc.h"
+#include "eac3enc.h"
 
 #define AC3ENC_TYPE AC3ENC_TYPE_AC3_FIXED
 #include "ac3enc_opts_template.c"
@@ -112,6 +113,22 @@ static void clip_coefficients(DSPContext *dsp, int32_t *coef, unsigned int len)
 }
 
 
+/**
+ * Calculate a single coupling coordinate.
+ */
+static CoefType calc_cpl_coord(CoefSumType energy_ch, CoefSumType energy_cpl)
+{
+    if (energy_cpl <= COEF_MAX) {
+        return 1048576;
+    } else {
+        uint64_t coord   = energy_ch / (energy_cpl >> 24);
+        uint32_t coord32 = FFMIN(coord, 1073741824);
+        coord32          = ff_sqrt(coord32) << 9;
+        return FFMIN(coord32, COEF_MAX);
+    }
+}
+
+
 static av_cold int ac3_fixed_encode_init(AVCodecContext *avctx)
 {
     AC3EncodeContext *s = avctx->priv_data;
diff --git a/libavcodec/ac3enc_float.c b/libavcodec/ac3enc_float.c
index b1d1221667d1940f83a9f4074ca744539fdebc9e..3876a8007b494a58b1c60e9128dd494fd9a41fe3 100644
--- a/libavcodec/ac3enc_float.c
+++ b/libavcodec/ac3enc_float.c
@@ -104,9 +104,10 @@ static int normalize_samples(AC3EncodeContext *s)
 static void scale_coefficients(AC3EncodeContext *s)
 {
     int chan_size = AC3_MAX_COEFS * s->num_blocks;
-    s->ac3dsp.float_to_fixed24(s->fixed_coef_buffer + chan_size,
-                               s->mdct_coef_buffer  + chan_size,
-                               chan_size * s->channels);
+    int cpl       = s->cpl_on;
+    s->ac3dsp.float_to_fixed24(s->fixed_coef_buffer + (chan_size * !cpl),
+                               s->mdct_coef_buffer  + (chan_size * !cpl),
+                               chan_size * (s->channels + cpl));
 }
 
 
@@ -119,6 +120,18 @@ static void clip_coefficients(DSPContext *dsp, float *coef, unsigned int len)
 }
 
 
+/**
+ * Calculate a single coupling coordinate.
+ */
+static CoefType calc_cpl_coord(CoefSumType energy_ch, CoefSumType energy_cpl)
+{
+    float coord = 0.125;
+    if (energy_cpl > 0)
+        coord *= sqrtf(energy_ch / energy_cpl);
+    return FFMIN(coord, COEF_MAX);
+}
+
+
 #if CONFIG_AC3_ENCODER
 AVCodec ff_ac3_encoder = {
     .name           = "ac3",
diff --git a/libavcodec/ac3enc_opts_template.c b/libavcodec/ac3enc_opts_template.c
index fdbbd5f7433e08ffbf238a941838e8419e6e8188..a8bbedbf9e0f71a0a5338a1f74eb7a8e64723e55 100644
--- a/libavcodec/ac3enc_opts_template.c
+++ b/libavcodec/ac3enc_opts_template.c
@@ -72,11 +72,9 @@ static const AVOption eac3_options[] = {
     {"hdcd",     "HDCD",               0, FF_OPT_TYPE_CONST, {.dbl = AC3ENC_OPT_ADCONV_HDCD     }, INT_MIN, INT_MAX, AC3ENC_PARAM, "ad_conv_type"},
 /* Other Encoding Options */
 {"stereo_rematrixing", "Stereo Rematrixing", OFFSET(stereo_rematrixing), FF_OPT_TYPE_INT, {.dbl = AC3ENC_OPT_ON }, AC3ENC_OPT_OFF, AC3ENC_OPT_ON, AC3ENC_PARAM},
-#if AC3ENC_TYPE != AC3ENC_TYPE_AC3_FIXED
 {"channel_coupling",   "Channel Coupling",   OFFSET(channel_coupling),   FF_OPT_TYPE_INT, {.dbl = AC3ENC_OPT_AUTO }, AC3ENC_OPT_AUTO, AC3ENC_OPT_ON, AC3ENC_PARAM, "channel_coupling"},
     {"auto", "Selected by the Encoder", 0, FF_OPT_TYPE_CONST, {.dbl = AC3ENC_OPT_AUTO }, INT_MIN, INT_MAX, AC3ENC_PARAM, "channel_coupling"},
 {"cpl_start_band", "Coupling Start Band", OFFSET(cpl_start), FF_OPT_TYPE_INT, {.dbl = AC3ENC_OPT_AUTO }, AC3ENC_OPT_AUTO, 15, AC3ENC_PARAM, "cpl_start_band"},
     {"auto", "Selected by the Encoder", 0, FF_OPT_TYPE_CONST, {.dbl = AC3ENC_OPT_AUTO }, INT_MIN, INT_MAX, AC3ENC_PARAM, "cpl_start_band"},
-#endif
 {NULL}
 };
diff --git a/libavcodec/ac3enc_template.c b/libavcodec/ac3enc_template.c
index dd759a732b927c31353fa048f2fe29ef38a3c1dd..7e2bf3a9caaffdb0d6e3bc9081e605bafeccb342 100644
--- a/libavcodec/ac3enc_template.c
+++ b/libavcodec/ac3enc_template.c
@@ -41,6 +41,8 @@ static int normalize_samples(AC3EncodeContext *s);
 
 static void clip_coefficients(DSPContext *dsp, CoefType *coef, unsigned int len);
 
+static CoefType calc_cpl_coord(CoefSumType energy_ch, CoefSumType energy_cpl);
+
 
 int AC3_NAME(allocate_sample_buffers)(AC3EncodeContext *s)
 {
@@ -118,32 +120,25 @@ static void apply_mdct(AC3EncodeContext *s)
 }
 
 
-/**
- * Calculate a single coupling coordinate.
- */
-static inline float calc_cpl_coord(float energy_ch, float energy_cpl)
-{
-    float coord = 0.125;
-    if (energy_cpl > 0)
-        coord *= sqrtf(energy_ch / energy_cpl);
-    return FFMIN(coord, COEF_MAX);
-}
-
-
 /**
  * Calculate coupling channel and coupling coordinates.
  */
 static void apply_channel_coupling(AC3EncodeContext *s)
 {
+    LOCAL_ALIGNED_16(CoefType, cpl_coords,      [AC3_MAX_BLOCKS], [AC3_MAX_CHANNELS][16]);
 #if CONFIG_AC3ENC_FLOAT
-    LOCAL_ALIGNED_16(float,   cpl_coords,       [AC3_MAX_BLOCKS], [AC3_MAX_CHANNELS][16]);
     LOCAL_ALIGNED_16(int32_t, fixed_cpl_coords, [AC3_MAX_BLOCKS], [AC3_MAX_CHANNELS][16]);
+#else
+    int32_t (*fixed_cpl_coords)[AC3_MAX_CHANNELS][16] = cpl_coords;
+#endif
     int blk, ch, bnd, i, j;
     CoefSumType energy[AC3_MAX_BLOCKS][AC3_MAX_CHANNELS][16] = {{{0}}};
     int cpl_start, num_cpl_coefs;
 
     memset(cpl_coords,       0, AC3_MAX_BLOCKS * sizeof(*cpl_coords));
-    memset(fixed_cpl_coords, 0, AC3_MAX_BLOCKS * sizeof(*fixed_cpl_coords));
+#if CONFIG_AC3ENC_FLOAT
+    memset(fixed_cpl_coords, 0, AC3_MAX_BLOCKS * sizeof(*cpl_coords));
+#endif
 
     /* align start to 16-byte boundary. align length to multiple of 32.
         note: coupling start bin % 4 will always be 1 */
@@ -168,10 +163,6 @@ static void apply_channel_coupling(AC3EncodeContext *s)
 
         /* coefficients must be clipped in order to be encoded */
         clip_coefficients(&s->dsp, cpl_coef, num_cpl_coefs);
-
-        /* scale coupling coefficients from float to 24-bit fixed-point */
-        s->ac3dsp.float_to_fixed24(&block->fixed_coef[CPL_CH][cpl_start],
-                                   cpl_coef, num_cpl_coefs);
     }
 
     /* calculate energy in each band in coupling channel and each fbw channel */
@@ -235,11 +226,11 @@ static void apply_channel_coupling(AC3EncodeContext *s)
                     } else {
                         CoefSumType coord_diff = 0;
                         for (bnd = 0; bnd < s->num_cpl_bands; bnd++) {
-                            coord_diff += fabs(cpl_coords[blk-1][ch][bnd] -
-                                               cpl_coords[blk  ][ch][bnd]);
+                            coord_diff += FFABS(cpl_coords[blk-1][ch][bnd] -
+                                                cpl_coords[blk  ][ch][bnd]);
                         }
                         coord_diff /= s->num_cpl_bands;
-                        if (coord_diff > 0.03)
+                        if (coord_diff > NEW_CPL_COORD_THRESHOLD)
                             block->new_cpl_coords[ch] = 1;
                     }
                 }
@@ -286,9 +277,11 @@ static void apply_channel_coupling(AC3EncodeContext *s)
         if (!block->cpl_in_use)
             continue;
 
+#if CONFIG_AC3ENC_FLOAT
         s->ac3dsp.float_to_fixed24(fixed_cpl_coords[blk][1],
                                    cpl_coords[blk][1],
                                    s->fbw_channels * 16);
+#endif
         s->ac3dsp.extract_exponents(block->cpl_coord_exp[1],
                                     fixed_cpl_coords[blk][1],
                                     s->fbw_channels * 16);
@@ -332,7 +325,6 @@ static void apply_channel_coupling(AC3EncodeContext *s)
 
     if (CONFIG_EAC3_ENCODER && s->eac3)
         ff_eac3_set_cpl_states(s);
-#endif /* CONFIG_AC3ENC_FLOAT */
 }
 
 
@@ -352,11 +344,6 @@ static void compute_rematrixing_strategy(AC3EncodeContext *s)
         block = &s->blocks[blk];
         block->new_rematrixing_strategy = !blk;
 
-        if (!s->rematrixing_enabled) {
-            block0 = block;
-            continue;
-        }
-
         block->num_rematrixing_bands = 4;
         if (block->cpl_in_use) {
             block->num_rematrixing_bands -= (s->start_freq[CPL_CH] <= 61);
@@ -366,6 +353,11 @@ static void compute_rematrixing_strategy(AC3EncodeContext *s)
         }
         nb_coefs = FFMIN(block->end_freq[1], block->end_freq[2]);
 
+        if (!s->rematrixing_enabled) {
+            block0 = block;
+            continue;
+        }
+
         for (bnd = 0; bnd < block->num_rematrixing_bands; bnd++) {
             /* calculate calculate sum of squared coeffs for one band in one block */
             int start = ff_ac3_rematrix_band_tab[bnd];
diff --git a/libavcodec/mpeg12.c b/libavcodec/mpeg12.c
index 069cd000a33e1fc113a1124dbb34069d3fbb9bf5..bff8619cbcf3fd8cf9fbb7a997936b124e1670d4 100644
--- a/libavcodec/mpeg12.c
+++ b/libavcodec/mpeg12.c
@@ -1949,7 +1949,7 @@ static int slice_decode_thread(AVCodecContext *c, void *arg){
 //ret, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, s->start_mb_y, s->end_mb_y, s->error_count);
         if(ret < 0){
             if (c->error_recognition >= FF_ER_EXPLODE)
-                return AVERROR_INVALIDDATA;
+                return ret;
             if(s->resync_mb_x>=0 && s->resync_mb_y>=0)
                 ff_er_add_slice(s, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, AC_ERROR|DC_ERROR|MV_ERROR);
         }else{
@@ -2303,10 +2303,11 @@ static int mpeg_decode_frame(AVCodecContext *avctx,
 
     s->slice_count= 0;
 
-    if(avctx->extradata && !avctx->frame_number &&
-       decode_chunks(avctx, picture, data_size, avctx->extradata, avctx->extradata_size) < 0 &&
-       avctx->error_recognition >= FF_ER_EXPLODE)
-      return AVERROR_INVALIDDATA;
+    if(avctx->extradata && !avctx->frame_number) {
+        int ret = decode_chunks(avctx, picture, data_size, avctx->extradata, avctx->extradata_size);
+        if (ret < 0 && avctx->error_recognition >= FF_ER_EXPLODE)
+            return ret;
+    }
 
     return decode_chunks(avctx, picture, data_size, buf, buf_size);
 }
@@ -2381,17 +2382,17 @@ static int decode_chunks(AVCodecContext *avctx,
                 s->slice_count = 0;
             }
             if(last_code == 0 || last_code == SLICE_MIN_START_CODE){
-            if(mpeg_decode_postinit(avctx) < 0){
-                av_log(avctx, AV_LOG_ERROR, "mpeg_decode_postinit() failure\n");
-                return -1;
-            }
+                ret = mpeg_decode_postinit(avctx);
+                if(ret < 0){
+                    av_log(avctx, AV_LOG_ERROR, "mpeg_decode_postinit() failure\n");
+                    return ret;
+                }
 
-            /* we have a complete image: we try to decompress it */
-            if(mpeg1_decode_picture(avctx,
-                                    buf_ptr, input_size) < 0)
-                s2->pict_type=0;
+                /* we have a complete image: we try to decompress it */
+                if (mpeg1_decode_picture(avctx, buf_ptr, input_size) < 0)
+                    s2->pict_type=0;
                 s2->first_slice = 1;
-            last_code= PICTURE_START_CODE;
+                last_code= PICTURE_START_CODE;
             }else{
                 av_log(avctx, AV_LOG_ERROR, "ignoring pic after %X\n", last_code);
                 if (avctx->error_recognition >= FF_ER_EXPLODE)
@@ -2437,9 +2438,8 @@ static int decode_chunks(AVCodecContext *avctx,
             break;
         case GOP_START_CODE:
             if(last_code == 0){
-            s2->first_field=0;
-            mpeg_decode_gop(avctx,
-                                    buf_ptr, input_size);
+                s2->first_field=0;
+                mpeg_decode_gop(avctx, buf_ptr, input_size);
                 s->sync=1;
             }else{
                 av_log(avctx, AV_LOG_ERROR, "ignoring GOP_START_CODE after %X\n", last_code);
@@ -2501,9 +2501,7 @@ static int decode_chunks(AVCodecContext *avctx,
                 }
                 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 (uses_vdpau(avctx)) {
@@ -2533,7 +2531,7 @@ static int decode_chunks(AVCodecContext *avctx,
 
                     if(ret < 0){
                         if (avctx->error_recognition >= FF_ER_EXPLODE)
-                            return AVERROR_INVALIDDATA;
+                            return ret;
                         if(s2->resync_mb_x>=0 && s2->resync_mb_y>=0)
                             ff_er_add_slice(s2, s2->resync_mb_x, s2->resync_mb_y, s2->mb_x, s2->mb_y, AC_ERROR|DC_ERROR|MV_ERROR);
                     }else{
diff --git a/libavcodec/wavpack.c b/libavcodec/wavpack.c
index ca52d0ac74bc0d3a1d9ecd190209548e371ac78b..9da1f91d1d60af011c4eee6dc947ac9ade6eddf1 100644
--- a/libavcodec/wavpack.c
+++ b/libavcodec/wavpack.c
@@ -470,6 +470,7 @@ static float wv_get_value_float(WavpackFrameContext *s, uint32_t *crc, int S)
 static void wv_reset_saved_context(WavpackFrameContext *s)
 {
     s->pos = 0;
+    s->samples_left = 0;
     s->sc.crc = s->extra_sc.crc = 0xFFFFFFFF;
 }
 
@@ -582,6 +583,7 @@ static inline int wv_unpack_stereo(WavpackFrameContext *s, GetBitContext *gb, vo
 
     s->samples_left -= count;
     if(!s->samples_left){
+        wv_reset_saved_context(s);
         if(crc != s->CRC){
             av_log(s->avctx, AV_LOG_ERROR, "CRC error\n");
             return -1;
@@ -590,7 +592,6 @@ static inline int wv_unpack_stereo(WavpackFrameContext *s, GetBitContext *gb, vo
             av_log(s->avctx, AV_LOG_ERROR, "Extra bits CRC error\n");
             return -1;
         }
-        wv_reset_saved_context(s);
     }else{
         s->pos = pos;
         s->sc.crc = crc;
@@ -660,6 +661,7 @@ static inline int wv_unpack_mono(WavpackFrameContext *s, GetBitContext *gb, void
 
     s->samples_left -= count;
     if(!s->samples_left){
+        wv_reset_saved_context(s);
         if(crc != s->CRC){
             av_log(s->avctx, AV_LOG_ERROR, "CRC error\n");
             return -1;
@@ -668,7 +670,6 @@ static inline int wv_unpack_mono(WavpackFrameContext *s, GetBitContext *gb, void
             av_log(s->avctx, AV_LOG_ERROR, "Extra bits CRC error\n");
             return -1;
         }
-        wv_reset_saved_context(s);
     }else{
         s->pos = pos;
         s->sc.crc = crc;
@@ -779,7 +780,7 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
         s->samples = AV_RL32(buf); buf += 4;
         if(!s->samples){
             *data_size = 0;
-            return buf_size;
+            return 0;
         }
     }else{
         s->samples = wc->samples;
@@ -1195,7 +1196,7 @@ static void wavpack_decode_flush(AVCodecContext *avctx)
     int i;
 
     for (i = 0; i < s->fdec_num; i++)
-        s->fdec[i]->samples_left = 0;
+        wv_reset_saved_context(s->fdec[i]);
 }
 
 AVCodec ff_wavpack_decoder = {
diff --git a/tests/fate-run.sh b/tests/fate-run.sh
index 3de097e515c1ce675dd8c0fae92a0ea18289e121..a09c13ab47ce544e4e781042c4746dc5a791d276 100755
--- a/tests/fate-run.sh
+++ b/tests/fate-run.sh
@@ -16,7 +16,7 @@ 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"
diff --git a/tests/fate/h264.mak b/tests/fate/h264.mak
index b0b6a9db4cf353203afe5ff6200b2342956792df..4716d9f521eeadc66a8e6da27a8638afe8966517 100644
--- a/tests/fate/h264.mak
+++ b/tests/fate/h264.mak
@@ -374,6 +374,6 @@ fate-h264-conformance-sva_fm1_e: CMD = framecrc -vsync 0 -i $(SAMPLES)/h264-conf
 fate-h264-conformance-sva_nl1_b: CMD = framecrc -vsync 0 -i $(SAMPLES)/h264-conformance/SVA_NL1_B.264
 fate-h264-conformance-sva_nl2_e: CMD = framecrc -vsync 0 -i $(SAMPLES)/h264-conformance/SVA_NL2_E.264
 
-fate-h264-interlace-crop: CMD = framecrc -vsync 0 -vframes 3 -i $(SAMPLES)/h264/interlaced_crop.mp4
+fate-h264-interlace-crop: CMD = framecrc -vsync 0 -i $(SAMPLES)/h264/interlaced_crop.mp4 -vframes 3
 fate-h264-lossless: CMD = framecrc -vsync 0 -i $(SAMPLES)/h264/lossless.h264
 fate-h264-extreme-plane-pred: CMD = framemd5 -strict 1 -vsync 0 -i $(SAMPLES)/h264/extreme-plane-pred.h264
diff --git a/tests/ref/acodec/ac3_fixed b/tests/ref/acodec/ac3_fixed
index ca8a082c75695995b6b2549aebda7a81cea60217..dba2dfc5e76e8c6ba5b3db4b69e88f5bafbb7c54 100644
--- a/tests/ref/acodec/ac3_fixed
+++ b/tests/ref/acodec/ac3_fixed
@@ -1,2 +1,2 @@
-0f14801e166819dd4a58981aea36e08b *./tests/data/acodec/ac3.rm
+e7fa185030a56d9db8663ad9e38c6c94 *./tests/data/acodec/ac3.rm
 98751 ./tests/data/acodec/ac3.rm
diff --git a/tests/ref/seek/ac3_rm b/tests/ref/seek/ac3_rm
index 05772fcf989a746581aaffef7d124c0be5a6079b..b38758bb2c6a1e77726106d3a33013307e81f4f0 100644
--- a/tests/ref/seek/ac3_rm
+++ b/tests/ref/seek/ac3_rm
@@ -5,35 +5,40 @@ ret:-1         st:-1 flags:1  ts: 1.894167
 ret:-1         st: 0 flags:0  ts: 0.788000
 ret: 0         st: 0 flags:1  ts:-0.317000
 ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:    271 size:   556
-ret: 0         st:-1 flags:0  ts: 2.576668
-ret: 0         st: 0 flags:1 dts: 2.577000 pts: 2.577000 pos:  42397 size:   558
+ret:-1         st:-1 flags:0  ts: 2.576668
 ret:-1         st:-1 flags:1  ts: 1.470835
 ret:-1         st: 0 flags:0  ts: 0.365000
 ret: 0         st: 0 flags:1  ts:-0.741000
 ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:    271 size:   556
-ret: 0         st:-1 flags:0  ts: 2.153336
-ret: 0         st: 0 flags:1 dts: 2.159000 pts: 2.159000 pos:  35567 size:   556
+ret:-1         st:-1 flags:0  ts: 2.153336
 ret:-1         st:-1 flags:1  ts: 1.047503
 ret: 0         st: 0 flags:0  ts:-0.058000
 ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:    271 size:   556
 ret:-1         st: 0 flags:1  ts: 2.836000
-ret:-1         st:-1 flags:0  ts: 1.730004
-ret:-1         st:-1 flags:1  ts: 0.624171
+ret: 0         st:-1 flags:0  ts: 1.730004
+ret: 0         st: 0 flags:1 dts:8589.800000 pts:8589.800000 pos:  65950 size: 32801
+ret: 0         st:-1 flags:1  ts: 0.624171
+ret: 0         st: 0 flags:1 dts: 0.256000 pts: 0.256000 pos:  65337 size:   400
 ret: 0         st: 0 flags:0  ts:-0.482000
 ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:    271 size:   556
-ret: 0         st: 0 flags:1  ts: 2.413000
-ret: 0         st: 0 flags:1 dts: 2.368000 pts: 2.368000 pos:  38981 size:   558
-ret:-1         st:-1 flags:0  ts: 1.306672
-ret:-1         st:-1 flags:1  ts: 0.200839
+ret:-1         st: 0 flags:1  ts: 2.413000
+ret: 0         st:-1 flags:0  ts: 1.306672
+ret: 0         st: 0 flags:1 dts:8589.800000 pts:8589.800000 pos:  65950 size: 32801
+ret: 0         st:-1 flags:1  ts: 0.200839
+ret: 0         st: 0 flags:1 dts: 0.034000 pts: 0.034000 pos:    839 size:   558
 ret: 0         st: 0 flags:0  ts:-0.905000
 ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:    271 size:   556
-ret:-1         st: 0 flags:1  ts: 1.989000
-ret:-1         st:-1 flags:0  ts: 0.883340
+ret: 0         st: 0 flags:1  ts: 1.989000
+ret: 0         st: 0 flags:1 dts: 0.256000 pts: 0.256000 pos:  65337 size:   400
+ret: 0         st:-1 flags:0  ts: 0.883340
+ret: 0         st: 0 flags:1 dts: 3.378000 pts: 3.378000 pos:  55491 size:   558
 ret: 0         st:-1 flags:1  ts:-0.222493
 ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:    271 size:   556
 ret: 0         st: 0 flags:0  ts: 2.672000
-ret: 0         st: 0 flags:1 dts: 2.821000 pts: 2.821000 pos:  46383 size:   556
-ret:-1         st: 0 flags:1  ts: 1.566000
-ret:-1         st:-1 flags:0  ts: 0.460008
+ret: 0         st: 0 flags:1 dts: 3.378000 pts: 3.378000 pos:  55491 size:   558
+ret: 0         st: 0 flags:1  ts: 1.566000
+ret: 0         st: 0 flags:1 dts: 0.256000 pts: 0.256000 pos:  65337 size:   400
+ret: 0         st:-1 flags:0  ts: 0.460008
+ret: 0         st: 0 flags:1 dts: 3.378000 pts: 3.378000 pos:  55491 size:   558
 ret: 0         st:-1 flags:1  ts:-0.645825
 ret: 0         st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:    271 size:   556