[FFmpeg-cvslog] avconv: make filtergraphs global.

Anton Khirnov git at videolan.org
Tue Apr 17 04:51:57 CEST 2012


ffmpeg | branch: master | Anton Khirnov <anton at khirnov.net> | Thu Mar 29 08:51:17 2012 +0200| [560f7774a4edde550e35f85e4b1c6cc74c85f48f] | committer: Anton Khirnov

avconv: make filtergraphs global.

This is the first step towards supporting complex filtergraphs with more
than one input and/or output.

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=560f7774a4edde550e35f85e4b1c6cc74c85f48f
---

 avconv.c |  237 ++++++++++++++++++++++++++++++++++++++++++++------------------
 1 files changed, 169 insertions(+), 68 deletions(-)

diff --git a/avconv.c b/avconv.c
index b5a171d..af1d77b 100644
--- a/avconv.c
+++ b/avconv.c
@@ -145,6 +145,27 @@ static unsigned int allocated_async_buf_size;
 
 #define DEFAULT_PASS_LOGFILENAME_PREFIX "av2pass"
 
+typedef struct InputFilter {
+    AVFilterContext    *filter;
+    struct InputStream *ist;
+    struct FilterGraph *graph;
+} InputFilter;
+
+typedef struct OutputFilter {
+    AVFilterContext     *filter;
+    struct OutputStream *ost;
+    struct FilterGraph  *graph;
+} OutputFilter;
+
+typedef struct FilterGraph {
+    AVFilterGraph *graph;
+
+    InputFilter   **inputs;
+    int          nb_inputs;
+    OutputFilter **outputs;
+    int         nb_outputs;
+} FilterGraph;
+
 typedef struct FrameBuffer {
     uint8_t *base[4];
     uint8_t *data[4];
@@ -184,6 +205,11 @@ typedef struct InputStream {
 
     /* a pool of free buffers for decoded data */
     FrameBuffer *buffer_pool;
+
+    /* decoded data from this stream goes into all those filters
+     * currently video only */
+    InputFilter **filters;
+    int        nb_filters;
 } InputStream;
 
 typedef struct InputFile {
@@ -224,6 +250,7 @@ typedef struct OutputStream {
     int top_field_first;
 
     float frame_aspect_ratio;
+    float last_quality;
 
     /* forced key frames */
     int64_t *forced_kf_pts;
@@ -241,10 +268,8 @@ typedef struct OutputStream {
     AVFifoBuffer *fifo;     /* for compression: one audio fifo per codec */
     FILE *logfile;
 
-    AVFilterContext *output_video_filter;
-    AVFilterContext *input_video_filter;
+    OutputFilter *filter;
     char *avfilter;
-    AVFilterGraph *graph;
 
     int64_t sws_flags;
     AVDictionary *opts;
@@ -276,6 +301,9 @@ static int         nb_output_streams = 0;
 static OutputFile   **output_files   = NULL;
 static int         nb_output_files   = 0;
 
+static FilterGraph **filtergraphs;
+int               nb_filtergraphs;
+
 typedef struct OptionsContext {
     /* input/output options */
     int64_t start_time;
@@ -556,8 +584,10 @@ static const enum PixelFormat *choose_pixel_fmts(OutputStream *ost)
         return NULL;
 }
 
-static int configure_video_filters(InputStream *ist, OutputStream *ost)
+static int configure_video_filters(FilterGraph *fg)
 {
+    InputStream  *ist = fg->inputs[0]->ist;
+    OutputStream *ost = fg->outputs[0]->ost;
     AVFilterContext *last_filter, *filter;
     /** filter graph containing all filters including input & output */
     AVCodecContext *codec = ost->st->codec;
@@ -566,7 +596,8 @@ static int configure_video_filters(InputStream *ist, OutputStream *ost)
     char args[255];
     int ret;
 
-    ost->graph = avfilter_graph_alloc();
+    avfilter_graph_free(&fg->graph);
+    fg->graph = avfilter_graph_alloc();
 
     if (ist->st->sample_aspect_ratio.num) {
         sample_aspect_ratio = ist->st->sample_aspect_ratio;
@@ -577,15 +608,16 @@ static int configure_video_filters(InputStream *ist, OutputStream *ost)
              ist->st->codec->height, ist->st->codec->pix_fmt, 1, AV_TIME_BASE,
              sample_aspect_ratio.num, sample_aspect_ratio.den);
 
-    ret = avfilter_graph_create_filter(&ost->input_video_filter, avfilter_get_by_name("buffer"),
-                                       "src", args, NULL, ost->graph);
+    ret = avfilter_graph_create_filter(&fg->inputs[0]->filter,
+                                       avfilter_get_by_name("buffer"),
+                                       "src", args, NULL, fg->graph);
     if (ret < 0)
         return ret;
-    ret = avfilter_graph_create_filter(&ost->output_video_filter, &sink,
-                                       "out", NULL, &sink_ctx, ost->graph);
+    ret = avfilter_graph_create_filter(&fg->outputs[0]->filter, &sink,
+                                       "out", NULL, &sink_ctx, fg->graph);
     if (ret < 0)
         return ret;
-    last_filter = ost->input_video_filter;
+    last_filter = fg->inputs[0]->filter;
 
     if (codec->width || codec->height) {
         snprintf(args, 255, "%d:%d:flags=0x%X",
@@ -593,7 +625,7 @@ static int configure_video_filters(InputStream *ist, OutputStream *ost)
                  codec->height,
                  (unsigned)ost->sws_flags);
         if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"),
-                                                NULL, args, NULL, ost->graph)) < 0)
+                                                NULL, args, NULL, fg->graph)) < 0)
             return ret;
         if ((ret = avfilter_link(last_filter, 0, filter, 0)) < 0)
             return ret;
