Share via


WMV エンコーダーの構成

Windows Media Video (WMV) エンコーダーの有効な出力の種類を作成するには、次の情報が必要です。

  • エンコードする圧縮されていないビデオの形式。
  • エンコードされた WMV 形式を表すビデオ サブタイプ。 「ビデオ サブタイプ GUID」を参照してください。
  • エンコードされたストリームのターゲット ビットレート。
  • エンコーダーで設定する構成プロパティ。

構成プロパティは、Windows Media Audio and Video Codec および DSP API のドキュメントに記載されています。 詳細については、「 エンコード プロパティ」の「Video Stream プロパティ」を参照してください。

エンコーダーの有効な出力の種類を取得するには、次の手順を実行します。

  1. エンコーダーのインスタンスを作成するには、 MFTEnum または MFTEnumEx 関数を使用します。

  2. エンコーダーに IPropertyStore インターフェイスのクエリを実行します。

  3. IPropertyStore インターフェイスを使用してエンコーダーを構成します。

  4. IMFTransform::SetInputType を呼び出して、エンコーダーで圧縮されていないビデオの種類を設定します。

  5. IMFTransform::GetOutputAvailableType を呼び出して、エンコーダーから圧縮形式の一覧を取得します。 WMV エンコーダーは、このメソッドから完全なメディアの種類を返しません。 メディアの種類には、次の 2 つの情報がありません。

    • ターゲット ビットレート。
    • エンコーダーからのプライベート コーデック データ。

    エンコーダーで出力の種類を設定する前に、これらの両方の項目をメディアの種類に追加する必要があります。

  6. ターゲット ビットレートを指定するには、メディア の種類に MF_MT_AVG_BITRATE 属性を設定します。

  7. 次のセクションで説明するように、メディアの種類にプライベート コーデック データを追加します。

  8. IMFTransform::SetOutputType を呼び出して、エンコーダーで圧縮メディアの種類を設定します。

プライベート コーデック データ

プライベート コーデック データは不透明なデータ構造であり、エンコーダーで圧縮の種類を設定する前に、WMV エンコーダーから取得し、圧縮の種類に追加する必要があります。 プライベート データを取得するには、Windows Media Format 11 SDK に記載されている IWMCodecPrivateData インターフェイスを使用する必要があります。

プライベート コーデック データを取得するには、次の手順を実行します。

  1. IMFTransform::GetOutputAvailableType を呼び出して、エンコーダーからメディアの種類を取得します。 (これは前のセクションの手順 6 です)。
  2. メディアの種類に MF_MT_AVG_BITRATE 属性を設定して、ターゲット ビットレートを指定します。
  3. MFInitAMMediaTypeFromMFMediaType 関数を呼び出して、メディアの種類をDMO_MEDIA_TYPE構造体に変換します。
  4. IWMCodecPrivateData インターフェイスのエンコーダーに対してクエリを実行します。
  5. 変換されたDMO_MEDIA_TYPE構造体を渡して、IWMCodecPrivateData::SetPartialOutputType メソッドを呼び出します。
  6. IWMCodecPrivateData::GetPrivateData メソッドを 2 回呼び出し、1 回はプライベート データのバッファーのサイズを取得し、1 回はデータをバッファーにコピーします。
  7. 種類に MF_MT_USER_DATA 属性を設定して、メディアの種類にプライベート データを追加します。

次の拡張例は、圧縮されていないビデオの種類から WMV 圧縮形式を作成する方法を示しています。

#include <wmcodecdsp.h>
#include <Wmsdk.h>
#include <Dmo.h>
#include <mfapi.h>
#include <uuids.h>

#include <mfidl.h>
#include <mftransform.h>
#include <mferror.h>

#pragma comment(lib, "Msdmo")
#pragma comment(lib, "mfplat")
#pragma comment(lib, "mfuuid")
#pragma comment(lib, "strmiids")
#pragma comment(lib, "propsys")

