教程:对 WMA 文件进行编码

本教程演示如何使用 转码 API 对 Windows Media Audio (WMA) 文件进行编码。

本教程将重用教程 编码 MP4 文件中的大部分代码,因此应先阅读该教程。 唯一不同的代码是 函数 CreateTranscodeProfile,它创建转码配置文件。

创建转码配置文件

转码配置文件描述编码参数和文件容器。 对于 WMA,文件容器是 ASF) 文件 (高级流式处理格式。 ASF 文件包含使用 Windows Media Audio Encoder 编码的音频流。

若要生成转码拓扑,请创建转码配置文件并指定音频流和容器的参数。 然后,通过指定输入源、输出 URL 和转码配置文件来创建拓扑。

若要创建配置文件,请执行以下步骤。

  1. 调用 MFCreateTranscodeProfile 函数以创建空转码配置文件。
  2. 调用 MFTranscodeGetAudioOutputAvailableTypes 从编码器获取音频媒体类型的列表。 此函数返回一个表示 IMFMediaType 指针集合的 IMFCollection 指针。
  3. 选择符合转码要求的音频媒体类型,并将属性复制到属性存储。 本教程使用列表中的第一个媒体类型。
  4. 调用 IMFTranscodeProfile::SetAudioAttributes 以设置音频流的属性。
  5. 调用 MFCreateAttributes 为容器级属性创建属性存储。
  6. MF_TRANSCODE_CONTAINERTYPE 属性设置为 MFTranscodeContainerType_ASF,以指定 ASF 文件容器。
  7. 调用 IMFTranscodeProfile::SetContainerAttributes 以在配置文件上设置容器级属性。
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;
}

转码 API