Share via


在媒體基礎中支援 Direct3D 11 視訊解碼

本主題描述如何在 Microsoft Media Foundation 解碼器中支援 Microsoft Direct3D 11。 具體來說,它會描述解碼器和視訊轉譯器之間的通訊。 本主題不會描述如何實作解碼作業。

概觀

本主題的其餘部分會使用下列詞彙:

  • 軟體解碼器 。 軟體解碼器是媒體基礎轉換 (MFT),可接收壓縮的視訊樣本,並輸出未壓縮的視訊畫面。
  • 解碼器裝置 。 解碼器裝置是視訊加速器,並由圖形驅動程式實作。 解碼器裝置會執行加速解碼作業。
  • 準銷售案源。 管線會裝載軟體解碼器,並從軟體解碼器來回傳遞緩衝區。 視應用程式而定,管線可能是直接呼叫 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.

以下是軟體解碼器在媒體基礎中必須執行以支援 Direct3D 11 的基本步驟:

  1. 開啟 Direct3D 11 裝置的控制碼。
  2. 尋找解碼器組態。
  3. 配置未壓縮的緩衝區。
  4. 解碼框架。

本主題其餘部分將詳細說明這些步驟。

開啟裝置控制碼

解碼器 MFT 會使用 DXGI 裝置管理員來取得 Direct3D 11 裝置的控制碼。 若要開啟裝置控制碼,請執行下列步驟:

  1. 解碼器 MFT 必須公開 值為 TRUE 的 MF_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_IDCT D3D11_DECODER_PROFILE_MPEG2_VLD
  5. 如果找到適當的解碼器 GUID,請呼叫 ID3D11VideoDevice::CheckVideoDecoderFormat 方法來檢查輸出格式。 傳入解碼器 GUID 和指定 轉譯目標格式DXGI_FORMAT 值。
  6. 接下來,尋找適合解碼器的組態。
    1. 呼叫 ID3D11VideoDevice::GetVideoDecoderConfigCount 以取得解碼器組態的數目。 傳入相同的解碼器裝置 GUID,以及 描述所建議轉譯目標格式的 D3D11_VIDEO_DECODER_DESC結構。
    2. 呼叫 ID3D11VideoDevice::GetVideoDecoderConfig 以列舉解碼器組態。

在 IMFTransform::GetOutputAvailableType 方法中 ,根據建議的轉譯目標格式傳回未壓縮的視訊格式。

IMFTransform::SetOutputType 方法中,根據轉譯目標格式檢查媒體類型。

軟體解碼的後援

MFT 可能找不到組態。 例如,圖形驅動程式可能不支援正確的功能。 在此情況下,MFT 必須回復為軟體解碼,如下所示。

  1. SetInputType 和 SetOutputType 方法應該都會傳回 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 設定 為等於解碼器所需的表面數目。 這包括:

    • 參考框架的介面。
    • 用於除交的介面(三個表面)。
    • 解碼器需要緩衝處理的介面。

    系結旗標 ( 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. 釋放與先前 Direct3D 11 裝置相關聯的所有資源,包括 ID3D11VideoDecoder、ID3D11VideoContextID3D11Texture2D ID3D11VideoDecoderOutputView 介面。
  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 規格描述。

在每個 DecoderBeginFrame SubmitDecoderBuffer 呼叫中,您可以多次呼叫 GetDecoderBuffer,但每個緩衝區類型只能呼叫一次。 如果您在不呼叫 SubmitDecoderBuffer 的情況下使用相同的緩衝區類型兩次,則會覆寫緩衝區中的數據。

Direct3D 11 影片 API

DirectX 影片加速 2.0