mirror of
https://github.com/jellyfin/jellyfin-ffmpeg.git
synced 2026-09-02 21:03:08 +03:00
``` compat/float/limits.h compat/stdbit/stdbit.h libavcodec/bitstream_template.h +libavfilter/vf_overlay_d3d11.h +libavfilter/vf_tonemap_d3d11.h +libavfilter/vf_yadif_d3d11.h tools/decode_simple.h Use of av_clip() where av_clip_uintp2() could be used: Use of av_clip() where av_clip_intp2() could be used: Test source failed. Look at tests/data/fate/source.err for details. make: *** [tests/Makefile:322: fate-source] Error 1 make: *** Waiting for unfinished jobs.... ``` Signed-off-by: nyanmisaka <nst799610810@gmail.com>
1570 lines
56 KiB
Diff
1570 lines
56 KiB
Diff
Index: FFmpeg/configure
|
|
===================================================================
|
|
--- FFmpeg.orig/configure
|
|
+++ FFmpeg/configure
|
|
@@ -3549,6 +3549,8 @@ ddagrab_filter_deps="d3d11va IDXGIOutput
|
|
gfxcapture_filter_deps="cxx17 threads d3d11va IGraphicsCaptureItemInterop __x_ABI_CWindows_CGraphics_CCapture_CIGraphicsCaptureSession3"
|
|
gfxcapture_filter_extralibs="-lstdc++"
|
|
scale_d3d11_filter_deps="d3d11va"
|
|
+bwdif_d3d11_filter_deps="d3d11va d3dcompiler_h"
|
|
+yadif_d3d11_filter_deps="d3d11va d3dcompiler_h"
|
|
scale_d3d12_filter_deps="d3d12va ID3D12VideoProcessor"
|
|
deinterlace_d3d12_filter_deps="d3d12va ID3D12VideoProcessor"
|
|
mestimate_d3d12_filter_deps="d3d12va ID3D12VideoMotionEstimator d3d12_motion_estimator"
|
|
@@ -7029,6 +7031,7 @@ fi
|
|
check_headers direct.h
|
|
check_headers dirent.h
|
|
check_headers dxgidebug.h
|
|
+check_headers d3dcompiler.h
|
|
check_headers dxva.h
|
|
check_headers dxva2api.h -D_WIN32_WINNT=0x0600
|
|
check_headers io.h
|
|
Index: FFmpeg/libavfilter/Makefile
|
|
===================================================================
|
|
--- FFmpeg.orig/libavfilter/Makefile
|
|
+++ FFmpeg/libavfilter/Makefile
|
|
@@ -222,6 +222,7 @@ OBJS-$(CONFIG_BOXBLUR_FILTER)
|
|
OBJS-$(CONFIG_BOXBLUR_OPENCL_FILTER) += vf_avgblur_opencl.o opencl.o \
|
|
opencl/avgblur.o boxblur.o
|
|
OBJS-$(CONFIG_BWDIF_FILTER) += vf_bwdif.o bwdifdsp.o yadif_common.o
|
|
+OBJS-$(CONFIG_BWDIF_D3D11_FILTER) += vf_yadif_d3d11.o yadif_common.o d3d11/deint.o d3d11_filter.o
|
|
OBJS-$(CONFIG_BWDIF_CUDA_FILTER) += vf_bwdif_cuda.o vf_bwdif_cuda.ptx.o \
|
|
yadif_common.o
|
|
OBJS-$(CONFIG_BWDIF_OPENCL_FILTER) += vf_bwdif_opencl.o opencl.o opencl/bwdif.o \
|
|
@@ -609,6 +610,7 @@ OBJS-$(CONFIG_XMEDIAN_FILTER)
|
|
OBJS-$(CONFIG_XPSNR_FILTER) += vf_xpsnr.o framesync.o psnr.o
|
|
OBJS-$(CONFIG_XSTACK_FILTER) += vf_stack.o framesync.o
|
|
OBJS-$(CONFIG_YADIF_FILTER) += vf_yadif.o yadif_common.o
|
|
+OBJS-$(CONFIG_YADIF_D3D11_FILTER) += vf_yadif_d3d11.o yadif_common.o d3d11/deint.o d3d11_filter.o
|
|
OBJS-$(CONFIG_YADIF_CUDA_FILTER) += vf_yadif_cuda.o vf_yadif_cuda.ptx.o \
|
|
yadif_common.o cuda/load_helper.o
|
|
OBJS-$(CONFIG_YADIF_OPENCL_FILTER) += vf_yadif_opencl.o opencl.o opencl/yadif.o \
|
|
@@ -721,10 +723,16 @@ TOOLS-$(CONFIG_LIBZMQ) += zmqsend
|
|
|
|
clean::
|
|
$(RM) $(CLEANSUFFIXES:%=libavfilter/dnn/%) $(CLEANSUFFIXES:%=libavfilter/opencl/%) \
|
|
- $(CLEANSUFFIXES:%=libavfilter/metal/%)
|
|
+ $(CLEANSUFFIXES:%=libavfilter/metal/%) $(CLEANSUFFIXES:%=libavfilter/d3d11/%)
|
|
|
|
OPENCL = $(subst $(SRC_PATH)/,,$(wildcard $(SRC_PATH)/libavfilter/opencl/*.cl))
|
|
.SECONDARY: $(OPENCL:.cl=.c)
|
|
libavfilter/opencl/%.c: TAG = OPENCL
|
|
libavfilter/opencl/%.c: $(SRC_PATH)/libavfilter/opencl/%.cl
|
|
$(M)$(SRC_PATH)/tools/source2c $< $@
|
|
+
|
|
+HLSL = $(subst $(SRC_PATH)/,,$(wildcard $(SRC_PATH)/libavfilter/d3d11/*.hlsl))
|
|
+.SECONDARY: $(HLSL:.hlsl=.c)
|
|
+libavfilter/d3d11/%.c: TAG = HLSL
|
|
+libavfilter/d3d11/%.c: $(SRC_PATH)/libavfilter/d3d11/%.hlsl
|
|
+ $(M)$(SRC_PATH)/tools/source2c $< $@
|
|
Index: FFmpeg/libavfilter/allfilters.c
|
|
===================================================================
|
|
--- FFmpeg.orig/libavfilter/allfilters.c
|
|
+++ FFmpeg/libavfilter/allfilters.c
|
|
@@ -203,6 +203,7 @@ extern const FFFilter ff_vf_bm3d;
|
|
extern const FFFilter ff_vf_boxblur;
|
|
extern const FFFilter ff_vf_boxblur_opencl;
|
|
extern const FFFilter ff_vf_bwdif;
|
|
+extern const FFFilter ff_vf_bwdif_d3d11;
|
|
extern const FFFilter ff_vf_bwdif_cuda;
|
|
extern const FFFilter ff_vf_bwdif_opencl;
|
|
extern const FFFilter ff_vf_bwdif_videotoolbox;
|
|
@@ -563,6 +564,7 @@ extern const FFFilter ff_vf_xmedian;
|
|
extern const FFFilter ff_vf_xpsnr;
|
|
extern const FFFilter ff_vf_xstack;
|
|
extern const FFFilter ff_vf_yadif;
|
|
+extern const FFFilter ff_vf_yadif_d3d11;
|
|
extern const FFFilter ff_vf_yadif_cuda;
|
|
extern const FFFilter ff_vf_yadif_opencl;
|
|
extern const FFFilter ff_vf_yadif_videotoolbox;
|
|
Index: FFmpeg/libavfilter/vf_yadif_d3d11.c
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ FFmpeg/libavfilter/vf_yadif_d3d11.c
|
|
@@ -0,0 +1,660 @@
|
|
+/*
|
|
+ * D3D11 YADIF/BWDIF deinterlacing filters
|
|
+ *
|
|
+ * Copyright (C) 2026 Gnattu OC <gnattuoc@me.com>
|
|
+ *
|
|
+ * 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 <windows.h>
|
|
+#ifndef COBJMACROS
|
|
+#define COBJMACROS
|
|
+#endif
|
|
+#include <d3d11.h>
|
|
+
|
|
+#include "libavutil/avassert.h"
|
|
+#include "libavutil/common.h"
|
|
+#include "libavutil/hwcontext.h"
|
|
+#include "libavutil/hwcontext_d3d11va.h"
|
|
+#include "libavutil/mem.h"
|
|
+#include "libavutil/opt.h"
|
|
+#include "libavutil/pixdesc.h"
|
|
+
|
|
+#include "filters.h"
|
|
+#include "video.h"
|
|
+#include "yadif.h"
|
|
+#include "vf_yadif_d3d11.h"
|
|
+#include "d3d11_source.h"
|
|
+#include "d3d11_filter.h"
|
|
+
|
|
+#define DEINT_D3D11_ALG_YADIF 0
|
|
+#define DEINT_D3D11_ALG_BWDIF 1
|
|
+
|
|
+typedef struct DeintD3D11Params {
|
|
+ int width;
|
|
+ int height;
|
|
+ int parity;
|
|
+ int tff;
|
|
+ int is_second_field;
|
|
+ int current_field;
|
|
+ int skip_spatial_check;
|
|
+ int algorithm;
|
|
+} DeintD3D11Params;
|
|
+
|
|
+typedef struct DeintD3D11Context {
|
|
+ YADIFContext yadif;
|
|
+
|
|
+ int algorithm;
|
|
+
|
|
+ AVD3D11VADeviceContext *hwctx;
|
|
+ AVBufferRef *device_ref;
|
|
+ AVBufferRef *input_frames_ref;
|
|
+ AVHWFramesContext *input_frames;
|
|
+
|
|
+ ID3D11Device *device;
|
|
+ ID3D11DeviceContext *context;
|
|
+ HMODULE d3dcompiler;
|
|
+ FFD3DCompileProc D3DCompile;
|
|
+
|
|
+ ID3D11ComputeShader *cs_y;
|
|
+ ID3D11ComputeShader *cs_uv;
|
|
+ ID3D11Buffer *params_buf;
|
|
+
|
|
+ ID3D11Texture2D *prev_tex;
|
|
+ ID3D11Texture2D *cur_tex;
|
|
+ ID3D11Texture2D *next_tex;
|
|
+ ID3D11Texture2D *work_tex;
|
|
+ int tex_w, tex_h;
|
|
+ int direct_input_srv;
|
|
+ int direct_output_uav;
|
|
+ int force_output_copy;
|
|
+} DeintD3D11Context;
|
|
+
|
|
+static void release_d3d11_resources(DeintD3D11Context *s)
|
|
+{
|
|
+ FF_D3D11_RELEASE(s->cs_y);
|
|
+ FF_D3D11_RELEASE(s->cs_uv);
|
|
+ FF_D3D11_RELEASE(s->params_buf);
|
|
+ FF_D3D11_RELEASE(s->prev_tex);
|
|
+ FF_D3D11_RELEASE(s->cur_tex);
|
|
+ FF_D3D11_RELEASE(s->next_tex);
|
|
+ FF_D3D11_RELEASE(s->work_tex);
|
|
+ s->tex_w = s->tex_h = 0;
|
|
+}
|
|
+
|
|
+static int compile_shader(AVFilterContext *ctx, const char *entry, ID3D11ComputeShader **shader)
|
|
+{
|
|
+ DeintD3D11Context *s = ctx->priv;
|
|
+
|
|
+ return ff_d3d11_compile_shader(ctx, s->device, s->D3DCompile,
|
|
+ ff_source_deint_hlsl, NULL, entry,
|
|
+ "cs_5_0", "D3D11 deinterlace", shader);
|
|
+}
|
|
+
|
|
+static int init_shaders(AVFilterContext *ctx)
|
|
+{
|
|
+ DeintD3D11Context *s = ctx->priv;
|
|
+ int ret;
|
|
+
|
|
+ if (s->cs_y)
|
|
+ return 0;
|
|
+
|
|
+ ret = ff_d3d11_load_shader_compiler(ctx, &s->d3dcompiler, &s->D3DCompile);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ if ((ret = compile_shader(ctx, "deint_y", &s->cs_y)) < 0 ||
|
|
+ (ret = compile_shader(ctx, "deint_uv", &s->cs_uv)) < 0)
|
|
+ return ret;
|
|
+
|
|
+ return ff_d3d11_create_const_buffer(ctx, s->device, sizeof(DeintD3D11Params),
|
|
+ "D3D11 deinterlace", &s->params_buf);
|
|
+}
|
|
+
|
|
+static int ensure_textures(AVFilterContext *ctx, int w, int h)
|
|
+{
|
|
+ DeintD3D11Context *s = ctx->priv;
|
|
+ D3D11_TEXTURE2D_DESC desc = { 0 };
|
|
+ HRESULT hr;
|
|
+
|
|
+ if (s->prev_tex && s->cur_tex && s->next_tex && s->work_tex && s->tex_w == w && s->tex_h == h)
|
|
+ return 0;
|
|
+
|
|
+ FF_D3D11_RELEASE(s->prev_tex);
|
|
+ FF_D3D11_RELEASE(s->cur_tex);
|
|
+ FF_D3D11_RELEASE(s->next_tex);
|
|
+ FF_D3D11_RELEASE(s->work_tex);
|
|
+
|
|
+ desc.Width = w;
|
|
+ desc.Height = h;
|
|
+ desc.MipLevels = 1;
|
|
+ desc.ArraySize = 1;
|
|
+ desc.Format = DXGI_FORMAT_NV12;
|
|
+ desc.SampleDesc.Count = 1;
|
|
+ desc.Usage = D3D11_USAGE_DEFAULT;
|
|
+ desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
|
+
|
|
+ hr = s->device->lpVtbl->CreateTexture2D(s->device, &desc, NULL, &s->prev_tex);
|
|
+ if (FAILED(hr)) goto fail;
|
|
+ hr = s->device->lpVtbl->CreateTexture2D(s->device, &desc, NULL, &s->cur_tex);
|
|
+ if (FAILED(hr)) goto fail;
|
|
+ hr = s->device->lpVtbl->CreateTexture2D(s->device, &desc, NULL, &s->next_tex);
|
|
+ if (FAILED(hr)) goto fail;
|
|
+
|
|
+ desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
|
|
+ hr = s->device->lpVtbl->CreateTexture2D(s->device, &desc, NULL, &s->work_tex);
|
|
+ if (FAILED(hr)) goto fail;
|
|
+
|
|
+ s->tex_w = w;
|
|
+ s->tex_h = h;
|
|
+ return 0;
|
|
+
|
|
+fail:
|
|
+ av_log(ctx, AV_LOG_ERROR, "Failed creating D3D11 deinterlace texture: HRESULT 0x%lX\n",
|
|
+ (unsigned long)hr);
|
|
+ return AVERROR_EXTERNAL;
|
|
+}
|
|
+
|
|
+static int create_nv12_srv_view(AVFilterContext *ctx, ID3D11Texture2D *tex,
|
|
+ UINT subresource, int plane, int log_level,
|
|
+ ID3D11ShaderResourceView **srv)
|
|
+{
|
|
+ DeintD3D11Context *s = ctx->priv;
|
|
+
|
|
+ return ff_d3d11_create_srv(ctx, s->device, tex, subresource,
|
|
+ ff_d3d11_plane_format(AV_PIX_FMT_NV12, plane),
|
|
+ log_level, "D3D11 deinterlace", srv);
|
|
+}
|
|
+
|
|
+static int create_nv12_srv(AVFilterContext *ctx, ID3D11Texture2D *tex, int plane,
|
|
+ ID3D11ShaderResourceView **srv)
|
|
+{
|
|
+ return create_nv12_srv_view(ctx, tex, 0, plane, AV_LOG_ERROR, srv);
|
|
+}
|
|
+
|
|
+static int create_nv12_uav_view(AVFilterContext *ctx, ID3D11Texture2D *tex,
|
|
+ UINT subresource, int plane, int log_level,
|
|
+ ID3D11UnorderedAccessView **uav)
|
|
+{
|
|
+ DeintD3D11Context *s = ctx->priv;
|
|
+
|
|
+ return ff_d3d11_create_uav(ctx, s->device, tex, subresource,
|
|
+ ff_d3d11_plane_format(AV_PIX_FMT_NV12, plane),
|
|
+ log_level, "D3D11 deinterlace", uav);
|
|
+}
|
|
+
|
|
+static int create_nv12_uav(AVFilterContext *ctx, ID3D11Texture2D *tex, int plane,
|
|
+ ID3D11UnorderedAccessView **uav)
|
|
+{
|
|
+ return create_nv12_uav_view(ctx, tex, 0, plane, AV_LOG_ERROR, uav);
|
|
+}
|
|
+
|
|
+static int create_frame_srvs(AVFilterContext *ctx, AVFrame *frame,
|
|
+ ID3D11ShaderResourceView **srv_y,
|
|
+ ID3D11ShaderResourceView **srv_uv)
|
|
+{
|
|
+ ID3D11Texture2D *tex = (ID3D11Texture2D *)frame->data[0];
|
|
+ UINT subresource = (UINT)(uintptr_t)frame->data[1];
|
|
+ int ret;
|
|
+
|
|
+ ret = create_nv12_srv_view(ctx, tex, subresource, 0, AV_LOG_DEBUG, srv_y);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+ ret = create_nv12_srv_view(ctx, tex, subresource, 1, AV_LOG_DEBUG, srv_uv);
|
|
+ if (ret < 0)
|
|
+ FF_D3D11_RELEASE(*srv_y);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int prepare_input_srvs(AVFilterContext *ctx, ID3D11ShaderResourceView **srvs)
|
|
+{
|
|
+ DeintD3D11Context *s = ctx->priv;
|
|
+ YADIFContext *y = &s->yadif;
|
|
+ int ret;
|
|
+
|
|
+ if (s->direct_input_srv) {
|
|
+ ret = create_frame_srvs(ctx, y->prev, &srvs[0], &srvs[3]);
|
|
+ if (ret >= 0)
|
|
+ ret = create_frame_srvs(ctx, y->cur, &srvs[1], &srvs[4]);
|
|
+ if (ret >= 0)
|
|
+ ret = create_frame_srvs(ctx, y->next, &srvs[2], &srvs[5]);
|
|
+ if (ret >= 0) {
|
|
+ if (s->direct_input_srv < 0) {
|
|
+ av_log(ctx, AV_LOG_DEBUG, "D3D11 shader input: direct SRV\n");
|
|
+ s->direct_input_srv = 1;
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+ for (int i = 0; i < 6; i++)
|
|
+ FF_D3D11_RELEASE(srvs[i]);
|
|
+ if (s->direct_input_srv < 0)
|
|
+ av_log(ctx, AV_LOG_DEBUG, "D3D11 shader input: copied to internal SRV texture\n");
|
|
+ s->direct_input_srv = 0;
|
|
+ }
|
|
+
|
|
+ ff_d3d11_copy_frame_to_texture(s->context, y->prev, s->prev_tex);
|
|
+ ff_d3d11_copy_frame_to_texture(s->context, y->cur, s->cur_tex);
|
|
+ ff_d3d11_copy_frame_to_texture(s->context, y->next, s->next_tex);
|
|
+
|
|
+#define MAKE_SRV(tex, plane, idx) do { ret = create_nv12_srv(ctx, tex, plane, &srvs[idx]); if (ret < 0) goto fail; } while (0)
|
|
+ MAKE_SRV(s->prev_tex, 0, 0);
|
|
+ MAKE_SRV(s->cur_tex, 0, 1);
|
|
+ MAKE_SRV(s->next_tex, 0, 2);
|
|
+ MAKE_SRV(s->prev_tex, 1, 3);
|
|
+ MAKE_SRV(s->cur_tex, 1, 4);
|
|
+ MAKE_SRV(s->next_tex, 1, 5);
|
|
+#undef MAKE_SRV
|
|
+
|
|
+ return 0;
|
|
+
|
|
+fail:
|
|
+#undef MAKE_SRV
|
|
+ for (int i = 0; i < 6; i++)
|
|
+ FF_D3D11_RELEASE(srvs[i]);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int prepare_output_uavs(AVFilterContext *ctx, AVFrame *dst,
|
|
+ ID3D11UnorderedAccessView **uavs, int *direct)
|
|
+{
|
|
+ DeintD3D11Context *s = ctx->priv;
|
|
+ ID3D11Texture2D *tex = (ID3D11Texture2D *)dst->data[0];
|
|
+ UINT subresource = (UINT)(uintptr_t)dst->data[1];
|
|
+ int ret;
|
|
+
|
|
+ *direct = 0;
|
|
+ if (s->direct_output_uav) {
|
|
+ ret = create_nv12_uav_view(ctx, tex, subresource, 0, AV_LOG_DEBUG, &uavs[0]);
|
|
+ if (ret >= 0)
|
|
+ ret = create_nv12_uav_view(ctx, tex, subresource, 1, AV_LOG_DEBUG, &uavs[1]);
|
|
+ if (ret >= 0) {
|
|
+ *direct = 1;
|
|
+ return 0;
|
|
+ }
|
|
+ FF_D3D11_RELEASE(uavs[0]);
|
|
+ FF_D3D11_RELEASE(uavs[1]);
|
|
+ if (s->direct_output_uav < 0)
|
|
+ av_log(ctx, AV_LOG_DEBUG, "D3D11 shader output: copied from internal UAV texture\n");
|
|
+ s->direct_output_uav = 0;
|
|
+ }
|
|
+
|
|
+ ret = create_nv12_uav(ctx, s->work_tex, 0, &uavs[0]);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+ ret = create_nv12_uav(ctx, s->work_tex, 1, &uavs[1]);
|
|
+ if (ret < 0)
|
|
+ FF_D3D11_RELEASE(uavs[0]);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int probe_output_uav_pool(AVFilterContext *ctx, AVBufferRef *frames_ref)
|
|
+{
|
|
+ AVHWFramesContext *frames_ctx = (AVHWFramesContext *)frames_ref->data;
|
|
+ AVD3D11VAFramesContext *frames_hwctx = frames_ctx->hwctx;
|
|
+ AVFrame *frame = NULL;
|
|
+ ID3D11Texture2D *tex;
|
|
+ ID3D11UnorderedAccessView *uavs[2] = { NULL, NULL };
|
|
+ UINT subresource;
|
|
+ int ret;
|
|
+
|
|
+ if (frames_hwctx->texture) {
|
|
+ tex = frames_hwctx->texture;
|
|
+ subresource = 0;
|
|
+ } else {
|
|
+ frame = av_frame_alloc();
|
|
+ if (!frame)
|
|
+ return AVERROR(ENOMEM);
|
|
+
|
|
+ ret = av_hwframe_get_buffer(frames_ref, frame, 0);
|
|
+ if (ret < 0)
|
|
+ goto done;
|
|
+
|
|
+ tex = (ID3D11Texture2D *)frame->data[0];
|
|
+ subresource = (UINT)(uintptr_t)frame->data[1];
|
|
+ }
|
|
+
|
|
+ ret = create_nv12_uav_view(ctx, tex, subresource, 0, AV_LOG_DEBUG, &uavs[0]);
|
|
+ if (ret >= 0)
|
|
+ ret = create_nv12_uav_view(ctx, tex, subresource, 1, AV_LOG_DEBUG, &uavs[1]);
|
|
+
|
|
+done:
|
|
+ FF_D3D11_RELEASE(uavs[0]);
|
|
+ FF_D3D11_RELEASE(uavs[1]);
|
|
+ av_frame_free(&frame);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int run_filter(AVFilterContext *ctx, AVFrame *dst, int parity, int tff)
|
|
+{
|
|
+ DeintD3D11Context *s = ctx->priv;
|
|
+ YADIFContext *y = &s->yadif;
|
|
+ ID3D11ShaderResourceView *srvs[6] = { NULL };
|
|
+ ID3D11ShaderResourceView *null_srvs[6] = { NULL };
|
|
+ ID3D11UnorderedAccessView *uavs[2] = { NULL, NULL };
|
|
+ ID3D11UnorderedAccessView *null_uavs[2] = { NULL, NULL };
|
|
+ ID3D11Buffer *null_cb[1] = { NULL };
|
|
+ D3D11_MAPPED_SUBRESOURCE mapped;
|
|
+ DeintD3D11Params params;
|
|
+ int direct_output = 0;
|
|
+ HRESULT hr;
|
|
+ int ret = 0;
|
|
+
|
|
+ ret = ensure_textures(ctx, y->cur->width, y->cur->height);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ ret = prepare_input_srvs(ctx, srvs);
|
|
+ if (ret < 0)
|
|
+ goto fail;
|
|
+
|
|
+ ret = prepare_output_uavs(ctx, dst, uavs, &direct_output);
|
|
+ if (ret < 0)
|
|
+ goto fail;
|
|
+
|
|
+ params.width = y->cur->width;
|
|
+ params.height = y->cur->height;
|
|
+ params.parity = parity;
|
|
+ params.tff = tff;
|
|
+ params.is_second_field = !(parity ^ tff);
|
|
+ params.current_field = y->current_field;
|
|
+ params.skip_spatial_check = y->mode & 2;
|
|
+ params.algorithm = s->algorithm;
|
|
+
|
|
+ hr = s->context->lpVtbl->Map(s->context, (ID3D11Resource *)s->params_buf,
|
|
+ 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
|
|
+ if (FAILED(hr)) {
|
|
+ av_log(ctx, AV_LOG_ERROR, "Failed mapping D3D11 deinterlace constant buffer: HRESULT 0x%lX\n",
|
|
+ (unsigned long)hr);
|
|
+ ret = AVERROR_EXTERNAL;
|
|
+ goto fail;
|
|
+ }
|
|
+ memcpy(mapped.pData, ¶ms, sizeof(params));
|
|
+ s->context->lpVtbl->Unmap(s->context, (ID3D11Resource *)s->params_buf, 0);
|
|
+
|
|
+ s->context->lpVtbl->CSSetConstantBuffers(s->context, 0, 1, &s->params_buf);
|
|
+ s->context->lpVtbl->CSSetShaderResources(s->context, 0, 6, srvs);
|
|
+ s->context->lpVtbl->CSSetUnorderedAccessViews(s->context, 0, 2, uavs, NULL);
|
|
+
|
|
+ s->context->lpVtbl->CSSetShader(s->context, s->cs_y, NULL, 0);
|
|
+ s->context->lpVtbl->Dispatch(s->context,
|
|
+ (params.width + DEINT_D3D11_TGX - 1) / DEINT_D3D11_TGX,
|
|
+ (params.height + DEINT_D3D11_TGY - 1) / DEINT_D3D11_TGY, 1);
|
|
+
|
|
+ s->context->lpVtbl->CSSetShader(s->context, s->cs_uv, NULL, 0);
|
|
+ s->context->lpVtbl->Dispatch(s->context,
|
|
+ (((params.width + 1) >> 1) + DEINT_D3D11_TGX - 1) / DEINT_D3D11_TGX,
|
|
+ (((params.height + 1) >> 1) + DEINT_D3D11_TGY - 1) / DEINT_D3D11_TGY, 1);
|
|
+
|
|
+ s->context->lpVtbl->CSSetShader(s->context, NULL, NULL, 0);
|
|
+ s->context->lpVtbl->CSSetShaderResources(s->context, 0, 6, null_srvs);
|
|
+ s->context->lpVtbl->CSSetUnorderedAccessViews(s->context, 0, 2, null_uavs, NULL);
|
|
+ s->context->lpVtbl->CSSetConstantBuffers(s->context, 0, 1, null_cb);
|
|
+
|
|
+ if (!direct_output)
|
|
+ ff_d3d11_copy_texture_to_frame(s->context, s->work_tex, dst);
|
|
+
|
|
+fail:
|
|
+ s->context->lpVtbl->CSSetShader(s->context, NULL, NULL, 0);
|
|
+ s->context->lpVtbl->CSSetShaderResources(s->context, 0, 6, null_srvs);
|
|
+ s->context->lpVtbl->CSSetUnorderedAccessViews(s->context, 0, 2, null_uavs, NULL);
|
|
+ s->context->lpVtbl->CSSetConstantBuffers(s->context, 0, 1, null_cb);
|
|
+ for (int i = 0; i < 6; i++)
|
|
+ FF_D3D11_RELEASE(srvs[i]);
|
|
+ FF_D3D11_RELEASE(uavs[0]);
|
|
+ FF_D3D11_RELEASE(uavs[1]);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void filter(AVFilterContext *ctx, AVFrame *dst, int parity, int tff)
|
|
+{
|
|
+ DeintD3D11Context *s = ctx->priv;
|
|
+ YADIFContext *y = &s->yadif;
|
|
+
|
|
+ run_filter(ctx, dst, parity, tff);
|
|
+
|
|
+ if (s->algorithm == DEINT_D3D11_ALG_BWDIF && y->current_field == YADIF_FIELD_END)
|
|
+ y->current_field = YADIF_FIELD_NORMAL;
|
|
+}
|
|
+
|
|
+static av_cold void deint_d3d11_uninit(AVFilterContext *ctx)
|
|
+{
|
|
+ DeintD3D11Context *s = ctx->priv;
|
|
+
|
|
+ release_d3d11_resources(s);
|
|
+ ff_yadif_uninit(ctx);
|
|
+ av_buffer_unref(&s->device_ref);
|
|
+ av_buffer_unref(&s->input_frames_ref);
|
|
+ s->hwctx = NULL;
|
|
+ s->input_frames = NULL;
|
|
+ ff_d3d11_unload_shader_compiler(&s->d3dcompiler, &s->D3DCompile);
|
|
+}
|
|
+
|
|
+static int config_input(AVFilterLink *inlink)
|
|
+{
|
|
+ FilterLink *l = ff_filter_link(inlink);
|
|
+ AVFilterContext *ctx = inlink->dst;
|
|
+ DeintD3D11Context *s = ctx->priv;
|
|
+
|
|
+ if (!l->hw_frames_ctx) {
|
|
+ av_log(ctx, AV_LOG_ERROR, "D3D11 deinterlacing requires a hardware frames context on input.\n");
|
|
+ return AVERROR(EINVAL);
|
|
+ }
|
|
+
|
|
+ s->input_frames_ref = av_buffer_ref(l->hw_frames_ctx);
|
|
+ if (!s->input_frames_ref)
|
|
+ return AVERROR(ENOMEM);
|
|
+ s->input_frames = (AVHWFramesContext *)s->input_frames_ref->data;
|
|
+
|
|
+ if (s->input_frames->format != AV_PIX_FMT_D3D11)
|
|
+ return AVERROR(EINVAL);
|
|
+ if (s->input_frames->sw_format != AV_PIX_FMT_NV12) {
|
|
+ av_log(ctx, AV_LOG_ERROR, "D3D11 deinterlacing currently supports NV12 only, got %s\n",
|
|
+ av_get_pix_fmt_name(s->input_frames->sw_format));
|
|
+ return AVERROR(ENOSYS);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int config_output(AVFilterLink *link)
|
|
+{
|
|
+ FilterLink *l = ff_filter_link(link);
|
|
+ AVHWFramesContext *output_frames;
|
|
+ AVFilterContext *ctx = link->src;
|
|
+ DeintD3D11Context *s = ctx->priv;
|
|
+ YADIFContext *y = &s->yadif;
|
|
+ int ret;
|
|
+
|
|
+ av_assert0(s->input_frames);
|
|
+
|
|
+ s->device_ref = av_buffer_ref(s->input_frames->device_ref);
|
|
+ if (!s->device_ref)
|
|
+ return AVERROR(ENOMEM);
|
|
+
|
|
+ s->hwctx = ((AVHWDeviceContext *)s->device_ref->data)->hwctx;
|
|
+ s->device = s->hwctx->device;
|
|
+ s->context = s->hwctx->device_context;
|
|
+
|
|
+ av_buffer_unref(&l->hw_frames_ctx);
|
|
+ s->direct_input_srv = -1;
|
|
+ s->direct_output_uav = -1;
|
|
+
|
|
+ for (int direct = !s->force_output_copy; direct >= 0; direct--) {
|
|
+ l->hw_frames_ctx = av_hwframe_ctx_alloc(s->device_ref);
|
|
+ if (!l->hw_frames_ctx)
|
|
+ return AVERROR(ENOMEM);
|
|
+
|
|
+ output_frames = (AVHWFramesContext *)l->hw_frames_ctx->data;
|
|
+ output_frames->format = AV_PIX_FMT_D3D11;
|
|
+ output_frames->sw_format = s->input_frames->sw_format;
|
|
+ output_frames->width = ctx->inputs[0]->w;
|
|
+ output_frames->height = ctx->inputs[0]->h;
|
|
+ output_frames->initial_pool_size = 4;
|
|
+
|
|
+ {
|
|
+ AVD3D11VAFramesContext *frames_hwctx = output_frames->hwctx;
|
|
+ frames_hwctx->BindFlags = direct ? D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE |
|
|
+ D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_VIDEO_ENCODER
|
|
+ : D3D11_BIND_RENDER_TARGET | D3D11_BIND_VIDEO_ENCODER;
|
|
+ }
|
|
+
|
|
+ ret = av_hwframe_ctx_init(l->hw_frames_ctx);
|
|
+ if (ret >= 0 && direct) {
|
|
+ ret = probe_output_uav_pool(ctx, l->hw_frames_ctx);
|
|
+ if (ret >= 0) {
|
|
+ s->direct_output_uav = 1;
|
|
+ av_log(ctx, AV_LOG_DEBUG, "D3D11 shader output: direct UAV\n");
|
|
+ break;
|
|
+ }
|
|
+ av_buffer_unref(&l->hw_frames_ctx);
|
|
+ av_log(ctx, AV_LOG_DEBUG, "D3D11 shader output: copied from internal UAV texture\n");
|
|
+ continue;
|
|
+ } else if (ret >= 0) {
|
|
+ s->direct_output_uav = 0;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ av_buffer_unref(&l->hw_frames_ctx);
|
|
+ if (direct)
|
|
+ av_log(ctx, AV_LOG_DEBUG, "D3D11 shader output: UAV encoder pool rejected, using internal UAV texture\n");
|
|
+ }
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+ if (s->force_output_copy)
|
|
+ av_log(ctx, AV_LOG_DEBUG, "D3D11 shader output: forced copy from internal UAV texture\n");
|
|
+
|
|
+ output_frames = (AVHWFramesContext *)l->hw_frames_ctx->data;
|
|
+
|
|
+ ret = ff_yadif_config_output_common(link);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ y->csp = av_pix_fmt_desc_get(output_frames->sw_format);
|
|
+ y->filter = filter;
|
|
+
|
|
+ ret = init_shaders(ctx);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ av_log(ctx, AV_LOG_VERBOSE, "D3D11 %s config: %dx%d\n",
|
|
+ s->algorithm == DEINT_D3D11_ALG_BWDIF ? "bwdif" : "yadif",
|
|
+ link->w, link->h);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static av_cold int yadif_d3d11_init(AVFilterContext *ctx)
|
|
+{
|
|
+ DeintD3D11Context *s = ctx->priv;
|
|
+ s->algorithm = DEINT_D3D11_ALG_YADIF;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static av_cold int bwdif_d3d11_init(AVFilterContext *ctx)
|
|
+{
|
|
+ DeintD3D11Context *s = ctx->priv;
|
|
+ s->algorithm = DEINT_D3D11_ALG_BWDIF;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#define DEINT_OFFSET(x) offsetof(DeintD3D11Context, x)
|
|
+#define YADIF_OFFSET(x) offsetof(DeintD3D11Context, yadif.x)
|
|
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
|
|
+#define CONST(name, help, val, u) { name, help, 0, AV_OPT_TYPE_CONST, { .i64 = val }, INT_MIN, INT_MAX, FLAGS, .unit = u }
|
|
+
|
|
+static const AVOption deint_d3d11_options[] = {
|
|
+ { "mode", "specify the interlacing mode", YADIF_OFFSET(mode), AV_OPT_TYPE_INT, { .i64 = YADIF_MODE_SEND_FRAME }, 0, 3, FLAGS, .unit = "mode" },
|
|
+ CONST("send_frame", "send one frame for each frame", YADIF_MODE_SEND_FRAME, "mode"),
|
|
+ CONST("send_field", "send one frame for each field", YADIF_MODE_SEND_FIELD, "mode"),
|
|
+ CONST("send_frame_nospatial", "send one frame for each frame, but skip spatial interlacing check", YADIF_MODE_SEND_FRAME_NOSPATIAL, "mode"),
|
|
+ CONST("send_field_nospatial", "send one frame for each field, but skip spatial interlacing check", YADIF_MODE_SEND_FIELD_NOSPATIAL, "mode"),
|
|
+ { "parity", "specify the assumed picture field parity", YADIF_OFFSET(parity), AV_OPT_TYPE_INT, { .i64 = YADIF_PARITY_AUTO }, -1, 1, FLAGS, .unit = "parity" },
|
|
+ CONST("tff", "assume top field first", YADIF_PARITY_TFF, "parity"),
|
|
+ CONST("bff", "assume bottom field first", YADIF_PARITY_BFF, "parity"),
|
|
+ CONST("auto", "auto detect parity", YADIF_PARITY_AUTO, "parity"),
|
|
+ { "deint", "specify which frames to deinterlace", YADIF_OFFSET(deint), AV_OPT_TYPE_INT, { .i64 = YADIF_DEINT_ALL }, 0, 1, FLAGS, .unit = "deint" },
|
|
+ CONST("all", "deinterlace all frames", YADIF_DEINT_ALL, "deint"),
|
|
+ CONST("interlaced", "only deinterlace frames marked as interlaced", YADIF_DEINT_INTERLACED, "deint"),
|
|
+ { "force_output_copy", "Force output through an internal unordered-access texture", DEINT_OFFSET(force_output_copy), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS },
|
|
+ { NULL }
|
|
+};
|
|
+
|
|
+#undef CONST
|
|
+#undef FLAGS
|
|
+#undef YADIF_OFFSET
|
|
+#undef DEINT_OFFSET
|
|
+
|
|
+static const AVClass yadif_d3d11_class = {
|
|
+ .class_name = "yadif_d3d11",
|
|
+ .item_name = av_default_item_name,
|
|
+ .option = deint_d3d11_options,
|
|
+ .version = LIBAVUTIL_VERSION_INT,
|
|
+ .category = AV_CLASS_CATEGORY_FILTER,
|
|
+};
|
|
+
|
|
+static const AVClass bwdif_d3d11_class = {
|
|
+ .class_name = "bwdif_d3d11",
|
|
+ .item_name = av_default_item_name,
|
|
+ .option = deint_d3d11_options,
|
|
+ .version = LIBAVUTIL_VERSION_INT,
|
|
+ .category = AV_CLASS_CATEGORY_FILTER,
|
|
+};
|
|
+
|
|
+static const AVFilterPad deint_d3d11_inputs[] = {
|
|
+ {
|
|
+ .name = "default",
|
|
+ .type = AVMEDIA_TYPE_VIDEO,
|
|
+ .filter_frame = ff_yadif_filter_frame,
|
|
+ .config_props = config_input,
|
|
+ },
|
|
+};
|
|
+
|
|
+static const AVFilterPad deint_d3d11_outputs[] = {
|
|
+ {
|
|
+ .name = "default",
|
|
+ .type = AVMEDIA_TYPE_VIDEO,
|
|
+ .request_frame = ff_yadif_request_frame,
|
|
+ .config_props = config_output,
|
|
+ },
|
|
+};
|
|
+
|
|
+const FFFilter ff_vf_yadif_d3d11 = {
|
|
+ .p.name = "yadif_d3d11",
|
|
+ .p.description = NULL_IF_CONFIG_SMALL("Deinterlace D3D11 frames using YADIF"),
|
|
+ .p.priv_class = &yadif_d3d11_class,
|
|
+ .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_HWDEVICE,
|
|
+ .priv_size = sizeof(DeintD3D11Context),
|
|
+ .init = yadif_d3d11_init,
|
|
+ .uninit = deint_d3d11_uninit,
|
|
+ FILTER_INPUTS(deint_d3d11_inputs),
|
|
+ FILTER_OUTPUTS(deint_d3d11_outputs),
|
|
+ FILTER_SINGLE_PIXFMT(AV_PIX_FMT_D3D11),
|
|
+ .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
|
|
+};
|
|
+
|
|
+const FFFilter ff_vf_bwdif_d3d11 = {
|
|
+ .p.name = "bwdif_d3d11",
|
|
+ .p.description = NULL_IF_CONFIG_SMALL("Deinterlace D3D11 frames using BWDIF"),
|
|
+ .p.priv_class = &bwdif_d3d11_class,
|
|
+ .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_HWDEVICE,
|
|
+ .priv_size = sizeof(DeintD3D11Context),
|
|
+ .init = bwdif_d3d11_init,
|
|
+ .uninit = deint_d3d11_uninit,
|
|
+ FILTER_INPUTS(deint_d3d11_inputs),
|
|
+ FILTER_OUTPUTS(deint_d3d11_outputs),
|
|
+ FILTER_SINGLE_PIXFMT(AV_PIX_FMT_D3D11),
|
|
+ .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
|
|
+};
|
|
Index: FFmpeg/libavfilter/vf_yadif_d3d11.h
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ FFmpeg/libavfilter/vf_yadif_d3d11.h
|
|
@@ -0,0 +1,29 @@
|
|
+/*
|
|
+ * D3D11 YADIF/BWDIF constants
|
|
+ *
|
|
+ * Copyright (C) 2026 Gnattu OC <gnattuoc@me.com>
|
|
+ *
|
|
+ * 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
|
|
+ */
|
|
+
|
|
+#ifndef AVFILTER_YADIF_D3D11_H
|
|
+#define AVFILTER_YADIF_D3D11_H
|
|
+
|
|
+#define DEINT_D3D11_TGX 16
|
|
+#define DEINT_D3D11_TGY 16
|
|
+
|
|
+#endif /* AVFILTER_YADIF_D3D11_H */
|
|
Index: FFmpeg/libavfilter/d3d11/deint.hlsl
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ FFmpeg/libavfilter/d3d11/deint.hlsl
|
|
@@ -0,0 +1,374 @@
|
|
+/*
|
|
+ * D3D11 YADIF/BWDIF deinterlace
|
|
+ *
|
|
+ * Copyright (C) 2026 Gnattu OC <gnattuoc@me.com>
|
|
+ *
|
|
+ * 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
|
|
+ */
|
|
+
|
|
+Texture2DArray<float4> prev_y : register(t0);
|
|
+Texture2DArray<float4> cur_y : register(t1);
|
|
+Texture2DArray<float4> next_y : register(t2);
|
|
+Texture2DArray<float4> prev_uv : register(t3);
|
|
+Texture2DArray<float4> cur_uv : register(t4);
|
|
+Texture2DArray<float4> next_uv : register(t5);
|
|
+
|
|
+RWTexture2DArray<float> dst_y : register(u0);
|
|
+RWTexture2DArray<float2> dst_uv : register(u1);
|
|
+
|
|
+cbuffer Params : register(b0) {
|
|
+ int width;
|
|
+ int height;
|
|
+ int parity;
|
|
+ int tff;
|
|
+ int is_second_field;
|
|
+ int current_field;
|
|
+ int skip_spatial_check;
|
|
+ int algorithm;
|
|
+};
|
|
+
|
|
+int clampi(int v, int lo, int hi)
|
|
+{
|
|
+ return min(max(v, lo), hi);
|
|
+}
|
|
+
|
|
+int2 pos_y(int x, int y)
|
|
+{
|
|
+ return int2(clampi(x, 0, width - 1), clampi(y, 0, height - 1));
|
|
+}
|
|
+
|
|
+int cw()
|
|
+{
|
|
+ return (width + 1) >> 1;
|
|
+}
|
|
+
|
|
+int ch()
|
|
+{
|
|
+ return (height + 1) >> 1;
|
|
+}
|
|
+
|
|
+int2 pos_uv(int x, int y)
|
|
+{
|
|
+ return int2(clampi(x, 0, cw() - 1), clampi(y, 0, ch() - 1));
|
|
+}
|
|
+
|
|
+float py(int x, int y)
|
|
+{
|
|
+ return prev_y.Load(int4(pos_y(x, y), 0, 0)).r;
|
|
+}
|
|
+
|
|
+float cy(int x, int y)
|
|
+{
|
|
+ return cur_y.Load(int4(pos_y(x, y), 0, 0)).r;
|
|
+}
|
|
+
|
|
+float ny(int x, int y)
|
|
+{
|
|
+ return next_y.Load(int4(pos_y(x, y), 0, 0)).r;
|
|
+}
|
|
+
|
|
+float2 puv(int x, int y)
|
|
+{
|
|
+ return prev_uv.Load(int4(pos_uv(x, y), 0, 0)).rg;
|
|
+}
|
|
+
|
|
+float2 cuv(int x, int y)
|
|
+{
|
|
+ return cur_uv.Load(int4(pos_uv(x, y), 0, 0)).rg;
|
|
+}
|
|
+
|
|
+float2 nuv(int x, int y)
|
|
+{
|
|
+ return next_uv.Load(int4(pos_uv(x, y), 0, 0)).rg;
|
|
+}
|
|
+
|
|
+float max3f(float a, float b, float c)
|
|
+{
|
|
+ return max(max(a, b), c);
|
|
+}
|
|
+
|
|
+float min3f(float a, float b, float c)
|
|
+{
|
|
+ return min(min(a, b), c);
|
|
+}
|
|
+
|
|
+float2 max3f2(float2 a, float2 b, float2 c)
|
|
+{
|
|
+ return max(max(a, b), c);
|
|
+}
|
|
+
|
|
+float2 min3f2(float2 a, float2 b, float2 c)
|
|
+{
|
|
+ return min(min(a, b), c);
|
|
+}
|
|
+
|
|
+float spatial1(float a, float b, float c, float d, float e, float f, float g,
|
|
+ float h, float i, float j, float k, float l, float m, float n)
|
|
+{
|
|
+ float spatial_pred = (d + k) * 0.5;
|
|
+ float spatial_score = abs(c - j) + abs(d - k) + abs(e - l) - (1.0 / 255.0);
|
|
+
|
|
+ float score = abs(b - k) + abs(c - l) + abs(d - m);
|
|
+ if (score < spatial_score) {
|
|
+ spatial_pred = (c + l) * 0.5;
|
|
+ spatial_score = score;
|
|
+ score = abs(a - l) + abs(b - m) + abs(c - n);
|
|
+ if (score < spatial_score) {
|
|
+ spatial_pred = (b + m) * 0.5;
|
|
+ spatial_score = score;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ score = abs(d - i) + abs(e - j) + abs(f - k);
|
|
+ if (score < spatial_score) {
|
|
+ spatial_pred = (e + j) * 0.5;
|
|
+ spatial_score = score;
|
|
+ score = abs(e - h) + abs(f - i) + abs(g - j);
|
|
+ if (score < spatial_score)
|
|
+ spatial_pred = (f + i) * 0.5;
|
|
+ }
|
|
+
|
|
+ return spatial_pred;
|
|
+}
|
|
+
|
|
+float2 spatial2(float2 a, float2 b, float2 c, float2 d, float2 e, float2 f, float2 g,
|
|
+ float2 h, float2 i, float2 j, float2 k, float2 l, float2 m, float2 n)
|
|
+{
|
|
+ return float2(spatial1(a.x, b.x, c.x, d.x, e.x, f.x, g.x, h.x, i.x, j.x, k.x, l.x, m.x, n.x),
|
|
+ spatial1(a.y, b.y, c.y, d.y, e.y, f.y, g.y, h.y, i.y, j.y, k.y, l.y, m.y, n.y));
|
|
+}
|
|
+
|
|
+float yadif_spatial_y(int x, int y)
|
|
+{
|
|
+ return spatial1(cy(x - 3, y - 1), cy(x - 2, y - 1), cy(x - 1, y - 1), cy(x, y - 1),
|
|
+ cy(x + 1, y - 1), cy(x + 2, y - 1), cy(x + 3, y - 1),
|
|
+ cy(x - 3, y + 1), cy(x - 2, y + 1), cy(x - 1, y + 1), cy(x, y + 1),
|
|
+ cy(x + 1, y + 1), cy(x + 2, y + 1), cy(x + 3, y + 1));
|
|
+}
|
|
+
|
|
+float2 yadif_spatial_uv(int x, int y)
|
|
+{
|
|
+ return spatial2(cuv(x - 3, y - 1), cuv(x - 2, y - 1), cuv(x - 1, y - 1), cuv(x, y - 1),
|
|
+ cuv(x + 1, y - 1), cuv(x + 2, y - 1), cuv(x + 3, y - 1),
|
|
+ cuv(x - 3, y + 1), cuv(x - 2, y + 1), cuv(x - 1, y + 1), cuv(x, y + 1),
|
|
+ cuv(x + 1, y + 1), cuv(x + 2, y + 1), cuv(x + 3, y + 1));
|
|
+}
|
|
+
|
|
+float temporal1(float A, float B, float C, float D, float E, float F,
|
|
+ float G, float H, float I, float J, float K, float L,
|
|
+ float spatial_pred)
|
|
+{
|
|
+ float p0 = (C + H) * 0.5;
|
|
+ float p1 = F;
|
|
+ float p2 = (D + I) * 0.5;
|
|
+ float p3 = G;
|
|
+ float p4 = (E + J) * 0.5;
|
|
+
|
|
+ float tdiff0 = abs(D - I);
|
|
+ float tdiff1 = (abs(A - F) + abs(B - G)) * 0.5;
|
|
+ float tdiff2 = (abs(K - F) + abs(G - L)) * 0.5;
|
|
+ float diff = max3f(tdiff0 * 0.5, tdiff1, tdiff2);
|
|
+
|
|
+ if (!skip_spatial_check) {
|
|
+ float maxi = max3f(p2 - p3, p2 - p1, min(p0 - p1, p4 - p3));
|
|
+ float mini = min3f(p2 - p3, p2 - p1, max(p0 - p1, p4 - p3));
|
|
+ diff = max3f(diff, mini, -maxi);
|
|
+ }
|
|
+
|
|
+ return clamp(spatial_pred, p2 - diff, p2 + diff);
|
|
+}
|
|
+
|
|
+float2 temporal2(float2 A, float2 B, float2 C, float2 D, float2 E, float2 F,
|
|
+ float2 G, float2 H, float2 I, float2 J, float2 K, float2 L,
|
|
+ float2 spatial_pred)
|
|
+{
|
|
+ return float2(temporal1(A.x, B.x, C.x, D.x, E.x, F.x, G.x, H.x, I.x, J.x, K.x, L.x, spatial_pred.x),
|
|
+ temporal1(A.y, B.y, C.y, D.y, E.y, F.y, G.y, H.y, I.y, J.y, K.y, L.y, spatial_pred.y));
|
|
+}
|
|
+
|
|
+float yadif_y(int x, int y)
|
|
+{
|
|
+ float sp = yadif_spatial_y(x, y);
|
|
+
|
|
+ if (is_second_field)
|
|
+ return temporal1(cy(x, y - 1), cy(x, y + 1),
|
|
+ py(x, y - 2), py(x, y), py(x, y + 2),
|
|
+ cy(x, y - 1), cy(x, y + 1),
|
|
+ ny(x, y - 2), ny(x, y), ny(x, y + 2),
|
|
+ ny(x, y - 1), ny(x, y + 1), sp);
|
|
+ return temporal1(py(x, y - 1), py(x, y + 1),
|
|
+ py(x, y - 2), py(x, y), py(x, y + 2),
|
|
+ cy(x, y - 1), cy(x, y + 1),
|
|
+ ny(x, y - 2), ny(x, y), ny(x, y + 2),
|
|
+ cy(x, y - 1), cy(x, y + 1), sp);
|
|
+}
|
|
+
|
|
+float2 yadif_uv(int x, int y)
|
|
+{
|
|
+ float2 sp = yadif_spatial_uv(x, y);
|
|
+
|
|
+ if (is_second_field)
|
|
+ return temporal2(cuv(x, y - 1), cuv(x, y + 1),
|
|
+ puv(x, y - 2), puv(x, y), puv(x, y + 2),
|
|
+ cuv(x, y - 1), cuv(x, y + 1),
|
|
+ nuv(x, y - 2), nuv(x, y), nuv(x, y + 2),
|
|
+ nuv(x, y - 1), nuv(x, y + 1), sp);
|
|
+ return temporal2(puv(x, y - 1), puv(x, y + 1),
|
|
+ puv(x, y - 2), puv(x, y), puv(x, y + 2),
|
|
+ cuv(x, y - 1), cuv(x, y + 1),
|
|
+ nuv(x, y - 2), nuv(x, y), nuv(x, y + 2),
|
|
+ cuv(x, y - 1), cuv(x, y + 1), sp);
|
|
+}
|
|
+
|
|
+float bwdif_intra1(float cur_prefs3, float cur_prefs, float cur_mrefs, float cur_mrefs3)
|
|
+{
|
|
+ return clamp((5077.0 * (cur_mrefs + cur_prefs) - 981.0 * (cur_mrefs3 + cur_prefs3)) / 8192.0, 0.0, 1.0);
|
|
+}
|
|
+
|
|
+float2 bwdif_intra2(float2 a, float2 b, float2 c, float2 d)
|
|
+{
|
|
+ return clamp((5077.0 * (c + b) - 981.0 * (d + a)) / 8192.0, 0.0, 1.0);
|
|
+}
|
|
+
|
|
+float bwdif_temp1(float cp3, float cp, float cm, float cm3,
|
|
+ float p2p4, float p2p2, float p20, float p2m2, float p2m4,
|
|
+ float p1p, float p1m, float n1p, float n1m,
|
|
+ float n2p4, float n2p2, float n20, float n2m2, float n2m4)
|
|
+{
|
|
+ float c = cm;
|
|
+ float d = (p20 + n20) * 0.5;
|
|
+ float e = cp;
|
|
+
|
|
+ float td0 = abs(p20 - n20);
|
|
+ float td1 = (abs(p1m - c) + abs(p1p - e)) * 0.5;
|
|
+ float td2 = (abs(n1m - c) + abs(n1p - e)) * 0.5;
|
|
+ float diff = max3f(td0 * 0.5, td1, td2);
|
|
+
|
|
+ if (!diff)
|
|
+ return d;
|
|
+
|
|
+ float b = ((p2m2 + n2m2) * 0.5) - c;
|
|
+ float f = ((p2p2 + n2p2) * 0.5) - e;
|
|
+ float dc = d - c;
|
|
+ float de = d - e;
|
|
+
|
|
+ float mmax = max3f(de, dc, min(b, f));
|
|
+ float mmin = min3f(de, dc, max(b, f));
|
|
+ diff = max3f(diff, mmin, -mmax);
|
|
+
|
|
+ float interpol;
|
|
+ if (abs(c - e) > td0)
|
|
+ interpol = (((5570.0 * (p20 + n20) -
|
|
+ 3801.0 * (p2m2 + n2m2 + p2p2 + n2p2) +
|
|
+ 1016.0 * (p2m4 + n2m4 + p2p4 + n2p4)) * 0.25) +
|
|
+ 4309.0 * (c + e) - 213.0 * (cm3 + cp3)) / 8192.0;
|
|
+ else
|
|
+ interpol = (5077.0 * (c + e) - 981.0 * (cm3 + cp3)) / 8192.0;
|
|
+
|
|
+ return clamp(clamp(interpol, d - diff, d + diff), 0.0, 1.0);
|
|
+}
|
|
+
|
|
+float2 bwdif_temp2(float2 cp3, float2 cp, float2 cm, float2 cm3,
|
|
+ float2 p2p4, float2 p2p2, float2 p20, float2 p2m2, float2 p2m4,
|
|
+ float2 p1p, float2 p1m, float2 n1p, float2 n1m,
|
|
+ float2 n2p4, float2 n2p2, float2 n20, float2 n2m2, float2 n2m4)
|
|
+{
|
|
+ return float2(bwdif_temp1(cp3.x, cp.x, cm.x, cm3.x,
|
|
+ p2p4.x, p2p2.x, p20.x, p2m2.x, p2m4.x,
|
|
+ p1p.x, p1m.x, n1p.x, n1m.x,
|
|
+ n2p4.x, n2p2.x, n20.x, n2m2.x, n2m4.x),
|
|
+ bwdif_temp1(cp3.y, cp.y, cm.y, cm3.y,
|
|
+ p2p4.y, p2p2.y, p20.y, p2m2.y, p2m4.y,
|
|
+ p1p.y, p1m.y, n1p.y, n1m.y,
|
|
+ n2p4.y, n2p2.y, n20.y, n2m2.y, n2m4.y));
|
|
+}
|
|
+
|
|
+float bwdif_y(int x, int y)
|
|
+{
|
|
+ float cp3 = cy(x, y + 3);
|
|
+ float cp = cy(x, y + 1);
|
|
+ float cm = cy(x, y - 1);
|
|
+ float cm3 = cy(x, y - 3);
|
|
+
|
|
+ if (current_field == 0)
|
|
+ return bwdif_intra1(cp3, cp, cm, cm3);
|
|
+
|
|
+ if (is_second_field)
|
|
+ return bwdif_temp1(cp3, cp, cm, cm3,
|
|
+ cy(x, y + 4), cy(x, y + 2), cy(x, y), cy(x, y - 2), cy(x, y - 4),
|
|
+ py(x, y + 1), py(x, y - 1), ny(x, y + 1), ny(x, y - 1),
|
|
+ ny(x, y + 4), ny(x, y + 2), ny(x, y), ny(x, y - 2), ny(x, y - 4));
|
|
+ return bwdif_temp1(cp3, cp, cm, cm3,
|
|
+ py(x, y + 4), py(x, y + 2), py(x, y), py(x, y - 2), py(x, y - 4),
|
|
+ py(x, y + 1), py(x, y - 1), ny(x, y + 1), ny(x, y - 1),
|
|
+ cy(x, y + 4), cy(x, y + 2), cy(x, y), cy(x, y - 2), cy(x, y - 4));
|
|
+}
|
|
+
|
|
+float2 bwdif_uv(int x, int y)
|
|
+{
|
|
+ float2 cp3 = cuv(x, y + 3);
|
|
+ float2 cp = cuv(x, y + 1);
|
|
+ float2 cm = cuv(x, y - 1);
|
|
+ float2 cm3 = cuv(x, y - 3);
|
|
+
|
|
+ if (current_field == 0)
|
|
+ return bwdif_intra2(cp3, cp, cm, cm3);
|
|
+
|
|
+ if (is_second_field)
|
|
+ return bwdif_temp2(cp3, cp, cm, cm3,
|
|
+ cuv(x, y + 4), cuv(x, y + 2), cuv(x, y), cuv(x, y - 2), cuv(x, y - 4),
|
|
+ puv(x, y + 1), puv(x, y - 1), nuv(x, y + 1), nuv(x, y - 1),
|
|
+ nuv(x, y + 4), nuv(x, y + 2), nuv(x, y), nuv(x, y - 2), nuv(x, y - 4));
|
|
+ return bwdif_temp2(cp3, cp, cm, cm3,
|
|
+ puv(x, y + 4), puv(x, y + 2), puv(x, y), puv(x, y - 2), puv(x, y - 4),
|
|
+ puv(x, y + 1), puv(x, y - 1), nuv(x, y + 1), nuv(x, y - 1),
|
|
+ cuv(x, y + 4), cuv(x, y + 2), cuv(x, y), cuv(x, y - 2), cuv(x, y - 4));
|
|
+}
|
|
+
|
|
+[numthreads(16, 16, 1)]
|
|
+void deint_y(uint3 id : SV_DispatchThreadID)
|
|
+{
|
|
+ if (id.x >= (uint)width || id.y >= (uint)height)
|
|
+ return;
|
|
+
|
|
+ int x = id.x;
|
|
+ int y = id.y;
|
|
+
|
|
+ if ((y & 1) == parity) {
|
|
+ dst_y[uint3(x, y, 0)] = cy(x, y);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ dst_y[uint3(x, y, 0)] = algorithm == 1 ? bwdif_y(x, y) : yadif_y(x, y);
|
|
+}
|
|
+
|
|
+[numthreads(16, 16, 1)]
|
|
+void deint_uv(uint3 id : SV_DispatchThreadID)
|
|
+{
|
|
+ if (id.x >= (uint)cw() || id.y >= (uint)ch())
|
|
+ return;
|
|
+
|
|
+ int x = id.x;
|
|
+ int y = id.y;
|
|
+
|
|
+ if ((y & 1) == parity) {
|
|
+ dst_uv[uint3(x, y, 0)] = cuv(x, y);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ dst_uv[uint3(x, y, 0)] = algorithm == 1 ? bwdif_uv(x, y) : yadif_uv(x, y);
|
|
+}
|
|
Index: FFmpeg/libavfilter/d3d11_source.h
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ FFmpeg/libavfilter/d3d11_source.h
|
|
@@ -0,0 +1,28 @@
|
|
+/*
|
|
+ * D3D11 HLSL shader source declarations
|
|
+ *
|
|
+ * Copyright (C) 2026 Gnattu OC <gnattuoc@me.com>
|
|
+ *
|
|
+ * 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
|
|
+ */
|
|
+
|
|
+#ifndef AVFILTER_D3D11_SOURCE_H
|
|
+#define AVFILTER_D3D11_SOURCE_H
|
|
+
|
|
+extern const char *ff_source_deint_hlsl;
|
|
+
|
|
+#endif /* AVFILTER_D3D11_SOURCE_H */
|
|
Index: FFmpeg/libavfilter/d3d11_filter.c
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ FFmpeg/libavfilter/d3d11_filter.c
|
|
@@ -0,0 +1,285 @@
|
|
+/*
|
|
+ * Common D3D11 filter helpers
|
|
+ *
|
|
+ * 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.
|
|
+ */
|
|
+
|
|
+#include "config.h"
|
|
+
|
|
+#include <stdint.h>
|
|
+#include <string.h>
|
|
+
|
|
+#include "libavutil/error.h"
|
|
+#include "libavutil/log.h"
|
|
+#include "libavutil/mem.h"
|
|
+
|
|
+#include "d3d11_filter.h"
|
|
+
|
|
+int ff_d3d11_load_shader_compiler(AVFilterContext *ctx, HMODULE *d3dcompiler,
|
|
+ FFD3DCompileProc *compile)
|
|
+{
|
|
+ if (!*d3dcompiler) {
|
|
+ *d3dcompiler = LoadLibraryA("d3dcompiler_47.dll");
|
|
+ if (!*d3dcompiler)
|
|
+ *d3dcompiler = LoadLibraryA("d3dcompiler_43.dll");
|
|
+ }
|
|
+ if (!*d3dcompiler) {
|
|
+ av_log(ctx, AV_LOG_ERROR, "Failed loading d3dcompiler DLL\n");
|
|
+ return AVERROR_EXTERNAL;
|
|
+ }
|
|
+
|
|
+ *compile = (FFD3DCompileProc)GetProcAddress(*d3dcompiler, "D3DCompile");
|
|
+ if (!*compile) {
|
|
+ av_log(ctx, AV_LOG_ERROR, "Failed loading D3DCompile\n");
|
|
+ return AVERROR_EXTERNAL;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void ff_d3d11_unload_shader_compiler(HMODULE *d3dcompiler, FFD3DCompileProc *compile)
|
|
+{
|
|
+ if (*d3dcompiler)
|
|
+ FreeLibrary(*d3dcompiler);
|
|
+ *d3dcompiler = NULL;
|
|
+ *compile = NULL;
|
|
+}
|
|
+
|
|
+int ff_d3d11_compile_shader(AVFilterContext *ctx, ID3D11Device *device,
|
|
+ FFD3DCompileProc compile, const char *source,
|
|
+ const D3D_SHADER_MACRO *macros, const char *entry,
|
|
+ const char *target, const char *name,
|
|
+ ID3D11ComputeShader **shader)
|
|
+{
|
|
+ ID3D10Blob *cs_blob = NULL;
|
|
+ ID3D10Blob *err_blob = NULL;
|
|
+ HRESULT hr;
|
|
+
|
|
+ hr = compile(source, strlen(source), NULL, macros, NULL, entry, target,
|
|
+ D3DCOMPILE_OPTIMIZATION_LEVEL3 |
|
|
+ D3DCOMPILE_IEEE_STRICTNESS, 0, &cs_blob, &err_blob);
|
|
+ if (FAILED(hr)) {
|
|
+ if (err_blob) {
|
|
+ av_log(ctx, AV_LOG_ERROR, "Failed compiling %s shader %s: %.*s\n",
|
|
+ name, entry, (int)err_blob->lpVtbl->GetBufferSize(err_blob),
|
|
+ (char *)err_blob->lpVtbl->GetBufferPointer(err_blob));
|
|
+ } else {
|
|
+ av_log(ctx, AV_LOG_ERROR, "Failed compiling %s shader %s: HRESULT 0x%lX\n",
|
|
+ name, entry, (unsigned long)hr);
|
|
+ }
|
|
+ FF_D3D11_RELEASE(err_blob);
|
|
+ return AVERROR_EXTERNAL;
|
|
+ }
|
|
+
|
|
+ hr = device->lpVtbl->CreateComputeShader(device,
|
|
+ cs_blob->lpVtbl->GetBufferPointer(cs_blob),
|
|
+ cs_blob->lpVtbl->GetBufferSize(cs_blob),
|
|
+ NULL, shader);
|
|
+ FF_D3D11_RELEASE(cs_blob);
|
|
+ FF_D3D11_RELEASE(err_blob);
|
|
+ if (FAILED(hr)) {
|
|
+ av_log(ctx, AV_LOG_ERROR, "Failed creating %s shader %s: HRESULT 0x%lX\n",
|
|
+ name, entry, (unsigned long)hr);
|
|
+ return AVERROR_EXTERNAL;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int ff_d3d11_create_const_buffer(AVFilterContext *ctx, ID3D11Device *device,
|
|
+ size_t size, const char *name,
|
|
+ ID3D11Buffer **buffer)
|
|
+{
|
|
+ D3D11_BUFFER_DESC bd = { 0 };
|
|
+ HRESULT hr;
|
|
+
|
|
+ bd.ByteWidth = size;
|
|
+ bd.Usage = D3D11_USAGE_DYNAMIC;
|
|
+ bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
|
+ bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
|
+
|
|
+ hr = device->lpVtbl->CreateBuffer(device, &bd, NULL, buffer);
|
|
+ if (FAILED(hr)) {
|
|
+ av_log(ctx, AV_LOG_ERROR, "Failed creating %s constant buffer: HRESULT 0x%lX\n",
|
|
+ name, (unsigned long)hr);
|
|
+ return AVERROR_EXTERNAL;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+DXGI_FORMAT ff_d3d11_texture_format(enum AVPixelFormat fmt)
|
|
+{
|
|
+ if (fmt == AV_PIX_FMT_P010)
|
|
+ return DXGI_FORMAT_P010;
|
|
+ if (fmt == AV_PIX_FMT_P016)
|
|
+ return DXGI_FORMAT_P016;
|
|
+ if (fmt == AV_PIX_FMT_BGRA)
|
|
+ return DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
+ return DXGI_FORMAT_NV12;
|
|
+}
|
|
+
|
|
+DXGI_FORMAT ff_d3d11_plane_format(enum AVPixelFormat fmt, int plane)
|
|
+{
|
|
+ if (fmt == AV_PIX_FMT_BGRA)
|
|
+ return DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
+ if (fmt == AV_PIX_FMT_NV12)
|
|
+ return plane ? DXGI_FORMAT_R8G8_UNORM : DXGI_FORMAT_R8_UNORM;
|
|
+ return plane ? DXGI_FORMAT_R16G16_UNORM : DXGI_FORMAT_R16_UNORM;
|
|
+}
|
|
+
|
|
+int ff_d3d11_ensure_texture(AVFilterContext *ctx, ID3D11Device *device,
|
|
+ ID3D11Texture2D **tex, int *cur_w, int *cur_h,
|
|
+ DXGI_FORMAT *cur_fmt, int w, int h,
|
|
+ DXGI_FORMAT fmt, UINT bind_flags,
|
|
+ const char *name)
|
|
+{
|
|
+ D3D11_TEXTURE2D_DESC desc = { 0 };
|
|
+ HRESULT hr;
|
|
+
|
|
+ if (*tex && *cur_w == w && *cur_h == h && (!cur_fmt || *cur_fmt == fmt))
|
|
+ return 0;
|
|
+
|
|
+ FF_D3D11_RELEASE(*tex);
|
|
+
|
|
+ desc.Width = w;
|
|
+ desc.Height = h;
|
|
+ desc.MipLevels = 1;
|
|
+ desc.ArraySize = 1;
|
|
+ desc.Format = fmt;
|
|
+ desc.SampleDesc.Count = 1;
|
|
+ desc.Usage = D3D11_USAGE_DEFAULT;
|
|
+ desc.BindFlags = bind_flags;
|
|
+
|
|
+ hr = device->lpVtbl->CreateTexture2D(device, &desc, NULL, tex);
|
|
+ if (FAILED(hr)) {
|
|
+ av_log(ctx, AV_LOG_ERROR, "Failed creating %s texture %dx%d format %u: HRESULT 0x%lX\n",
|
|
+ name, w, h, fmt, (unsigned long)hr);
|
|
+ return AVERROR_EXTERNAL;
|
|
+ }
|
|
+
|
|
+ *cur_w = w;
|
|
+ *cur_h = h;
|
|
+ if (cur_fmt)
|
|
+ *cur_fmt = fmt;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void ff_d3d11_fill_srv_desc(ID3D11Texture2D *tex, UINT subresource,
|
|
+ DXGI_FORMAT fmt, D3D11_SHADER_RESOURCE_VIEW_DESC *desc)
|
|
+{
|
|
+ D3D11_TEXTURE2D_DESC tex_desc;
|
|
+ UINT mip_slice = 0, array_slice = 0;
|
|
+
|
|
+ ID3D11Texture2D_GetDesc(tex, &tex_desc);
|
|
+ if (tex_desc.MipLevels) {
|
|
+ mip_slice = subresource % tex_desc.MipLevels;
|
|
+ array_slice = subresource / tex_desc.MipLevels;
|
|
+ }
|
|
+
|
|
+ desc->Format = fmt;
|
|
+ desc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
|
|
+ desc->Texture2DArray.MostDetailedMip = mip_slice;
|
|
+ desc->Texture2DArray.MipLevels = 1;
|
|
+ desc->Texture2DArray.FirstArraySlice = array_slice;
|
|
+ desc->Texture2DArray.ArraySize = 1;
|
|
+}
|
|
+
|
|
+void ff_d3d11_fill_uav_desc(ID3D11Texture2D *tex, UINT subresource,
|
|
+ DXGI_FORMAT fmt, D3D11_UNORDERED_ACCESS_VIEW_DESC *desc)
|
|
+{
|
|
+ D3D11_TEXTURE2D_DESC tex_desc;
|
|
+ UINT mip_slice = 0, array_slice = 0;
|
|
+
|
|
+ ID3D11Texture2D_GetDesc(tex, &tex_desc);
|
|
+ if (tex_desc.MipLevels) {
|
|
+ mip_slice = subresource % tex_desc.MipLevels;
|
|
+ array_slice = subresource / tex_desc.MipLevels;
|
|
+ }
|
|
+
|
|
+ desc->Format = fmt;
|
|
+ desc->ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY;
|
|
+ desc->Texture2DArray.MipSlice = mip_slice;
|
|
+ desc->Texture2DArray.FirstArraySlice = array_slice;
|
|
+ desc->Texture2DArray.ArraySize = 1;
|
|
+}
|
|
+
|
|
+int ff_d3d11_create_srv(AVFilterContext *ctx, ID3D11Device *device,
|
|
+ ID3D11Texture2D *tex, UINT subresource,
|
|
+ DXGI_FORMAT fmt, int log_level, const char *name,
|
|
+ ID3D11ShaderResourceView **srv)
|
|
+{
|
|
+ D3D11_SHADER_RESOURCE_VIEW_DESC desc = { 0 };
|
|
+ HRESULT hr;
|
|
+
|
|
+ ff_d3d11_fill_srv_desc(tex, subresource, fmt, &desc);
|
|
+ hr = device->lpVtbl->CreateShaderResourceView(device, (ID3D11Resource *)tex,
|
|
+ &desc, srv);
|
|
+ if (FAILED(hr)) {
|
|
+ av_log(ctx, log_level, "Failed creating %s SRV: HRESULT 0x%lX\n",
|
|
+ name, (unsigned long)hr);
|
|
+ return AVERROR_EXTERNAL;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int ff_d3d11_create_uav(AVFilterContext *ctx, ID3D11Device *device,
|
|
+ ID3D11Texture2D *tex, UINT subresource,
|
|
+ DXGI_FORMAT fmt, int log_level, const char *name,
|
|
+ ID3D11UnorderedAccessView **uav)
|
|
+{
|
|
+ D3D11_UNORDERED_ACCESS_VIEW_DESC desc = { 0 };
|
|
+ HRESULT hr;
|
|
+
|
|
+ ff_d3d11_fill_uav_desc(tex, subresource, fmt, &desc);
|
|
+ hr = device->lpVtbl->CreateUnorderedAccessView(device, (ID3D11Resource *)tex,
|
|
+ &desc, uav);
|
|
+ if (FAILED(hr)) {
|
|
+ av_log(ctx, log_level, "Failed creating %s UAV: HRESULT 0x%lX\n",
|
|
+ name, (unsigned long)hr);
|
|
+ return AVERROR_EXTERNAL;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void ff_d3d11_copy_frame_to_texture(ID3D11DeviceContext *context, AVFrame *src,
|
|
+ ID3D11Texture2D *dst)
|
|
+{
|
|
+ ID3D11Texture2D *src_tex = (ID3D11Texture2D *)src->data[0];
|
|
+ UINT src_sub = (UINT)(uintptr_t)src->data[1];
|
|
+ D3D11_BOX box = { 0, 0, 0, src->width, src->height, 1 };
|
|
+
|
|
+ context->lpVtbl->CopySubresourceRegion(context, (ID3D11Resource *)dst, 0,
|
|
+ 0, 0, 0, (ID3D11Resource *)src_tex,
|
|
+ src_sub, &box);
|
|
+}
|
|
+
|
|
+void ff_d3d11_copy_texture_to_frame(ID3D11DeviceContext *context, ID3D11Texture2D *src,
|
|
+ AVFrame *dst)
|
|
+{
|
|
+ ID3D11Texture2D *dst_tex = (ID3D11Texture2D *)dst->data[0];
|
|
+ UINT dst_sub = (UINT)(uintptr_t)dst->data[1];
|
|
+
|
|
+ context->lpVtbl->CopySubresourceRegion(context, (ID3D11Resource *)dst_tex,
|
|
+ dst_sub, 0, 0, 0, (ID3D11Resource *)src,
|
|
+ 0, NULL);
|
|
+}
|
|
+
|
|
+void ff_d3d11_copy_frame_to_frame(ID3D11DeviceContext *context, AVFrame *src,
|
|
+ AVFrame *dst)
|
|
+{
|
|
+ ID3D11Texture2D *src_tex = (ID3D11Texture2D *)src->data[0];
|
|
+ ID3D11Texture2D *dst_tex = (ID3D11Texture2D *)dst->data[0];
|
|
+ UINT src_sub = (UINT)(uintptr_t)src->data[1];
|
|
+ UINT dst_sub = (UINT)(uintptr_t)dst->data[1];
|
|
+ D3D11_BOX box = { 0, 0, 0, src->width, src->height, 1 };
|
|
+
|
|
+ context->lpVtbl->CopySubresourceRegion(context, (ID3D11Resource *)dst_tex,
|
|
+ dst_sub, 0, 0, 0, (ID3D11Resource *)src_tex,
|
|
+ src_sub, &box);
|
|
+}
|
|
Index: FFmpeg/libavfilter/d3d11_filter.h
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ FFmpeg/libavfilter/d3d11_filter.h
|
|
@@ -0,0 +1,84 @@
|
|
+/*
|
|
+ * Common D3D11 filter helpers
|
|
+ *
|
|
+ * 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.
|
|
+ */
|
|
+
|
|
+#ifndef AVFILTER_D3D11_FILTER_H
|
|
+#define AVFILTER_D3D11_FILTER_H
|
|
+
|
|
+#include <windows.h>
|
|
+#ifndef COBJMACROS
|
|
+#define COBJMACROS
|
|
+#endif
|
|
+#include <d3d11.h>
|
|
+#include <d3dcompiler.h>
|
|
+
|
|
+#include "libavutil/frame.h"
|
|
+#include "libavutil/pixfmt.h"
|
|
+#include "avfilter.h"
|
|
+
|
|
+#define FF_D3D11_RELEASE(p) do { if (p) { (p)->lpVtbl->Release(p); (p) = NULL; } } while (0)
|
|
+
|
|
+#ifndef D3DCOMPILE_OPTIMIZATION_LEVEL3
|
|
+#define D3DCOMPILE_OPTIMIZATION_LEVEL3 (1 << 15)
|
|
+#endif
|
|
+#ifndef D3DCOMPILE_IEEE_STRICTNESS
|
|
+#define D3DCOMPILE_IEEE_STRICTNESS (1 << 13)
|
|
+#endif
|
|
+
|
|
+typedef HRESULT (WINAPI *FFD3DCompileProc)(LPCVOID, SIZE_T, LPCSTR,
|
|
+ const D3D_SHADER_MACRO *, ID3DInclude *,
|
|
+ LPCSTR, LPCSTR, UINT, UINT,
|
|
+ ID3D10Blob **, ID3D10Blob **);
|
|
+
|
|
+int ff_d3d11_load_shader_compiler(AVFilterContext *ctx, HMODULE *d3dcompiler,
|
|
+ FFD3DCompileProc *compile);
|
|
+void ff_d3d11_unload_shader_compiler(HMODULE *d3dcompiler, FFD3DCompileProc *compile);
|
|
+
|
|
+int ff_d3d11_compile_shader(AVFilterContext *ctx, ID3D11Device *device,
|
|
+ FFD3DCompileProc compile, const char *source,
|
|
+ const D3D_SHADER_MACRO *macros, const char *entry,
|
|
+ const char *target, const char *name,
|
|
+ ID3D11ComputeShader **shader);
|
|
+
|
|
+int ff_d3d11_create_const_buffer(AVFilterContext *ctx, ID3D11Device *device,
|
|
+ size_t size, const char *name,
|
|
+ ID3D11Buffer **buffer);
|
|
+
|
|
+DXGI_FORMAT ff_d3d11_texture_format(enum AVPixelFormat fmt);
|
|
+DXGI_FORMAT ff_d3d11_plane_format(enum AVPixelFormat fmt, int plane);
|
|
+
|
|
+int ff_d3d11_ensure_texture(AVFilterContext *ctx, ID3D11Device *device,
|
|
+ ID3D11Texture2D **tex, int *cur_w, int *cur_h,
|
|
+ DXGI_FORMAT *cur_fmt, int w, int h,
|
|
+ DXGI_FORMAT fmt, UINT bind_flags,
|
|
+ const char *name);
|
|
+
|
|
+void ff_d3d11_fill_srv_desc(ID3D11Texture2D *tex, UINT subresource,
|
|
+ DXGI_FORMAT fmt, D3D11_SHADER_RESOURCE_VIEW_DESC *desc);
|
|
+void ff_d3d11_fill_uav_desc(ID3D11Texture2D *tex, UINT subresource,
|
|
+ DXGI_FORMAT fmt, D3D11_UNORDERED_ACCESS_VIEW_DESC *desc);
|
|
+
|
|
+int ff_d3d11_create_srv(AVFilterContext *ctx, ID3D11Device *device,
|
|
+ ID3D11Texture2D *tex, UINT subresource,
|
|
+ DXGI_FORMAT fmt, int log_level, const char *name,
|
|
+ ID3D11ShaderResourceView **srv);
|
|
+int ff_d3d11_create_uav(AVFilterContext *ctx, ID3D11Device *device,
|
|
+ ID3D11Texture2D *tex, UINT subresource,
|
|
+ DXGI_FORMAT fmt, int log_level, const char *name,
|
|
+ ID3D11UnorderedAccessView **uav);
|
|
+
|
|
+void ff_d3d11_copy_frame_to_texture(ID3D11DeviceContext *context, AVFrame *src,
|
|
+ ID3D11Texture2D *dst);
|
|
+void ff_d3d11_copy_texture_to_frame(ID3D11DeviceContext *context, ID3D11Texture2D *src,
|
|
+ AVFrame *dst);
|
|
+void ff_d3d11_copy_frame_to_frame(ID3D11DeviceContext *context, AVFrame *src,
|
|
+ AVFrame *dst);
|
|
+
|
|
+#endif /* AVFILTER_D3D11_FILTER_H */
|