]> git.sesse.net Git - ffmpeg/blobdiff - ffmpeg.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / ffmpeg.c
index 6848f252e4fc2aa1ec833a4b682926f8d11bdeb2..849bd708fe2870faf7720fe6ec21ba42c969115d 100644 (file)
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -176,12 +176,14 @@ typedef struct InputFilter {
     AVFilterContext    *filter;
     struct InputStream *ist;
     struct FilterGraph *graph;
+    uint8_t            *name;
 } InputFilter;
 
 typedef struct OutputFilter {
     AVFilterContext     *filter;
     struct OutputStream *ost;
     struct FilterGraph  *graph;
+    uint8_t             *name;
 
     /* temporary storage until stream maps are processed */
     AVFilterInOut       *out_tmp;
@@ -234,6 +236,8 @@ typedef struct InputStream {
     int saw_first_ts;
     int showed_multi_packet_warning;
     AVDictionary *opts;
+    AVRational framerate;               /* framerate forced with -r */
+    int top_field_first;
 
     int resample_height;
     int resample_width;
@@ -276,6 +280,9 @@ typedef struct OutputStream {
        for A/V sync */
     struct InputStream *sync_ist; /* input stream to sync against */
     int64_t sync_opts;       /* output frame counter, could be changed to some true timestamp */ // FIXME look at frame_number
+    /* pts of the first frame encoded for this stream, used for limiting
+     * recording time */
+    int64_t first_pts;
     AVBitStreamFilterContext *bitstream_filters;
     AVCodec *enc;
     int64_t max_frames;
@@ -435,6 +442,8 @@ typedef struct OptionsContext {
     int        nb_filters;
 } OptionsContext;
 
+static void do_video_stats(AVFormatContext *os, OutputStream *ost, int frame_size);
+
 #define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\
 {\
     int i, ret;\
@@ -708,7 +717,7 @@ static char *choose_pix_fmts(OutputStream *ost)
     }
     if (ost->st->codec->pix_fmt != PIX_FMT_NONE) {
         return av_strdup(av_get_pix_fmt_name(choose_pixel_fmt(ost->st, ost->enc, ost->st->codec->pix_fmt)));
-    } else if (ost->enc->pix_fmts) {
+    } else if (ost->enc && ost->enc->pix_fmts) {
         const enum PixelFormat *p;
         AVIOContext *s = NULL;
         uint8_t *ret;
@@ -794,281 +803,6 @@ DEF_CHOOSE_FORMAT(int, sample_rate, supported_samplerates, 0,
 DEF_CHOOSE_FORMAT(uint64_t, channel_layout, channel_layouts, 0,
                   GET_CH_LAYOUT_NAME, ",")
 
-static int configure_audio_filters(FilterGraph *fg, AVFilterContext **in_filter,
-                                   AVFilterContext **out_filter)
-{
-    InputStream  *ist = fg->inputs[0]->ist;
-    OutputStream *ost = fg->outputs[0]->ost;
-    AVCodecContext *codec  = ost->st->codec;
-    AVCodecContext *icodec = ist->st->codec;
-    char *sample_fmts, *sample_rates, *channel_layouts;
-    char args[256];
-    int ret;
-
-    avfilter_graph_free(&fg->graph);
-    if (!(fg->graph = avfilter_graph_alloc()))
-        return AVERROR(ENOMEM);
-
-    snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:"
-             "channel_layout=0x%"PRIx64, ist->st->time_base.num,
-             ist->st->time_base.den, icodec->sample_rate,
-             av_get_sample_fmt_name(icodec->sample_fmt), icodec->channel_layout);
-    ret = avfilter_graph_create_filter(&fg->inputs[0]->filter,
-                                       avfilter_get_by_name("abuffer"),
-                                       "src", args, NULL, fg->graph);
-    if (ret < 0)
-        return ret;
-
-    ret = avfilter_graph_create_filter(&fg->outputs[0]->filter,
-                                       avfilter_get_by_name("abuffersink_old"),
-                                       "out", NULL, NULL, fg->graph);
-    if (ret < 0)
-        return ret;
-
-    *in_filter  = fg->inputs[0]->filter;
-    *out_filter = fg->outputs[0]->filter;
-
-    if (codec->channels && !codec->channel_layout)
-        codec->channel_layout = av_get_default_channel_layout(codec->channels);
-
-    sample_fmts     = choose_sample_fmts(ost);
-    sample_rates    = choose_sample_rates(ost);
-    channel_layouts = choose_channel_layouts(ost);
-    if (sample_fmts || sample_rates || channel_layouts) {
-        AVFilterContext *format;
-        char args[256];
-        int len = 0;
-
-        if (sample_fmts)
-            len += snprintf(args + len, sizeof(args) - len, "sample_fmts=%s:",
-                            sample_fmts);
-        if (sample_rates)
-            len += snprintf(args + len, sizeof(args) - len, "sample_rates=%s:",
-                            sample_rates);
-        if (channel_layouts)
-            len += snprintf(args + len, sizeof(args) - len, "channel_layouts=%s:",
-                            channel_layouts);
-        args[len - 1] = 0;
-
-        av_freep(&sample_fmts);
-        av_freep(&sample_rates);
-        av_freep(&channel_layouts);
-
-        ret = avfilter_graph_create_filter(&format,
-                                           avfilter_get_by_name("aformat"),
-                                           "aformat", args, NULL, fg->graph);
-        if (ret < 0)
-            return ret;
-
-        ret = avfilter_link(format, 0, fg->outputs[0]->filter, 0);
-        if (ret < 0)
-            return ret;
-
-        *out_filter = format;
-    }
-
-    if (audio_sync_method > 0) {
-        AVFilterContext *aswr;
-        char args[256] = {0};
-
-        av_strlcatf(args, sizeof(args), "min_comp=0.001:min_hard_comp=%f", audio_drift_threshold);
-
-        if (audio_sync_method > 1)
-            av_strlcatf(args, sizeof(args), ":max_soft_comp=%f", audio_sync_method/(double)icodec->sample_rate);
-
-        av_log(NULL, AV_LOG_INFO, "-async %d is forwarded to lavfi similarly to -af aresample=%s\n", audio_sync_method, args);
-
-        ret = avfilter_graph_create_filter(&aswr, avfilter_get_by_name("aresample"),
-                                           "aresample", args, NULL, fg->graph);
-        if (ret < 0)
-            return ret;
-
-        ret = avfilter_link(*in_filter, 0, aswr, 0);
-        if (ret < 0)
-            return ret;
-
-        *in_filter = aswr;
-    }
-
-#define AUTO_INSERT_FILTER(opt_name, filter_name, arg) do {                 \
-    AVFilterContext *filt_ctx;                                              \
-                                                                            \
-    av_log(NULL, AV_LOG_INFO, opt_name " is forwarded to lavfi "            \
-           "similarly to -af " filter_name "=%s.\n", arg);                  \
-                                                                            \
-    ret = avfilter_graph_create_filter(&filt_ctx,                           \
-                                       avfilter_get_by_name(filter_name),   \
-                                       filter_name, arg, NULL, fg->graph);  \
-    if (ret < 0)                                                            \
-        return ret;                                                         \
-                                                                            \
-    ret = avfilter_link(*in_filter, 0, filt_ctx, 0);                        \
-    if (ret < 0)                                                            \
-        return ret;                                                         \
-                                                                            \
-    *in_filter = filt_ctx;                                                  \
-} while (0)
-
-    if (ost->audio_channels_mapped) {
-        int i;
-        AVBPrint pan_buf;
-
-        av_bprint_init(&pan_buf, 256, 8192);
-        av_bprintf(&pan_buf, "0x%"PRIx64,
-                   av_get_default_channel_layout(ost->audio_channels_mapped));
-        for (i = 0; i < ost->audio_channels_mapped; i++)
-            if (ost->audio_channels_map[i] != -1)
-                av_bprintf(&pan_buf, ":c%d=c%d", i, ost->audio_channels_map[i]);
-
-        AUTO_INSERT_FILTER("-map_channel", "pan", pan_buf.str);
-        av_bprint_finalize(&pan_buf, NULL);
-    }
-
-    if (audio_volume != 256) {
-        char args[256];
-
-        snprintf(args, sizeof(args), "%lf", audio_volume / 256.);
-        AUTO_INSERT_FILTER("-vol", "volume", args);
-    }
-
-    return 0;
-}
-
-static int configure_video_filters(FilterGraph *fg, AVFilterContext **in_filter,
-                                   AVFilterContext **out_filter)
-{
-    InputStream  *ist = fg->inputs[0]->ist;
-    OutputStream *ost = fg->outputs[0]->ost;
-    AVFilterContext *filter;
-    AVCodecContext *codec = ost->st->codec;
-    AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc();
-    char *pix_fmts;
-    AVRational sample_aspect_ratio;
-    char args[255];
-    int ret;
-
-    if (ist->st->sample_aspect_ratio.num) {
-        sample_aspect_ratio = ist->st->sample_aspect_ratio;
-    } else
-        sample_aspect_ratio = ist->st->codec->sample_aspect_ratio;
-
-    snprintf(args, 255, "%d:%d:%d:%d:%d:%d:%d:flags=%d", ist->st->codec->width,
-             ist->st->codec->height, ist->st->codec->pix_fmt,
-             1, AV_TIME_BASE,
-             sample_aspect_ratio.num, sample_aspect_ratio.den,
-             SWS_BILINEAR + ((ist->st->codec->flags&CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0));
-
-    ret = avfilter_graph_create_filter(&fg->inputs[0]->filter,
-                                       avfilter_get_by_name("buffer"),
-                                       "src", args, NULL, fg->graph);
-    if (ret < 0)
-        return ret;
-
-#if FF_API_OLD_VSINK_API
-    ret = avfilter_graph_create_filter(&fg->outputs[0]->filter,
-                                       avfilter_get_by_name("buffersink"),
-                                       "out", NULL, NULL, fg->graph);
-#else
-    ret = avfilter_graph_create_filter(&fg->outputs[0]->filter,
-                                       avfilter_get_by_name("buffersink"),
-                                       "out", NULL, buffersink_params, fg->graph);
-#endif
-    av_freep(&buffersink_params);
-
-    if (ret < 0)
-        return ret;
-    *in_filter  = fg->inputs[0]->filter;
-    *out_filter = fg->outputs[0]->filter;
-
-    if (codec->width || codec->height) {
-        snprintf(args, 255, "%d:%d:flags=0x%X",
-                 codec->width,
-                 codec->height,
-                 (unsigned)ost->sws_flags);
-        if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"),
-                                                NULL, args, NULL, fg->graph)) < 0)
-            return ret;
-        if ((ret = avfilter_link(*in_filter, 0, filter, 0)) < 0)
-            return ret;
-        *in_filter = filter;
-    }
-
-    if ((pix_fmts = choose_pix_fmts(ost))) {
-        if ((ret = avfilter_graph_create_filter(&filter,
-                                                avfilter_get_by_name("format"),
-                                                "format", pix_fmts, NULL,
-                                                fg->graph)) < 0)
-            return ret;
-        if ((ret = avfilter_link(filter, 0, *out_filter, 0)) < 0)
-            return ret;
-
-        *out_filter = filter;
-        av_freep(&pix_fmts);
-    }
-
-    snprintf(args, sizeof(args), "flags=0x%X", (unsigned)ost->sws_flags);
-    fg->graph->scale_sws_opts = av_strdup(args);
-
-    return 0;
-}
-
-static int configure_simple_filtergraph(FilterGraph *fg)
-{
-    OutputStream *ost = fg->outputs[0]->ost;
-    AVFilterContext *in_filter, *out_filter;
-    int ret;
-
-    avfilter_graph_free(&fg->graph);
-    fg->graph = avfilter_graph_alloc();
-    if (!fg->graph)
-        return AVERROR(ENOMEM);
-
-    switch (ost->st->codec->codec_type) {
-    case AVMEDIA_TYPE_VIDEO:
-        ret = configure_video_filters(fg, &in_filter, &out_filter);
-        break;
-    case AVMEDIA_TYPE_AUDIO:
-        ret = configure_audio_filters(fg, &in_filter, &out_filter);
-        break;
-    default: av_assert0(0);
-    }
-    if (ret < 0)
-        return ret;
-
-    if (ost->avfilter) {
-        AVFilterInOut *outputs = avfilter_inout_alloc();
-        AVFilterInOut *inputs  = avfilter_inout_alloc();
-
-        outputs->name    = av_strdup("in");
-        outputs->filter_ctx = in_filter;
-        outputs->pad_idx = 0;
-        outputs->next    = NULL;
-
-        inputs->name    = av_strdup("out");
-        inputs->filter_ctx = out_filter;
-        inputs->pad_idx = 0;
-        inputs->next    = NULL;
-
-        if ((ret = avfilter_graph_parse(fg->graph, ost->avfilter, &inputs, &outputs, NULL)) < 0)
-            return ret;
-        av_freep(&ost->avfilter);
-    } else {
-        if ((ret = avfilter_link(in_filter, 0, out_filter, 0)) < 0)
-            return ret;
-    }
-
-    if (ost->keep_pix_fmt)
-        avfilter_graph_set_auto_convert(fg->graph,
-                                        AVFILTER_AUTO_CONVERT_NONE);
-
-    if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0)
-        return ret;
-
-    ost->filter = fg->outputs[0];
-
-    return 0;
-}
-
 static FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost)
 {
     FilterGraph *fg = av_mallocz(sizeof(*fg));
@@ -1084,6 +818,8 @@ static FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost)
     fg->outputs[0]->ost   = ost;
     fg->outputs[0]->graph = fg;
 
