vf_split: support user-specifiable number of outputs.
authorAnton Khirnov <anton@khirnov.net>
Fri, 27 Apr 2012 05:41:32 +0000 (07:41 +0200)
committerAnton Khirnov <anton@khirnov.net>
Sun, 6 May 2012 14:21:00 +0000 (16:21 +0200)
doc/filters.texi
libavfilter/vf_split.c

index b012dc7..c5a56f4 100644 (file)
@@ -1666,6 +1666,19 @@ not specified it will use the default value of 16.
 Adding this in the beginning of filter chains should make filtering
 faster due to better use of the memory cache.
 
 Adding this in the beginning of filter chains should make filtering
 faster due to better use of the memory cache.
 
+@section split
+
+Split input video into several identical outputs.
+
+The filter accepts a single parameter which specifies the number of outputs. If
+unspecified, it defaults to 2.
+
+For example
+@example
+avconv -i INPUT -filter_complex split=5 OUTPUT
+@end example
+will create 5 copies of the input video.
+
 @section transpose
 
 Transpose rows with columns in the input video and optionally flip it.
 @section transpose
 
 Transpose rows with columns in the input video and optionally flip it.
index 54fdd21..da6b3ff 100644 (file)
 
 #include "avfilter.h"
 
 
 #include "avfilter.h"
 
+static int split_init(AVFilterContext *ctx, const char *args, void *opaque)
+{
+    int i, nb_outputs = 2;
+
+    if (args) {
+        nb_outputs = strtol(args, NULL, 0);
+        if (nb_outputs <= 0) {
+            av_log(ctx, AV_LOG_ERROR, "Invalid number of outputs specified: %d.\n",
+                   nb_outputs);
+            return AVERROR(EINVAL);
+        }
+    }
+
+    for (i = 0; i < nb_outputs; i++) {
+        char name[32];
+        AVFilterPad pad = { 0 };
+
+        snprintf(name, sizeof(name), "output%d", i);
+        pad.type = AVMEDIA_TYPE_VIDEO;
+        pad.name = av_strdup(name);
+
+        avfilter_insert_outpad(ctx, i, &pad);
+    }
+
+    return 0;
+}
+
+static void split_uninit(AVFilterContext *ctx)
+{
+    int i;
+
+    for (i = 0; i < ctx->output_count; i++)
+        av_freep(&ctx->output_pads[i].name);
+}
+
 static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
 {
 static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
 {
-    avfilter_start_frame(inlink->dst->outputs[0],
-                         avfilter_ref_buffer(picref, ~AV_PERM_WRITE));
-    avfilter_start_frame(inlink->dst->outputs[1],
-                         avfilter_ref_buffer(picref, ~AV_PERM_WRITE));
+    AVFilterContext *ctx = inlink->dst;
+    int i;
+
+    for (i = 0; i < ctx->output_count; i++)
+        avfilter_start_frame(ctx->outputs[i],
+                             avfilter_ref_buffer(picref, ~AV_PERM_WRITE));
 }
 
 static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
 {
 }
 
 static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
 {
-    avfilter_draw_slice(inlink->dst->outputs[0], y, h, slice_dir);
-    avfilter_draw_slice(inlink->dst->outputs[1], y, h, slice_dir);
+    AVFilterContext *ctx = inlink->dst;
+    int i;
+
+    for (i = 0; i < ctx->output_count; i++)
+        avfilter_draw_slice(ctx->outputs[i], y, h, slice_dir);
 }
 
 static void end_frame(AVFilterLink *inlink)
 {
 }
 
 static void end_frame(AVFilterLink *inlink)
 {
-    avfilter_end_frame(inlink->dst->outputs[0]);
-    avfilter_end_frame(inlink->dst->outputs[1]);
+    AVFilterContext *ctx = inlink->dst;
+    int i;
+
+    for (i = 0; i < ctx->output_count; i++)
+        avfilter_end_frame(ctx->outputs[i]);
 
     avfilter_unref_buffer(inlink->cur_buf);
 }
 
     avfilter_unref_buffer(inlink->cur_buf);
 }
@@ -51,6 +94,9 @@ AVFilter avfilter_vf_split = {
     .name      = "split",
     .description = NULL_IF_CONFIG_SMALL("Pass on the input to two outputs."),
 
     .name      = "split",
     .description = NULL_IF_CONFIG_SMALL("Pass on the input to two outputs."),
 
+    .init   = split_init,
+    .uninit = split_uninit,
+
     .inputs    = (AVFilterPad[]) {{ .name            = "default",
                                     .type            = AVMEDIA_TYPE_VIDEO,
                                     .get_video_buffer= avfilter_null_get_video_buffer,
     .inputs    = (AVFilterPad[]) {{ .name            = "default",
                                     .type            = AVMEDIA_TYPE_VIDEO,
                                     .get_video_buffer= avfilter_null_get_video_buffer,
@@ -58,9 +104,5 @@ AVFilter avfilter_vf_split = {
                                     .draw_slice      = draw_slice,
                                     .end_frame       = end_frame, },
                                   { .name = NULL}},
                                     .draw_slice      = draw_slice,
                                     .end_frame       = end_frame, },
                                   { .name = NULL}},
-    .outputs   = (AVFilterPad[]) {{ .name            = "output1",
-                                    .type            = AVMEDIA_TYPE_VIDEO, },
-                                  { .name            = "output2",
-                                    .type            = AVMEDIA_TYPE_VIDEO, },
-                                  { .name = NULL}},
+    .outputs   = (AVFilterPad[]) {{ .name = NULL}},
 };
 };