DXVA-HD 비디오 프로세서 만들기

Microsoft DirectX 비디오 가속 고화질(DXVA-HD)은 두 가지 기본 인터페이스를 사용합니다.

  • IDXVAHD _ 디바이스. DXVA-HD 디바이스를 나타냅니다. 이 인터페이스를 사용하여 디바이스 기능을 쿼리하고 비디오 프로세서를 만듭니다.
  • IDXVAHD _ VideoProcessor . 비디오 처리 기능 집합을 나타냅니다. 이 인터페이스를 사용하여 비디오 처리 blit를 수행합니다.

다음 코드에서는 다음과 같은 전역 변수가 가정됩니다.

IDirect3D9Ex            *g_pD3D = NULL;     
IDirect3DDevice9Ex      *g_pD3DDevice = NULL;   // Direct3D device.
IDXVAHD_Device          *g_pDXVAHD = NULL;      // DXVA-HD device.
IDXVAHD_VideoProcessor  *g_pDXVAVP = NULL;      // DXVA-HD video processor.
IDirect3DSurface9       *g_pSurface = NULL;     // Video surface.
        
const D3DFORMAT     RENDER_TARGET_FORMAT = D3DFMT_X8R8G8B8;
const D3DFORMAT     VIDEO_FORMAT         = D3DFMT_X8R8G8B8; 
const UINT          VIDEO_FPS            = 60;
const UINT          VIDEO_WIDTH          = 640;
const UINT          VIDEO_HEIGHT         = 480;

DXVA-HD 비디오 프로세서를 만들려면 다음을 수행합니다.

  1. DXVAHD CONTENT _ _ DESC 구조체를 비디오 콘텐츠에 대한 설명으로 채웁니다. 드라이버는 이 정보를 힌트로 사용하여 비디오 프로세서의 기능을 최적화합니다. 구조체에 전체 형식 설명이 포함되어 있지 않습니다.

        DXVAHD_RATIONAL fps = { VIDEO_FPS, 1 }; 
    
        DXVAHD_CONTENT_DESC desc;
    
        desc.InputFrameFormat = DXVAHD_FRAME_FORMAT_PROGRESSIVE;
        desc.InputFrameRate = fps;
        desc.InputWidth = VIDEO_WIDTH;
        desc.InputHeight = VIDEO_HEIGHT;
        desc.OutputFrameRate = fps;
        desc.OutputWidth = VIDEO_WIDTH;
        desc.OutputHeight = VIDEO_HEIGHT;
    
  2. DXVAHD _ CreateDevice를 호출하여 DXVA-HD 디바이스를 만듭니다. 이 함수는 IDXVAHD 디바이스 인터페이스에 대한 _ 포인터를 반환합니다.

        hr = DXVAHD_CreateDevice(g_pD3DDevice, &desc, DXVAHD_DEVICE_USAGE_PLAYBACK_NORMAL,
            NULL, &pDXVAHD);
    
  3. IDXVAHD _ Device::GetVideoProcessorDeviceCaps를 호출합니다. 이 메서드는 DXVAHD _ VPDEVCAPS 구조체를 디바이스 기능으로 채웁니다. Luma 키 지정 또는 이미지 필터링과 같은 특정 비디오 처리 기능이 필요한 경우 이 구조를 사용하여 가용성을 확인합니다.

        DXVAHD_VPDEVCAPS caps;
    
        hr = pDXVAHD->GetVideoProcessorDeviceCaps(&caps);
    
  4. DXVA-HD 디바이스가 필요한 입력 비디오 형식을 지원하는지 확인합니다. 지원되는 DXVA-HD 형식 확인 항목에서는 이 단계를 자세히 설명합니다.

  5. DXVA-HD 디바이스가 필요한 출력 형식을 지원하는지 확인합니다. 지원되는 DXVA-HD 형식 확인 섹션에서는 이 단계를 자세히 설명합니다.

  6. DXVAHD _ VPCAPS 구조의 배열을 할당합니다. 할당해야 하는 배열 요소의 수는 3단계에서 얻은 DXVAHD _ VPDEVCAPS 구조체의 VideoProcessorCount 멤버에 의해 지정됩니다.

        // Create the array of video processor caps. 
    
        DXVAHD_VPCAPS *pVPCaps = 
            new (std::nothrow) DXVAHD_VPCAPS[ caps.VideoProcessorCount ];
    
        if (pVPCaps == NULL)
        {
            return E_OUTOFMEMORY;
        }
    
  7. DXVAHD _ VPCAPS 구조는 고유한 비디오 프로세서를 나타냅니다. 이 배열을 반복하여 각 비디오 프로세서의 기능을 검색할 수 있습니다. 구조에는 비디오 프로세서의 디인터레이싱, 원격 통신 및 프레임 속도 변환 기능에 대한 정보가 포함됩니다.

  8. 만들 비디오 프로세서를 선택합니다. DXVAHD _ VPCAPS 구조의 VPGuid 멤버에는 비디오 프로세서를 고유하게 식별하는 GUID가 포함되어 있습니다. 이 GUID를 IDXVAHD _ Device::CreateVideoProcessor 메서드에 전달합니다. 메서드는 IDXVAHD _ VideoProcessor 포인터를 반환합니다.

        HRESULT hr = pDXVAHD->GetVideoProcessorCaps(
            caps.VideoProcessorCount, pVPCaps);
    
  9. 필요에 따라 IDXVAHD _ Device::CreateVideoSurface를 호출하여 입력 비디오 화면 배열을 만듭니다.

다음 코드 예제에서는 단계의 전체 시퀀스를 보여줍니다.

// Initializes the DXVA-HD video processor.

// NOTE: The following example makes some simplifying assumptions:
//
// 1. There is a single input stream.
// 2. The input frame rate matches the output frame rate.
// 3. No advanced DXVA-HD features are needed, such as luma keying or IVTC.
// 4. The application uses a single input video surface.

HRESULT InitializeDXVAHD()
{
    if (g_pD3DDevice == NULL)
    {
        return E_FAIL;
    }

    HRESULT hr = S_OK;

    IDXVAHD_Device          *pDXVAHD = NULL;
    IDXVAHD_VideoProcessor  *pDXVAVP = NULL;
    IDirect3DSurface9       *pSurf = NULL;

    DXVAHD_RATIONAL fps = { VIDEO_FPS, 1 }; 

    DXVAHD_CONTENT_DESC desc;

    desc.InputFrameFormat = DXVAHD_FRAME_FORMAT_PROGRESSIVE;
    desc.InputFrameRate = fps;
    desc.InputWidth = VIDEO_WIDTH;
    desc.InputHeight = VIDEO_HEIGHT;
    desc.OutputFrameRate = fps;
    desc.OutputWidth = VIDEO_WIDTH;
    desc.OutputHeight = VIDEO_HEIGHT;

#ifdef USE_SOFTWARE_PLUGIN    
    HMODULE hSWPlugin = LoadLibrary(L"C:\\dxvahdsw.dll");

    PDXVAHDSW_Plugin pSWPlugin = (PDXVAHDSW_Plugin)GetProcAddress(hSWPlugin, "DXVAHDSW_Plugin");

    hr = DXVAHD_CreateDevice(g_pD3DDevice, &desc,DXVAHD_DEVICE_USAGE_PLAYBACK_NORMAL,
        pSWPlugin, &pDXVAHD);
#else
    hr = DXVAHD_CreateDevice(g_pD3DDevice, &desc, DXVAHD_DEVICE_USAGE_PLAYBACK_NORMAL,
        NULL, &pDXVAHD);
#endif
    if (FAILED(hr))
    {
        goto done;
    }

    DXVAHD_VPDEVCAPS caps;

    hr = pDXVAHD->GetVideoProcessorDeviceCaps(&caps);
    if (FAILED(hr))
    {
        goto done;
    }

    // Check whether the device supports the input and output formats.

    hr = CheckInputFormatSupport(pDXVAHD, caps, VIDEO_FORMAT);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = CheckOutputFormatSupport(pDXVAHD, caps, RENDER_TARGET_FORMAT);
    if (FAILED(hr))
    {
        goto done;
    }

    // Create the VP device.
    hr = CreateVPDevice(pDXVAHD, caps, &pDXVAVP);
    if (FAILED(hr))
    {
        goto done;
    }

    // Create the video surface for the primary video stream.
    hr = pDXVAHD->CreateVideoSurface(
        VIDEO_WIDTH,
        VIDEO_HEIGHT,
        VIDEO_FORMAT,
        caps.InputPool,
        0,  // Usage
        DXVAHD_SURFACE_TYPE_VIDEO_INPUT,
        1,      // Number of surfaces to create
        &pSurf, // Array of surface pointers
        NULL
        );

    if (FAILED(hr))
    {
        goto done;
    }


    g_pDXVAHD = pDXVAHD;
    g_pDXVAHD->AddRef();

    g_pDXVAVP = pDXVAVP;
    g_pDXVAVP->AddRef();

    g_pSurface = pSurf;
    g_pSurface->AddRef();

done:
    SafeRelease(&pDXVAHD);
    SafeRelease(&pDXVAVP);
    SafeRelease(&pSurf);
    return hr;
}

이 예제에 표시된 CreateVPDevice 함수는 비디오 프로세서를 만듭니다(5~7단계).

// Creates a DXVA-HD video processor.

HRESULT CreateVPDevice(
    IDXVAHD_Device          *pDXVAHD,
    const DXVAHD_VPDEVCAPS& caps,
    IDXVAHD_VideoProcessor  **ppDXVAVP
    )
{
    // Create the array of video processor caps. 
    
    DXVAHD_VPCAPS *pVPCaps = 
        new (std::nothrow) DXVAHD_VPCAPS[ caps.VideoProcessorCount ];

    if (pVPCaps == NULL)
    {
        return E_OUTOFMEMORY;
    }

    HRESULT hr = pDXVAHD->GetVideoProcessorCaps(
        caps.VideoProcessorCount, pVPCaps);

    // At this point, an application could loop through the array and examine
    // the capabilities. For purposes of this example, however, we simply
    // create the first video processor in the list.

    if (SUCCEEDED(hr))
    {
        // The VPGuid member contains the GUID that identifies the video 
        // processor.

        hr = pDXVAHD->CreateVideoProcessor(&pVPCaps[0].VPGuid, ppDXVAVP);
    }

    delete [] pVPCaps;
    return hr;
}

DXVA-HD