+    ost->filter = fg->outputs[0];
+
     fg->inputs = grow_array(fg->inputs, sizeof(*fg->inputs), &fg->nb_inputs,
                             fg->nb_inputs + 1);
     if (!(fg->inputs[0] = av_mallocz(sizeof(*fg->inputs[0]))))
@@ -1175,7 +911,8 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
 static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
 {
     char *pix_fmts;
-    AVCodecContext *codec = ofilter->ost->st->codec;
+    OutputStream *ost = ofilter->ost;
+    AVCodecContext *codec = ost->st->codec;
     AVFilterContext *last_filter = out->filter_ctx;
     int pad_idx = out->pad_idx;
     int ret;
@@ -1202,7 +939,7 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
         snprintf(args, sizeof(args), "%d:%d:flags=0x%X",
                  codec->width,
                  codec->height,
-                 (unsigned)ofilter->ost->sws_flags);
+                 (unsigned)ost->sws_flags);
         if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"),
                                                 NULL, args, NULL, fg->graph)) < 0)
             return ret;
@@ -1213,7 +950,7 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
         pad_idx = 0;
     }
 
-    if ((pix_fmts = choose_pix_fmts(ofilter->ost))) {
+    if ((pix_fmts = choose_pix_fmts(ost))) {
         AVFilterContext *filter;
         if ((ret = avfilter_graph_create_filter(&filter,
                                                 avfilter_get_by_name("format"),
@@ -1228,6 +965,24 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
         av_freep(&pix_fmts);
     }
 
+    if (ost->frame_rate.num && 0) {
+        AVFilterContext *fps;
+        char args[255];
+
+        snprintf(args, sizeof(args), "fps=%d/%d", ost->frame_rate.num,
+                 ost->frame_rate.den);
+        ret = avfilter_graph_create_filter(&fps, avfilter_get_by_name("fps"),
+                                           "fps", args, NULL, fg->graph);
+        if (ret < 0)
+            return ret;
+
+        ret = avfilter_link(last_filter, pad_idx, fps, 0);
+        if (ret < 0)
+            return ret;
+        last_filter = fps;
+        pad_idx = 0;
+    }
+
     if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)
         return ret;
 
@@ -1244,7 +999,7 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter,
     int ret;
 
     ret = avfilter_graph_create_filter(&ofilter->filter,
-                                       avfilter_get_by_name("abuffersink"),
+                                       avfilter_get_by_name("abuffersink_old"),
                                        "out", NULL, NULL, fg->graph);
     if (ret < 0)
         return ret;
@@ -1271,123 +1026,280 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter,
                             channel_layouts);
         args[len - 1] = 0;
 
-        av_freep(&sample_fmts);
-        av_freep(&sample_rates);
-        av_freep(&channel_layouts);
+        av_freep(&sample_fmts);
+        av_freep(&sample_rates);
+        av_freep(&channel_layouts);
+
+        ret = avfilter_graph_create_filter(&format,
+                                           avfilter_get_by_name("aformat"),
+                                           "aformat", args, NULL, fg->graph);
+        if (ret < 0)
+            return ret;
+
+        ret = avfilter_link(last_filter, pad_idx, format, 0);
+        if (ret < 0)
+            return ret;
+
+        last_filter = format;
+        pad_idx = 0;
+    }
+
+#define AUTO_INSERT_FILTER(opt_name, filter_name, arg) do {                 \
+    AVFilterContext *filt_ctx;                                              \
+                                                                            \
+    av_log(NULL, AV_LOG_INFO, opt_name " is forwarded to lavfi "            \
+           "similarly to -af " filter_name "=%s.\n", arg);                  \
+                                                                            \
+    ret = avfilter_graph_create_filter(&filt_ctx,                           \
+                                       avfilter_get_by_name(filter_name),   \
+                                       filter_name, arg, NULL, fg->graph);  \
+    if (ret < 0)                                                            \
+        return ret;                                                         \
+                                                                            \
+    ret = avfilter_link(last_filter, pad_idx, filt_ctx, 0);                 \
+    if (ret < 0)                                                            \
+        return ret;                                                         \
+                                                                            \
+    last_filter = filt_ctx;                                                 \
+    pad_idx = 0;                                                            \
+} while (0)
+
+    if (audio_sync_method > 0 && 0) {
+        char args[256] = {0};
+
+        av_strlcatf(args, sizeof(args), "min_comp=0.001:min_hard_comp=%f", audio_drift_threshold);
+        if (audio_sync_method > 1)
+            av_strlcatf(args, sizeof(args), ":max_soft_comp=%d", -audio_sync_method);
+        AUTO_INSERT_FILTER("-async", "aresample", args);
+    }
+
+    if (ost->audio_channels_mapped) {
+        int i;
+        AVBPrint pan_buf;
+        av_bprint_init(&pan_buf, 256, 8192);
+        av_bprintf(&pan_buf, "0x%"PRIx64,
+                   av_get_default_channel_layout(ost->audio_channels_mapped));
+        for (i = 0; i < ost->audio_channels_mapped; i++)
+            if (ost->audio_channels_map[i] != -1)
+                av_bprintf(&pan_buf, ":c%d=c%d", i, ost->audio_channels_map[i]);
+
+        AUTO_INSERT_FILTER("-map_channel", "pan", pan_buf.str);
+        av_bprint_finalize(&pan_buf, NULL);
+    }
+
+    if (audio_volume != 256) {
+        char args[256];
+
+        snprintf(args, sizeof(args), "%f", audio_volume / 256.);
+        AUTO_INSERT_FILTER("-vol", "volume", args);
+    }
+
+    if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)
+        return ret;
+
+    return 0;
+}
+
+#define DESCRIBE_FILTER_LINK(f, inout, in)                         \
+{                                                                  \
+    AVFilterContext *ctx = inout->filter_ctx;                      \
+    AVFilterPad *pads = in ? ctx->input_pads  : ctx->output_pads;  \
+    int       nb_pads = in ? ctx->input_count : ctx->output_count; \
+    AVIOContext *pb;                                               \
+                                                                   \
+    if (avio_open_dyn_buf(&pb) < 0)                                \
+        exit_program(1);                                           \
+                                                                   \
+    avio_printf(pb, "%s", ctx->filter->name);                      \
+    if (nb_pads > 1)                                               \
+        avio_printf(pb, ":%s", pads[inout->pad_idx].name);         \
+    avio_w8(pb, 0);                                                \
+    avio_close_dyn_buf(pb, &f->name);                              \
+}
+
+static int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
+{
+    av_freep(&ofilter->name);
+    DESCRIBE_FILTER_LINK(ofilter, out, 0);
+
+    switch (out->filter_ctx->output_pads[out->pad_idx].type) {
+    case AVMEDIA_TYPE_VIDEO: return configure_output_video_filter(fg, ofilter, out);
+    case AVMEDIA_TYPE_AUDIO: return configure_output_audio_filter(fg, ofilter, out);
+    default: av_assert0(0);
+    }
+}
+
+static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
+                                        AVFilterInOut *in)
+{
+    AVFilterContext *first_filter = in->filter_ctx;
+    AVFilter *filter = avfilter_get_by_name("buffer");
+    InputStream *ist = ifilter->ist;
+    AVRational tb = ist->framerate.num ? (AVRational){ist->framerate.den,
+                                                      ist->framerate.num} :
+                                         ist->st->time_base;
+    AVRational sar;
+    char args[255];
+    int pad_idx = in->pad_idx;
+    int ret;
+
+    sar = ist->st->sample_aspect_ratio.num ?
+          ist->st->sample_aspect_ratio :
+          ist->st->codec->sample_aspect_ratio;
+    snprintf(args, sizeof(args), "%d:%d:%d:%d:%d:%d:%d:flags=%d", ist->st->codec->width,
+             ist->st->codec->height, ist->st->codec->pix_fmt,
+             tb.num, tb.den, sar.num, sar.den,
+             SWS_BILINEAR + ((ist->st->codec->flags&CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0));
+
+    if ((ret = avfilter_graph_create_filter(&ifilter->filter, filter, in->name,
+                                            args, NULL, fg->graph)) < 0)
+        return ret;
 
-        ret = avfilter_graph_create_filter(&format,
-                                           avfilter_get_by_name("aformat"),
-                                           "aformat", args, NULL, fg->graph);
-        if (ret < 0)
+    if (ist->framerate.num) {
+        AVFilterContext *setpts;
+
+        if ((ret = avfilter_graph_create_filter(&setpts,
+                                                avfilter_get_by_name("setpts"),
+                                                "setpts", "N", NULL,
+                                                fg->graph)) < 0)
             return ret;
 
-        ret = avfilter_link(last_filter, pad_idx, format, 0);
-        if (ret < 0)
+        if ((ret = avfilter_link(setpts, 0, first_filter, pad_idx)) < 0)
             return ret;
 
-        last_filter = format;
+        first_filter = setpts;
         pad_idx = 0;
     }
 
-    if (audio_sync_method > 0) {
-        AVFilterContext *async;
-        char args[256];
-        int  len = 0;
+    if ((ret = avfilter_link(ifilter->filter, 0, first_filter, pad_idx)) < 0)
+        return ret;
+    return 0;
+}
+
+static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
+                                        AVFilterInOut *in)
+{
+    AVFilterContext *first_filter = in->filter_ctx;
+    AVFilter *filter = avfilter_get_by_name("abuffer");
+    InputStream *ist = ifilter->ist;
+    int pad_idx = in->pad_idx;
+    char args[255];
+    int ret;
+
+    snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s"
+             ":channel_layout=0x%"PRIx64,
+             ist->st->time_base.num, ist->st->time_base.den,
+             ist->st->codec->sample_rate,
+             av_get_sample_fmt_name(ist->st->codec->sample_fmt),
+             ist->st->codec->channel_layout);
+
+    if ((ret = avfilter_graph_create_filter(&ifilter->filter, filter,
+                                            in->name, args, NULL,
+                                            fg->graph)) < 0)
+        return ret;
+
+#define AUTO_INSERT_FILTER_INPUT(opt_name, filter_name, arg) do {                 \
+    AVFilterContext *filt_ctx;                                              \
+                                                                            \
+    av_log(NULL, AV_LOG_INFO, opt_name " is forwarded to lavfi "            \
+           "similarly to -af " filter_name "=%s.\n", arg);                  \
+                                                                            \
+    ret = avfilter_graph_create_filter(&filt_ctx,                           \
+                                       avfilter_get_by_name(filter_name),   \
+                                       filter_name, arg, NULL, fg->graph);  \
+    if (ret < 0)                                                            \
+        return ret;                                                         \
+                                                                            \
+    ret = avfilter_link(filt_ctx, 0, first_filter, pad_idx);                \
+    if (ret < 0)                                                            \
+        return ret;                                                         \
+                                                                            \
+    first_filter = filt_ctx;                                                  \
+} while (0)
 
