다음을 통해 공유


WMV 인코더 구성

WMV(Windows Media Video) 인코더에 유효한 출력 형식을 만들려면 다음 정보가 있어야 합니다.

  • 인코딩할 압축되지 않은 비디오의 형식입니다.
  • 인코딩된 WMV 형식을 다시 표시하는 비디오 하위 형식입니다. 비디오 하위 형식 GUID를 참조하세요.
  • 인코딩된 스트림의 대상 비트 전송률입니다.
  • 인코더에서 설정할 구성 속성입니다.

구성 속성은 Windows Media 오디오 및 비디오 코덱 및 DSP API 설명서에 설명되어 있습니다. 자세한 내용은 인코딩 속성의 "비디오 스트림 속성"을 참조하세요.

인코더에 대한 유효한 출력 형식을 얻으려면 다음 단계를 수행합니다.

  1. MFTEnum 또는 MFTEnumEx 함수를 사용하여 인코더의 instance 만듭니다.

  2. IPropertyStore 인터페이스에 대한 인코더를 쿼리합니다.

  3. IPropertyStore 인터페이스를 사용하여 인코더를 구성합니다.

  4. IMFTransform::SetInputType을 호출하여 인코더에서 압축되지 않은 비디오 형식을 설정합니다.

  5. IMFTransform::GetOutputAvailableType을 호출하여 인코더에서 압축 형식 목록을 가져옵니다. WMV 인코더는 이 메서드에서 전체 미디어 형식을 반환하지 않습니다. 미디어 유형에 다음 두 가지 정보가 누락되었습니다.

    • 대상 비트 전송률입니다.
    • 인코더의 프라이빗 코덱 데이터입니다.

    인코더에서 출력 형식을 설정하기 전에 이러한 두 항목을 미디어 형식에 추가해야 합니다.

  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 메서드를 두 번 호출하고, 한 번은 프라이빗 데이터에 대한 버퍼 크기를, 한 번은 버퍼에 데이터를 복사합니다.
  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 인코더