Поделиться через


Настройка кодировщика WMV

Чтобы создать допустимый тип вывода для кодировщика Windows Media Video (WMV), необходимо иметь следующие сведения:

  • Формат несжатого видео, который вы будете кодировать.
  • Подтип видео, который повторяет закодированный формат WMV. См. раздел Идентификаторы GUID подтипа видео.
  • Целевая скорость для закодированного потока.
  • Свойства конфигурации, устанавливаемые в кодировщике.

Свойства конфигурации описаны в документации по API аудио- и видеокодека Windows Media и DSP. Дополнительные сведения см. в разделе "Свойства видеопотока" статьи Свойства кодирования.

Чтобы получить допустимый тип вывода для кодировщика, выполните следующие действия.

  1. Используйте функцию MFTEnum или MFTEnumEx для создания экземпляра кодировщика.

  2. Запрос кодировщика для интерфейса IPropertyStore .

  3. Используйте интерфейс IPropertyStore для настройки кодировщика.

  4. Вызовите IMFTransform::SetInputType , чтобы задать несжатый тип видео в кодировщике.

  5. Вызовите IMFTransform::GetOutputAvailableType , чтобы получить список форматов сжатия из кодировщика. Кодировщики WMV не возвращают полный тип носителя из этого метода. В типах мультимедиа отсутствуют два элемента информации:

    • Целевая скорость.
    • Частные данные кодека из кодировщика.

    Прежде чем задавать тип вывода в кодировщике, необходимо добавить оба этих элемента в тип носителя.

  6. Чтобы указать целевую скорость, задайте атрибут MF_MT_AVG_BITRATE для типа носителя.

  7. Добавьте данные частного кодека в тип носителя, как описано в следующем разделе.

  8. Вызовите IMFTransform::SetOutputType , чтобы задать тип носителя сжатия в кодировщике.

Частные данные кодека

Частные данные кодека — это непрозрачная структура данных, которую необходимо получить из кодировщика WMV и добавить в тип сжатия, прежде чем задавать тип сжатия в кодировщике. Чтобы получить личные данные, необходимо использовать интерфейс IWMCodecPrivateData , который описан в пакете SDK для Windows Media Format 11.

Чтобы получить данные частного кодека, выполните следующие действия.

  1. Вызовите IMFTransform::GetOutputAvailableType , чтобы получить тип мультимедиа из кодировщика. (Это шаг 6 из предыдущего раздела.)
  2. Укажите целевую скорость, задав атрибут MF_MT_AVG_BITRATE для типа носителя.
  3. Преобразуйте тип мультимедиа в структуру DMO_MEDIA_TYPE путем вызова функции MFInitAMMediaTypeFromMFMediaType .
  4. Запрос кодировщика для интерфейса IWMCodecPrivateData .
  5. Вызовите метод IWMCodecPrivateData::SetPartialOutputType , передав преобразованную структуру DMO_MEDIA_TYPE .
  6. Вызовите метод IWMCodecPrivateData::GetPrivateData дважды, один раз, чтобы получить размер буфера для частных данных, и один раз, чтобы скопировать данные в буфер.
  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