-        av_log(NULL, AV_LOG_WARNING, "-async has been deprecated. Used the "
-               "asyncts audio filter instead.\n");
+    if (audio_sync_method > 0) {
+        char args[256] = {0};
 
+        av_strlcatf(args, sizeof(args), "min_comp=0.001:min_hard_comp=%f", audio_drift_threshold);
         if (audio_sync_method > 1)
-            len += snprintf(args + len, sizeof(args) - len, "compensate=1:"
-                            "max_comp=%d:", audio_sync_method);
-        snprintf(args + len, sizeof(args) - len, "min_delta=%f",
-                 audio_drift_threshold);
-
-        ret = avfilter_graph_create_filter(&async,
-                                           avfilter_get_by_name("asyncts"),
-                                           "async", args, NULL, fg->graph);
-        if (ret < 0)
-            return ret;
+            av_strlcatf(args, sizeof(args), ":max_soft_comp=%f", audio_sync_method/(double)ist->st->codec->sample_rate);
+        AUTO_INSERT_FILTER_INPUT("-async", "aresample", args);
+    }
+
+//     if (ost->audio_channels_mapped) {
+//         int i;
+//         AVBPrint pan_buf;
+//         av_bprint_init(&pan_buf, 256, 8192);
+//         av_bprintf(&pan_buf, "0x%"PRIx64,
+//                    av_get_default_channel_layout(ost->audio_channels_mapped));
+//         for (i = 0; i < ost->audio_channels_mapped; i++)
+//             if (ost->audio_channels_map[i] != -1)
+//                 av_bprintf(&pan_buf, ":c%d=c%d", i, ost->audio_channels_map[i]);
+//         AUTO_INSERT_FILTER_INPUT("-map_channel", "pan", pan_buf.str);
+//         av_bprint_finalize(&pan_buf, NULL);
+//     }
 
