Media Foundation에서 DXVA 2.0 지원

이 항목에서는 Microsoft Direct3D 9를 사용하여 MFT(Media Foundation 변환)에서 DXVA(DirectX Video Acceleration) 2.0을 지원하는 방법을 설명합니다. 특히 토폴로지 로더에서 중재하는 디코더와 비디오 렌더러 간의 통신에 대해 설명합니다. 이 항목에서는 DXVA 디코딩을 구현하는 방법을 설명하지 않습니다.

이 항목의 나머지 부분에서 디코더 라는 용어는 압축된 비디오를 수신하고 압축되지 않은 비디오를 출력하는 디코더 MFT를 나타냅니다. 디코더 디바이스라는 용어는 그래픽 드라이버에서 구현한 하드웨어 비디오 가속기를 나타냅니다.

Microsoft Direct3D 11 비디오 디코딩에 대한 자세한 내용은 Media Foundation에서 Direct3D 11 비디오 디코딩 지원을 참조하세요.

 

참고

Windows 스토어 앱은 Direct3D 11을 사용해야 합니다.

 

Media Foundation에서 DXVA 2.0을 지원하기 위해 디코더가 수행해야 하는 기본 단계는 다음과 같습니다.

  1. Direct3D 9 디바이스에 대한 핸들을 엽니다.
  2. DXVA 디코더 구성을 찾습니다.
  3. 압축되지 않은 버퍼를 할당합니다.
  4. 프레임을 디코딩합니다.

이러한 단계는 이 항목의 나머지 부분에서 자세히 설명합니다.

Direct3D 디바이스 핸들 열기

MFT는 Microsoft Direct3D 디바이스 관리자를 사용하여 Direct3D 9 디바이스에 대한 핸들을 가져옵니다. 디바이스 핸들을 열려면 다음 단계를 수행합니다.

  1. 값이 TRUEMF_SA_D3D_AWARE 특성을 노출합니다. 토폴로지 로더는 IMFTransform::GetAttributes를 호출하여 이 특성을 쿼리합니다. 특성을 TRUE 로 설정하면 MFT가 DXVA를 지원한다는 토폴로지 로더에 알릴 수 있습니다.
  2. 형식 협상이 시작되면 토폴로지 로더는 MFT_MESSAGE_SET_D3D_MANAGER 메시지와 함께 IMFTransform::P rocessMessage를 호출합니다. ulParam 매개 변수는 비디오 렌더러의 Direct3D 디바이스 관리자에 대한 IUnknown 포인터입니다. IDirect3DDeviceManager9 인터페이스에 대해 이 포인터를 쿼리합니다.
  3. IDirect3DDeviceManager9::OpenDeviceHandle을 호출하여 렌더러의 Direct3D 디바이스에 대한 핸들을 가져옵니다.
  4. IDirect3DDeviceManager9::GetVideoService를 호출하고 디바이스 핸들을 전달합니다. 이 메서드는 IDirectXVideoDecoderService 인터페이스에 대한 포인터를 반환합니다.
  5. 포인터 및 디바이스 핸들을 캐시합니다.

디코더 구성 찾기

MFT는 DXVA 디코더 디바이스에 대한 호환되는 구성을 찾아야 합니다. 입력 형식의 유효성을 검사한 후 IMFTransform::SetInputType 메서드 내에서 다음 단계를 수행합니다.

  1. IDirectXVideoDecoderService::GetDecoderDeviceGuids를 호출합니다. 이 메서드는 디코더 디바이스 GUID 배열을 반환합니다.

  2. 디코더 GUID 배열을 반복하여 디코더가 지원하는 GUID를 찾습니다. 예를 들어 MPEG-2 디코더의 경우 DXVA2_ModeMPEG2_MOCOMP, DXVA2_ModeMPEG2_IDCT 또는 DXVA2_ModeMPEG2_VLD 찾습니다.

  3. 후보 디코더 디바이스 GUID를 찾으면 GUID를 IDirectXVideoDecoderService::GetDecoderRenderTargets 메서드에 전달합니다. 이 메서드는 D3DFORMAT 값으로 지정된 렌더링 대상 형식의 배열을 반환합니다.

  4. 렌더링 대상 형식을 반복하고 디코더에서 지원하는 형식을 찾습니다.

  5. IDirectXVideoDecoderService::GetDecoderConfigurations를 호출합니다. 제안된 출력 형식을 설명하는 DXVA2_VideoDesc 구조와 함께 동일한 디코더 디바이스 GUID를 전달합니다. 메서드는 DXVA2_ConfigPictureDecode 구조체의 배열을 반환합니다. 각 구조체는 디코더 디바이스에 대한 하나의 가능한 구성을 설명합니다. 디코더가 지원하는 구성을 찾습니다.

  6. 렌더링 대상 형식 및 구성을 저장합니다.

IMFTransform::GetOutputAvailableType 메서드에서 제안된 렌더링 대상 형식에 따라 압축되지 않은 비디오 형식을 반환합니다.

IMFTransform::SetOutputType 메서드에서 렌더링 대상 형식에 대해 미디어 형식을 검사.

소프트웨어 디코딩으로 대체

