X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavfilter%2Fsplit.c;h=41395e7f480eceacad606d84037ab2b76d2166f9;hb=eac77fcd56fc2a3391f0d86faf54302afb368ff7;hp=e5ff0e56dcea53beed675890d76bc19f1c1fc2ea;hpb=1fce361d70296cb9f8828f58bf26cd1ce4e8a47a;p=ffmpeg diff --git a/libavfilter/split.c b/libavfilter/split.c index e5ff0e56dce..41395e7f480 100644 --- a/libavfilter/split.c +++ b/libavfilter/split.c @@ -25,27 +25,27 @@ #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) +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 }; @@ -59,7 +59,7 @@ static int split_init(AVFilterContext *ctx, const char *args) return 0; } -static void split_uninit(AVFilterContext *ctx) +static av_cold void split_uninit(AVFilterContext *ctx) { int i; @@ -67,98 +67,95 @@ static void split_uninit(AVFilterContext *ctx) av_freep(&ctx->output_pads[i].name); } -static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref) +static int filter_frame(AVFilterLink *inlink, AVFrame *frame) { AVFilterContext *ctx = inlink->dst; int i, ret = 0; for (i = 0; i < ctx->nb_outputs; i++) { - AVFilterBufferRef *buf_out = avfilter_ref_buffer(picref, ~AV_PERM_WRITE); - if (!buf_out) - return AVERROR(ENOMEM); + AVFrame *buf_out = av_frame_clone(frame); + if (!buf_out) { + ret = AVERROR(ENOMEM); + break; + } - ret = ff_start_frame(ctx->outputs[i], buf_out); + ret = ff_filter_frame(ctx->outputs[i], buf_out); if (ret < 0) break; } + av_frame_free(&frame); return ret; } -static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) -{ - AVFilterContext *ctx = inlink->dst; - int i, ret = 0; +#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++) { - ret = ff_draw_slice(ctx->outputs[i], y, h, slice_dir); - if (ret < 0) - break; - } - return ret; -} +static const AVClass split_class = { + .class_name = "split", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; -static int end_frame(AVFilterLink *inlink) -{ - AVFilterContext *ctx = inlink->dst; - int i, ret = 0; +static const AVClass asplit_class = { + .class_name = "asplit", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; - for (i = 0; i < ctx->nb_outputs; i++) { - ret = ff_end_frame(ctx->outputs[i]); - if (ret < 0) - break; - } - return ret; -} +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 avfilter_vf_split = { +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 = (const 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}}, + .inputs = avfilter_vf_split_inputs, .outputs = NULL, -}; -static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *samplesref) -{ - AVFilterContext *ctx = inlink->dst; - int i, ret = 0; - - for (i = 0; i < ctx->nb_outputs; i++) { - AVFilterBufferRef *buf_out = avfilter_ref_buffer(samplesref, - ~AV_PERM_WRITE); - if (!buf_out) { - ret = AVERROR(ENOMEM); - break; - } + .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS, +}; - ret = ff_filter_samples(inlink->dst->outputs[i], buf_out); - if (ret < 0) - break; - } - avfilter_unref_buffer(samplesref); - return ret; -} +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 }}, + .inputs = avfilter_af_asplit_inputs, .outputs = NULL, + + .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS, };