-        ret = avfilter_link(last_filter, pad_idx, async, 0);
-        if (ret < 0)
-            return ret;
+    if (audio_volume != 256) {
+        char args[256];
 
-        last_filter = async;
-        pad_idx = 0;
+        snprintf(args, sizeof(args), "%f", audio_volume / 256.);
+        AUTO_INSERT_FILTER_INPUT("-vol", "volume", args);
     }
-
-    if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)
+    if ((ret = avfilter_link(ifilter->filter, 0, first_filter, pad_idx)) < 0)
         return ret;
 
     return 0;
 }
 
-static int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
+static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter,
+                                  AVFilterInOut *in)
 {
-    switch (out->filter_ctx->output_pads[out->pad_idx].type) {
-    case AVMEDIA_TYPE_VIDEO: return configure_output_video_filter(fg, ofilter, out);
-    case AVMEDIA_TYPE_AUDIO: return configure_output_audio_filter(fg, ofilter, out);
+    av_freep(&ifilter->name);
+    DESCRIBE_FILTER_LINK(ifilter, in, 1);
+
+    switch (in->filter_ctx->input_pads[in->pad_idx].type) {
+    case AVMEDIA_TYPE_VIDEO: return configure_input_video_filter(fg, ifilter, in);
+    case AVMEDIA_TYPE_AUDIO: return configure_input_audio_filter(fg, ifilter, in);
     default: av_assert0(0);
     }
 }
 
-static int configure_complex_filter(FilterGraph *fg)
+static int configure_filtergraph(FilterGraph *fg)
 {
     AVFilterInOut *inputs, *outputs, *cur;
-    int ret, i, init = !fg->graph;
+    int ret, i, init = !fg->graph, simple = !fg->graph_desc;
+    const char *graph_desc = simple ? fg->outputs[0]->ost->avfilter :
+                                      fg->graph_desc;
 
     avfilter_graph_free(&fg->graph);
     if (!(fg->graph = avfilter_graph_alloc()))
         return AVERROR(ENOMEM);
 
-    if ((ret = avfilter_graph_parse2(fg->graph, fg->graph_desc, &inputs, &outputs)) < 0)
-        return ret;
+    if (simple) {
+        OutputStream *ost = fg->outputs[0]->ost;
+        char args[255];
+        snprintf(args, sizeof(args), "flags=0x%X", (unsigned)ost->sws_flags);
+        fg->graph->scale_sws_opts = av_strdup(args);
+    }
 
-    for (cur = inputs; init && cur; cur = cur->next)
-        init_input_filter(fg, cur);
+    if ((ret = avfilter_graph_parse2(fg->graph, graph_desc, &inputs, &outputs)) < 0)
+        return ret;
 
-    for (cur = inputs, i = 0; cur; cur = cur->next, i++) {
-        InputFilter *ifilter = fg->inputs[i];
-        InputStream     *ist = ifilter->ist;
-        AVRational       sar;
-        AVFilter     *filter;
-        char            args[255];
+    if (simple && (!inputs || inputs->next || !outputs || outputs->next)) {
+        av_log(NULL, AV_LOG_ERROR, "Simple filtergraph '%s' does not have "
+               "exactly one input and output.\n", graph_desc);
+        return AVERROR(EINVAL);
+    }
 
-        switch (cur->filter_ctx->input_pads[cur->pad_idx].type) {
-        case AVMEDIA_TYPE_VIDEO:
-            sar = ist->st->sample_aspect_ratio.num ?
-                  ist->st->sample_aspect_ratio :
-                  ist->st->codec->sample_aspect_ratio;
-            snprintf(args, sizeof(args), "%d:%d:%d:%d:%d:%d:%d", ist->st->codec->width,
-                     ist->st->codec->height, ist->st->codec->pix_fmt, 1, AV_TIME_BASE,
-                     sar.num, sar.den);
-            filter = avfilter_get_by_name("buffer");
-            break;
-        case AVMEDIA_TYPE_AUDIO:
-            snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:"
-                     "sample_fmt=%s:channel_layout=0x%"PRIx64,
-                     ist->st->time_base.num, ist->st->time_base.den,
-                     ist->st->codec->sample_rate,
-                     av_get_sample_fmt_name(ist->st->codec->sample_fmt),
-                     ist->st->codec->channel_layout);
-            filter = avfilter_get_by_name("abuffer");
-            break;
-        default:
-            av_assert0(0);
-        }
+    for (cur = inputs; !simple && init && cur; cur = cur->next)
+        init_input_filter(fg, cur);
 
-        if ((ret = avfilter_graph_create_filter(&ifilter->filter,
-                                                filter, cur->name,
-                                                args, NULL, fg->graph)) < 0)
-            return ret;
-        if ((ret = avfilter_link(ifilter->filter, 0,
-                                 cur->filter_ctx, cur->pad_idx)) < 0)
+    for (cur = inputs, i = 0; cur; cur = cur->next, i++)
+        if ((ret = configure_input_filter(fg, fg->inputs[i], cur)) < 0)
             return ret;
-    }
     avfilter_inout_free(&inputs);
 
-    if (!init) {
+    if (!init || simple) {
         /* we already know the mappings between lavfi outputs and output streams,
          * so we can finish the setup */
         for (cur = outputs, i = 0; cur; cur = cur->next, i++)
@@ -1419,17 +1331,11 @@ static int configure_complex_filters(void)
 
     for (i = 0; i < nb_filtergraphs; i++)
         if (!filtergraphs[i]->graph &&
-            (ret = configure_complex_filter(filtergraphs[i])) < 0)
+            (ret = configure_filtergraph(filtergraphs[i])) < 0)
             return ret;
     return 0;
 }
 
-static int configure_filtergraph(FilterGraph *fg)
-{
-    return fg->graph_desc ? configure_complex_filter(fg) :
-                            configure_simple_filtergraph(fg);
-}
-
 static int ist_in_filtergraph(FilterGraph *fg, InputStream *ist)
 {
     int i;
@@ -1560,11 +1466,15 @@ void av_noreturn exit_program(int ret)
 
     for (i = 0; i < nb_filtergraphs; i++) {
         avfilter_graph_free(&filtergraphs[i]->graph);
-        for (j = 0; j < filtergraphs[i]->nb_inputs; j++)
+        for (j = 0; j < filtergraphs[i]->nb_inputs; j++) {
+            av_freep(&filtergraphs[i]->inputs[j]->name);
             av_freep(&filtergraphs[i]->inputs[j]);
+        }
         av_freep(&filtergraphs[i]->inputs);
-        for (j = 0; j < filtergraphs[i]->nb_outputs; j++)
+        for (j = 0; j < filtergraphs[i]->nb_outputs; j++) {
+            av_freep(&filtergraphs[i]->outputs[j]->name);
             av_freep(&filtergraphs[i]->outputs[j]);
+        }
         av_freep(&filtergraphs[i]->outputs);
         av_freep(&filtergraphs[i]);
     }
@@ -1674,13 +1584,6 @@ static void choose_sample_fmt(AVStream *st, AVCodec *codec)
     }
 }
 
