Настройка кодировщика WMV
Чтобы создать допустимый тип вывода для кодировщика видео Windows Media (WMV), необходимо иметь следующие сведения:
- Формат несжатого видео, который вы закодируете.
- Подтип видео, который представляет кодированный формат WMV. См. GUID'ы подтипов видео .
- Целевая скорость для закодированного потока.
- Свойства конфигурации, заданные в кодировщике.
Свойства конфигурации описаны в документации по API аудио и видеокодека Windows Media и DSP. Дополнительные сведения см. в разделе "Свойства видеопотока" в свойства кодировки.
Чтобы получить допустимый тип вывода для кодировщика, выполните следующие действия.
Чтобы создать экземпляр кодировщика, используйте функцию MFTEnum или MFTEnumEx.
Запрос кодировщика для интерфейса IPropertyStore.
Используйте интерфейс IPropertyStore для настройки кодировщика.
Вызовите IMFTransform::SetInputType, чтобы задать несжатый тип видео в кодировщике.
Вызовите IMFTransform::GetOutputAvailableType, чтобы получить список форматов сжатия из кодировщика. Кодировщики WMV не возвращают полный тип носителя из этого метода. Информация о типах носителей отсутствует в двух частях.
- Целевой битрейт.
- Приватные данные кодека из кодировщика.
Прежде чем задать тип выходных данных в кодировщике, необходимо добавить оба этих элемента в тип носителя.
Чтобы указать целевую скорость, задайте атрибут MF_MT_AVG_BITRATE для типа носителя.
Добавьте данные частного кодека в тип носителя, как описано в следующем разделе.
Вызовите IMFTransform::SetOutputType, чтобы задать тип носителя сжатия в кодировщике.
Данные частного кодека
Данные частного кодека — это непрозрачная структура данных, которую необходимо получить из кодировщика WMV и добавить в тип сжатия, прежде чем задать тип сжатия для кодировщика. Чтобы получить частные данные, необходимо использовать интерфейс IWMCodecPrivateData, который задокументирован в пакете SDK для Формата Windows Media 11.
Чтобы получить данные частного кодека, выполните следующие действия.
- Вызовите IMFTransform::GetOutputAvailableType, чтобы получить тип носителя из кодировщика. (Это шаг 6 из предыдущего раздела.)
- Укажите целевую скорость, задав атрибут MF_MT_AVG_BITRATE для типа носителя.
- Преобразуйте тип носителя в структуру DMO_MEDIA_TYPE, вызвав функцию MFInitAMMediaTypeFromMFMediaType с помощью .
- Запрос кодировщика для интерфейса IWMCodecPrivateData.
- Вызовите метод IWMCodecPrivateData::SetPartialOutputType, передавая преобразованную структуру DMO_MEDIA_TYPE.
- Вызовите метод IWMCodecPrivateData::GetPrivateData дважды, чтобы получить размер буфера для частных данных и один раз скопировать данные в буфер.
- Добавьте частные данные в тип носителя, задав атрибут 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;
}
Связанные разделы