Media Foundation에서 Direct3D 11 비디오 디코딩 지원

이 항목에서는 Microsoft Media Foundation 디코더에서 Microsoft Direct3D 11을 지원하는 방법을 설명합니다. 특히 디코더와 비디오 렌더러 간의 통신을 설명합니다. 이 항목에서는 디코딩 작업을 구현하는 방법을 설명하지 않습니다.

개요

이 항목의 re기본der에서 다음 용어가 사용됩니다.

  • 소프트웨어 디코더. 소프트웨어 디코더는 압축된 비디오 샘플을 수신하고 압축되지 않은 비디오 프레임을 출력하는 MFT(Media Foundation 변환)입니다.
  • 디코더 디바이스. 디코더 디바이스는 비디오 가속기이며 그래픽 드라이버에 의해 구현됩니다. 디코더 디바이스는 가속 디코딩 작업을 수행합니다.
  • 파이프라인. 파이프라인은 소프트웨어 디코더를 호스트하고 소프트웨어 디코더와 버퍼를 전달합니다. 애플리케이션에 따라 파이프라인은 MFT에 직접 호출하는 미디어 세션, 원본 판독기 또는 애플리케이션 코드일 수 있습니다.

Direct3D 11을 사용하여 디코딩을 수행하려면 소프트웨어 디코더에 Direct3D 11 디바이스에 대한 포인터가 있어야 합니다. Direct3D 11 디바이스는 소프트웨어 디코더 외부에 만들어집니다. 미디어 세션 시나리오에서 비디오 렌더러는 Direct3D 11 디바이스를 만듭니다. 원본 판독기 시나리오에서 애플리케이션은 일반적으로 Direct3D 11 디바이스를 만듭니다.

DXGI 장치 관리자 구성 요소 간에 Direct3D 11을 공유하는 데 사용됩니다. DXGI 장치 관리자 IMFDXGIDeviceManager 인터페이스를 노출합니다. 파이프라인은 MFT_MESSAGE_SET_D3D_MANAGER 메시지를 전송하여 소프트웨어 디코더에 대한 IMFDXGIDeviceManager 포인터를 설정합니다.

다음 다이어그램은 소프트웨어 디코더, Direct3D 11 및 파이프라인 간의 관계를 보여줍니다.

a diagram that shows the software decoder and the dxgi device manager.

Media Foundation에서 Direct3D 11을 지원하기 위해 소프트웨어 디코더가 수행해야 하는 기본 단계는 다음과 같습니다.

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

이러한 단계는 이 항목의 re기본der에 자세히 설명되어 있습니다.

디바이스 핸들 열기

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

  1. 디코더 MFT는 값이 TRUEMF_SA_D3D11_AWARE 특성을 노출해야 합니다.
  2. 토폴로지 로더는 IMFTransform::GetAttributes를 호출 하여 이 특성을 쿼리합니다. TRUE은 MFT가 Direct3D 11을 지원한다는 것을 나타냅니다.
  3. 토폴로지 로더는 MFT_MESSAGE_SET_D3D_MANAGER 메시지를 사용하여 IMFTransform::P rocessMessage 호출합니다. ulParam 매개 변수는 DXGI 디바이스 관리자에 대한 IUnknown 포인터입니다. IMFDXGIDeviceManager 인터페이스에 대해 이 포인터를 쿼리합니다.
  4. IMFDXGIDeviceManager::OpenDeviceHandle을 호출하여 Direct3D 11 디바이스에 대한 핸들을 가져옵니다.
  5. Direct3D 11 디바이스에 대한 포인터를 얻으려면 IMFDXGIDeviceManager::GetVideoService를 호출 합니다. 디바이스 핸들과 IID_ID3D11Device 값을 전달합니다. 이 메서드는 ID3D11Device 인터페이스에 대한 포인터를 반환합니다.
  6. 비디오 가속기에 대한 포인터를 얻으려면 IMFDXGIDeviceManager::GetVideoService를 다시 호출합니다. 이번에는 디바이스 핸들과 IID_ID3D11VideoDevice 값을 전달합니다. 이 메서드는 ID3D11VideoDevice 인터페이스에 대한 포인터를 반환합니다.
  7. ID3D11Device::GetImmediateContext를 호출하여 ID3D11DeviceContext 포인터를 가져옵니다.
  8. ID3D11DeviceContext에서 QueryInterface를 호출하여 ID3D11VideoContext 포인터를 가져옵니다.
  9. 디바이스 컨텍스트에서 다중 스레드 보호를 사용하여 ID3D11VideoContext::GetDecoderBuffer 또는 ID3D11VideoContext::ReleaseDecoderBuffer를 호출할 때 발생할 수 있는 교착 상태 문제를 방지하는 것이 좋습니다. 다중 스레드 보호를 설정하려면 먼저 ID3D11Device에서 QueryInterface를 호출하여 ID3D10Multithread 포인터를 가져옵니다. 그런 다음, ID3D10Multithread::SetMultithreadProtected를 호출하고 bMTProtect대해 true전달합니다.