-static double
-get_sync_ipts(const OutputStream *ost, int64_t pts)
-{
-    OutputFile *of = output_files[ost->file_index];
-    return (double)(pts - of->start_time) / AV_TIME_BASE;
-}
-
 static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
 {
     AVBitStreamFilterContext *bsfc = ost->bitstream_filters;
@@ -1744,18 +1647,18 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
     }
 }
 
-// static int check_recording_time(OutputStream *ost)
-// {
-//     OutputFile *of = output_files[ost->file_index];
-//
-//     if (of->recording_time != INT64_MAX &&
-//         av_compare_ts(ost->sync_opts - ost->first_pts, ost->st->codec->time_base, of->recording_time,
-//                       AV_TIME_BASE_Q) >= 0) {
-//         ost->is_past_recording_time = 1;
-//         return 0;
-//     }
-//     return 1;
-// }
+static int check_recording_time(OutputStream *ost)
+{
+    OutputFile *of = output_files[ost->file_index];
+
+    if (of->recording_time != INT64_MAX &&
+        av_compare_ts(ost->sync_opts - ost->first_pts, ost->st->codec->time_base, of->recording_time,
+                      AV_TIME_BASE_Q) >= 0) {
+        ost->is_past_recording_time = 1;
+        return 0;
+    }
+    return 1;
+}
 
 static void do_audio_out(AVFormatContext *s, OutputStream *ost,
                          AVFrame *frame)
@@ -1908,54 +1811,15 @@ static void do_subtitle_out(AVFormatContext *s,
     }
 }
 
