- [媒體基礎程式設計指南 - Win32 apps | Microsoft Docs](https://docs.microsoft.com/zh-tw/windows/win32/medfound/media-foundation-programming-guide) ## 研究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的數量 ```cpp 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。 ```cpp 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: - [MFCreateDeviceSourceActivate function (mfidl.h)](https://docs.microsof.com/en-us/windows/win32/api/mfidl/nf-mfidl-mfcreatedevicesourceactivate) - [IMFAttributes::SetGUID (mfobjects.h)](https://docs.microsoft.com/en-us/windows/win32/api/mfobjects/nf-mfobjects-imfattributes-setguid) - [IMFAttributes::SetString (mfobjects.h)](https://docs.microsoft.com/en-us/windows/win32/api/mfobjects/nf-mfobjects-imfattributes-setstring) - [IMFAttributes::GetString (mfobjects.h)](https://docs.microsoft.com/en-us/windows/win32/api/mfobjects/nf-mfobjects-imfattributes-getstring) ## 建立Audio capture device 相對於video capture是用`MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK`來建立IMFActivate,audio 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`。 ```cpp hret = mfMediaSource->QueryInterface( IID_IAMCameraControl, (void**)&pCameraControl ); ``` 2. 接下來就可以用`IAMCameraControl->GetRange()`、`Set()`、`Get()`來取得property,根據[CameraControlProperty](https://docs.microsoft.com/en-us/windows/win32/api/strmif/ne-strmif-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](https://stackoverflow.com/questions/63124813/media-foundation-exposure-in-milliseconds),裡面有人提到可以用ksmedia的property:`KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE`(要使用這個property必須include ``與``),你會發現這個property定義在``裡面的`KSPROPERTY_CAMERACONTROL_EXTENDED_PROPERTY`這個enum裡面,然後順藤摸瓜的可以找到`KSPROPERTY_VIDCAP_CAMERACONTROL`這個enum,裡面就有定義`KSPROPERTY_CAMERACONTROL_PAN_RELATIVE`、`KSPROPERTY_CAMERACONTROL_TILT_RELATIVE`這些relative相關的東西了。 4. 現在我們可以用`IAMCameraControl->GetRange()`來把`KSPROPERTY_CAMERACONTROL_PAN_RELATIVE`的值讀出來。 ```cpp 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來表示左轉與右轉。 ```cpp hret = pCameraControl->Set( KSPROPERTY_CAMERACONTROL_PAN_RELATIVE, -1, // or 1 flag ); ``` 5. `KSPROPERTY_CAMERACONTROL_TILT_RELATIVE`的控制方法跟Pan一樣,只是用1跟-1是表示上與下。 6. Pan relative test code ```cpp 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](https://docs.microsoft.com/en-us/windows/win32/api/strmif/ne-strmif-videoprocampproperty)這個頁面看到詳細定義。節錄如下: - `VideoProcAmp_Brightness` - `VideoProcAmp_Contrast` - `VideoProcAmp_Hue` - `VideoProcAmp_Saturation` - `VideoProcAmp_Sharpness` - `VideoProcAmp_Gamma` - `VideoProcAmp_ColorEnable` - `VideoProcAmp_WhiteBalance` - `VideoProcAmp_BacklightCompensation` - `VideoProcAmp_Gain`