1

我正在尝试在基于 Windows Media Foundation 的 Windows 上编写一些代码,以与一些可以提供 H.264 流的 USB UVC1.5 相机一起使用。现在我可以通过 IMFSourceReader 接口从摄像机中转储 H.264 流。但我不知道如何配置编码器单元的设置。

我刚刚在 Microsoft Docs 中找到一页谈论“H.264 UVC 1.5 相机编码器”。这是链接https://docs.microsoft.com/en-us/windows/win32/medfound/camera-encoder-h264-uvc-1-5。它列出了编码器的一些属性,这正是我所期望的,但它只是一个列表:( 它还提到了 ICodecAPI,我还尝试使用来自 Microsoft 示例代码的以下函数来枚举 H. 264编码器,但仍然没有运气。(它可以枚举我PC中的所有编码器,但没有“H.264 UVC 1.5相机编码器”相关。)

HRESULT EnumerateEncodersEx(const GUID& subtype, IMFTransform** ppEncoder)
{
    HRESULT hr = S_OK;
    UINT32 count = 0;

    IMFActivate** ppActivate = NULL;    // Array of activation objects.

    MFT_REGISTER_TYPE_INFO info = { 0 };

    ICodecAPI* pCodecAPI = NULL;

    info.guidMajorType = MFMediaType_Video;
    info.guidSubtype = subtype;

    UINT32 unFlags = 0
        // enumerate all three kinds of data flow
        | MFT_ENUM_FLAG_SYNCMFT
        | MFT_ENUM_FLAG_ASYNCMFT
        | MFT_ENUM_FLAG_HARDWARE

        // include not-usually-included kinds of MFTs
        | MFT_ENUM_FLAG_FIELDOFUSE
        | MFT_ENUM_FLAG_LOCALMFT
        | MFT_ENUM_FLAG_TRANSCODE_ONLY;

    hr = MFTEnumEx(
        MFT_CATEGORY_VIDEO_ENCODER,
        unFlags,
        NULL,
        &info,
        &ppActivate,
        &count
    );

    if (SUCCEEDED(hr) && count == 0)
    {
        hr = MF_E_TOPO_CODEC_NOT_FOUND;
    }

    if (SUCCEEDED(hr))
    {
        for (UINT32 i = 0; i < count; i++)
        {
            WCHAR* pEncoderName;
#pragma prefast(suppress: __WARNING_PASSING_FUNCTION_UNEXPECTED_NULL, "IMFAttributes::GetAllocatedString third argument is optional");
            hr = ppActivate[i]->GetAllocatedString(
                MFT_FRIENDLY_NAME_Attribute,
                &pEncoderName,
                NULL
            );
            if (MF_E_ATTRIBUTENOTFOUND == hr)
            {
                hr = S_OK;
                continue;
            }
            else if (FAILED(hr))
            {
                abort();
            }

            DBGMSG(L"Encoder[%d]'s Friendly Name: %s\n", i, pEncoderName);

            CoTaskMemFree(pEncoderName);
        }
    }

    if (SUCCEEDED(hr))
    {
        hr = ppActivate[0]->ActivateObject(IID_PPV_ARGS(ppEncoder));
    }

    if (SUCCEEDED(hr))
    {
        hr = (*ppEncoder)->QueryInterface(IID_PPV_ARGS(&pCodecAPI));
    }

    if (SUCCEEDED(hr))
    {
        SafeRelease(&pCodecAPI);
    }

    for (UINT32 i = 0; i < count; i++)
    {
        ppActivate[i]->Release();
    }
    CoTaskMemFree(ppActivate);
    return hr;
}

似乎我需要从 IMFMediaSource 获取 ICodecAPI 接口。但不知道该怎么做。

有人可以建议吗?在此先感谢您的帮助。

4

2 回答 2

1

我已经弄清楚了解决方案。ICodecAPI 接口可以直接从 IMFMediaSource 获取。

IMFMediaSource* ppSource = NULL;
CreateVideoDeviceSource(&ppSource);
HRESULT hr;
IMFSourceReader* pReader;

hr = EnumerateCaptureFormats(ppSource);  // This can show the formats the camera support.
if (FAILED(hr))
    abort();

hr = MFCreateSourceReaderFromMediaSource(ppSource, NULL, &pReader);
if (FAILED(hr))
    abort();

ICodecAPI* pCodecApi = NULL;
hr = ppSource->QueryInterface(IID_PPV_ARGS(&pCodecApi));
if (FAILED(hr))
    abort();

我可以通过这个 ICodecAPI 接口更改 UVC1.5 的 H264 编码器设置。

于 2019-09-20T07:19:34.177 回答
0

我自己无法检查,但如果您已成功使用 IMFSourceReader,请尝试使用它:

  • 使用 MF_SOURCE_READER_FIRST_VIDEO_STREAM 调用 IMFSourceReader::GetServiceForStream 以获取 IMFTransform : GetServiceForStream
  • 比 QueryInterface for ICodecAPI 和 IMFTransform 像你一样。

PS:也许您需要在设置 MediaType 之前或之后执行此操作。

于 2019-09-19T18:51:47.313 回答