-static double psnr(double d)
-{
-    return -10.0 * log(d) / log(10.0);
-}
-
-static void do_video_stats(AVFormatContext *os, OutputStream *ost,
-                           int frame_size)
-{
-    AVCodecContext *enc;
-    int frame_number;
-    double ti1, bitrate, avg_bitrate;
-
-    /* this is executed just the first time do_video_stats is called */
-    if (!vstats_file) {
-        vstats_file = fopen(vstats_filename, "w");
-        if (!vstats_file) {
-            perror("fopen");
-            exit_program(1);
-        }
-    }
-
-    enc = ost->st->codec;
-    if (enc->codec_type == AVMEDIA_TYPE_VIDEO) {
-        frame_number = ost->frame_number;
-        fprintf(vstats_file, "frame= %5d q= %2.1f ", frame_number, enc->coded_frame->quality / (float)FF_QP2LAMBDA);
-        if (enc->flags&CODEC_FLAG_PSNR)
-            fprintf(vstats_file, "PSNR= %6.2f ", psnr(enc->coded_frame->error[0] / (enc->width * enc->height * 255.0 * 255.0)));
-
-        fprintf(vstats_file,"f_size= %6d ", frame_size);
-        /* compute pts value */
-        ti1 = ost->sync_opts * av_q2d(enc->time_base);
-        if (ti1 < 0.01)
-            ti1 = 0.01;
-
-        bitrate     = (frame_size * 8) / av_q2d(enc->time_base) / 1000.0;
-        avg_bitrate = (double)(video_size * 8) / ti1 / 1000.0;
-        fprintf(vstats_file, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ",
-               (double)video_size / 1024, ti1, bitrate, avg_bitrate);
-        fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(enc->coded_frame->pict_type));
-    }
-}
-
-
-static void do_video_out(AVFormatContext *s, OutputStream *ost,
-                         AVFrame *in_picture, float quality)
+static void do_video_out(AVFormatContext *s,
+                         OutputStream *ost,
+                         AVFrame *in_picture,
+                         float quality)
 {
-    int nb_frames, i, ret, format_video_sync;
-    AVCodecContext *enc;
+    int ret, format_video_sync;
+    AVPacket pkt;
+    AVCodecContext *enc = ost->st->codec;
+    int nb_frames, i;
     double sync_ipts, delta;
     double duration = 0;
     int frame_size = 0;
@@ -1964,12 +1828,10 @@ static void do_video_out(AVFormatContext *s, OutputStream *ost,
     if (ost->source_index >= 0)
         ist = input_streams[ost->source_index];
 
-    enc = ost->st->codec;
-
     if(ist && ist->st->start_time != AV_NOPTS_VALUE && ist->st->first_dts != AV_NOPTS_VALUE && ost->frame_rate.num)
         duration = 1/(av_q2d(ost->frame_rate) * av_q2d(enc->time_base));
 
-    sync_ipts = get_sync_ipts(ost, in_picture->pts) / av_q2d(enc->time_base);
+    sync_ipts = in_picture->pts;
     delta = sync_ipts - ost->sync_opts + duration;
 
     /* by default, we output a single frame */
@@ -2011,99 +1873,144 @@ static void do_video_out(AVFormatContext *s, OutputStream *ost,
         av_log(NULL, AV_LOG_VERBOSE, "*** %d dup!\n", nb_frames - 1);
     }
 
-    /* duplicates frame if needed */
-    for (i = 0; i < nb_frames; i++) {
-        AVPacket pkt;
-        av_init_packet(&pkt);
-        pkt.data = NULL;
-        pkt.size = 0;
-
-        if (s->oformat->flags & AVFMT_RAWPICTURE &&
-            enc->codec->id == CODEC_ID_RAWVIDEO) {
-            /* raw pictures are written as AVPicture structure to
-               avoid any copies. We support temporarily the older
-               method. */
-            enc->coded_frame->interlaced_frame = in_picture->interlaced_frame;
-            enc->coded_frame->top_field_first  = in_picture->top_field_first;
-            pkt.data   = (uint8_t *)in_picture;
-            pkt.size   =  sizeof(AVPicture);
-            pkt.pts    = av_rescale_q(ost->sync_opts, enc->time_base, ost->st->time_base);
-            pkt.flags |= AV_PKT_FLAG_KEY;
 
-            write_frame(s, &pkt, ost);
-        } else {
-            int got_packet;
-            AVFrame big_picture;
-
-            big_picture = *in_picture;
-            /* better than nothing: use input picture interlaced
-               settings */
-            big_picture.interlaced_frame = in_picture->interlaced_frame;
-            if (ost->st->codec->flags & (CODEC_FLAG_INTERLACED_DCT|CODEC_FLAG_INTERLACED_ME)) {
-                if (ost->top_field_first == -1)
-                    big_picture.top_field_first = in_picture->top_field_first;
-                else
-                    big_picture.top_field_first = !!ost->top_field_first;
-            }
+duplicate_frame:
+    av_init_packet(&pkt);
+    pkt.data = NULL;
+    pkt.size = 0;
 
-            /* handles same_quant here. This is not correct because it may
-               not be a global option */
-            big_picture.quality = quality;
-            if (!enc->me_threshold)
-                big_picture.pict_type = 0;
-            big_picture.pts = ost->sync_opts;
-            if (ost->forced_kf_index < ost->forced_kf_count &&
-                big_picture.pts >= ost->forced_kf_pts[ost->forced_kf_index]) {
-                big_picture.pict_type = AV_PICTURE_TYPE_I;
-                ost->forced_kf_index++;
-            }
-            update_benchmark(NULL);
-            ret = avcodec_encode_video2(enc, &pkt, &big_picture, &got_packet);
-            update_benchmark("encode_video %d.%d", ost->file_index, ost->index);
-            if (ret < 0) {
-                av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
-                exit_program(1);
-            }
+    in_picture->pts = ost->sync_opts;
 
-            if (got_packet) {
-                if (pkt.pts == AV_NOPTS_VALUE && !(enc->codec->capabilities & CODEC_CAP_DELAY))
-                    pkt.pts = ost->sync_opts;
+    if (s->oformat->flags & AVFMT_RAWPICTURE &&
+        enc->codec->id == CODEC_ID_RAWVIDEO) {
+        /* raw pictures are written as AVPicture structure to
+           avoid any copies. We support temporarily the older
+           method. */
+        enc->coded_frame->interlaced_frame = in_picture->interlaced_frame;
+        enc->coded_frame->top_field_first  = in_picture->top_field_first;
+        pkt.data   = (uint8_t *)in_picture;
+        pkt.size   =  sizeof(AVPicture);
+        pkt.pts    = av_rescale_q(in_picture->pts, enc->time_base, ost->st->time_base);
+        pkt.flags |= AV_PKT_FLAG_KEY;
 
-                if (pkt.pts != AV_NOPTS_VALUE)
-                    pkt.pts = av_rescale_q(pkt.pts, enc->time_base, ost->st->time_base);
-                if (pkt.dts != AV_NOPTS_VALUE)
-                    pkt.dts = av_rescale_q(pkt.dts, enc->time_base, ost->st->time_base);
+        write_frame(s, &pkt, ost);
+    } else {
+        int got_packet;
+        AVFrame big_picture;
+
+        big_picture = *in_picture;
+        /* better than nothing: use input picture interlaced
+           settings */
+        big_picture.interlaced_frame = in_picture->interlaced_frame;
+        if (ost->st->codec->flags & (CODEC_FLAG_INTERLACED_DCT|CODEC_FLAG_INTERLACED_ME)) {
+            if (ost->top_field_first == -1)
+                big_picture.top_field_first = in_picture->top_field_first;
+            else
+                big_picture.top_field_first = !!ost->top_field_first;
+        }
 
-                if (debug_ts) {
-                    av_log(NULL, AV_LOG_INFO, "encoder -> type:video "
-                           "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n",
-                           av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ost->st->time_base),
-                           av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ost->st->time_base));
-                }
+        /* handles same_quant here. This is not correct because it may
+           not be a global option */
+        big_picture.quality = quality;
+        if (!enc->me_threshold)
+            big_picture.pict_type = 0;
+        if (ost->forced_kf_index < ost->forced_kf_count &&
+            big_picture.pts >= ost->forced_kf_pts[ost->forced_kf_index]) {
+            big_picture.pict_type = AV_PICTURE_TYPE_I;
+            ost->forced_kf_index++;
+        }
+        update_benchmark(NULL);
+        ret = avcodec_encode_video2(enc, &pkt, &big_picture, &got_packet);
+        update_benchmark("encode_video %d.%d", ost->file_index, ost->index);
+        if (ret < 0) {
+            av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
+            exit_program(1);
+        }
 
-                write_frame(s, &pkt, ost);
-                frame_size = pkt.size;
-                video_size += pkt.size;
-                av_free_packet(&pkt);
+        if (got_packet) {
+            if (pkt.pts == AV_NOPTS_VALUE && !(enc->codec->capabilities & CODEC_CAP_DELAY))
+                pkt.pts = ost->sync_opts;
 
-                /* if two pass, output log */
-                if (ost->logfile && enc->stats_out) {
-                    fprintf(ost->logfile, "%s", enc->stats_out);
-                }
+            if (pkt.pts != AV_NOPTS_VALUE)
+                pkt.pts = av_rescale_q(pkt.pts, enc->time_base, ost->st->time_base);
+            if (pkt.dts != AV_NOPTS_VALUE)
+                pkt.dts = av_rescale_q(pkt.dts, enc->time_base, ost->st->time_base);
+
+            if (debug_ts) {
+                av_log(NULL, AV_LOG_INFO, "encoder -> type:video "
+                    "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n",
+                    av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ost->st->time_base),
+                    av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ost->st->time_base));
+            }
+
+            write_frame(s, &pkt, ost);
+            frame_size = pkt.size;
+            video_size += pkt.size;
+            av_free_packet(&pkt);
+
+            /* if two pass, output log */
+            if (ost->logfile && enc->stats_out) {
+                fprintf(ost->logfile, "%s", enc->stats_out);
             }
         }
-        ost->sync_opts++;
-        /*
-         * For video, number of frames in == number of packets out.
-         * But there may be reordering, so we can't throw away frames on encoder
-         * flush, we need to limit them here, before they go into encoder.
-         */
-        ost->frame_number++;
     }
+    ost->sync_opts++;
+    /*
+     * For video, number of frames in == number of packets out.
+     * But there may be reordering, so we can't throw away frames on encoder
+     * flush, we need to limit them here, before they go into encoder.
+     */
+    ost->frame_number++;
+
+    if(--nb_frames)
+        goto duplicate_frame;
+
     if (vstats_filename && frame_size)
         do_video_stats(output_files[ost->file_index]->ctx, ost, frame_size);
 }
 
