Tutorial: Encoding a WMA File

This tutorial shows how to use the Transcode API to encode a Windows Media Audio (WMA) file.

This tutorial reuses most of the code from the tutorial Encoding an MP4 File, so you should read that tutorial first. The only code that differs is the function CreateTranscodeProfile, which creates the transcode profile.

Create the Transcode Profile

A transcode profile describes the encoding parameters and the file container. For WMA, the file container is an Advanced Streaming Format (ASF) file. The ASF file contains an audio stream, which is encoded using the Windows Media Audio Encoder.

To build the transcode topology, create the transcode profile and specify the parameters for the audio stream and the container. Then create the topology by specifying the input source, the output URL, and the transcode profile.

To create the profile, perform the following steps.

  1. Call the MFCreateTranscodeProfile function to create an empty transcode profile.
  2. Call MFTranscodeGetAudioOutputAvailableTypes to get a list of audio media types from the encoder. This function returns an IMFCollection pointer that represents a collection of IMFMediaType pointers.
  3. Choose the audio media type that matches your transcoding requirements and copy the attributes to an attribute store. For this tutorial, the first media type in the list is used.
  4. Call IMFTranscodeProfile::SetAudioAttributes to set the attributes for the audio stream.
  5. Call MFCreateAttributes to create an attribute store for the container-level attributes.
  6. Set the MF_TRANSCODE_CONTAINERTYPE attribute to MFTranscodeContainerType_ASF, which specifies an ASF file container.
  7. Call IMFTranscodeProfile::SetContainerAttributes to set the container-level attributes on the profile.
template <class Q>
HRESULT GetCollectionObject(IMFCollection *pCollection, DWORD index, Q **ppObj)
{
    IUnknown *pUnk;
    HRESULT hr = pCollection->GetElement(index, &pUnk);
    if (SUCCEEDED(hr))
    {
        hr = pUnk->QueryInterface(IID_PPV_ARGS(ppObj));
        pUnk->Release();
    }
    return hr;
}

HRESULT CreateTranscodeProfile(IMFTranscodeProfile **ppProfile)
{
    IMFTranscodeProfile *pProfile = NULL;     // Transcode profile.
    IMFCollection   *pAvailableTypes = NULL;  // List of audio media types.
    IMFMediaType    *pAudioType = NULL;       // Audio media type.
    IMFAttributes   *pAudioAttrs = NULL;      // Copy of the audio media type.
    IMFAttributes   *pContainer = NULL;       // Container attributes.

    DWORD dwMTCount = 0;
    
    // Create an empty transcode profile.
    HRESULT hr = MFCreateTranscodeProfile(&pProfile);
    if (FAILED(hr))
    {
        goto done;
    }

    // Get output media types for the Windows Media audio encoder.

    // Enumerate all codecs except for codecs with field-of-use restrictions.
    // Sort the results.

    DWORD dwFlags = 
        (MFT_ENUM_FLAG_ALL & (~MFT_ENUM_FLAG_FIELDOFUSE)) | 
        MFT_ENUM_FLAG_SORTANDFILTER;

    hr = MFTranscodeGetAudioOutputAvailableTypes(MFAudioFormat_WMAudioV9, 
        dwFlags, NULL, &pAvailableTypes);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pAvailableTypes->GetElementCount(&dwMTCount);
    if (FAILED(hr))
    {
        goto done;
    }
    if (dwMTCount == 0)
    {
        hr = E_FAIL;
        goto done;
    }

    // Get the first audio type in the collection and make a copy.
    hr = GetCollectionObject(pAvailableTypes, 0, &pAudioType);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = MFCreateAttributes(&pAudioAttrs, 0);       
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pAudioType->CopyAllItems(pAudioAttrs);
    if (FAILED(hr))
    {
        goto done;
    }

    // Set the audio attributes on the profile.
    hr = pProfile->SetAudioAttributes(pAudioAttrs);
    if (FAILED(hr))
    {
        goto done;
    }

    // Set the container attributes.
    hr = MFCreateAttributes(&pContainer, 1);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pContainer->SetGUID(MF_TRANSCODE_CONTAINERTYPE, MFTranscodeContainerType_ASF);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pProfile->SetContainerAttributes(pContainer);
    if (FAILED(hr))
    {
        goto done;
    }

    *ppProfile = pProfile;
    (*ppProfile)->AddRef();

done:
    SafeRelease(&pProfile);
    SafeRelease(&pAvailableTypes);
    SafeRelease(&pAudioType);
    SafeRelease(&pAudioAttrs);
    SafeRelease(&pContainer);
    return hr;
}

Transcode API