X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavfilter%2Fsplit.c;h=41395e7f480eceacad606d84037ab2b76d2166f9;hb=a83fd5010c4ef51fbdbd5a42c9f5128a3e0d444b;hp=b7d037804a9f7886e22b840f785f6383b88bdb0b;hpb=9baeff9506a890c8f9f27c08cf331f827c24726a;p=ffmpeg diff --git a/libavfilter/split.c b/libavfilter/split.c index b7d037804a9..41395e7f480 100644 --- a/libavfilter/split.c +++ b/libavfilter/split.c @@ -23,25 +23,29 @@ * audio and video splitter */ +#include + +#include "libavutil/attributes.h" +#include "libavutil/internal.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" + #include "avfilter.h" #include "audio.h" #include "internal.h" #include "video.h" -static int split_init(AVFilterContext *ctx, const char *args, void *opaque) +typedef struct SplitContext { + const AVClass *class; + int nb_outputs; +} SplitContext; + +static av_cold int split_init(AVFilterContext *ctx) { - 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); - } - } + SplitContext *s = ctx->priv; + int i; - for (i = 0; i < nb_outputs; i++) { + for (i = 0; i < s->nb_outputs; i++) { char name[32]; AVFilterPad pad = { 0 }; @@ -55,7 +59,7 @@ static int split_init(AVFilterContext *ctx, const char *args, void *opaque) return 0; } -static void split_uninit(AVFilterContext *ctx) +static av_cold void split_uninit(AVFilterContext *ctx) { int i; @@ -63,74 +67,95 @@ static void split_uninit(AVFilterContext *ctx) av_freep(&ctx->output_pads[i].name); } -static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref) +static int filter_frame(AVFilterLink *inlink, AVFrame *frame) { AVFilterContext *ctx = inlink->dst; - int i; - - for (i = 0; i < ctx->nb_outputs; i++) - ff_start_frame(ctx->outputs[i], - avfilter_ref_buffer(picref, ~AV_PERM_WRITE)); -} + int i, ret = 0; -static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) -{ - AVFilterContext *ctx = inlink->dst; - int i; + for (i = 0; i < ctx->nb_outputs; i++) { + AVFrame *buf_out = av_frame_clone(frame); + if (!buf_out) { + ret = AVERROR(ENOMEM); + break; + } - for (i = 0; i < ctx->nb_outputs; i++) - ff_draw_slice(ctx->outputs[i], y, h, slice_dir); + ret = ff_filter_frame(ctx->outputs[i], buf_out); + if (ret < 0) + break; + } + av_frame_free(&frame); + return ret; } -static void end_frame(AVFilterLink *inlink) -{ - AVFilterContext *ctx = inlink->dst; - int i; +#define OFFSET(x) offsetof(SplitContext, x) +#define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_VIDEO_PARAM +static const AVOption options[] = { + { "outputs", "Number of outputs", OFFSET(nb_outputs), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, INT_MAX, FLAGS }, + { NULL }, +}; - for (i = 0; i < ctx->nb_outputs; i++) - ff_end_frame(ctx->outputs[i]); +static const AVClass split_class = { + .class_name = "split", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; - avfilter_unref_buffer(inlink->cur_buf); -} +static const AVClass asplit_class = { + .class_name = "asplit", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; -AVFilter avfilter_vf_split = { +static const AVFilterPad avfilter_vf_split_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .get_video_buffer = ff_null_get_video_buffer, + .filter_frame = filter_frame, + }, + { NULL } +}; + +AVFilter ff_vf_split = { .name = "split", - .description = NULL_IF_CONFIG_SMALL("Pass on the input to two outputs."), + .description = NULL_IF_CONFIG_SMALL("Pass on the input to N video outputs."), + + .priv_size = sizeof(SplitContext), + .priv_class = &split_class, .init = split_init, .uninit = split_uninit, - .inputs = (AVFilterPad[]) {{ .name = "default", - .type = AVMEDIA_TYPE_VIDEO, - .get_video_buffer= ff_null_get_video_buffer, - .start_frame = start_frame, - .draw_slice = draw_slice, - .end_frame = end_frame, }, - { .name = NULL}}, - .outputs = (AVFilterPad[]) {{ .name = NULL}}, -}; + .inputs = avfilter_vf_split_inputs, + .outputs = NULL, -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *samplesref) -{ - AVFilterContext *ctx = inlink->dst; - int i; + .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS, +}; - for (i = 0; i < ctx->nb_outputs; i++) - ff_filter_samples(inlink->dst->outputs[i], - avfilter_ref_buffer(samplesref, ~AV_PERM_WRITE)); -} +static const AVFilterPad avfilter_af_asplit_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .get_audio_buffer = ff_null_get_audio_buffer, + .filter_frame = filter_frame, + }, + { NULL } +}; -AVFilter avfilter_af_asplit = { +AVFilter ff_af_asplit = { .name = "asplit", .description = NULL_IF_CONFIG_SMALL("Pass on the audio input to N audio outputs."), + .priv_size = sizeof(SplitContext), + .priv_class = &asplit_class, + .init = split_init, .uninit = split_uninit, - .inputs = (const AVFilterPad[]) {{ .name = "default", - .type = AVMEDIA_TYPE_AUDIO, - .get_audio_buffer = ff_null_get_audio_buffer, - .filter_samples = filter_samples }, - { .name = NULL }}, - .outputs = (const AVFilterPad[]) {{ .name = NULL }}, + .inputs = avfilter_af_asplit_inputs, + .outputs = NULL, + + .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS, };