| @@ -28,6 +28,11 @@ | |||
| #include "limiter.h" | |||
| #include "video.h" | |||
| typedef struct ThreadData { | |||
| AVFrame *in; | |||
| AVFrame *out; | |||
| } ThreadData; | |||
| typedef struct LimiterContext { | |||
| const AVClass *class; | |||
| int min; | |||
| @@ -161,13 +166,46 @@ static int config_props(AVFilterLink *inlink) | |||
| 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) | |||
| { | |||
| AVFilterContext *ctx = inlink->dst; | |||
| LimiterContext *s = ctx->priv; | |||
| AVFilterLink *outlink = ctx->outputs[0]; | |||
| ThreadData td; | |||
| AVFrame *out; | |||
| int p; | |||
| if (av_frame_is_writable(in)) { | |||
| out = in; | |||
| @@ -180,20 +218,10 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *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) | |||
| av_frame_free(&in); | |||
| @@ -227,5 +255,5 @@ AVFilter ff_vf_limiter = { | |||
| .query_formats = query_formats, | |||
| .inputs = inputs, | |||
| .outputs = outputs, | |||
| .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, | |||
| .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, | |||
| }; | |||