Direct3D 视频运动估计

本文包含有关使用 Direct3D 12 视频 API 进行运动矢量估计的指导。 此功能是在 Windows 10 版本 2004(10.0) 中引入的;内部版本 19041)。 运动估计是确定运动向量的过程,用于描述从一个二维图像到另一个图像的转换。 运动估计是视频编码的重要组成部分,可用于帧速率转换算法。

虽然运动估计可以通过着色器实现,但 D3D12 运动估计功能的目的是公开固定函数加速,以便运动搜索从 3D 卸载这部分工作。 这通常以公开 GPU 视频编码器运动估算器的形式出现。 D3D12 运动估计的目标是光学流,但应指出,编码器运动估算器可以针对改进压缩进行优化。

检查支持

通过调用 ID3D12VideoDevice::CheckFeatureSupport 并传入 D3D12_FEATURE_VIDEO 枚举中的值来指定正在查询支持的功能,从而确定对所有 D3D 视频功能的支持。 若要查询给定格式支持的块大小和分辨率,请使用 D3D12_FEATURE_VIDEO_MOTION_ESTIMATOR 值并为 pFeatureSupportData 提供 D3D12_FEATURE_DATA_VIDEO_MOTION_ESTIMATOR 结构,如以下示例所示。 在当前版本中,仅支持 DXGI_FORMAT_NV12,因此其他格式的内容可能需要进行颜色转换和向下采样才能使用运动估计。

D3D12_FEATURE_DATA_VIDEO_MOTION_ESTIMATOR MotionEstimatorSupport = {0u, DXGI_FORMAT_NV12};
VERIFY(spVideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_MOTION_ESTIMATOR, &MotionEstimatorSupport, sizeof(MotionEstimatorSupport)));

运动估算器上下文对象

ID3D12VideoMotionEstimator 对象维护视频动作估计作的上下文。 通过调用 ID3D12VideoDevice1::CreateVideoMotionEstimator创建此接口的新实例。

所选块大小、精度和支持的大小范围取决于从 D3D12_FEATURE_VIDEO_MOTION_ESTIMATOR 功能检查返回的硬件支持的值。 可以选择比驱动程序支持的更小的范围。 大小范围通知内部分配大小。

D3D12_VIDEO_MOTION_ESTIMATOR_DESC motionEstimatorDesc = { 
    0, //NodeIndex
    DXGI_FORMAT_NV12, 
    D3D12_VIDEO_MOTION_ESTIMATOR_SEARCH_BLOCK_SIZE_16X16,
    D3D12_VIDEO_MOTION_ESTIMATOR_VECTOR_PRECISION_QUARTER_PEL, 
    {1920, 1080, 1280, 720} // D3D12_VIDEO_SIZE_RANGE
    }; 

CComPtr<ID3D12VideoMotionEstimator> spVideoMotionEstimator;
VERIFY_SUCCEEDED(spVideoDevice->CreateVideoMotionEstimator(
    &motionEstimatorDesc, 
    nullptr,
    IID_PPV_ARGS(&spVideoMotionEstimator)));

运动向量存储

ID3D12VideoMotionVectorHeap 存储运动向量。 此接口由从 ID3D12VideoEncodeCommandList::EstimateMotion返回的 D3D12_VIDEO_MOTION_ESTIMATOR_OUTPUT 结构使用。 解析的输出 2D 纹理是一个 DXGI_FORMAT_R16G16_SINT 纹理,R 保存水平分量,G 保存运动向量的垂直部分。 此纹理的大小设置为每个块包含一对组件。 调用 ID3D12VideoEncodeCommandList::ResolveMotionVectorHeap,将 EstimateMotion 的运动矢量输出转换为视频运动估计 API 定义的一致格式。