@@ -601,7 +633,7 @@ static int configure_video_filters(InputStream *ist, OutputStream *ost)
     }
 
     snprintf(args, sizeof(args), "flags=0x%X", (unsigned)ost->sws_flags);
-    ost->graph->scale_sws_opts = av_strdup(args);
+    fg->graph->scale_sws_opts = av_strdup(args);
 
     if (ost->avfilter) {
         AVFilterInOut *outputs = avfilter_inout_alloc();
@@ -613,31 +645,65 @@ static int configure_video_filters(InputStream *ist, OutputStream *ost)
         outputs->next    = NULL;
 
         inputs->name    = av_strdup("out");
-        inputs->filter_ctx = ost->output_video_filter;
+        inputs->filter_ctx = fg->outputs[0]->filter;
         inputs->pad_idx = 0;
         inputs->next    = NULL;
 
-        if ((ret = avfilter_graph_parse(ost->graph, ost->avfilter, inputs, outputs, NULL)) < 0)
+        if ((ret = avfilter_graph_parse(fg->graph, ost->avfilter, inputs, outputs, NULL)) < 0)
             return ret;
     } else {
-        if ((ret = avfilter_link(last_filter, 0, ost->output_video_filter, 0)) < 0)
+        if ((ret = avfilter_link(last_filter, 0, fg->outputs[0]->filter, 0)) < 0)
             return ret;
     }
 
-    if ((ret = avfilter_graph_config(ost->graph, NULL)) < 0)
+    if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0)
         return ret;
 
-    codec->width  = ost->output_video_filter->inputs[0]->w;
-    codec->height = ost->output_video_filter->inputs[0]->h;
+    codec->width  = fg->outputs[0]->filter->inputs[0]->w;
+    codec->height = fg->outputs[0]->filter->inputs[0]->h;
     codec->sample_aspect_ratio = ost->st->sample_aspect_ratio =
         ost->frame_aspect_ratio ? // overridden by the -aspect cli option
         av_d2q(ost->frame_aspect_ratio * codec->height/codec->width, 255) :
-        ost->output_video_filter->inputs[0]->sample_aspect_ratio;
-    codec->pix_fmt = ost->output_video_filter->inputs[0]->format;
+        fg->outputs[0]->filter->inputs[0]->sample_aspect_ratio;
+    codec->pix_fmt = fg->outputs[0]->filter->inputs[0]->format;
+
+    ost->filter = fg->outputs[0];
 
     return 0;
 }
 
+static FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost)
+{
+    FilterGraph *fg = av_mallocz(sizeof(*fg));
+
+    if (!fg)
+        exit_program(1);
+
+    fg->outputs = grow_array(fg->outputs, sizeof(*fg->outputs), &fg->nb_outputs,
+                             fg->nb_outputs + 1);
+    if (!(fg->outputs[0] = av_mallocz(sizeof(*fg->outputs[0]))))
+        exit_program(1);
+    fg->outputs[0]->ost   = ost;
+    fg->outputs[0]->graph = fg;
+
+    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]))))
+        exit_program(1);
+    fg->inputs[0]->ist   = ist;
+    fg->inputs[0]->graph = fg;
+
+    ist->filters = grow_array(ist->filters, sizeof(*ist->filters),
+                              &ist->nb_filters, ist->nb_filters + 1);
+    ist->filters[ist->nb_filters - 1] = fg->inputs[0];
+
+    filtergraphs = grow_array(filtergraphs, sizeof(*filtergraphs),
+                              &nb_filtergraphs, nb_filtergraphs + 1);
+    filtergraphs[nb_filtergraphs - 1] = fg;
+
+    return fg;
+}
+
 static void term_exit(void)
 {
     av_log(NULL, AV_LOG_QUIET, "");
@@ -672,7 +738,19 @@ static const AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL };
 
 void exit_program(int ret)
 {
-    int i;
+    int i, j;
+
+    for (i = 0; i < nb_filtergraphs; i++) {
+        avfilter_graph_free(&filtergraphs[i]->graph);
+        for (j = 0; j < filtergraphs[i]->nb_inputs; j++)
+            av_freep(&filtergraphs[i]->inputs[j]);
+        av_freep(&filtergraphs[i]->inputs);
+        for (j = 0; j < filtergraphs[i]->nb_outputs; j++)
+            av_freep(&filtergraphs[i]->outputs[j]);
+        av_freep(&filtergraphs[i]->outputs);
+        av_freep(&filtergraphs[i]);
+    }
+    av_freep(&filtergraphs);
 
     /* close files */
     for (i = 0; i < nb_output_files; i++) {
@@ -711,6 +789,7 @@ void exit_program(int ret)
         av_freep(&input_streams[i]->decoded_frame);
         av_dict_free(&input_streams[i]->opts);
         free_buffer_pool(input_streams[i]);
+        av_freep(&input_streams[i]->filters);
         av_freep(&input_streams[i]);
     }
 
@@ -1474,6 +1553,59 @@ static void do_video_stats(AVFormatContext *os, OutputStream *ost,
     }
 }
 
+/* check for new output on any of the filtergraphs */
+static int poll_filters(void)
+{
+    AVFilterBufferRef *picref;
+    AVFrame *filtered_frame = NULL;
+    int i, frame_size, ret;
+
+    for (i = 0; i < nb_output_streams; i++) {
+        OutputStream *ost = output_streams[i];
+        OutputFile    *of = output_files[ost->file_index];
+
+        if (!ost->filter || ost->is_past_recording_time)
+            continue;
+
+        if (!ost->filtered_frame && !(ost->filtered_frame = avcodec_alloc_frame())) {
+            return AVERROR(ENOMEM);
+        } else
+            avcodec_get_frame_defaults(ost->filtered_frame);
+        filtered_frame = ost->filtered_frame;
+
+        while (avfilter_poll_frame(ost->filter->filter->inputs[0])) {
+            AVRational ist_pts_tb;
+            if ((ret = get_filtered_video_frame(ost->filter->filter,
+                                                filtered_frame, &picref,
+                                                &ist_pts_tb)) < 0)
+                return ret;
+            filtered_frame->pts = av_rescale_q(picref->pts, ist_pts_tb, AV_TIME_BASE_Q);
+
+            if (of->start_time && filtered_frame->pts < of->start_time)
+                return 0;
+
+            switch (ost->filter->filter->inputs[0]->type) {
+            case AVMEDIA_TYPE_VIDEO:
+                if (!ost->frame_aspect_ratio)
+                    ost->st->codec->sample_aspect_ratio = picref->video->pixel_aspect;
+
+                do_video_out(of->ctx, ost, filtered_frame, &frame_size,
+                             same_quant ? ost->last_quality :
+                                          ost->st->codec->global_quality);
+                if (vstats_filename && frame_size)
+                    do_video_stats(of->ctx, ost, frame_size);
+                break;
+            default:
+                // TODO support audio/subtitle filters
+                av_assert0(0);
+            }
+
+            avfilter_unref_buffer(picref);
+        }
+    }
+    return 0;
+}
+
 static void print_report(int is_last_report, int64_t timer_start)
 {
     char buf[1024];
@@ -1867,11 +1999,10 @@ static int transcode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
 
 static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int64_t *pkt_pts)
 {
-    AVFrame *decoded_frame, *filtered_frame = NULL;
+    AVFrame *decoded_frame;
     void *buffer_to_free = NULL;
     int i, ret = 0, resample_changed;
     float quality;
-    int frame_available = 1;
 
     if (!ist->decoded_frame && !(ist->decoded_frame = avcodec_alloc_frame()))
         return AVERROR(ENOMEM);
@@ -1917,21 +2048,17 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int
         ist->resample_pix_fmt = decoded_frame->format;
     }
 
-    for (i = 0; i < nb_output_streams; i++) {
-        OutputStream *ost = output_streams[i];
-        int frame_size;
-
-        if (!check_output_constraints(ist, ost) || !ost->encoding_needed)
-            continue;
-
-        if (resample_changed) {
-            avfilter_graph_free(&ost->graph);
-            if (configure_video_filters(ist, ost)) {
+    for (i = 0; i < ist->nb_filters; i++) {
+        if (resample_changed &&
+            configure_video_filters(ist->filters[i]->graph)) {
                 av_log(NULL, AV_LOG_FATAL, "Error reinitializing filters!\n");
                 exit_program(1);
-            }
         }
 
+        // XXX what an ugly hack
+        if (ist->filters[i]->graph->nb_outputs == 1)
+            ist->filters[i]->graph->outputs[0]->ost->last_quality = quality;
+
         if (ist->st->codec->codec->capabilities & CODEC_CAP_DR1) {
             FrameBuffer      *buf = decoded_frame->opaque;
             AVFilterBufferRef *fb = avfilter_get_video_buffer_ref_from_arrays(
@@ -1945,40 +2072,12 @@ static int transcode_video(InputStream *ist, AVPacket *pkt, int *got_output, int
             fb->buf->free           = filter_release_buffer;
 
             buf->refcount++;
-            av_buffersrc_buffer(ost->input_video_filter, fb);
+            av_buffersrc_buffer(ist->filters[i]->filter, fb);
         } else
-            av_vsrc_buffer_add_frame(ost->input_video_filter, decoded_frame,
+            av_vsrc_buffer_add_frame(ist->filters[i]->filter, decoded_frame,
                                      decoded_frame->pts, decoded_frame->sample_aspect_ratio);
-
-        if (!ost->filtered_frame && !(ost->filtered_frame = avcodec_alloc_frame())) {
-            ret = AVERROR(ENOMEM);
-            goto fail;
-        } else
-            avcodec_get_frame_defaults(ost->filtered_frame);
-        filtered_frame = ost->filtered_frame;
-
-        frame_available = avfilter_poll_frame(ost->output_video_filter->inputs[0]);
-        while (frame_available) {
-            AVFilterBufferRef *picref;
-            AVRational ist_pts_tb;
-            if ((ret = get_filtered_video_frame(ost->output_video_filter,
-                                                filtered_frame, &picref,
-                                                &ist_pts_tb)) < 0)
-                goto fail;
-            filtered_frame->pts = av_rescale_q(picref->pts, ist_pts_tb, AV_TIME_BASE_Q);
-            if (!ost->frame_aspect_ratio)
-                ost->st->codec->sample_aspect_ratio = picref->video->pixel_aspect;
-
-            do_video_out(output_files[ost->file_index]->ctx, ost, filtered_frame, &frame_size,
-                         same_quant ? quality : ost->st->codec->global_quality);
-            if (vstats_filename && frame_size)
-                do_video_stats(output_files[ost->file_index]->ctx, ost, frame_size);
-            frame_available = ost->output_video_filter && avfilter_poll_frame(ost->output_video_filter->inputs[0]);
-            avfilter_unref_buffer(picref);
-        }
     }
 
-fail:
     av_free(buffer_to_free);
     return ret;
 }
@@ -2352,6 +2451,8 @@ static int transcode_init(void)
                 abort();
             }
         } else {
+            FilterGraph *fg;
+
             if (!ost->enc)
                 ost->enc = avcodec_find_encoder(ost->st->codec->codec_id);
 
@@ -2413,7 +2514,8 @@ static int transcode_init(void)
                 } else
                     codec->time_base = ist->st->time_base;
 
-                if (configure_video_filters(ist, ost)) {
+                fg = init_simple_filtergraph(ist, ost);
+                if (configure_video_filters(fg)) {
                     av_log(NULL, AV_LOG_FATAL, "Error opening filters!\n");
                     exit(1);
                 }
@@ -2732,8 +2834,7 @@ static int transcode(void)
         }
 
         // fprintf(stderr,"read #%d.%d size=%d\n", ist->file_index, ist->st->index, pkt.size);
-        if (output_packet(ist, &pkt) < 0) {
-
+        if (output_packet(ist, &pkt) < 0 || poll_filters() < 0) {
             av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d\n",
                    ist->file_index, ist->st->index);
             if (exit_on_error)
@@ -2756,6 +2857,7 @@ static int transcode(void)
             output_packet(ist, NULL);
         }
     }
+    poll_filters();
     flush_encoders();
 
     term_exit();
@@ -2776,7 +2878,6 @@ static int transcode(void)
             av_freep(&ost->st->codec->stats_in);
             avcodec_close(ost->st->codec);
         }
-        avfilter_graph_free(&ost->graph);
     }
 
     /* close each decoder */



More information about the ffmpeg-cvslog mailing list