Files
Obsidian-Main/-20.01. Programming/Media Foundation/20210604 - Windows media foundation.md

10 KiB
Raw Blame History

研究MFVideoEVRWebcam.cpp

  • IMFActivate: 代表實際的device但是實際的device object是在IMFActivate->ActivateObject()才真的建立。
  • IID_PPV_ARGS取得interface的IID value並取得其pointer。詳細參考20210726 - COM Interface#IID_PPV_ARGS Marco
CoInitializeEx
MFStartup
    ↳ ListVideoDevicesWithBriefFormat
        MFCreateAttributes(&pDeviceAttributes, 1)
        pDeviceAttributes->SetGUID()
        MFEnumDeviceSources(pDeviceAttributes, &ppDevices, &deviceCount)
        ppDevices[i]->GetAllocatedString
        ppDevices[i]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &friendlyName, &friendlyNameLength)
        ppDevices[i]->ActivateObject(IID_PPV_ARGS(&pMediaSource))
        MFCreateSourceReaderFromMediaSource(...)
            ↳ ListModes
                pReader->GetNativeMediaType(0, dwMediaTypeIndex, &pType)
                    ↳ GetMediaTypeDescription
                        pMediaType->GetMajorType(&MajorType)
                        pMediaType->GetCount(&cAttrCount)
                        MediaType->GetItemByIndex
                        pMediaType->GetItemType
                    ↪ GetVideoTypeDescriptionBrief(...)
                        pMediaType->GetGUID(MF_MT_SUBTYPE, &subType)
                        MFGetAttributeSize(pMediaType, MF_MT_FRAME_SIZE, &width, &height)
                        MFGetAttributeRatio(pMediaType, MF_MT_FRAME_RATE, &fpsNum, &fpsDen)
    ↳ MFCreateVideoRendererActivate(_hwnd, &pActive)
      pActive->ActivateObject(IID_IMFMediaSink, (void**)&pVideoSink)
      pVideoSink->QueryInterface(__uuidof(IMFVideoRenderer), (void**)&pVideoRenderer)
      pVideoRenderer->InitializeRenderer(NULL, NULL)
      pVideoSink->QueryInterface(__uuidof(IMFGetService), (void**)&pService)
      pService->GetService(MR_VIDEO_RENDER_SERVICE, __uuidof(IMFVideoDisplayControl), (void**)&pVideoDisplayControl)
      pVideoDisplayControl->SetVideoWindow(_hwnd)
      pVideoDisplayControl->SetVideoPosition(NULL, &rc)
      pVideoSink->GetStreamSinkByIndex(0, &pStreamSink)
      pStreamSink->GetMediaTypeHandler(&pSinkMediaTypeHandler)
      pSinkMediaTypeHandler->GetMediaTypeCount(&sinkMediaTypeCount)
      GetVideoSourceFromDevice(WEBCAM_DEVICE_INDEX, &pVideoSource, &pVideoReader)
        ↳ 
      pVideoReader->SetStreamSelection((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, TRUE)
      pVideoSource->CreatePresentationDescriptor(&pSourcePresentationDescriptor)
      pSourcePresentationDescriptor->GetStreamDescriptorByIndex(0, &fSelected, &pSourceStreamDescriptor)
      pSourceStreamDescriptor->GetMediaTypeHandler(&pSourceMediaTypeHandler)
      pSourceMediaTypeHandler->GetMediaTypeCount(&srcMediaTypeCount)
      MFCreateMediaType(&pWebcamSourceType)
      FindMatchingVideoType(pSourceMediaTypeHandler, ...)
        ↳ 
      pSourceMediaTypeHandler->IsMediaTypeSupported(pWebcamSourceType, &pWebCamMatchingType)
      pSourceMediaTypeHandler->SetCurrentMediaType(pWebCamMatchingType)
      pSourceMediaTypeHandler->SetCurrentMediaType(pWebcamSourceType)
      pSourceMediaTypeHandler->GetCurrentMediaType(&pVideoSourceOutputType)
      

建立Video capture device

1. 取得video capture的數量

IMFAttributes* pDeviceAttributes = NULL;
IMFActivate** ppDevices = NULL;
UINT32 deviceCount = 0;

CHECK_HR(MFCreateAttributes(&pDeviceAttributes, 1), 
    "Error creating device attributes.");

// Request video capture devices.
CHECK_HR(pDeviceAttributes->SetGUID(
    MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
    MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID), 
    "Error initialising video configuration object.");

CHECK_HR(MFEnumDeviceSources(pDeviceAttributes, &ppDevices, &deviceCount), 
    "Error enumerating devices.");

2. 用Symbolic來建立IMFActivate

MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK可以用來取得一個獨一無二的ID相對的也可以用來建立IMFActivate。

IMFAttributes* pDeviceAttributes = NULL;
IMFActivate*   pDevice           = NULL;
UINT32         deviceCount       = 0;
bool           result            = false;

CHECK_HR(MFCreateAttributes(&pDeviceAttributes, 1),
    "Error creating device attributes.");

CHECK_HR(pDeviceAttributes->SetGUID(
    MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
    MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID),
    "Error initialising video configuration object.");

CHECK_HR(pDeviceAttributes->SetString(
    MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
    deviceSymbolic.c_str()),
    "Error setting video capture symbolic link");

CHECK_HR(MFCreateDeviceSourceActivate(pDeviceAttributes, &pDevice),
    "Error create activate device");

API:

建立Audio capture device

相對於video capture是用MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK來建立IMFActivateaudio capture是用MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID來建立獨一無二的ID

IAMCameraControl interface

使用IAMCameraControl來控制webcam的行為例如曝光與20210604 - Windows media foundation#Pan Tilt Relative Control

Pan/Tilt Relative Control

  1. 需要先用IMFMediaSource->QueryInterface()取得IID_IAMCameraControl
    hret = mfMediaSource->QueryInterface(
        IID_IAMCameraControl,
        (void**)&pCameraControl
    );
    
  2. 接下來就可以用IAMCameraControl->GetRange()Set()Get()來取得property根據CameraControlProperty可以看到可以用的property有
    1. CameraControl_Pan
    2. CameraControl_Tilt
    3. CameraControl_Roll
    4. CameraControl_Zoom
    5. CameraControl_Exposure
    6. CameraControl_Iris
    7. CameraControl_Focus
  3. 但裡面並沒有關於PanRelative或是TiltRlative的控制在google之後在Stackoverflow上發現這篇Media Foundation Exposure in milliseconds裡面有人提到可以用ksmedia的propertyKSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE要使用這個property必須include <ks.h><ksmedia.h>你會發現這個property定義在<ksmedia.h>裡面的KSPROPERTY_CAMERACONTROL_EXTENDED_PROPERTY這個enum裡面然後順藤摸瓜的可以找到KSPROPERTY_VIDCAP_CAMERACONTROL這個enum裡面就有定義KSPROPERTY_CAMERACONTROL_PAN_RELATIVEKSPROPERTY_CAMERACONTROL_TILT_RELATIVE這些relative相關的東西了。
  4. 現在我們可以用IAMCameraControl->GetRange()來把KSPROPERTY_CAMERACONTROL_PAN_RELATIVE的值讀出來。
    hret = pCameraControl->GetRange(
        KSPROPERTY_CAMERACONTROL_PAN_RELATIVE,
        &min,
        &max,
        &steppingDelta,
        &default,
        &capsFlags
    );
    printf("KSPROPERTY_CAMERACONTROL_PAN_RELATIVE hret = 0x%08X\n", hret);
    printf("min = %d\n", min);                      // get 1
    printf("max = %d\n", max);                      // get 1
    printf("steppingDelta = %d\n", steppingDelta);  // get 1
    printf("default = %d\n", default);              // get 1
    printf("capsFlags = %d\n", capsFlags);          // get 0
    
    但你會發現min、max的值都一樣。 但是IAMCameraControl->Set()還是能用用1跟-1來表示左轉與右轉。
    hret = pCameraControl->Set(
        KSPROPERTY_CAMERACONTROL_PAN_RELATIVE,
        -1, // or 1
        flag
    );
    
  5. KSPROPERTY_CAMERACONTROL_TILT_RELATIVE的控制方法跟Pan一樣只是用1跟-1是表示上與下。
  6. Pan relative test code
    HRESULT hret;
    IAMCameraControl* pCameraControl = NULL;
    
    hret = mfMediaSource->QueryInterface(
        IID_IAMCameraControl,
        (void**)&pCameraControl
    );
    printf("hret = 0x%08X\n", hret);
    
    long min;
    long max;
    long steppingDelta;
    long default;
    long capsFlags;
    long value;
    KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE;
    hret = pCameraControl->GetRange(
        KSPROPERTY_CAMERACONTROL_PAN_RELATIVE,
        &min,
        &max,
        &steppingDelta,
        &default,
        &capsFlags
    );
    printf("KSPROPERTY_CAMERACONTROL_PAN_RELATIVE hret = 0x%08X\n", hret);
    printf("min = %d\n", min);
    printf("max = %d\n", max);
    printf("steppingDelta = %d\n", steppingDelta);
    printf("default = %d\n", default);
    printf("capsFlags = %d\n", capsFlags);
    
    hret = pCameraControl->Get(
        KSPROPERTY_CAMERACONTROL_PAN_RELATIVE,
        &value,
        &capsFlags
    );
    printf("CameraControl_Pan hret = 0x%08X\n", hret);
    printf("value = %d\n", value);
    printf("capsFlags = 0x%08X\n", capsFlags);
    
    long flag = CameraControl_Flags_Manual;
    hret = pCameraControl->Set(
        KSPROPERTY_CAMERACONTROL_PAN_RELATIVE,
        -1,
        flag
    );
    printf("pCameraControl->Set(KSPROPERTY_CAMERACONTROL_PAN_RELATIVE, -1) hret = 0x%08X\n", hret);
    Sleep(500);
    hret = pCameraControl->Set(
        KSPROPERTY_CAMERACONTROL_PAN_RELATIVE,
        1,
        flag
    );
    printf("pCameraControl->Set(KSPROPERTY_CAMERACONTROL_PAN_RELATIVE, 1) hret = 0x%08X\n", hret);
    Sleep(500);
    

IAMVideoProcAmp interface

使用IAMVideoProcAmp來控制webcam的影像相關部份。可以從VideoProcAmpProperty enumeration這個頁面看到詳細定義。節錄如下:

  • VideoProcAmp_Brightness
  • VideoProcAmp_Contrast
  • VideoProcAmp_Hue
  • VideoProcAmp_Saturation
  • VideoProcAmp_Sharpness
  • VideoProcAmp_Gamma
  • VideoProcAmp_ColorEnable
  • VideoProcAmp_WhiteBalance
  • VideoProcAmp_BacklightCompensation
  • VideoProcAmp_Gain