디코더 구성 찾기

디코딩을 수행하려면 소프트웨어 디코더가 렌더링 대상 형식을 포함하여 디코더 디바이스에서 지원하는 호환되는 구성을 찾아야 합니다. 이 단계는 다음과 같이 IMFTransform::SetInputType 메서드 내에서 발생합니다.

  1. 입력 미디어 형식의 유효성을 검사합니다. 형식이 거부되면 다시 기본 단계를 건너뛰고 오류 코드를 반환합니다.
  2. ID3D11VideoDevice::GetVideoDecoderProfileCount를 호출하여 지원되는 프로필 수를 가져옵니다.
  3. ID3D11VideoDevice::GetVideoDecoderProfile을 호출하여 프로필을 열거하고 프로필 GUID를 가져옵니다.
  4. 비디오 형식 및 소프트웨어 디코더의 기능과 일치하는 프로필 GUID를 찾습니다. 예를 들어 MPEG-2 디코더는 D3D11_DECODER_PROFILE_MPEG2_MOCOMP, D3D11_DECODER_PROFILE_MPEG2_IDCTD3D11_DECODER_PROFILE_MPEG2_VLD습니다.
  5. 적절한 디코더 GUID가 발견되면 ID3D11VideoDevice::CheckVideoDecoderFormat 메서드를 호출하여 출력 형식을 검사. 렌더링 대상 형식을 지정하는 디코더 GUID 및 DXGI_FORMAT 값을 전달합니다.
  6. 다음으로 디코더에 적합한 구성을 찾습니다.
    1. ID3D11VideoDevice::GetVideoDecoderConfigCount를 호출하여 디코더 구성 수를 가져옵니다. 제안된 렌더링 대상 형식을 설명하는 D3D11_VIDEO_DECODER_DESC 구조와 함께 동일한 디코더 디바이스 GUID를 전달합니다.
    2. ID3D11VideoDevice::GetVideoDecoderConfig를 호출하여 디코더 구성을 열거합니다.

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

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

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

MFT에서 구성을 찾을 수 없을 수 있습니다. 예를 들어 그래픽 드라이버는 올바른 기능을 지원하지 않을 수 있습니다. 이 경우 MFT는 다음과 같이 소프트웨어 디코딩으로 대체해야 합니다.

  1. SetInputTypeSetOutputType 메서드는 모두 MF_E_UNSUPPORTED_D3D_TYPE 반환해야 합니다.
  2. 이에 대한 응답으로 토폴로지 로더는 ulParam 매개 변수에 대한 NULL과 함께 MFT_MESSAGE_SET_D3D_MANAGER 메시지를 보냅니다.
  3. MFT는 IMFDXGIDeviceManager 인터페이스에 대한 포인터를 해제합니다.
  4. 토폴로지 로더는 미디어 형식을 재협상합니다.

이 시점에서 MFT는 소프트웨어 디코딩을 사용할 수 있습니다.

압축되지 않은 버퍼 할당

디코더는 압축되지 않은 비디오 버퍼로 사용하도록 Direct3D 11 텍스처를 할당합니다. 출력 스트림 특성의 MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT 특성(IMFTransform::GetOutputStreamAttributes 참조)은 디코더가 탈인터레이싱에 사용할 비디오 렌더러에 할당해야 하는 표면 수를 결정하는 데 사용됩니다. 디코더는 이 값을 사용하여 적절한 상한 및 하한(예: 3-32)에 대해 경계를 지정해야 합니다. 점진적 콘텐츠는 MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT_PROGRESSIVE 참조하세요.

IMFTransform::GetOutputStreamInfo 메서드에서 MFT_OUTPUT_STREAM_INFO 구조에서 MFT_OUTPUT_STREAM_PROVIDES_SAMPLES 플래그를 설정합니다. 이 플래그는 MFT가 자체 출력 샘플을 할당한다는 것을 미디어 세션에 알깁니다. 출력 샘플을 할당하기 위해 MFT는 다음 단계를 수행합니다.

  1. ID3D11Device::CreateTexture2D를 호출 하여 2D 텍스처 배열을 만듭니다. D3D11_TEXTURE2D_DESC 구조체에서 ArraySize를 디코더에 필요한 표면 수와 동일하게 설정합니다. 다음 내용이 포함됩니다.

    • 참조 프레임의 표면입니다.
    • 디인터레이싱을 위한 표면(3개 표면).
    • 디코더가 버퍼링에 필요한 표면입니다.

    바인딩 플래그(BindFlags)에는 D3D11_BIND_DECODER 플래그와 출력 스트림 특성의 MF_SA_D3D11_BINDFLAGS 특성을 통해 설정된 모든 바인딩 플래그가 포함되어야 합니다.

  2. 텍스처 배열의 각 표면에 대해 ID3D11VideoDevice::CreateVideoDecoderOutputView를 호출하여 비디오 디코더 출력 뷰를 만듭니다. 디코딩하는 동안 이러한 출력 뷰는 ID3D11VideoContext::D ecoderBeginFrame 메서드에 전달됩니다.

  3. 텍스처 배열의 각 표면에 대해 다음과 같이 미디어 샘플을 만듭니다.

    1. MFCreateDXGISurfaceBuffer 함수를 호출하여 DXGI 미디어 버퍼를 만듭니다. 텍스처 배열의 각 요소에 대한 ID3D11Texture2D 포인터 및 오프셋을 전달합니다. 이 함수는 IMFMediaBuffer 포인터를 반환합니다.
    2. MFCreateVideoSampleFromSurface 함수를 호출하여 빈 미디어 샘플을 만듭니다. pUnkSurface 매개 변수를 NULL동일하게 설정합니다. 이 함수는 IMFSample 포인터를 반환합니다.
    3. IMFSample::AddBuffer를 호출하여 샘플에 미디어 버퍼를 추가합니다.

일부만 삭제하고 미리 알림을 계속 사용하는 대신 만드는 모든 텍스처를 동시에 삭제해야 합니다.

디코딩

디코더 디바이스를 만들려면 ID3D11VideoDevice::CreateVideoDecoder를 호출 합니다. 이 메서드는 ID3D11VideoDecoder 인터페이스에 대한 포인터 반환합니다. 디코딩은 IMFTransform::P rocessOutput 메서드 내에서 발생해야 합니다. 각 프레임에서 IMFDXGIDeviceManager::TestDevice를 호출하여 DXGI의 가용성을 테스트합니다. 디바이스가 변경된 경우 소프트웨어 디코더는 다음과 같이 디코더 디바이스를 다시 만들어야 합니다.

  1. IMFDXGIDeviceManager::CloseDeviceHandle을 호출 하여 디바이스 핸들을 닫습니다.
  2. ID3D11VideoDecoder, ID3D11VideoContext, ID3D11Texture2D 및 ID3D11VideoDecoderOutputView 인터페이스를 포함하여 이전 Direct3D 11 디바이스와 연결된 모든 리소스를 해제합니다.
  3. 새 디바이스 핸들을 엽니다.
  4. 디코더 구성 찾기에서 이전에 설명한 대로 새 디코더 구성을 협상합니다. 디바이스 기능이 변경되었을 수 있으므로 이 단계가 필요합니다.
  5. 새 디코더 디바이스를 만듭니다.

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

  1. 현재 사용되지 않는 사용 가능한 표면을 가져옵니다. 처음에는 모든 표면을 사용할 수 있습니다.
  2. IMFTrackedSample 인터페이스에 대한 미디어 샘플을 쿼리합니다.
  3. IMFTrackedSample::SetAllocator를 호출하고 IMFAsyncCallback 인터페이스에 대한 포인터를 제공합니다. (소프트웨어 디코더는 이 인터페이스를 구현해야 합니다.) 비디오 렌더러가 샘플을 해제하면 콜백이 호출됩니다. 이 콜백을 사용하여 현재 사용할 수 있는 샘플과 사용 중인 샘플을 추적합니다.
  4. ID3D11VideoContext::D ecoderBeginFrame을 호출 합니다. 디코더 디바이스의 ID3D11VideoDecoder 인터페이스 및 출력 뷰에 대한 ID3D11VideoDecoderOutputView 인터페이스에 대한 포인터를 전달합니다.
  5. 다음을 하나 이상 수행합니다.
    1. ID3D11VideoContext::GetDecoderBuffer를 호출하여 버퍼를 가져옵니다.
    2. 버퍼를 채웁니다.
    3. ID3D11VideoContext::ReleaseDecoderBuffer를 호출 합니다.
    4. ID3D11VideoContext::SubmitDecoderBuffer를 호출 합니다. 이 메서드는 디코더 디바이스가 프레임에서 디코딩 작업을 수행하도록 지시합니다.
  6. ID3D11VideoContext::D ecoderEndFrame을 호출하여 현재 프레임에 대한 디코딩 종료 신호를 보냅니다.

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

각 DecoderBeginFrameSubmitDecoderBuffer 호출 쌍 내에서 GetDecoderBuffer를 여러 번 호출할 수 있지만 각 버퍼 유형에 대해 한 번만 호출할 수 있습니다. SubmitDecoderBuffer를 호출하지 않고 동일한 버퍼 형식을 두 번 사용하는 경우 버퍼의 데이터를 덮어씁니다.

Direct3D 11 비디오 API

DirectX 비디오 가속 2.0