HRESULT GetEncodedVideoType(
    IMFMediaType *pTypeIn, 
    REFGUID subtype,
    UINT32 TargetBitrate, 
    IPropertyStore *pEncoderProps, 
    IMFMediaType **ppEncodingType,
    DWORD mftEnumFlags = MFT_ENUM_FLAG_SYNCMFT
    );

HRESULT CreateVideoEncoder(REFGUID subtype, DWORD mftEnumFlags, IMFTransform **ppMFT);
HRESULT AddPrivateData(IMFTransform *pMFT, IMFMediaType *pTypeOut);
HRESULT CopyPropertyStore(IPropertyStore *pSrc, IPropertyStore *pDest);

//
// GetEncodedVideoType
// Given an uncompressed video type, finds a suitable WMV type.
//

HRESULT GetEncodedVideoType(
    IMFMediaType *pTypeIn,          // Uncompressed format
    REFGUID subtype,                // Compression format
    UINT32 TargetBitrate,           // Target bit rate
    IPropertyStore *pEncoderProps,  // Encoder properties (can be NULL)
    IMFMediaType **ppEncodingType,  // Receives the WMV type.
    DWORD mftEnumFlags              // MFTEnumEx flags
    )
{
    HRESULT hr = S_OK;

    IMFTransform *pMFT = NULL;
    IPropertyStore *pPropStore = NULL;
    IMFMediaType *pTypeOut = NULL;

    // Instantiate the encoder
    hr = CreateVideoEncoder(subtype, mftEnumFlags, &pMFT);

    // Copy the properties to the encoder.

    if (SUCCEEDED(hr))
    {
        if (pEncoderProps)
        {
            hr = pMFT->QueryInterface(IID_PPV_ARGS(&pPropStore));

            if (SUCCEEDED(hr))
            {
                hr = CopyPropertyStore(pEncoderProps, pPropStore);
            }
        }
    }

    // Set the uncompressed type.
    if (SUCCEEDED(hr))
    {
        hr = pMFT->SetInputType(0, pTypeIn, 0);
    }

    // Get the partial output type
    if (SUCCEEDED(hr))
    {
        hr = pMFT->GetOutputAvailableType(0, 0, &pTypeOut);
    }

    // Set the bit rate.
    // You must set this before getting the codec private data.

    if (SUCCEEDED(hr))
    {
        hr = pTypeOut->SetUINT32(MF_MT_AVG_BITRATE, TargetBitrate);   
    }

    if (SUCCEEDED(hr))
    {
        hr = AddPrivateData(pMFT, pTypeOut);
    }

    if (SUCCEEDED(hr))
    {
        hr = pMFT->SetOutputType(0, pTypeOut, 0);
    }

    if (SUCCEEDED(hr))
    {
        *ppEncodingType = pTypeOut;
        (*ppEncodingType)->AddRef();
    }

    SafeRelease(&pMFT);
    SafeRelease(&pPropStore);
    SafeRelease(&pTypeOut);
    return hr;
}

CreateVideoEncoder 関数は、指定したビデオ サブタイプのビデオ エンコーダーを作成します( 例: MFVideoFormat_WMV3)。

//
// CreateVideoEncoder
// Creates a video encoder for a specified video subtype.
//

