Udostępnij za pośrednictwem


Konfigurowanie kodera WMV

Aby utworzyć prawidłowy typ danych wyjściowych dla kodera Windows Media Video (WMV), musisz mieć następujące informacje:

  • Format nieskompresowanego wideo, który zostanie zakodowany.
  • Podtyp wideo, który reprezentuje zakodowany format WMV. Zobacz GUIDy podtypów wideo .
  • Docelowa szybkość transmisji bitów dla zakodowanego strumienia.
  • Właściwości konfiguracji do ustawienia w koderze.

Właściwości konfiguracji są udokumentowane w dokumentacji interfejsów API Windows Media Audio and Video Codec oraz DSP. Aby uzyskać więcej informacji, zobacz "Właściwości strumienia wideo" w Właściwości Kodowania.

Aby uzyskać prawidłowy typ danych wyjściowych dla kodera, wykonaj następujące kroki.

  1. Aby utworzyć wystąpienie kodera, użyj funkcji MFTEnum lub MFTEnumEx.

  2. Wykonaj zapytanie dotyczące interfejsu IPropertyStore.

  3. Aby skonfigurować koder, użyj interfejsu IPropertyStore.

  4. Wywołaj IMFTransform::SetInputType, aby ustawić nieskompresowany typ wideo w koderze.

  5. Wywołaj IMFTransform::GetOutputAvailableType, aby pobrać listę formatów kompresji z enkodera. Koderzy WMV nie zwracają kompletnego typu nośnika z tej metody. Brakuje dwóch informacji dotyczących typów multimediów.

    • Docelowa szybkość transmisji bitów.
    • Prywatne dane kodeka z kodera.

    Przed ustawieniem typu danych wyjściowych w koderze należy dodać oba te elementy do typu nośnika.

  6. Aby określić docelową szybkość transmisji bitów, ustaw atrybut MF_MT_AVG_BITRATE na typ nośnika.

  7. Dodaj prywatne dane kodeka do typu mediów, jak wyjaśniono w następnej sekcji.

  8. Wywołaj IMFTransform::SetOutputType, aby ustawić typ nośnika kompresji w koderze.

Prywatne dane kodeka

Prywatne dane kodeka to nieprzezroczysta struktura danych, którą należy pobrać z kodera WMV i dodać do typu kompresji, zanim ustawisz typ kompresji w koderze. Aby uzyskać dane prywatne, należy użyć interfejsu IWMCodecPrivateData, który jest udokumentowany w zestawie SDK programu Windows Media Format 11.

Aby uzyskać dane kodera prywatnego, wykonaj następujące kroki:

  1. Wywołaj IMFTransform::GetOutputAvailableType, aby pobrać typ nośnika z enkodera. (Jest to krok 6 z poprzedniej sekcji).
  2. Określ docelową szybkość transmisji bitów, ustawiając atrybut MF_MT_AVG_BITRATE w typie nośnika.
  3. Przekonwertuj typ nośnika na strukturę DMO_MEDIA_TYPE, wywołując funkcję MFInitAMMediaTypeFromMFMediaType.
  4. Wykonaj zapytanie względem kodera interfejsu IWMCodecPrivateData.
  5. Wywołaj metodę IWMCodecPrivateData::SetPartialOutputType, przekazując przekonwertowaną strukturę DMO_MEDIA_TYPE.
  6. Wywołaj metodę IWMCodecPrivateData::GetPrivateData dwa razy, raz, aby uzyskać rozmiar buforu dla danych prywatnych, a następnie raz skopiować dane do buforu.
  7. Dodaj dane prywatne do typu multimediów, ustawiając atrybut MF_MT_USER_DATA dla tego typu.

W poniższym rozszerzonym przykładzie pokazano, jak utworzyć format kompresji JPEG na podstawie nieskompresowanego typu wideo:

#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;
}

Funkcja CreateVideoEncoder tworzy koder wideo dla określonego podtypu wideo, takiego jak 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;
}

Funkcja AddPrivateData dodaje prywatne dane kodeka do typu kompresji:

//
// 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;
}

Funkcja CopyPropertyStore to funkcja pomocnika, która kopiuje właściwości z jednego magazynu właściwości do innego:

//
// 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;
}

Tworzenie instancji MFT kodera

Koderów Windows Media