为什么 MediaFoundation InitializeSinkWriter (SetInputMediaType) 只接受 WMV3 格式?

Why MediaFoundation InitializeSinkWriter (SetInputMediaType) only accepts WMV3 format?

取自 MSDN 帮助页面,只要视频编码和视频输入格式为 WMV3/RGB32,InitializeSinkWriter 就可以正常工作,但是如果我将其更改为 WMV1、MPEG2 等,则 SetInputMediaType 会失败。

AFAIK 根据 Sherlock the Codec Detective 程序,我将 WMV1 安装为编解码器。

这是导致问题的代码: (要查找问题代码,请在源代码注释中搜索 "problem",其中有很多无关紧要的样板代码)

// Format constants
const UINT32 VIDEO_WIDTH = 640;
const UINT32 VIDEO_HEIGHT = 480;
const UINT32 VIDEO_FPS = 30;
const UINT64 VIDEO_FRAME_DURATION = 10 * 1000 * 1000 / VIDEO_FPS;
const UINT32 VIDEO_BIT_RATE = 800000;
const GUID   VIDEO_ENCODING_FORMAT = MFVideoFormat_WMV1 ; // problem here, must be WMV3
const GUID   VIDEO_INPUT_FORMAT = MFVideoFormat_WMV3 ;    // problem here if not wmv3 too
const UINT32 VIDEO_PELS = VIDEO_WIDTH * VIDEO_HEIGHT;
const UINT32 VIDEO_FRAME_COUNT = 20 * VIDEO_FPS;

HRESULT InitializeSinkWriter(IMFSinkWriter **ppWriter, DWORD *pStreamIndex)
{
    *ppWriter = NULL;
    *pStreamIndex = NULL;

    IMFSinkWriter   *pSinkWriter = NULL;
    IMFMediaType    *pMediaTypeOut = NULL;
    IMFMediaType    *pMediaTypeIn = NULL;
    DWORD           streamIndex;

    HRESULT hr = MFCreateSinkWriterFromURL(L"output.wmv", NULL, NULL, &pSinkWriter);

    // Set the output media type.
    if (SUCCEEDED(hr))
    {
        hr = MFCreateMediaType(&pMediaTypeOut);
    }
    if (SUCCEEDED(hr))
    {
        hr = pMediaTypeOut->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
    }
    if (SUCCEEDED(hr))
    {
        hr = pMediaTypeOut->SetGUID(MF_MT_SUBTYPE, VIDEO_ENCODING_FORMAT);
    }
    if (SUCCEEDED(hr))
    {
        hr = pMediaTypeOut->SetUINT32(MF_MT_AVG_BITRATE, VIDEO_BIT_RATE);
    }
    if (SUCCEEDED(hr))
    {
        hr = pMediaTypeOut->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
    }
    if (SUCCEEDED(hr))
    {
        hr = MFSetAttributeSize(pMediaTypeOut, MF_MT_FRAME_SIZE, VIDEO_WIDTH, VIDEO_HEIGHT);
    }
    if (SUCCEEDED(hr))
    {
        hr = MFSetAttributeRatio(pMediaTypeOut, MF_MT_FRAME_RATE, VIDEO_FPS, 1);
    }
    if (SUCCEEDED(hr))
    {
        hr = MFSetAttributeRatio(pMediaTypeOut, MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
    }
    if (SUCCEEDED(hr))
    {
        hr = pSinkWriter->AddStream(pMediaTypeOut, &streamIndex);
    }

    // Set the input media type.
    if (SUCCEEDED(hr))
    {
        hr = MFCreateMediaType(&pMediaTypeIn);
    }
    if (SUCCEEDED(hr))
    {
        hr = pMediaTypeIn->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
    }
    if (SUCCEEDED(hr))
    {
        hr = pMediaTypeIn->SetGUID(MF_MT_SUBTYPE, VIDEO_INPUT_FORMAT);
    }
    if (SUCCEEDED(hr))
    {
        hr = pMediaTypeIn->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
    }
    if (SUCCEEDED(hr))
    {
        hr = MFSetAttributeSize(pMediaTypeIn, MF_MT_FRAME_SIZE, VIDEO_WIDTH, VIDEO_HEIGHT);
    }
    if (SUCCEEDED(hr))
    {
        hr = MFSetAttributeRatio(pMediaTypeIn, MF_MT_FRAME_RATE, VIDEO_FPS, 1);
    }
    if (SUCCEEDED(hr))
    {
        hr = MFSetAttributeRatio(pMediaTypeIn, MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
    }
    if (SUCCEEDED(hr))
    {
        // Problem here! Codec issue with wmv1, mpeg, etc.
        hr = pSinkWriter->SetInputMediaType(streamIndex, pMediaTypeIn, NULL);  
    }
    else {
        puts("setattributeratio failed");
    }

    // Tell the sink writer to start accepting data.
    if (SUCCEEDED(hr))
    {
        hr = pSinkWriter->BeginWriting();
    } 
    else {
        puts("setinputmediatype failed");  // <-- HR result problem here
    }
    // Return the pointer to the caller.
    if (SUCCEEDED(hr))
    {
        *ppWriter = pSinkWriter;
        (*ppWriter)->AddRef();
        *pStreamIndex = streamIndex;
    }
    else {
        puts("beginwriting failed");
    }

    SafeRelease(&pSinkWriter);
    SafeRelease(&pMediaTypeOut);
    SafeRelease(&pMediaTypeIn);
    return hr;
}

使用此代码调用初始化接收器编写器:

void main()
{
    DWORD streamidx = 0;
    const WCHAR *SAMPLE_FILE = L"sample.wmv";
    IMFSourceReader *pReader = NULL;
    IMFSinkWriter *pWriter = NULL;
    puts("Initializing...");

    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    if (SUCCEEDED(hr))
    {
        hr = MFStartup(MF_VERSION);
        if (SUCCEEDED(hr))
        {
            // problem here !
            hr = InitializeSinkWriter(&pWriter, &streamidx);  
            if (SUCCEEDED(hr))
            {
                // more code would go here...

            }
            else {
                puts("InitializeSinkWriter failed"); // this is called
            }

            SafeRelease(&pWriter);
            MFShutdown();
        }

        CoUninitialize();
    }
    puts("Finished...");
}

这是我使用的标准 Windows7 计算机,所以,如果它只接受 WMV3 作为编码器或输入类型,是否意味着我必须安装编解码器?这似乎很荒谬,因为应该已经安装了 WMV1 和 MPEG 等流行格式,而且 Sherlock 编解码器侦探说它们是

Windows Media Foundation 不支持您正在尝试的编解码器(即使某些第三方软件可以报告其他 API 的其他编解码器的可用性)。

参见: