Search code examples
webcamvideo-capturems-media-foundationuvc

How to use the "H.264 UVC 1.5 camera encoders" in Windows Media Foundation


I am trying to write some code on Windows based on Windows Media Foundation to work with some USB UVC1.5 cameras, which can provide the H.264 stream. Now I can dump the H.264 stream from the cameras via IMFSourceReader interface. But I don't know how to configure the settings of Encoder Unit.

I just found one page in Microsoft Docs talking about the "H.264 UVC 1.5 camera encoders". Here is the link https://learn.microsoft.com/en-us/windows/win32/medfound/camera-encoder-h264-uvc-1-5. It lists some properties of the encoder which are exactly what I am expecting, but it is just a list :( It also says about the ICodecAPI, and I also tried to use below function which comes from the Microsoft's sample code to enumerate the H.264 encoders, but still no luck. (It can enumerate all the encoders in my PC, but no "H.264 UVC 1.5 camera encoders" related.)

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;
}

Seems I need to get the ICodecAPI Interface from the IMFMediaSource. But don't know how to do it.

Can someone advise? Thanks in advance for your help.


Solution

  • I have figure out the solution. The ICodecAPI interface can be gotten from IMFMediaSource directly.

    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();
    

    I can change the UVC1.5's H264 encoder settings via this ICodecAPI interface.