-
-
Save mmozeiko/a5adab1ad11ea6d0643ceb67bb8e3e19 to your computer and use it in GitHub Desktop.
| #define COBJMACROS | |
| #define WIN32_LEAN_AND_MEAN | |
| #include <windows.h> | |
| #include <mfapi.h> | |
| #include <mfidl.h> | |
| #include <mfreadwrite.h> | |
| #include <stdio.h> | |
| #include <intrin.h> | |
| #pragma comment (lib, "ole32.lib") | |
| #pragma comment (lib, "mf.lib") | |
| #pragma comment (lib, "mfplat.lib") | |
| #pragma comment (lib, "mfuuid.lib") | |
| #pragma comment (lib, "mfreadwrite.lib") | |
| #define ASSERT(x) do { if (!(x)) __debugbreak(); } while (0) | |
| #define CHECK(hr) ASSERT(SUCCEEDED(hr)) | |
| int main(int argc, char* argv[]) | |
| { | |
| HRESULT hr; | |
| hr = CoInitializeEx(0, COINIT_MULTITHREADED); | |
| CHECK(hr); | |
| hr = MFStartup(MF_VERSION, MFSTARTUP_NOSOCKET); | |
| CHECK(hr); | |
| if (argc == 1) // enumerate available devices | |
| { | |
| UINT32 count; | |
| IMFActivate** devices; | |
| { | |
| IMFAttributes* attr; | |
| hr = MFCreateAttributes(&attr, 1); | |
| CHECK(hr); | |
| hr = IMFAttributes_SetGUID(attr, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID); | |
| CHECK(hr); | |
| hr = MFEnumDeviceSources(attr, &devices, &count); | |
| CHECK(hr); | |
| IMFAttributes_Release(attr); | |
| } | |
| printf("Detected %u devices:\n", count); | |
| for (UINT32 i = 0; i < count; i++) | |
| { | |
| UINT32 length; | |
| LPWSTR name; | |
| LPWSTR symlink; | |
| hr = IMFActivate_GetAllocatedString(devices[i], &MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &name, &length); | |
| CHECK(hr); | |
| hr = IMFActivate_GetAllocatedString(devices[i], &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &symlink, &length); | |
| CHECK(hr); | |
| printf("%S = %S\n", name, symlink); | |
| CoTaskMemFree(name); | |
| CoTaskMemFree(symlink); | |
| IMFActivate_Release(devices[i]); | |
| } | |
| CoTaskMemFree(devices); | |
| } | |
| else // create device from name | |
| { | |
| IMFMediaSource* device; | |
| { | |
| IMFAttributes* attr; | |
| hr = MFCreateAttributes(&attr, 2); | |
| CHECK(hr); | |
| hr = IMFAttributes_SetGUID(attr, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID); | |
| CHECK(hr); | |
| WCHAR name[1024]; | |
| MultiByteToWideChar(CP_UTF8, 0, argv[1], -1, name, 1024); | |
| hr = IMFAttributes_SetString(attr, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, name); | |
| CHECK(hr); | |
| hr = MFCreateDeviceSource(attr, &device); | |
| CHECK(hr); | |
| IMFAttributes_Release(attr); | |
| } | |
| IMFSourceReader* reader; | |
| hr = MFCreateSourceReaderFromMediaSource(device, NULL, &reader); | |
| CHECK(hr); | |
| IMFMediaSource_Release(device); | |
| // this assumes camera can provide mjpeg output | |
| // typically webcams provide YUV2 format, you'll need to convert it to | |
| // RGB yourself or with help of IMFTransform | |
| // you can enumerate all supported types with IMFSourceReader_GetNativeMediaType | |
| { | |
| IMFMediaType* type; | |
| hr = MFCreateMediaType(&type); | |
| CHECK(hr); | |
| hr = IMFMediaType_SetGUID(type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); | |
| CHECK(hr); | |
| hr = IMFMediaType_SetGUID(type, &MF_MT_SUBTYPE, &MFVideoFormat_MJPG); | |
| CHECK(hr); | |
| // you can also set desired width/height here | |
| hr = IMFSourceReader_SetCurrentMediaType(reader, MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, type); | |
| CHECK(hr); | |
| IMFMediaType_Release(type); | |
| } | |
| UINT32 width; | |
| UINT32 height; | |
| // get width/height | |
| { | |
| IMFMediaType* type; | |
| hr = IMFSourceReader_GetCurrentMediaType(reader, MF_SOURCE_READER_FIRST_VIDEO_STREAM, &type); | |
| CHECK(hr); | |
| UINT64 tmp; | |
| hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &tmp); | |
| CHECK(hr); | |
| width = (UINT32)(tmp >> 32); | |
| height = (UINT32)(tmp); | |
| IMFMediaType_Release(type); | |
| } | |
| printf("Size = %ux%u\n", width, height); | |
| // read one frame and save it to file | |
| { | |
| IMFSample* sample; | |
| DWORD stream; | |
| DWORD flags; | |
| LONGLONG timestamp; | |
| for (;;) | |
| { | |
| // this is reading in syncronous blocking mode, MF supports also async calls | |
| hr = IMFSourceReader_ReadSample(reader, MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, &stream, &flags, ×tamp, &sample); | |
| CHECK(hr); | |
| if (flags & MF_SOURCE_READERF_STREAMTICK) | |
| { | |
| continue; | |
| } | |
| break; | |
| } | |
| { | |
| IMFMediaBuffer* buffer; | |
| hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer); | |
| CHECK(hr); | |
| BYTE* data; | |
| DWORD size; | |
| hr = IMFMediaBuffer_Lock(buffer, &data, NULL, &size); | |
| CHECK(hr); | |
| { | |
| HANDLE h = CreateFileA("image.jpg", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); | |
| ASSERT(h != INVALID_HANDLE_VALUE); | |
| DWORD written; | |
| BOOL ok = WriteFile(h, data, size, &written, NULL); | |
| ASSERT(ok && written == size); | |
| CloseHandle(h); | |
| } | |
| IMFMediaBuffer_Unlock(buffer); | |
| IMFMediaBuffer_Release(buffer); | |
| } | |
| IMFSample_Release(sample); | |
| } | |
| IMFSourceReader_Release(reader); | |
| } | |
| MFShutdown(); | |
| CoUninitialize(); | |
| } |
Those are macros available in C from mf* headers when you define COBJMACROS before including windows headers.
How to compile this?
You save the code to webcam_capture.c file and then use MSVC or Clang compiler to compile it - cl.exe webcam_capture.c or clang-cl.exe webcam_capture.c
Hi, from where I can obtain more detailed manual for MF ?
For example what is "MFCreateAttributes" ?. How many attributes I have to create ?
Or ... on lines 160-172 why there is the cycle for ?
Can someone help where is more detailed manual ?
I found this:
https://learn.microsoft.com/en-us/windows/win32/api/mfapi/nf-mfapi-mfcreateattributes
but this MS manual is really very brief.
Jerry
Check the functions where attributes are used. In this code example it is used for two functions:
- MFEnumDeviceSources - https://learn.microsoft.com/en-us/windows/win32/api/mfidl/nf-mfidl-mfenumdevicesources
- MFCreateDeviceSource - https://learn.microsoft.com/en-us/windows/win32/api/mfidl/nf-mfidl-mfcreatedevicesource
Documentation of these functions explains exactly what attributes to set and why.
Where are these defined?