X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavfilter%2Fvf_lut2.c;h=658a0bfa567ff51e797d5b2c07b7c08685a678f2;hb=3f27021143f1bc6a55be5bac37f4c2d3c742e023;hp=d765dc9ad2a44245bdcda93cb35401cbe8248df0;hpb=398000abcf980d239a789da6f69811913d2fc635;p=ffmpeg diff --git a/libavfilter/vf_lut2.c b/libavfilter/vf_lut2.c index d765dc9ad2a..658a0bfa567 100644 --- a/libavfilter/vf_lut2.c +++ b/libavfilter/vf_lut2.c @@ -70,18 +70,22 @@ typedef struct LUT2Context { int tlut2; AVFrame *prev_frame; /* only used with tlut2 */ - void (*lut2)(struct LUT2Context *s, AVFrame *dst, AVFrame *srcx, AVFrame *srcy); - + int (*lut2)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); } LUT2Context; +typedef struct ThreadData { + AVFrame *out, *srcx, *srcy; +} ThreadData; + #define OFFSET(x) offsetof(LUT2Context, x) #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM +#define TFLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM static const AVOption options[] = { - { "c0", "set component #0 expression", OFFSET(comp_expr_str[0]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS }, - { "c1", "set component #1 expression", OFFSET(comp_expr_str[1]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS }, - { "c2", "set component #2 expression", OFFSET(comp_expr_str[2]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS }, - { "c3", "set component #3 expression", OFFSET(comp_expr_str[3]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS }, + { "c0", "set component #0 expression", OFFSET(comp_expr_str[0]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = TFLAGS }, + { "c1", "set component #1 expression", OFFSET(comp_expr_str[1]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = TFLAGS }, + { "c2", "set component #2 expression", OFFSET(comp_expr_str[2]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = TFLAGS }, + { "c3", "set component #3 expression", OFFSET(comp_expr_str[3]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = TFLAGS }, { "d", "set output depth", OFFSET(odepth), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 16, .flags = FLAGS }, { NULL } }; @@ -122,11 +126,12 @@ static av_cold void uninit(AVFilterContext *ctx) #define BIT12_FMTS \ AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12, \ + AV_PIX_FMT_YUVA422P12, AV_PIX_FMT_YUVA444P12, \ AV_PIX_FMT_GRAY12, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRP12, #define BIT14_FMTS \ AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14, \ - AV_PIX_FMT_GRAY12, AV_PIX_FMT_GBRP14, + AV_PIX_FMT_GRAY14, AV_PIX_FMT_GBRP14, #define BIT16_FMTS \ AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, \ @@ -173,7 +178,7 @@ static int query_formats(AVFilterContext *ctx) if (s->tlut2 || !s->odepth) return ff_set_common_formats(ctx, ff_make_format_list(all_pix_fmts)); - ret = ff_formats_ref(ff_make_format_list(all_pix_fmts), &ctx->inputs[0]->out_formats); + ret = ff_formats_ref(ff_make_format_list(all_pix_fmts), &ctx->inputs[0]->outcfg.formats); if (ret < 0) return ret; @@ -188,7 +193,7 @@ static int query_formats(AVFilterContext *ctx) return AVERROR(EINVAL); } - return ff_formats_ref(ff_make_format_list(pix_fmts), &ctx->outputs[0]->in_formats); + return ff_formats_ref(ff_make_format_list(pix_fmts), &ctx->outputs[0]->incfg.formats); } static int config_inputx(AVFilterLink *inlink) @@ -238,24 +243,31 @@ static int config_inputy(AVFilterLink *inlink) } #define DEFINE_LUT2(zname, xname, yname, ztype, xtype, ytype, zdiv, xdiv, ydiv) \ -static void lut2_##zname##_##xname##_##yname(struct LUT2Context *s, \ - AVFrame *out, \ - AVFrame *srcx, AVFrame *srcy) \ +static int lut2_##zname##_##xname##_##yname(AVFilterContext *ctx, \ + void *arg, \ + int jobnr, int nb_jobs) \ { \ + LUT2Context *s = ctx->priv; \ + ThreadData *td = arg; \ + AVFrame *out = td->out; \ + AVFrame *srcx = td->srcx; \ + AVFrame *srcy = td->srcy; \ const int odepth = s->odepth; \ int p, y, x; \ \ for (p = 0; p < s->nb_planes; p++) { \ + const int slice_start = (s->heightx[p] * jobnr) / nb_jobs; \ + const int slice_end = (s->heightx[p] * (jobnr+1)) / nb_jobs; \ const uint16_t *lut = s->lut[p]; \ const xtype *srcxx; \ const ytype *srcyy; \ ztype *dst; \ \ - dst = (ztype *)out->data[p]; \ - srcxx = (const xtype *)srcx->data[p]; \ - srcyy = (const ytype *)srcy->data[p]; \ + dst = (ztype *)(out->data[p] + slice_start * out->linesize[p]); \ + srcxx = (const xtype *)(srcx->data[p] + slice_start * srcx->linesize[p]);\ + srcyy = (const ytype *)(srcy->data[p] + slice_start * srcy->linesize[p]);\ \ - for (y = 0; y < s->heightx[p]; y++) { \ + for (y = slice_start; y < slice_end; y++) { \ for (x = 0; x < s->widthx[p]; x++) { \ dst[x] = av_clip_uintp2_c(lut[(srcyy[x] << s->depthx) | srcxx[x]], odepth); \ } \ @@ -265,6 +277,7 @@ static void lut2_##zname##_##xname##_##yname(struct LUT2Context *s, srcyy += srcy->linesize[p] / ydiv; \ } \ } \ + return 0; \ } DEFINE_LUT2(8, 8, 8, uint8_t, uint8_t, uint8_t, 1, 1, 1) @@ -293,12 +306,17 @@ static int process_frame(FFFrameSync *fs) if (!out) return AVERROR(ENOMEM); } else { + ThreadData td; + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!out) return AVERROR(ENOMEM); av_frame_copy_props(out, srcx); - s->lut2(s, out, srcx, srcy); + td.out = out; + td.srcx = srcx; + td.srcy = srcy; + ctx->internal->execute(ctx, s->lut2, &td, NULL, FFMIN(s->heightx[1], ff_filter_get_nb_threads(ctx))); } out->pts = av_rescale_q(s->fs.pts, s->fs.time_base, outlink->time_base); @@ -336,7 +354,8 @@ static int config_output(AVFilterLink *outlink) } for (p = 0; p < s->nb_planes; p++) { - s->lut[p] = av_malloc_array(1 << s->depth, sizeof(uint16_t)); + if (!s->lut[p]) + s->lut[p] = av_malloc_array(1 << s->depth, sizeof(uint16_t)); if (!s->lut[p]) return AVERROR(ENOMEM); } @@ -491,7 +510,10 @@ static int lut2_config_output(AVFilterLink *outlink) if ((ret = config_output(outlink)) < 0) return ret; - return ff_framesync_configure(&s->fs); + ret = ff_framesync_configure(&s->fs); + outlink->time_base = s->fs.time_base; + + return ret; } static int activate(AVFilterContext *ctx) @@ -523,11 +545,22 @@ static const AVFilterPad outputs[] = { { NULL } }; +static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, + char *res, int res_len, int flags) +{ + int ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags); + + if (ret < 0) + return ret; + + return config_output(ctx->outputs[0]); +} + #define lut2_options options FRAMESYNC_DEFINE_CLASS(lut2, LUT2Context, fs); -AVFilter ff_vf_lut2 = { +const AVFilter ff_vf_lut2 = { .name = "lut2", .description = NULL_IF_CONFIG_SMALL("Compute and apply a lookup table from two video inputs."), .preinit = lut2_framesync_preinit, @@ -538,7 +571,9 @@ AVFilter ff_vf_lut2 = { .activate = activate, .inputs = inputs, .outputs = outputs, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, + .process_command = process_command, }; #if CONFIG_TLUT2_FILTER @@ -564,6 +599,8 @@ static int tlut2_filter_frame(AVFilterLink *inlink, AVFrame *frame) if (ctx->is_disabled) { out = av_frame_clone(frame); } else { + ThreadData td; + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!out) { av_frame_free(&s->prev_frame); @@ -572,7 +609,11 @@ static int tlut2_filter_frame(AVFilterLink *inlink, AVFrame *frame) } av_frame_copy_props(out, frame); - s->lut2(s, out, frame, s->prev_frame); + + td.out = out; + td.srcx = frame; + td.srcy = s->prev_frame; + ctx->internal->execute(ctx, s->lut2, &td, NULL, FFMIN(s->heightx[1], ff_filter_get_nb_threads(ctx))); } av_frame_free(&s->prev_frame); s->prev_frame = frame; @@ -583,10 +624,10 @@ static int tlut2_filter_frame(AVFilterLink *inlink, AVFrame *frame) } static const AVOption tlut2_options[] = { - { "c0", "set component #0 expression", OFFSET(comp_expr_str[0]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS }, - { "c1", "set component #1 expression", OFFSET(comp_expr_str[1]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS }, - { "c2", "set component #2 expression", OFFSET(comp_expr_str[2]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS }, - { "c3", "set component #3 expression", OFFSET(comp_expr_str[3]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS }, + { "c0", "set component #0 expression", OFFSET(comp_expr_str[0]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = TFLAGS }, + { "c1", "set component #1 expression", OFFSET(comp_expr_str[1]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = TFLAGS }, + { "c2", "set component #2 expression", OFFSET(comp_expr_str[2]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = TFLAGS }, + { "c3", "set component #3 expression", OFFSET(comp_expr_str[3]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = TFLAGS }, { NULL } }; @@ -611,7 +652,7 @@ static const AVFilterPad tlut2_outputs[] = { { NULL } }; -AVFilter ff_vf_tlut2 = { +const AVFilter ff_vf_tlut2 = { .name = "tlut2", .description = NULL_IF_CONFIG_SMALL("Compute and apply a lookup table from two successive frames."), .priv_size = sizeof(LUT2Context), @@ -621,7 +662,9 @@ AVFilter ff_vf_tlut2 = { .uninit = uninit, .inputs = tlut2_inputs, .outputs = tlut2_outputs, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, + .process_command = process_command, }; #endif