+static double psnr(double d)
+{
+    return -10.0 * log(d) / log(10.0);
+}
+
+static void do_video_stats(AVFormatContext *os, OutputStream *ost,
+                           int frame_size)
+{
+    AVCodecContext *enc;
+    int frame_number;
+    double ti1, bitrate, avg_bitrate;
+
+    /* this is executed just the first time do_video_stats is called */
+    if (!vstats_file) {
+        vstats_file = fopen(vstats_filename, "w");
+        if (!vstats_file) {
+            perror("fopen");
+            exit_program(1);
+        }
+    }
+
+    enc = ost->st->codec;
+    if (enc->codec_type == AVMEDIA_TYPE_VIDEO) {
+        frame_number = ost->frame_number;
+        fprintf(vstats_file, "frame= %5d q= %2.1f ", frame_number, enc->coded_frame->quality / (float)FF_QP2LAMBDA);
+        if (enc->flags&CODEC_FLAG_PSNR)
+            fprintf(vstats_file, "PSNR= %6.2f ", psnr(enc->coded_frame->error[0] / (enc->width * enc->height * 255.0 * 255.0)));
+
+        fprintf(vstats_file,"f_size= %6d ", frame_size);
+        /* compute pts value */
+        ti1 = ost->sync_opts * av_q2d(enc->time_base);
+        if (ti1 < 0.01)
+            ti1 = 0.01;
+
+        bitrate     = (frame_size * 8) / av_q2d(enc->time_base) / 1000.0;
+        avg_bitrate = (double)(video_size * 8) / ti1 / 1000.0;
+        fprintf(vstats_file, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ",
+               (double)video_size / 1024, ti1, bitrate, avg_bitrate);
+        fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(enc->coded_frame->pict_type));
+    }
+}
+
 /* check for new output on any of the filtergraphs */
 static int poll_filters(void)
 {
@@ -2152,22 +2059,22 @@ static int poll_filters(void)
                     break;
                 }
                 frame_pts = AV_NOPTS_VALUE;
-                if (ost->enc->type == AVMEDIA_TYPE_VIDEO)
-                    filtered_frame->pts = frame_pts = av_rescale_q(picref->pts, ist_pts_tb, AV_TIME_BASE_Q);
-                else if (picref->pts != AV_NOPTS_VALUE)
+                if (picref->pts != AV_NOPTS_VALUE) {
                     filtered_frame->pts = frame_pts = av_rescale_q(picref->pts,
                                                     ost->filter->filter->inputs[0]->time_base,
                                                     ost->st->codec->time_base) -
                                         av_rescale_q(of->start_time,
                                                     AV_TIME_BASE_Q,
                                                     ost->st->codec->time_base);
+
+                    if (of->start_time && filtered_frame->pts < 0) {
+                        avfilter_unref_buffer(picref);
+                        continue;
+                    }
+                }
                 //if (ost->source_index >= 0)
                 //    *filtered_frame= *input_streams[ost->source_index]->decoded_frame; //for me_threshold
 
-                if (of->start_time && filtered_frame->pts < of->start_time) {
-                    avfilter_unref_buffer(picref);
-                    continue;
-                }
 
                 switch (ost->filter->filter->inputs[0]->type) {
                 case AVMEDIA_TYPE_VIDEO:
@@ -2535,7 +2442,7 @@ static int guess_input_channel_layout(InputStream *ist)
     return 1;
 }
 
-static int transcode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
+static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
 {
     AVFrame *decoded_frame;
     AVCodecContext *avctx = ist->st->codec;
@@ -2636,7 +2543,7 @@ static int transcode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
     return ret;
 }
 
-static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int64_t *pkt_pts)
+static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
 {
     AVFrame *decoded_frame;
     void *buffer_to_free = NULL;
@@ -2650,9 +2557,7 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int
     else
         avcodec_get_frame_defaults(ist->decoded_frame);
     decoded_frame = ist->decoded_frame;
-    pkt->pts  = *pkt_pts;
-    pkt->dts  = ist->dts;
-    *pkt_pts  = AV_NOPTS_VALUE;
+    pkt->dts  = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ist->st->time_base);
 
     update_benchmark(NULL);
     ret = avcodec_decode_video2(ist->st->codec,
@@ -2670,9 +2575,12 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int
         return ret;
     }
 
+    if(ist->top_field_first>=0)
+        decoded_frame->top_field_first = ist->top_field_first;
+
     best_effort_timestamp= av_frame_get_best_effort_timestamp(decoded_frame);
     if(best_effort_timestamp != AV_NOPTS_VALUE)
-        ist->next_pts = ist->pts = decoded_frame->pts = best_effort_timestamp;
+        ist->next_pts = ist->pts = av_rescale_q(decoded_frame->pts = best_effort_timestamp, ist->st->time_base, AV_TIME_BASE_Q);
 
     pkt->size = 0;
     pre_process_video_frame(ist, (AVPicture *)decoded_frame, &buffer_to_free);
