Add lumakey_opencl filter. Behaves like existing lumakey filter. --- configure | 1 + libavfilter/Makefile | 2 + libavfilter/allfilters.c | 1 + libavfilter/opencl/lumakey.cl | 43 +++++++ libavfilter/opencl_source.h | 1 + libavfilter/vf_lumakey_opencl.c | 243 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 291 insertions(+) create mode 100644 libavfilter/opencl/lumakey.cl create mode 100644 libavfilter/vf_lumakey_opencl.c
diff --git a/configure b/configure index 5783407..9816ebb 100755 --- a/configure +++ b/configure @@ -3356,6 +3356,7 @@ interlace_filter_deps="gpl" kerndeint_filter_deps="gpl" ladspa_filter_deps="ladspa libdl" lensfun_filter_deps="liblensfun version3" +lumakey_opencl_filter_deps="opencl" lv2_filter_deps="lv2" mcdeint_filter_deps="avcodec gpl" movie_filter_deps="avcodec avformat" diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 5d4549e..2a01bf3 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -253,6 +253,8 @@ OBJS-$(CONFIG_LIBVMAF_FILTER) += vf_libvmaf.o framesync.o OBJS-$(CONFIG_LIMITER_FILTER) += vf_limiter.o OBJS-$(CONFIG_LOOP_FILTER) += f_loop.o OBJS-$(CONFIG_LUMAKEY_FILTER) += vf_lumakey.o +OBJS-$(CONFIG_LUMAKEY_OPENCL_FILTER) += vf_lumakey_opencl.o opencl.o \ + opencl/lumakey.o OBJS-$(CONFIG_LUT_FILTER) += vf_lut.o OBJS-$(CONFIG_LUT2_FILTER) += vf_lut2.o framesync.o OBJS-$(CONFIG_LUT3D_FILTER) += vf_lut3d.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 521bc53..065ad9f 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -242,6 +242,7 @@ extern AVFilter ff_vf_libvmaf; extern AVFilter ff_vf_limiter; extern AVFilter ff_vf_loop; extern AVFilter ff_vf_lumakey; +extern AVFilter ff_vf_lumakey_opencl; extern AVFilter ff_vf_lut; extern AVFilter ff_vf_lut2; extern AVFilter ff_vf_lut3d; diff --git a/libavfilter/opencl/lumakey.cl b/libavfilter/opencl/lumakey.cl new file mode 100644 index 0000000..dbee63e --- /dev/null +++ b/libavfilter/opencl/lumakey.cl @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018 Danil Iashchenko + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +__kernel void lumakey_global(__write_only image2d_t dstAlpha, + __read_only image2d_t srcLuma, + float w, + float b, + int so) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_ADDRESS_CLAMP_TO_EDGE | + CLK_FILTER_NEAREST); + + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + float4 lumaPix = read_imagef(srcLuma, sampler, loc) * 255; + + if (lumaPix.x >= b && lumaPix.x <= w) { + write_imagef(dstAlpha, loc, (float4)(0.0f)); + } else if (lumaPix.x > b - so && lumaPix.x < w + so) { + if (lumaPix.x < b) { + write_imagef(dstAlpha, loc, (float4)((1 - (lumaPix.x - b + so) / so))); + } else { + write_imagef(dstAlpha, loc, (float4)(((lumaPix.x - w) / so))); + } + } +} diff --git a/libavfilter/opencl_source.h b/libavfilter/opencl_source.h index de4e66e..dba701e 100644 --- a/libavfilter/opencl_source.h +++ b/libavfilter/opencl_source.h @@ -22,6 +22,7 @@ extern const char *ff_opencl_source_avgblur; extern const char *ff_opencl_source_colorspace_common; extern const char *ff_opencl_source_convolution; +extern const char *ff_opencl_source_lumakey; extern const char *ff_opencl_source_overlay; extern const char *ff_opencl_source_tonemap; extern const char *ff_opencl_source_unsharp; diff --git a/libavfilter/vf_lumakey_opencl.c b/libavfilter/vf_lumakey_opencl.c new file mode 100644 index 0000000..8879a88 --- /dev/null +++ b/libavfilter/vf_lumakey_opencl.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2018 Danil Iashchenko + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/common.h" +#include "libavutil/imgutils.h" +#include "libavutil/opt.h" + + +#include "avfilter.h" +#include "internal.h" +#include "opencl.h" +#include "opencl_source.h" +#include "video.h" + +typedef struct LumakeyOpenCLContext { + OpenCLFilterContext ocf; + + int initialised; + cl_kernel kernel; + cl_command_queue command_queue; + + cl_int threshold; + cl_int tolerance; + cl_int softness; + + cl_float black; + cl_float white; + +} LumakeyOpenCLContext; + +static int lumakey_opencl_init(AVFilterContext *avctx) +{ + LumakeyOpenCLContext *ctx = avctx->priv; + cl_int cle; + int err; + + err = ff_opencl_filter_load_program(avctx, &ff_opencl_source_lumakey, 1); + if (err < 0) + goto fail; + + ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context, + ctx->ocf.hwctx->device_id, + 0, &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create OpenCL " + "command queue %d.\n", cle); + + ctx->kernel = clCreateKernel(ctx->ocf.program, "lumakey_global", &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create " + "kernel %d.\n", cle); + + ctx->initialised = 1; + return 0; + +fail: + if (ctx->command_queue) + clReleaseCommandQueue(ctx->command_queue); + if (ctx->kernel) + clReleaseKernel(ctx->kernel); + return err; +} + + +static int lumakey_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) +{ + AVFilterContext *avctx = inlink->dst; + AVFilterLink *outlink = avctx->outputs[0]; + LumakeyOpenCLContext *ctx = avctx->priv; + AVFrame *output = NULL; + cl_int cle; + size_t global_work[2]; + cl_mem src, dst; + int err, i; + size_t origin[3] = {0, 0, 0}; + size_t region[3] = {0, 0, 1}; + + av_log(ctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(input->format), + input->width, input->height, input->pts); + + if (!input->hw_frames_ctx) + return AVERROR(EINVAL); + + if (!ctx->initialised) { + err = lumakey_opencl_init(avctx); + if (err < 0) + goto fail; + + ctx->white = ctx->threshold + ctx->tolerance; + ctx->black = ctx->threshold - ctx->tolerance; + } + + output = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!output) { + err = AVERROR(ENOMEM); + goto fail; + } + + for (i = 0; i < FF_ARRAY_ELEMS(output->data) - 1; i++) { + src = (cl_mem) input->data[i]; + dst = (cl_mem)output->data[i]; + + if (!dst) + break; + + err = ff_opencl_filter_work_size_from_image(avctx, region, output, i, 0); + if (err < 0) + goto fail; + + cle = clEnqueueCopyImage(ctx->command_queue, src, dst, + origin, origin, region, 0, NULL, NULL); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to copy plane %d: %d.\n", + i, cle); + } + + src = (cl_mem) input->data[0]; + dst = (cl_mem)output->data[3]; + + CL_SET_KERNEL_ARG(ctx->kernel, 0, cl_mem, &dst); + CL_SET_KERNEL_ARG(ctx->kernel, 1, cl_mem, &src); + CL_SET_KERNEL_ARG(ctx->kernel, 2, cl_float, &ctx->white); + CL_SET_KERNEL_ARG(ctx->kernel, 3, cl_float, &ctx->black); + CL_SET_KERNEL_ARG(ctx->kernel, 4, cl_int, &ctx->softness); + + err = ff_opencl_filter_work_size_from_image(avctx, global_work, output, 0, 0); + if (err < 0) + goto fail; + + av_log(avctx, AV_LOG_DEBUG, "Run kernel on plane %d" + "(%"SIZE_SPECIFIER"x%"SIZE_SPECIFIER").\n", + 0, global_work[0], global_work[1]); + + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel, 2, NULL, + global_work, NULL, + 0, NULL, NULL); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to enqueue " + "kernel: %d.\n", cle); + + + cle = clFinish(ctx->command_queue); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to finish command queue: %d.\n", cle); + + err = av_frame_copy_props(output, input); + if (err < 0) + goto fail; + + av_frame_free(&input); + + av_log(ctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(output->format), + output->width, output->height, output->pts); + + return ff_filter_frame(outlink, output); + +fail: + clFinish(ctx->command_queue); + av_frame_free(&input); + av_frame_free(&output); + return err; +} + + +static av_cold void lumakey_opencl_uninit(AVFilterContext *avctx) +{ + LumakeyOpenCLContext *ctx = avctx->priv; + cl_int cle; + + if (ctx->kernel) { + cle = clReleaseKernel(ctx->kernel); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "kernel: %d.\n", cle); + } + + if (ctx->command_queue) { + cle = clReleaseCommandQueue(ctx->command_queue); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "command queue: %d.\n", cle); + } + + ff_opencl_filter_uninit(avctx); +} + +static const AVFilterPad lumakey_opencl_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = &lumakey_opencl_filter_frame, + .config_props = &ff_opencl_filter_config_input, + }, + { NULL } +}; + +static const AVFilterPad lumakey_opencl_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &ff_opencl_filter_config_output, + }, + { NULL } +}; + +#define OFFSET(x) offsetof(LumakeyOpenCLContext, x) +#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) + +static const AVOption lumakey_opencl_options[] = { + { "threshold", "set the threshold value", OFFSET(threshold), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS }, + { "tolerance", "set the tolerance value", OFFSET(tolerance), AV_OPT_TYPE_INT, {.i64=1}, 0, UINT16_MAX, FLAGS }, + { "softness", "set the softness value", OFFSET(softness), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(lumakey_opencl); + +AVFilter ff_vf_lumakey_opencl = { + .name = "lumakey_opencl", + .description = NULL_IF_CONFIG_SMALL("Apply convolution mask to input video"), + .priv_size = sizeof(LumakeyOpenCLContext), + .priv_class = &lumakey_opencl_class, + .init = &ff_opencl_filter_init, + .uninit = &lumakey_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .inputs = lumakey_opencl_inputs, + .outputs = lumakey_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; -- 2.7.4 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel