Erstellen eines DXVA-HD-Videoprozessors

Microsoft DirectX Video Acceleration High Definition (DXVA-HD) verwendet zwei primäre Schnittstellen:

  • IDXVAHD_Device. Stellt das DXVA-HD-Gerät dar. Verwenden Sie diese Schnittstelle, um die Gerätefunktionen abzufragen und den Videoprozessor zu erstellen.
  • IDXVAHD_VideoProcessor. Stellt eine Reihe von Videoverarbeitungsfunktionen dar. Verwenden Sie diese Schnittstelle, um den Videoverarbeitungsblit auszuführen.

Im folgenden Code werden die folgenden globalen Variablen angenommen:

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;

So erstellen Sie einen DXVA-HD-Videoprozessor:

  1. Geben Sie eine DXVAHD_CONTENT_DESC-Struktur mit einer Beschreibung des Videoinhalts ein. Der Treiber verwendet diese Informationen als Hinweis, um die Funktionen des Videoprozessors zu optimieren. Die Struktur enthält keine vollständige Formatbeschreibung.

        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. Rufen Sie DXVAHD_CreateDevice auf, um das DXVA-HD-Gerät zu erstellen. Diese Funktion gibt einen Zeiger auf die IDXVAHD_Device-Schnittstelle zurück.

        hr = DXVAHD_CreateDevice(g_pD3DDevice, &desc, DXVAHD_DEVICE_USAGE_PLAYBACK_NORMAL,
            NULL, &pDXVAHD);
    
  3. Rufen Sie IDXVAHD_Device::GetVideoProcessorDeviceCaps auf. Diese Methode füllt eine DXVAHD_VPDEVCAPS-Struktur mit den Gerätefunktionen aus. Wenn Sie bestimmte Videoverarbeitungsfeatures wie Luma-Keying oder Bildfilterung benötigen, überprüfen Sie deren Verfügbarkeit mithilfe dieser Struktur.

        DXVAHD_VPDEVCAPS caps;
    
        hr = pDXVAHD->GetVideoProcessorDeviceCaps(&caps);
    
  4. Überprüfen Sie, ob das DXVA-HD-Gerät die von Ihnen benötigten Eingabevideoformate unterstützt. Im Thema Überprüfung unterstützter DXVA-HD-Formate wird dieser Schritt ausführlicher beschrieben.

  5. Überprüfen Sie, ob das DXVA-HD-Gerät das gewünschte Ausgabeformat unterstützt. Im Abschnitt Überprüfung unterstützter DXVA-HD-Formate wird dieser Schritt ausführlicher beschrieben.

  6. Ordnen Sie ein Array von DXVAHD_VPCAPS Strukturen zu. Die Anzahl der Arrayelemente, die zugeordnet werden müssen, wird vom VideoProcessorCount-Member der DXVAHD_VPDEVCAPS-Struktur angegeben, das in Schritt 3 abgerufen wurde.

        // Create the array of video processor caps. 
    
        DXVAHD_VPCAPS *pVPCaps = 
            new (std::nothrow) DXVAHD_VPCAPS[ caps.VideoProcessorCount ];
    
        if (pVPCaps == NULL)
        {
            return E_OUTOFMEMORY;
        }
    
  7. Jede DXVAHD_VPCAPS-Struktur stellt einen unterschiedlichen Videoprozessor dar. Sie können dieses Array durchlaufen, um die Funktionen der einzelnen Videoprozessoren zu ermitteln. Die Struktur enthält Informationen zu den Konvertierungsfunktionen deinterlacing, telecine und frame rate des Videoprozessors.

  8. Wählen Sie einen zu erstellenden Videoprozessor aus. Das VPGuid-Element der DXVAHD_VPCAPS-Struktur enthält eine GUID, die den Videoprozessor eindeutig identifiziert. Übergeben Sie diese GUID an die IDXVAHD_Device::CreateVideoProcessor-Methode . Die -Methode gibt einen IDXVAHD_VideoProcessor-Zeiger zurück.

        HRESULT hr = pDXVAHD->GetVideoProcessorCaps(
            caps.VideoProcessorCount, pVPCaps);
    
  9. Rufen Sie optional IDXVAHD_Device::CreateVideoSurface auf, um ein Array von Eingabevideooberflächen zu erstellen.

Das folgende Codebeispiel zeigt die vollständige Abfolge der Schritte:

// 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;
}

Die In diesem Beispiel gezeigte CreateVPDevice-Funktion erstellt den Videoprozessor (Schritte 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