D3D12_VIDEO_MOTION_VECTOR_HEAP_DESC MotionVectorHeapDesc = { 
    0, // NodeIndex 
    DXGI_FORMAT_NV12, 
    D3D12_VIDEO_MOTION_ESTIMATOR_SEARCH_BLOCK_SIZE_16X16,
    D3D12_VIDEO_MOTION_ESTIMATOR_VECTOR_PRECISION_QUARTER_PEL, 
    {1920, 1080, 1280, 720} // D3D12_VIDEO_SIZE_RANGE
    }; 

CComPtr<ID3D12VideoMotionVectorHeap> spVideoMotionVectorHeap;
VERIFY_SUCCEEDED(spVideoDevice->CreateVideoMotionVectorHeap(
    &MotionVectorHeapDesc, 
    nullptr, 
    IID_PPV_ARGS(&spVideoMotionVectorHeap)));
    CD3DX12_RESOURCE_DESC::Tex2D(
        DXGI_FORMAT_R16G16_SINT, 
        Align(1920, 16) / 16, // This example uses a 16x16 block size. Pixel width and height
        Align(1080, 16) / 16, // are adjusted to store the vectors for those blocks.
        1, // ArraySize
        1  // MipLevels
        );

    ATL::CComPtr< ID3D12Resource > spResolvedMotionVectors;
    VERIFY_SUCCEEDED(pDevice->CreateCommittedResource(
        &Properties,
        D3D12_HEAP_FLAG_NONE,
        &resolvedMotionVectorDesc,
        D3D12_RESOURCE_STATE_COMMON,
        nullptr,
        IID_PPV_ARGS(&spResolvedMotionVectors)));

ID3D12VideoMotionVectorHeap 还用于在 D3D12_VIDEO_MOTION_ESTIMATOR_INPUT 结构中提供提示向量。

估计命令列表中的动作

ID3D12VideoEncodeCommandList 调用 EstimateMotion,以调用运动估计作。

下面的示例执行运动搜索,并将运动向量解析为具有 D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE的 2D 纹理。 用作 EstimateMotion 输入的 D3D12 资源必须处于 D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ 状态,ResolveMotionVectorHeap 写入的资源必须处于 D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE 状态。

const D3D12_VIDEO_MOTION_ESTIMATOR_OUTPUT outputArgs = {spVideoMotionVectorHeap};

const D3D12_VIDEO_MOTION_ESTIMATOR_INPUT inputArgs = {
    spCurrentResource,
    0,
    spReferenceResource,
    0,
    nullptr // pHintMotionVectorHeap
    };

spCommandList->EstimateMotion(spVideoMotionEstimator, &outputArgs, &inputArgs);

const D3D12_RESOLVE_VIDEO_MOTION_VECTOR_HEAP_OUTPUT outputArgs = { 
    spResolvedMotionVectors,
    {}};

const D3D12_RESOLVE_VIDEO_MOTION_VECTOR_HEAP_INPUT inputArgs = {
    spVideoMotionVectorHeap,
    1920,
    1080
    };

spCommandList->ResolveMotionVectorHeap(&outputArgs, &inputArgs);
        
VERIFY(spCommandList->Close());

// Execute Commandlist.
ID3D12CommandList *ppCommandLists[1] = { spCommandList.p };
spCommandQueue->ExecuteCommandLists(1, ppCommandLists);

受保护的资源

Direct3D 12 运动矢量估计支持在驱动程序支持时从硬件 DRM 保护的资源读取和写入。 如果输入资源受硬件 DRM 保护,则输出也是硬件 DRM 保护的资源。用于创建运动估计上下文对象和运动向量堆的方法, ID3D12VideoDevice1::CreateVideoMotionEstimatorID3D12VideoDevice1::CreateVideoMotionVectorHeap均接受用于管理对受保护资源的访问的 ID3D12ProtectedResourceSession

使用 ID3D12VideoMotionEstimator::GetProtectedResourceSessionID3D12VideoMotionVectorHeap::GetProtectedResourceSession 检索创建对象时提供的 ID3D12ProtectedResourceSession 对象。