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

229 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
- [媒體基礎程式設計指南 - 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`來建立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`
```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 `<ks.h>`與`<ksmedia.h>`你會發現這個property定義在`<ksmedia.h>`裡面的`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`