| @@ -28,6 +28,11 @@ | |||||
| #include "limiter.h" | #include "limiter.h" | ||||
| #include "video.h" | #include "video.h" | ||||
| typedef struct ThreadData { | |||||
| AVFrame *in; | |||||
| AVFrame *out; | |||||
| } ThreadData; | |||||
| typedef struct LimiterContext { | typedef struct LimiterContext { | ||||
| const AVClass *class; | const AVClass *class; | ||||
| int min; | int min; | ||||
| @@ -161,13 +166,46 @@ static int config_props(AVFilterLink *inlink) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |||||
| { | |||||
| LimiterContext *s = ctx->priv; | |||||
| ThreadData *td = arg; | |||||
| AVFrame *in = td->in; | |||||
| AVFrame *out = td->out; | |||||
| int p; | |||||
| for (p = 0; p < s->nb_planes; p++) { | |||||
| const int h = s->height[p]; | |||||
| const int slice_start = (h * jobnr) / nb_jobs; | |||||
| const int slice_end = (h * (jobnr+1)) / nb_jobs; | |||||
| if (!((1 << p) & s->planes)) { | |||||
| if (out != in) | |||||
| av_image_copy_plane(out->data[p] + slice_start * out->linesize[p], | |||||
| out->linesize[p], | |||||
| in->data[p] + slice_start * in->linesize[p], | |||||
| in->linesize[p], | |||||
| s->linesize[p], slice_end - slice_start); | |||||
| continue; | |||||
| } | |||||
| s->dsp.limiter(in->data[p] + slice_start * in->linesize[p], | |||||
| out->data[p] + slice_start * out->linesize[p], | |||||
| in->linesize[p], out->linesize[p], | |||||
| s->width[p], slice_end - slice_start, | |||||
| s->min, s->max); | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| static int filter_frame(AVFilterLink *inlink, AVFrame *in) | static int filter_frame(AVFilterLink *inlink, AVFrame *in) | ||||
| { | { | ||||
| AVFilterContext *ctx = inlink->dst; | AVFilterContext *ctx = inlink->dst; | ||||
| LimiterContext *s = ctx->priv; | LimiterContext *s = ctx->priv; | ||||
| AVFilterLink *outlink = ctx->outputs[0]; | AVFilterLink *outlink = ctx->outputs[0]; | ||||
| ThreadData td; | |||||
| AVFrame *out; | AVFrame *out; | ||||
| int p; | |||||
| if (av_frame_is_writable(in)) { | if (av_frame_is_writable(in)) { | ||||
| out = in; | out = in; | ||||
| @@ -180,20 +218,10 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) | |||||
| av_frame_copy_props(out, in); | av_frame_copy_props(out, in); | ||||
| } | } | ||||
| for (p = 0; p < s->nb_planes; p++) { | |||||
| if (!((1 << p) & s->planes)) { | |||||
| if (out != in) | |||||
| av_image_copy_plane(out->data[p], out->linesize[p], in->data[p], in->linesize[p], | |||||
| s->linesize[p], s->height[p]); | |||||
| continue; | |||||
| } | |||||
| s->dsp.limiter(in->data[p], out->data[p], | |||||
| in->linesize[p], out->linesize[p], | |||||
| s->width[p], s->height[p], | |||||
| s->min, s->max); | |||||
| } | |||||
| td.out = out; | |||||
| td.in = in; | |||||
| ctx->internal->execute(ctx, filter_slice, &td, NULL, | |||||
| FFMIN(s->height[2], ff_filter_get_nb_threads(ctx))); | |||||
| if (out != in) | if (out != in) | ||||
| av_frame_free(&in); | av_frame_free(&in); | ||||
| @@ -227,5 +255,5 @@ AVFilter ff_vf_limiter = { | |||||
| .query_formats = query_formats, | .query_formats = query_formats, | ||||
| .inputs = inputs, | .inputs = inputs, | ||||
| .outputs = outputs, | .outputs = outputs, | ||||
| .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, | |||||
| .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, | |||||
| }; | }; | ||||