Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH v1] avfilter: add vf_scale_d3d12
@ 2025-08-29  3:07 jianfeng.zheng via ffmpeg-devel
  0 siblings, 0 replies; only message in thread
From: jianfeng.zheng via ffmpeg-devel @ 2025-08-29  3:07 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: jianfeng.zheng

Switch to msvc toolchain if mingw64 toolchain don't support dx12vp.

Signed-off-by: jianfeng.zheng <jianfeng.zheng@mthreads.com>
---
 configure                    |   5 +
 libavfilter/Makefile         |   1 +
 libavfilter/allfilters.c     |   1 +
 libavfilter/vf_scale_d3d12.c | 425 +++++++++++++++++++++++++++++++++++
 4 files changed, 432 insertions(+)
 create mode 100644 libavfilter/vf_scale_d3d12.c

diff --git a/configure b/configure
index 9fe28c5af4..1d11775b1a 100755
--- a/configure
+++ b/configure
@@ -4072,6 +4072,7 @@ zscale_filter_deps="libzimg const_nan"
 scale_vaapi_filter_deps="vaapi"
 scale_vt_filter_deps="videotoolbox VTPixelTransferSessionCreate"
 scale_vulkan_filter_deps="vulkan spirv_compiler"
+scale_d3d12_filter_deps="d3d12va ID3D12VideoProcessor ID3D12VideoProcessCommandList D3D12_VIDEO_PROCESS_OUTPUT_STREAM_ARGUMENTS D3D12_VIDEO_PROCESS_INPUT_STREAM_ARGUMENTS"
 vpp_qsv_filter_deps="libmfx"
 vpp_qsv_filter_select="qsvvpp"
 xfade_opencl_filter_deps="opencl"
@@ -6885,6 +6886,10 @@ check_type "windows.h d3d11.h" "ID3D11VideoContext"
 check_type "windows.h d3d12.h" "ID3D12Device"
 check_type "windows.h d3d12video.h" "ID3D12VideoDecoder"
 check_type "windows.h d3d12video.h" "ID3D12VideoEncoder"
+check_type "windows.h d3d12video.h" "ID3D12VideoProcessor"
+check_type "windows.h d3d12video.h" "ID3D12VideoProcessCommandList"
+check_type "windows.h d3d12video.h" "D3D12_VIDEO_PROCESS_OUTPUT_STREAM_ARGUMENTS"
+check_type "windows.h d3d12video.h" "D3D12_VIDEO_PROCESS_INPUT_STREAM_ARGUMENTS"
 test_code cc "windows.h d3d12video.h" "D3D12_FEATURE_VIDEO feature = D3D12_FEATURE_VIDEO_ENCODER_CODEC" && \
 test_code cc "windows.h d3d12video.h" "D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOURCE_REQUIREMENTS req" && enable d3d12_encoder_feature
 check_type "windows.h" "DPI_AWARENESS_CONTEXT" -D_WIN32_WINNT=0x0A00
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 07fb4c3d6c..732551fd56 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -474,6 +474,7 @@ OBJS-$(CONFIG_SCALE_QSV_FILTER)              += vf_vpp_qsv.o
 OBJS-$(CONFIG_SCALE_VAAPI_FILTER)            += vf_scale_vaapi.o scale_eval.o vaapi_vpp.o
 OBJS-$(CONFIG_SCALE_VT_FILTER)               += vf_scale_vt.o scale_eval.o
 OBJS-$(CONFIG_SCALE_VULKAN_FILTER)           += vf_scale_vulkan.o vulkan.o vulkan_filter.o
+OBJS-$(CONFIG_SCALE_D3D12_FILTER)            += vf_scale_d3d12.o
 OBJS-$(CONFIG_SCALE2REF_FILTER)              += vf_scale.o scale_eval.o framesync.o
 OBJS-$(CONFIG_SCALE2REF_NPP_FILTER)          += vf_scale_npp.o scale_eval.o
 OBJS-$(CONFIG_SCDET_FILTER)                  += vf_scdet.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index cca4ce0288..5cbd1a804d 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -440,6 +440,7 @@ extern const FFFilter ff_vf_vpp_amf;
 extern const FFFilter ff_vf_sr_amf;
 extern const FFFilter ff_vf_scale_cuda;
 extern const FFFilter ff_vf_scale_d3d11;
+extern const FFFilter ff_vf_scale_d3d12;
 extern const FFFilter ff_vf_scale_npp;
 extern const FFFilter ff_vf_scale_qsv;
 extern const FFFilter ff_vf_scale_vaapi;
diff --git a/libavfilter/vf_scale_d3d12.c b/libavfilter/vf_scale_d3d12.c
new file mode 100644
index 0000000000..8d38e05b6f
--- /dev/null
+++ b/libavfilter/vf_scale_d3d12.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2025 Jianfeng.Zheng <jianfeng.zheng@mthreads.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 "libavutil/opt.h"
+#include "libavfilter/avfilter.h"
+#include "libavfilter/scale_eval.h"
+#include "libavutil/pixdesc.h"
+#include "video.h"
+#include "compat/w32dlfcn.h"
+#include "libavcodec/mf_utils.h"
+#include "libavutil/hwcontext_d3d12va_internal.h"
+#include "libavutil/hwcontext_d3d12va.h"
+
+#define DXHR_CHECK(hr, fmt, ...)    \
+    if (FAILED(hr)) {               \
+        av_log(avctx, AV_LOG_ERROR, "[WinErr:0x%lX] ", hr);     \
+        av_log(avctx, AV_LOG_ERROR, fmt, ##__VA_ARGS__);        \
+        goto fail;                  \
+    }
+
+#define COND_CHECK(cond, fmt, ...)  \
+    if (cond) {                     \
+        av_log(avctx, AV_LOG_ERROR, fmt, ##__VA_ARGS__);        \
+        goto fail;                  \
+    }
+
+#define DX_RELEASE(p, rls)          \
+    if (p) {                        \
+        rls(p);                     \
+        p = NULL;                   \
+    }
+
+typedef struct ScaleD3d12Context {
+    const AVClass                   *classCtx;
+
+    /**
+     * input device reference
+     */
+    AVBufferRef                     *av_device_ref;
+    AVD3D12VADeviceContext          *input_hwctx;
+    ID3D12Device                    *d3d_device_ref;
+
+    /**
+     * filter's device context
+     */
+    ID3D12VideoDevice               *video_dev;
+    ID3D12VideoProcessor            *vp;
+    ID3D12CommandQueue              *vp_command_queue;
+    ID3D12CommandAllocator          *vp_command_allocator;
+    ID3D12VideoProcessCommandList   *vp_command_list;
+    AVD3D12VASyncContext            vp_sync;
+    int                             gpu_mask;
+    
+
+    char                            *w_expr;
+    char                            *h_expr;
+    int                             force_original_aspect_ratio;
+    int                             force_divisible_by;
+} ScaleD3d12Context;
+
+
+static int scale_d3d12_init(AVFilterContext* avctx)
+{
+    ScaleD3d12Context *ctx = avctx->priv;
+    ctx->gpu_mask = 1;
+    return 0;
+}
+
+static HRESULT mtvsr_fence_completion(AVD3D12VASyncContext *psync_ctx)
+{
+    uint64_t completion = ID3D12Fence_GetCompletedValue(psync_ctx->fence);
+    if (completion < psync_ctx->fence_value) {
+        HRESULT hr = ID3D12Fence_SetEventOnCompletion(psync_ctx->fence, psync_ctx->fence_value, psync_ctx->event);
+        if (FAILED(hr))
+            return hr;
+
+        WaitForSingleObjectEx(psync_ctx->event, INFINITE, FALSE);
+    }
+
+    return 0;
+}
+
+static HRESULT wait_queue_idle(AVD3D12VASyncContext *psync_ctx, ID3D12CommandQueue *cmd_queue)
+{
+    ID3D12CommandQueue_Signal(cmd_queue, psync_ctx->fence, ++psync_ctx->fence_value);
+    return mtvsr_fence_completion(psync_ctx);
+}
+
+static DXGI_COLOR_SPACE_TYPE get_dxgi_color_space(DXGI_FORMAT dxgi_fmt)
+{
+    DXGI_COLOR_SPACE_TYPE cspace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
+    switch (dxgi_fmt)
+    {
+    case DXGI_FORMAT_R16G16B16A16_FLOAT:
+        cspace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
+        break;
+    case DXGI_FORMAT_R10G10B10A2_UNORM:
+        cspace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
+        break;
+    case DXGI_FORMAT_NV12:
+        cspace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
+        break;
+    case DXGI_FORMAT_P010:
+        cspace = DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020;
+        break;
+    case DXGI_FORMAT_B8G8R8A8_UNORM:
+    case DXGI_FORMAT_R8G8B8A8_UNORM:
+        cspace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
+        break;
+    }
+
+    return cspace;
+}
+
+static HRESULT create_video_processor(AVFilterContext *avctx, ID3D12VideoProcessor **pp_vp,
+                                      DXGI_FORMAT ifmt, DXGI_FORMAT ofmt)
+{
+    ScaleD3d12Context *ctx = avctx->priv;
+    AVFilterLink   *inlink = avctx->inputs[0];
+    AVFilterLink  *outlink = avctx->outputs[0];
+    HRESULT             hr = 0;
+
+    D3D12_VIDEO_PROCESS_OUTPUT_STREAM_DESC outdesc= {
+        .Format     = ofmt,
+        .ColorSpace = get_dxgi_color_space(ofmt),
+        .FrameRate  = {60, 1},
+    };
+
+    D3D12_VIDEO_SIZE_RANGE size_range = {
+        .MinWidth   = 64,
+        .MinHeight  = 64,
+        .MaxWidth   = 3840,
+        .MaxHeight  = 3840,
+    };
+    D3D12_VIDEO_PROCESS_INPUT_STREAM_DESC indesc = {
+        .Format     = ifmt,
+        .ColorSpace = get_dxgi_color_space(ifmt),
+        .FrameRate  = {60, 1},
+        .SourceAspectRatio      = {1, 1},
+        .DestinationAspectRatio = {1, 1},
+        .SourceSizeRange        = size_range,
+        .DestinationSizeRange   = size_range,
+    };
+
+    hr = ID3D12VideoDevice_CreateVideoProcessor(ctx->video_dev, ctx->gpu_mask, 
+                                                &outdesc, 1, &indesc, 
+                                                &IID_ID3D12VideoProcessor, pp_vp);
+    DXHR_CHECK(hr, "Failed to create D3D12 VP (fmt %d->%d).\n", (int)ifmt, (int)ofmt);
+
+fail:
+    return hr;
+}
+
+static int filter_frame(AVFilterLink* inlink, AVFrame* in) 
+{
+    AVFilterContext *avctx = inlink->dst;
+    ScaleD3d12Context *ctx = avctx->priv;
+    AVFilterLink  *outlink = avctx->outputs[0];
+
+    AVFrame           *out = NULL;
+    HRESULT             hr = 0;
+    int                ret = 0;
+
+    D3D12_VIDEO_PROCESS_OUTPUT_STREAM_ARGUMENTS out_stream = {};
+    D3D12_VIDEO_PROCESS_INPUT_STREAM_ARGUMENTS   in_stream = {};
+
+    if (in->format != AV_PIX_FMT_D3D12) {
+        av_log(avctx, AV_LOG_ERROR, "Not D3D12 hardware inputs.\n");
+        return AVERROR(EINVAL);
+    }
+
+    // Allocate output frame, see d3d12va_get_buffer()
+    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+    if (!out) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to allocate output frame.\n");
+        return AVERROR(ENOMEM);
+    }
+    av_frame_copy_props(out, in);
+
+    hr = ID3D12CommandAllocator_Reset(ctx->vp_command_allocator);
+    DXHR_CHECK(hr, "Failed to reset command allocator.\n");
+    hr = ID3D12VideoProcessCommandList_Reset(ctx->vp_command_list, ctx->vp_command_allocator);
+    DXHR_CHECK(hr, "Failed to reset vp command list.\n");
+
+    out_stream.OutputStream[0].pTexture2D   = ((AVD3D12VAFrame *)out->data[0])->texture;
+    out_stream.OutputStream[0].Subresource  = 0;
+    SetRect(&out_stream.TargetRectangle, 0, 0, outlink->w, outlink->h);
+
+    in_stream.InputStream[0].pTexture2D     = ((AVD3D12VAFrame *)in->data[0])->texture;
+    in_stream.InputStream[0].Subresource    = (int)(intptr_t)in->data[1];
+    SetRect(&in_stream.Transform.SourceRectangle, 0, 0, inlink->w, inlink->h);
+    SetRect(&in_stream.Transform.DestinationRectangle, 0, 0, outlink->w, outlink->h);
+
+    ID3D12VideoProcessCommandList_ProcessFrames(ctx->vp_command_list, ctx->vp, &out_stream, 1, &in_stream);
+
+    hr = ID3D12VideoProcessCommandList_Close(ctx->vp_command_list);
+    DXHR_CHECK(hr, "Failed to close vp command list.\n");
+    ID3D12CommandQueue_ExecuteCommandLists(ctx->vp_command_queue, 1, &ctx->vp_command_list);
+    hr = wait_queue_idle(&ctx->vp_sync, ctx->vp_command_queue);
+    DXHR_CHECK(hr, "Failed to sync VP command queue.\n");
+
+    av_frame_free(&in);
+    return ff_filter_frame(outlink, out);
+
+fail:
+    av_frame_free(&in);
+    av_frame_free(&out);
+    return AVERROR_EXTERNAL;
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+    AVFilterContext *avctx = inlink->dst;
+    ScaleD3d12Context *ctx = avctx->priv;
+    AVHWFramesContext *frames_ctx;
+    AVHWDeviceContext *device_ctx;
+    FilterLink        *inl = ff_filter_link(inlink);
+
+    if (!inl->hw_frames_ctx) {
+        av_log(ctx, AV_LOG_ERROR, "Not HW frame inputs for vf_scale_d3d12.\n");
+        return AVERROR(EINVAL);
+    }
+
+    frames_ctx = (AVHWFramesContext *)inl->hw_frames_ctx->data;
+    device_ctx = (AVHWDeviceContext *)frames_ctx->device_ref->data;
+
+    if (device_ctx->type != AV_HWDEVICE_TYPE_D3D12VA) {
+        av_log(ctx, AV_LOG_ERROR, "Not D3D12VA inputs for vf_scale_d3d12.\n");
+        return AVERROR(EINVAL);
+    }
+
+    return 0;
+}
+
+static int config_output(AVFilterLink* outlink) 
+{
+    AVFilterContext *avctx = outlink->src;
+    ScaleD3d12Context *ctx = avctx->priv;
+    AVFilterLink   *inlink = avctx->inputs[0];
+    FilterLink        *inl = ff_filter_link(inlink);
+    FilterLink       *outl = ff_filter_link(outlink);
+    AVHWFramesContext       *in_frames_ctx;
+    AVHWDeviceContext       *in_device_ctx;
+    AVHWFramesContext       *out_frames_ctx;
+    DXGI_FORMAT             dxgi_format;
+    HRESULT                  hr;
+    D3D12_COMMAND_QUEUE_DESC queue_desc;
+    double           w_adj = 1.0;
+
+    // Evaluate output dimensions
+    int w, h;
+    int ret = ff_scale_eval_dimensions(ctx, ctx->w_expr, ctx->h_expr, inlink, outlink, &w, &h);
+    if (ret < 0) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to evaluate dimensions.\n");
+        return AVERROR(EINVAL);
+    }
+
+    ff_scale_adjust_dimensions(inlink, &w, &h, ctx->force_original_aspect_ratio, ctx->force_divisible_by, w_adj);
+
+    outlink->w = w;
+    outlink->h = h;
+
+    // Reference to input device 
+    in_frames_ctx       = (AVHWFramesContext *)inl->hw_frames_ctx->data;
+    ctx->av_device_ref  = av_buffer_ref(in_frames_ctx->device_ref);
+    in_device_ctx       = (AVHWDeviceContext *)ctx->av_device_ref->data;
+    ctx->input_hwctx    = (AVD3D12VADeviceContext *)in_device_ctx->hwctx;
+    if (!ctx->input_hwctx->device) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to initialize filter device or context in config_props.\n");
+        return AVERROR(EINVAL);
+    }
+    ID3D12Device_AddRef(ctx->input_hwctx->device);
+    ctx->d3d_device_ref = ctx->input_hwctx->device;
+
+    // Create output hw frame context
+    outl->hw_frames_ctx = av_hwframe_ctx_alloc(ctx->av_device_ref);
+    if (!outl->hw_frames_ctx) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to alloc HW frame context for output.\n");
+        return AVERROR(ENOMEM);
+    }
+    out_frames_ctx = (AVHWFramesContext*)outl->hw_frames_ctx->data;
+    out_frames_ctx->format    = in_frames_ctx->format;
+    out_frames_ctx->sw_format = in_frames_ctx->sw_format;
+    out_frames_ctx->width     = w;
+    out_frames_ctx->height    = h;
+    out_frames_ctx->initial_pool_size = 0;  // Dynamic allocation
+    ff_filter_init_hw_frames(avctx, outlink, 10);
+    ret = av_hwframe_ctx_init(outl->hw_frames_ctx);
+    if (ret < 0) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to int HW frame context for output.\n");
+        return AVERROR(ENOMEM);
+    }
+
+    av_log(avctx, AV_LOG_VERBOSE, "format=%s, %dx%d -> %dx%d.\n",
+            av_get_pix_fmt_name(in_frames_ctx->sw_format),
+            inlink->w, inlink->h, outlink->w, outlink->h);
+
+    hr = ID3D12Device_QueryInterface(ctx->d3d_device_ref, &IID_ID3D12VideoDevice, (void **)&ctx->video_dev);
+    DXHR_CHECK(hr,  "Failed to create D3D12VideoDevice.\n")
+
+    queue_desc = (D3D12_COMMAND_QUEUE_DESC){
+        .Type = D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS,
+        .NodeMask = ctx->gpu_mask,
+    };
+    hr = ID3D12Device_CreateCommandQueue(ctx->d3d_device_ref, &queue_desc,
+                                        &IID_ID3D12CommandQueue, &ctx->vp_command_queue);
+    DXHR_CHECK(hr, "Frailed to create command queue.\n");
+
+    hr = ID3D12Device_CreateFence(ctx->d3d_device_ref, (ctx->vp_sync.fence_value = 0), 
+                                D3D12_FENCE_FLAG_NONE, 
+                                &IID_ID3D12Fence, &ctx->vp_sync.fence);
+    DXHR_CHECK(hr, "Failed to create vp fence.\n");
+    ctx->vp_sync.event = CreateEvent(NULL, FALSE, FALSE, NULL);
+    COND_CHECK(!ctx->vp_sync.event, "Failed to create vp sync event.\n");
+
+    hr = ID3D12Device_CreateCommandAllocator(ctx->d3d_device_ref, D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS,
+                                            &IID_ID3D12CommandAllocator, &ctx->vp_command_allocator);
+    DXHR_CHECK(hr, "Frailed to create command allocator.\n");
+
+    hr = ID3D12Device_CreateCommandList(ctx->d3d_device_ref, ctx->gpu_mask, D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS,
+                                        ctx->vp_command_allocator, NULL,
+                                        &IID_ID3D12VideoProcessCommandList, &ctx->vp_command_list);
+    DXHR_CHECK(hr, "Frailed to create VP command list.\n");
+
+    hr = ID3D12VideoProcessCommandList_Close(ctx->vp_command_list);
+    DXHR_CHECK(hr, "Frailed to close VP command list.\n");
+
+    ID3D12CommandQueue_ExecuteCommandLists(ctx->vp_command_queue, 1, &ctx->vp_command_list);
+    hr = wait_queue_idle(&ctx->vp_sync, ctx->vp_command_queue);
+    DXHR_CHECK(hr, "Failed to sync VP command queue.\n");
+
+    dxgi_format = ((AVD3D12VAFramesContext*)(in_frames_ctx->hwctx))->format;
+    if (create_video_processor(avctx, &ctx->vp, dxgi_format, dxgi_format) < 0) {
+        goto fail;
+    }
+
+    return 0;
+
+fail:
+    return AVERROR_EXTERNAL;
+}
+
+static void scale_d3d12_uninit(AVFilterContext* avctx)
+{
+    ScaleD3d12Context *ctx = avctx->priv;
+
+    DX_RELEASE(ctx->vp,                 ID3D12VideoProcessor_Release);
+    DX_RELEASE(ctx->vp_command_list,    ID3D12VideoProcessCommandList_Release);
+    DX_RELEASE(ctx->vp_command_allocator,   ID3D12CommandAllocator_Release);
+    DX_RELEASE(ctx->vp_command_queue,   ID3D12CommandQueue_Release);
+    DX_RELEASE(ctx->vp_sync.fence,      ID3D12Fence_Release);
+    DX_RELEASE(ctx->vp_sync.event,      CloseHandle);
+    DX_RELEASE(ctx->video_dev,          ID3D12VideoDevice_Release);
+    DX_RELEASE(ctx->d3d_device_ref,     ID3D12Device_Release);
+
+    av_buffer_unref(&ctx->av_device_ref);
+}
+
+static const AVFilterPad scale_d3d12_inputs[] = {
+    {
+        .name         = "default",
+        .type         = AVMEDIA_TYPE_VIDEO,
+        .filter_frame = &filter_frame,
+        .config_props = &config_input,
+    },
+};
+
+static const AVFilterPad scale_d3d12_outputs[] = {
+    {
+        .name         = "default",
+        .type         = AVMEDIA_TYPE_VIDEO,
+        .config_props = &config_output,
+    },
+};
+
+#define OFFSET(x) offsetof(ScaleD3d12Context, x)
+#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
+static const AVOption scale_d3d12_options[] = {
+    { "w", "Output video output_width",
+            OFFSET(w_expr), AV_OPT_TYPE_STRING, {.str = "iw"}, .flags = FLAGS },
+    { "h", "Output video output_height",
+            OFFSET(h_expr), AV_OPT_TYPE_STRING, {.str = "ih"}, .flags = FLAGS },
+    { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR",
+            OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0}, 0, 2, FLAGS, .unit = "force_oar" },
+    { "disable",  NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, .unit = "force_oar" },
+    { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, .unit = "force_oar" },
+    { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, .unit = "force_oar" },
+    { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used",
+            OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1}, 1, 256, FLAGS },
+    { NULL }
+};
+
+
+AVFILTER_DEFINE_CLASS(scale_d3d12);
+
+const FFFilter ff_vf_scale_d3d12 = {
+    .p.name         = "scale_d3d12",
+    .p.description  = NULL_IF_CONFIG_SMALL("Scale video using D3D12 VPP"),
+    .priv_size      = sizeof(ScaleD3d12Context),
+    .p.priv_class   = &scale_d3d12_class,
+    .init           = scale_d3d12_init,
+    .uninit         = scale_d3d12_uninit,
+    FILTER_INPUTS(scale_d3d12_inputs),
+    FILTER_OUTPUTS(scale_d3d12_outputs),
+    FILTER_SINGLE_PIXFMT(AV_PIX_FMT_D3D12),
+    .p.flags        = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+    .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
+};
-- 
2.48.1

_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2025-08-29  3:08 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-08-29  3:07 [FFmpeg-devel] [PATCH v1] avfilter: add vf_scale_d3d12 jianfeng.zheng via ffmpeg-devel

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git