Files
jellyfin-ffmpeg/debian/patches/0093-add-d3d11-deinterlace-filter.patch
T

1297 lines
45 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"
+yadif_d3d11_filter_deps="d3d11va"
scale_d3d12_filter_deps="d3d12va ID3D12VideoProcessor"
deinterlace_d3d12_filter_deps="d3d12va ID3D12VideoProcessor"
mestimate_d3d12_filter_deps="d3d12va ID3D12VideoMotionEstimator d3d12_motion_estimator"
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
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
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,774 @@
+/*
+ * 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 <d3dcompiler.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"
+
+#define 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
+
+
+#define DEINT_D3D11_ALG_YADIF 0
+#define DEINT_D3D11_ALG_BWDIF 1
+
+typedef HRESULT (WINAPI *D3DCompileProc)(LPCVOID, SIZE_T, LPCSTR,
+ const D3D_SHADER_MACRO *, ID3DInclude *,
+ LPCSTR, LPCSTR, UINT, UINT,
+ ID3D10Blob **, ID3D10Blob **);
+
+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;
+ D3DCompileProc 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;
+} DeintD3D11Context;
+
+static void release_d3d11_resources(DeintD3D11Context *s)
+{
+ D3D11_RELEASE(s->cs_y);
+ D3D11_RELEASE(s->cs_uv);
+ D3D11_RELEASE(s->params_buf);
+ D3D11_RELEASE(s->prev_tex);
+ D3D11_RELEASE(s->cur_tex);
+ D3D11_RELEASE(s->next_tex);
+ 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;
+ ID3D10Blob *cs_blob = NULL;
+ ID3D10Blob *err_blob = NULL;
+ HRESULT hr;
+
+ hr = s->D3DCompile(ff_source_deint_hlsl, strlen(ff_source_deint_hlsl),
+ NULL, NULL, NULL, entry, "cs_5_0",
+ D3DCOMPILE_OPTIMIZATION_LEVEL3, 0, &cs_blob, &err_blob);
+ if (FAILED(hr)) {
+ if (err_blob) {
+ av_log(ctx, AV_LOG_ERROR, "Failed compiling D3D11 deinterlace shader %s: %.*s\n",
+ entry, (int)err_blob->lpVtbl->GetBufferSize(err_blob),
+ (char *)err_blob->lpVtbl->GetBufferPointer(err_blob));
+ } else {
+ av_log(ctx, AV_LOG_ERROR, "Failed compiling D3D11 deinterlace shader %s: HRESULT 0x%lX\n",
+ entry, (unsigned long)hr);
+ }
+ D3D11_RELEASE(err_blob);
+ return AVERROR_EXTERNAL;
+ }
+
+ hr = s->device->lpVtbl->CreateComputeShader(s->device,
+ cs_blob->lpVtbl->GetBufferPointer(cs_blob),
+ cs_blob->lpVtbl->GetBufferSize(cs_blob),
+ NULL, shader);
+ D3D11_RELEASE(cs_blob);
+ D3D11_RELEASE(err_blob);
+ if (FAILED(hr)) {
+ av_log(ctx, AV_LOG_ERROR, "Failed creating D3D11 deinterlace shader %s: HRESULT 0x%lX\n",
+ entry, (unsigned long)hr);
+ return AVERROR_EXTERNAL;
+ }
+ return 0;
+}
+
+static int init_shaders(AVFilterContext *ctx)
+{
+ DeintD3D11Context *s = ctx->priv;
+ D3D11_BUFFER_DESC bd = { 0 };
+ HRESULT hr;
+ int ret;
+
+ if (s->cs_y)
+ return 0;
+
+ if (!s->d3dcompiler) {
+ s->d3dcompiler = LoadLibraryA("d3dcompiler_47.dll");
+ if (!s->d3dcompiler)
+ s->d3dcompiler = LoadLibraryA("d3dcompiler_43.dll");
+ }
+ if (!s->d3dcompiler) {
+ av_log(ctx, AV_LOG_ERROR, "Failed loading d3dcompiler DLL\n");
+ return AVERROR_EXTERNAL;
+ }
+
+ s->D3DCompile = (D3DCompileProc)GetProcAddress(s->d3dcompiler, "D3DCompile");
+ if (!s->D3DCompile) {
+ av_log(ctx, AV_LOG_ERROR, "Failed loading D3DCompile\n");
+ return AVERROR_EXTERNAL;
+ }
+
+ if ((ret = compile_shader(ctx, "deint_y", &s->cs_y)) < 0 ||
+ (ret = compile_shader(ctx, "deint_uv", &s->cs_uv)) < 0)
+ return ret;
+
+ bd.ByteWidth = sizeof(DeintD3D11Params);
+ bd.Usage = D3D11_USAGE_DYNAMIC;
+ bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+ bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ hr = s->device->lpVtbl->CreateBuffer(s->device, &bd, NULL, &s->params_buf);
+ if (FAILED(hr)) {
+ av_log(ctx, AV_LOG_ERROR, "Failed creating D3D11 deinterlace constant buffer: HRESULT 0x%lX\n",
+ (unsigned long)hr);
+ return AVERROR_EXTERNAL;
+ }
+
+ return 0;
+}
+
+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;
+
+ D3D11_RELEASE(s->prev_tex);
+ D3D11_RELEASE(s->cur_tex);
+ D3D11_RELEASE(s->next_tex);
+ 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 void fill_tex2d_srv_desc(ID3D11Texture2D *tex, UINT subresource,
+ DXGI_FORMAT fmt, D3D11_SHADER_RESOURCE_VIEW_DESC *desc)
+{
+ D3D11_TEXTURE2D_DESC tex_desc;
+ UINT mip_slice = 0;
+ UINT 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;
+}
+
+static void fill_tex2d_uav_desc(ID3D11Texture2D *tex, UINT subresource,
+ DXGI_FORMAT fmt, D3D11_UNORDERED_ACCESS_VIEW_DESC *desc)
+{
+ D3D11_TEXTURE2D_DESC tex_desc;
+ UINT mip_slice = 0;
+ UINT 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;
+}
+
+static int create_nv12_srv_view(AVFilterContext *ctx, ID3D11Texture2D *tex,
+ UINT subresource, int plane, int log_level,
+ ID3D11ShaderResourceView **srv)
+{
+ DeintD3D11Context *s = ctx->priv;
+ D3D11_SHADER_RESOURCE_VIEW_DESC desc = { 0 };
+ HRESULT hr;
+
+ fill_tex2d_srv_desc(tex, subresource, plane ? DXGI_FORMAT_R8G8_UNORM : DXGI_FORMAT_R8_UNORM, &desc);
+
+ hr = s->device->lpVtbl->CreateShaderResourceView(s->device, (ID3D11Resource *)tex,
+ &desc, srv);
+ if (FAILED(hr)) {
+ av_log(ctx, log_level, "Failed creating D3D11 deinterlace SRV plane %d: HRESULT 0x%lX\n",
+ plane, (unsigned long)hr);
+ return AVERROR_EXTERNAL;
+ }
+ return 0;
+}
+
+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;
+ D3D11_UNORDERED_ACCESS_VIEW_DESC desc = { 0 };
+ HRESULT hr;
+
+ fill_tex2d_uav_desc(tex, subresource, plane ? DXGI_FORMAT_R8G8_UNORM : DXGI_FORMAT_R8_UNORM, &desc);
+
+ hr = s->device->lpVtbl->CreateUnorderedAccessView(s->device, (ID3D11Resource *)tex,
+ &desc, uav);
+ if (FAILED(hr)) {
+ av_log(ctx, log_level, "Failed creating D3D11 deinterlace UAV plane %d: HRESULT 0x%lX\n",
+ plane, (unsigned long)hr);
+ return AVERROR_EXTERNAL;
+ }
+ return 0;
+}
+
+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 void copy_frame_to_texture(DeintD3D11Context *s, 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 };
+
+ s->context->lpVtbl->CopySubresourceRegion(s->context, (ID3D11Resource *)dst, 0,
+ 0, 0, 0, (ID3D11Resource *)src_tex,
+ src_sub, &box);
+}
+
+static void copy_texture_to_frame(DeintD3D11Context *s, ID3D11Texture2D *src, AVFrame *dst)
+{
+ ID3D11Texture2D *dst_tex = (ID3D11Texture2D *)dst->data[0];
+ UINT dst_sub = (UINT)(uintptr_t)dst->data[1];
+
+ s->context->lpVtbl->CopySubresourceRegion(s->context, (ID3D11Resource *)dst_tex,
+ dst_sub, 0, 0, 0, (ID3D11Resource *)src,
+ 0, NULL);
+}
+
+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)
+ 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++)
+ 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;
+ }
+
+ copy_frame_to_texture(s, y->prev, s->prev_tex);
+ copy_frame_to_texture(s, y->cur, s->cur_tex);
+ copy_frame_to_texture(s, 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++)
+ 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;
+ }
+ D3D11_RELEASE(uavs[0]);
+ 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)
+ 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:
+ D3D11_RELEASE(uavs[0]);
+ 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, &params, 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)
+ copy_texture_to_frame(s, 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++)
+ D3D11_RELEASE(srvs[i]);
+ D3D11_RELEASE(uavs[0]);
+ 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;
+ if (s->d3dcompiler)
+ FreeLibrary(s->d3dcompiler);
+}
+
+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 = 1; 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;
+
+ 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;
+}
+
+static const AVClass yadif_d3d11_class = {
+ .class_name = "yadif_d3d11",
+ .item_name = av_default_item_name,
+ .option = ff_yadif_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 = ff_yadif_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_VF_YADIF_D3D11_H
+#define AVFILTER_VF_YADIF_D3D11_H
+
+#define DEINT_D3D11_TGX 16
+#define DEINT_D3D11_TGY 16
+
+#endif /* AVFILTER_VF_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);
+
+ 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, 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(py(x, y - 1), py(x, y + 1),
+ cy(x, y - 2), cy(x, y), cy(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),
+ cy(x, y - 2), cy(x, y), cy(x, y + 2),
+ ny(x, y - 1), ny(x, y + 1), sp);
+}
+
+float2 yadif_uv(int x, int y)
+{
+ float2 sp = yadif_spatial_uv(x, y);
+
+ if (is_second_field)
+ return temporal2(puv(x, y - 1), puv(x, y + 1),
+ cuv(x, y - 2), cuv(x, y), cuv(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),
+ cuv(x, y - 2), cuv(x, y), cuv(x, y + 2),
+ nuv(x, y - 1), nuv(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,
+ py(x, y + 4), py(x, y + 2), py(x, y), py(x, y - 2), py(x, y - 4),
+ cy(x, y + 1), cy(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), cy(x, y + 1), cy(x, y - 1),
+ ny(x, y + 4), ny(x, y + 2), ny(x, y), ny(x, y - 2), ny(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,
+ puv(x, y + 4), puv(x, y + 2), puv(x, y), puv(x, y - 2), puv(x, y - 4),
+ cuv(x, y + 1), cuv(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), cuv(x, y + 1), cuv(x, y - 1),
+ nuv(x, y + 4), nuv(x, y + 2), nuv(x, y), nuv(x, y - 2), nuv(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 */