WMV エンコーダーの構成
Windows Media Video (WMV) エンコーダーの有効な出力の種類を作成するには、次の情報が必要です。
- エンコードする圧縮されていないビデオの形式。
- エンコードされた WMV 形式を表すビデオ サブタイプ。 「ビデオ サブタイプ GUID」を参照してください。
- エンコードされたストリームのターゲット ビットレート。
- エンコーダーで設定する構成プロパティ。
構成プロパティは、Windows Media Audio and Video Codec および DSP API のドキュメントに記載されています。 詳細については、「 エンコード プロパティ」の「Video Stream プロパティ」を参照してください。
エンコーダーの有効な出力の種類を取得するには、次の手順を実行します。
エンコーダーに IPropertyStore インターフェイスのクエリを実行します。
IPropertyStore インターフェイスを使用してエンコーダーを構成します。
IMFTransform::SetInputType を呼び出して、エンコーダーで圧縮されていないビデオの種類を設定します。
IMFTransform::GetOutputAvailableType を呼び出して、エンコーダーから圧縮形式の一覧を取得します。 WMV エンコーダーは、このメソッドから完全なメディアの種類を返しません。 メディアの種類には、次の 2 つの情報がありません。
- ターゲット ビットレート。
- エンコーダーからのプライベート コーデック データ。
エンコーダーで出力の種類を設定する前に、これらの両方の項目をメディアの種類に追加する必要があります。
ターゲット ビットレートを指定するには、メディア の種類に MF_MT_AVG_BITRATE 属性を設定します。
次のセクションで説明するように、メディアの種類にプライベート コーデック データを追加します。
IMFTransform::SetOutputType を呼び出して、エンコーダーで圧縮メディアの種類を設定します。
プライベート コーデック データ
プライベート コーデック データは不透明なデータ構造であり、エンコーダーで圧縮の種類を設定する前に、WMV エンコーダーから取得し、圧縮の種類に追加する必要があります。 プライベート データを取得するには、Windows Media Format 11 SDK に記載されている IWMCodecPrivateData インターフェイスを使用する必要があります。
プライベート コーデック データを取得するには、次の手順を実行します。
- IMFTransform::GetOutputAvailableType を呼び出して、エンコーダーからメディアの種類を取得します。 (これは前のセクションの手順 6 です)。
- メディアの種類に MF_MT_AVG_BITRATE 属性を設定して、ターゲット ビットレートを指定します。
- MFInitAMMediaTypeFromMFMediaType 関数を呼び出して、メディアの種類をDMO_MEDIA_TYPE構造体に変換します。
- IWMCodecPrivateData インターフェイスのエンコーダーに対してクエリを実行します。
- 変換されたDMO_MEDIA_TYPE構造体を渡して、IWMCodecPrivateData::SetPartialOutputType メソッドを呼び出します。
- IWMCodecPrivateData::GetPrivateData メソッドを 2 回呼び出し、1 回はプライベート データのバッファーのサイズを取得し、1 回はデータをバッファーにコピーします。
- 種類に 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;
}
関連トピック