@@ -2774,7 +2682,6 @@ static int output_packet(InputStream *ist, const AVPacket *pkt)
 {
     int ret = 0, i;
     int got_output;
-    int64_t pkt_pts = AV_NOPTS_VALUE;
 
     AVPacket avpkt;
     if (!ist->saw_first_ts) {
@@ -2807,8 +2714,6 @@ static int output_packet(InputStream *ist, const AVPacket *pkt)
         if (ist->st->codec->codec_type != AVMEDIA_TYPE_VIDEO || !ist->decoding_needed)
             ist->next_pts = ist->pts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
     }
-    if(pkt->pts != AV_NOPTS_VALUE)
-        pkt_pts = av_rescale_q(pkt->pts, ist->st->time_base, AV_TIME_BASE_Q);
 
     // while we have more to decode or while the decoder did output something on EOF
     while (ist->decoding_needed && (avpkt.size > 0 || (!pkt && got_output))) {
@@ -2826,10 +2731,10 @@ static int output_packet(InputStream *ist, const AVPacket *pkt)
 
         switch (ist->st->codec->codec_type) {
         case AVMEDIA_TYPE_AUDIO:
-            ret = transcode_audio    (ist, &avpkt, &got_output);
+            ret = decode_audio    (ist, &avpkt, &got_output);
             break;
         case AVMEDIA_TYPE_VIDEO:
-            ret = transcode_video    (ist, &avpkt, &got_output, &pkt_pts);
+            ret = decode_video    (ist, &avpkt, &got_output);
             if (avpkt.duration) {
                 duration = av_rescale_q(avpkt.duration, ist->st->time_base, AV_TIME_BASE_Q);
             } else if(ist->st->codec->time_base.num != 0 && ist->st->codec->time_base.den != 0) {
@@ -3150,12 +3055,21 @@ static int transcode_init(void)
                 ist->decoding_needed = 1;
             ost->encoding_needed = 1;
 
+            if (codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+                if (ist && !ost->frame_rate.num)
+                    ost->frame_rate = ist->st->r_frame_rate.num ? ist->st->r_frame_rate : (AVRational){25, 1};
+                if (ost->enc && ost->enc->supported_framerates && !ost->force_fps) {
+                    int idx = av_find_nearest_q_idx(ost->frame_rate, ost->enc->supported_framerates);
+                    ost->frame_rate = ost->enc->supported_framerates[idx];
+                }
+            }
+
             if (!ost->filter &&
                 (codec->codec_type == AVMEDIA_TYPE_VIDEO ||
                  codec->codec_type == AVMEDIA_TYPE_AUDIO)) {
                     FilterGraph *fg;
                     fg = init_simple_filtergraph(ist, ost);
-                    if (configure_simple_filtergraph(fg)) {
+                    if (configure_filtergraph(fg)) {
                         av_log(NULL, AV_LOG_FATAL, "Error opening filters!\n");
                         exit(1);
                     }
@@ -3170,12 +3084,6 @@ static int transcode_init(void)
                 codec->time_base      = (AVRational){ 1, codec->sample_rate };
                 break;
             case AVMEDIA_TYPE_VIDEO:
-                if (ist && !ost->frame_rate.num)
-                    ost->frame_rate = ist->st->r_frame_rate.num ? ist->st->r_frame_rate : (AVRational){25, 1};
-                if (ost->enc && ost->enc->supported_framerates && !ost->force_fps) {
-                    int idx = av_find_nearest_q_idx(ost->frame_rate, ost->enc->supported_framerates);
-                    ost->frame_rate = ost->enc->supported_framerates[idx];
-                }
                 codec->time_base = (AVRational){ost->frame_rate.den, ost->frame_rate.num};
                 if (   av_q2d(codec->time_base) < 0.001 && video_sync_method != VSYNC_PASSTHROUGH
                    && (video_sync_method == VSYNC_CFR || (video_sync_method == VSYNC_AUTO && !(oc->oformat->flags & AVFMT_VARIABLE_FPS)))){
@@ -3307,8 +3215,12 @@ static int transcode_init(void)
     for (i = 0; i < nb_output_files; i++) {
         oc = output_files[i]->ctx;
         oc->interrupt_callback = int_cb;
-        if (avformat_write_header(oc, &output_files[i]->opts) < 0) {
-            snprintf(error, sizeof(error), "Could not write header for output file #%d (incorrect codec parameters ?)", i);
+        if ((ret = avformat_write_header(oc, &output_files[i]->opts)) < 0) {
+            char errbuf[128];
+            const char *errbuf_ptr = errbuf;
+            if (av_strerror(ret, errbuf, sizeof(errbuf)) < 0)
+                errbuf_ptr = strerror(AVUNERROR(ret));
+            snprintf(error, sizeof(error), "Could not write header for output file #%d (incorrect codec parameters ?): %s", i, errbuf_ptr);
             ret = AVERROR(EINVAL);
             goto dump_format;
         }
@@ -3331,13 +3243,10 @@ static int transcode_init(void)
         ist = input_streams[i];
 
         for (j = 0; j < ist->nb_filters; j++) {
-            AVFilterLink *link = ist->filters[j]->filter->outputs[0];
             if (ist->filters[j]->graph->graph_desc) {
                 av_log(NULL, AV_LOG_INFO, "  Stream #%d:%d (%s) -> %s",
                        ist->file_index, ist->st->index, ist->dec ? ist->dec->name : "?",
-                       link->dst->filter->name);
-                if (link->dst->input_count > 1)
-                    av_log(NULL, AV_LOG_INFO, ":%s", link->dstpad->name);
+                       ist->filters[j]->name);
                 if (nb_filtergraphs > 1)
                     av_log(NULL, AV_LOG_INFO, " (graph %d)", ist->filters[j]->graph->index);
                 av_log(NULL, AV_LOG_INFO, "\n");
@@ -3357,10 +3266,7 @@ static int transcode_init(void)
 
         if (ost->filter && ost->filter->graph->graph_desc) {
             /* output from a complex graph */
-            AVFilterLink *link = ost->filter->filter->inputs[0];
-            av_log(NULL, AV_LOG_INFO, "  %s", link->src->filter->name);
-            if (link->src->output_count > 1)
-                av_log(NULL, AV_LOG_INFO, ":%s", link->srcpad->name);
+            av_log(NULL, AV_LOG_INFO, "  %s", ost->filter->name);
             if (nb_filtergraphs > 1)
                 av_log(NULL, AV_LOG_INFO, " (graph %d)", ost->filter->graph->index);
 
@@ -4133,6 +4039,7 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
         AVStream *st = ic->streams[i];
         AVCodecContext *dec = st->codec;
         InputStream *ist = av_mallocz(sizeof(*ist));
+        char *framerate = NULL;
 
         if (!ist)
             exit_program(1);
@@ -4171,6 +4078,17 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
             ist->resample_width   = dec->width;
             ist->resample_pix_fmt = dec->pix_fmt;
 
+            MATCH_PER_STREAM_OPT(frame_rates, str, framerate, ic, st);
+            if (framerate && av_parse_video_rate(&ist->framerate,
+                                                 framerate) < 0) {
+                av_log(NULL, AV_LOG_ERROR, "Error parsing framerate %s.\n",
+                       framerate);
+                exit_program(1);
+            }
+
+            ist->top_field_first = -1;
+            MATCH_PER_STREAM_OPT(top_field_first, i, ist->top_field_first, ic, st);
+
             break;
         case AVMEDIA_TYPE_AUDIO:
             guess_input_channel_layout(ist);
@@ -4298,7 +4216,14 @@ static int opt_input_file(OptionsContext *o, const char *opt, const char *filena
         }
     }
     if (o->nb_frame_rates) {
-        av_dict_set(&format_opts, "framerate", o->frame_rates[o->nb_frame_rates - 1].u.str, 0);
+        /* set the format-level framerate option;
+         * this is important for video grabbers, e.g. x11 */
+        if (file_iformat && file_iformat->priv_class &&
+            av_opt_find(&file_iformat->priv_class, "framerate", NULL, 0,
+                        AV_OPT_SEARCH_FAKE_OBJ)) {
+            av_dict_set(&format_opts, "framerate",
+                        o->frame_rates[o->nb_frame_rates - 1].u.str, 0);
+        }
     }
     if (o->nb_frame_sizes) {
         av_dict_set(&format_opts, "video_size", o->frame_sizes[o->nb_frame_sizes - 1].u.str, 0);
@@ -4618,7 +4543,8 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, in
         const char *p = NULL;
         char *forced_key_frames = NULL, *frame_rate = NULL, *frame_size = NULL;
         char *frame_aspect_ratio = NULL, *frame_pix_fmt = NULL;
-        char *intra_matrix = NULL, *inter_matrix = NULL, *filters = NULL;
+        char *intra_matrix = NULL, *inter_matrix = NULL;
+        const char *filters = "null";
         int i;
 
         MATCH_PER_STREAM_OPT(frame_rates, str, frame_rate, oc, st);
@@ -4729,8 +4655,7 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, in
         MATCH_PER_STREAM_OPT(top_field_first, i, ost->top_field_first, oc, st);
 
         MATCH_PER_STREAM_OPT(filters, str, filters, oc, st);
-        if (filters)
-            ost->avfilter = av_strdup(filters);
+        ost->avfilter = av_strdup(filters);
     } else {
         MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc ,st);
     }
@@ -4752,7 +4677,8 @@ static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, in
     audio_enc->codec_type = AVMEDIA_TYPE_AUDIO;
 
     if (!ost->stream_copy) {
-        char *sample_fmt = NULL, *filters = NULL;
+        char *sample_fmt = NULL;
+        const char *filters = "anull";
 
         MATCH_PER_STREAM_OPT(audio_channels, i, audio_enc->channels, oc, st);
 
@@ -4766,8 +4692,9 @@ static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, in
         MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st);
 
         MATCH_PER_STREAM_OPT(filters, str, filters, oc, st);
-        if (filters)
-            ost->avfilter = av_strdup(filters);
+
+        av_assert1(filters);
+        ost->avfilter = av_strdup(filters);
 
         /* check for channel mapping for this audio stream */
         for (n = 0; n < o->nb_audio_channel_maps; n++) {
@@ -5020,6 +4947,8 @@ static void opt_output_file(void *optctx, const char *filename)
                 if(ist->st->codec->codec_type == ost->st->codec->codec_type){
                     ost->sync_ist= ist;
                     ost->source_index= i;
+                    if(ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO) ost->avfilter = av_strdup("anull");
+                    if(ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) ost->avfilter = av_strdup("null");
                     ist->discard = 0;
                     ist->st->discard = AVDISCARD_NONE;
                     break;