MFT가 DXVA 구성을 찾을 수 없는 경우(예: 그래픽 드라이버에 올바른 기능이 없는 경우) SetInputTypeSetOutputType 메서드에서 MF_E_UNSUPPORTED_D3D_TYPE 오류 코드를 반환해야 합니다. 토폴로지 로더는 ulParam 매개 변수에 대한 NULL 값으로 MFT_MESSAGE_SET_D3D_MANAGER 메시지를 보내 응답합니다. MFT는 IDirect3DDeviceManager9 인터페이스에 대한 포인터를 해제해야 합니다. 그러면 토폴로지 로더가 미디어 형식을 재협상하고 MFT는 소프트웨어 디코딩을 사용할 수 있습니다.

압축되지 않은 버퍼 할당

DXVA 2.0에서 디코더는 압축되지 않은 비디오 버퍼로 사용할 Direct3D 표면을 할당해야 합니다. 디코더는 EVR이 디인터레이싱에 사용할 3개의 표면을 할당해야 합니다. Media Foundation은 EVR에서 그래픽 드라이버가 디인터레이싱에 필요한 표면 수를 지정하는 방법을 제공하지 않으므로 이 숫자는 수정되었습니다. 모든 드라이버에 대해 3개의 표면으로 충분해야 합니다.

IMFTransform::GetOutputStreamInfo 메서드에서 MFT_OUTPUT_STREAM_INFO 구조체에서 MFT_OUTPUT_STREAM_PROVIDES_SAMPLES 플래그를 설정합니다. 이 플래그는 미디어 세션에 MFT가 자체 출력 샘플을 할당한다는 것을 알 수 있습니다.

표면을 만들려면 IDirectXVideoAccelerationService::CreateSurface를 호출합니다. ( IDirectXVideoDecoderService 인터페이스는 IDirectXVideoAccelerationService에서 이 메서드를 상속합니다.) 렌더링 대상 형식을 찾은 후 SetInputType에서 이 작업을 수행할 수 있습니다.

각 표면에 대해 MFCreateVideoSampleFromSurface 를 호출하여 표면을 보관할 미디어 샘플을 만듭니다. 메서드는 IMFSample 인터페이스에 대한 포인터를 반환합니다.

디코딩

디코더 디바이스를 만들려면 IDirectXVideoDecoderService::CreateVideoDecoder를 호출합니다. 메서드는 디코더 디바이스의 IDirectXVideoDecoder 인터페이스에 대한 포인터를 반환합니다.

디코딩은 IMFTransform::P rocessOutput 메서드 내에서 발생해야 합니다. 각 프레임에서 IDirect3DDeviceManager9::TestDevice 를 호출하여 디바이스 핸들을 테스트합니다. 디바이스가 변경된 경우 메서드는 DXVA2_E_NEW_VIDEO_DEVICE 반환합니다. 이 경우 다음을 수행합니다.

  1. IDirect3DDeviceManager9::CloseDeviceHandle을 호출하여 디바이스 핸들을 닫습니다.
  2. IDirectXVideoDecoderServiceIDirectXVideoDecoder 포인터를 해제합니다.
  3. 새 디바이스 핸들을 엽니다.
  4. 이 페이지의 앞부분에 있는 "디코더 구성 찾기"에 설명된 대로 새 디코더 구성을 협상합니다.
  5. 새 디코더 디바이스를 만듭니다.

디바이스 핸들이 유효하다고 가정하면 디코딩 프로세스는 다음과 같이 작동합니다.

  1. 현재 사용되지 않는 사용 가능한 표면을 가져옵니다. (처음에는 모든 표면을 사용할 수 있습니다.)
  2. IMFTrackedSample 인터페이스에 대한 미디어 샘플을 쿼리합니다.
  3. IMFTrackedSample::SetAllocator를 호출하고 디코더에 의해 구현된 IMFAsyncCallback 인터페이스에 대한 포인터를 제공합니다. 비디오 렌더러가 샘플을 해제하면 디코더의 콜백이 호출됩니다.
  4. IDirectXVideoDecoder::BeginFrame을 호출합니다.
  5. 다음을 하나 이상 수행합니다.
    1. IDirectXVideoDecoder::GetBuffer를 호출하여 DXVA 디코더 버퍼를 가져옵니다.
    2. 버퍼를 채웁니다.
    3. IDirectXVideoDecoder::ReleaseBuffer를 호출합니다.
    4. IDirectXVideoDecoder::Execute를 호출하여 프레임에서 디코딩 작업을 수행합니다.

DXVA 2.0은 디코딩 작업에 DXVA 1.0과 동일한 데이터 구조를 사용합니다. 원래 DXVA 프로필 집합(H.261, H.263 및 MPEG-2의 경우)의 경우 이러한 데이터 구조는 DXVA 1.0 사양에 설명되어 있습니다.

BeginFrame/Execute 호출의 각 쌍 내에서 GetBuffer를 여러 번 호출할 수 있지만 각 유형의 DXVA 버퍼에 대해 한 번만 호출할 수 있습니다. 동일한 버퍼 형식으로 두 번 호출하는 경우 데이터를 덮어씁 수 있습니다.

SetAllocator 메서드(3단계)의 콜백을 사용하여 현재 사용할 수 있는 샘플과 사용 중인 샘플을 추적합니다.

DirectX 비디오 가속 2.0

Media Foundation 변환