HRESULT CreateVideoEncoder(
    REFGUID subtype,            // Encoding subtype.
    DWORD mftEnumFlags,         // Flags for MFTEnumEx
    IMFTransform **ppMFT        // Receives a pointer to the encoder.
    )
{
    HRESULT hr = S_OK;
    IMFTransform *pMFT = NULL;

    MFT_REGISTER_TYPE_INFO info;
    info.guidMajorType = MFMediaType_Video;
    info.guidSubtype = subtype;

    IMFActivate **ppActivates = NULL;    
    UINT32 count = 0;

    hr = MFTEnumEx(
        MFT_CATEGORY_VIDEO_ENCODER,
        mftEnumFlags | MFT_ENUM_FLAG_SORTANDFILTER,
        NULL,
        &info,
        &ppActivates,
        &count
        );

    if (count == 0)
    {
        hr = E_FAIL;
    }

    if (SUCCEEDED(hr))
    {
        hr = ppActivates[0]->ActivateObject(
            __uuidof(IMFTransform),
            (void**)&pMFT
            );
    }

    if (SUCCEEDED(hr))
    {
        *ppMFT = pMFT;
        (*ppMFT)->AddRef();
    }

    // Clean up

    for (DWORD i = 0; i < count; i++)
    {
        ppActivates[i]->Release();
    }
    CoTaskMemFree(ppActivates);
    SafeRelease(&pMFT);
    return hr;
}

AddPrivateData 関数は、圧縮の種類にプライベート コーデック データを追加します。

//
// AddPrivateData
// Appends the private codec data to a media type.
//
// pMFT: The video encoder
// pTypeOut: A video type from the encoder's type list.
//
// The function modifies pTypeOut by adding the codec data.
//

HRESULT AddPrivateData(IMFTransform *pMFT, IMFMediaType *pTypeOut)
{
    HRESULT hr = S_OK;
    ULONG cbData = 0;
    BYTE *pData = NULL;

    IWMCodecPrivateData *pPrivData = NULL;

    DMO_MEDIA_TYPE mtOut = { 0 };

    // Convert the type to a DMO type.
    hr = MFInitAMMediaTypeFromMFMediaType(
        pTypeOut, 
        FORMAT_VideoInfo, 
        (AM_MEDIA_TYPE*)&mtOut
        );
    
    if (SUCCEEDED(hr))
    {
        hr = pMFT->QueryInterface(IID_PPV_ARGS(&pPrivData));
    }

    if (SUCCEEDED(hr))
    {
        hr = pPrivData->SetPartialOutputType(&mtOut);
    }

    //
    // Get the private codec data
    //

    // First get the buffer size.
    if (SUCCEEDED(hr))
    {
        hr = pPrivData->GetPrivateData(NULL, &cbData);
    }

    if (SUCCEEDED(hr))
    {
        pData = new BYTE[cbData];

        if (pData == NULL)
        {
            hr = E_OUTOFMEMORY;
        }
    }

    // Now get the data.
    if (SUCCEEDED(hr))
    {
        hr = pPrivData->GetPrivateData(pData, &cbData);
    }

    // Add the data to the media type.
    if (SUCCEEDED(hr))
    {
        hr = pTypeOut->SetBlob(MF_MT_USER_DATA, pData, cbData);
    }

    delete [] pData;
    MoFreeMediaType(&mtOut);
    SafeRelease(&pPrivData);
    return hr;
}

CopyPropertyStore 関数は、あるプロパティ ストアから別のプロパティ ストアにプロパティをコピーするヘルパー関数です。

//
// CopyPropertyStore
// Helper function to copy properties from one property
// store to another property store.
//

HRESULT CopyPropertyStore(IPropertyStore *pSrc, IPropertyStore *pDest)
{
    HRESULT hr = S_OK;
    DWORD cProps = 0;

    PROPERTYKEY key;
    PROPVARIANT var;

    PropVariantInit(&var);

    hr = pSrc->GetCount(&cProps);

    if (SUCCEEDED(hr))
    {
        for (DWORD i = 0; i < cProps; i++)
        {
            hr = pSrc->GetAt(i, &key);

            if (FAILED(hr)) { break; }

            hr = pSrc->GetValue(key, &var);

            if (FAILED(hr)) { break; }

            hr = pDest->SetValue(key, var);

            if (FAILED(hr)) { break; }

            PropVariantClear(&var);
        }
    }

    PropVariantClear(&var);
    return hr;
}

エンコーダー MFT のインスタンス化

Windows Media Encoders