master ohmu/fastfetch-openbsd / src / detection / camera / camera_windows.cpp
ohmu  ·  2026-10-15
  1extern "C" {
  2#include "camera.h"
  3#include "common/debug.h"
  4#include "common/library.h"
  5#include "common/windows/com.h"
  6}
  7#include "common/windows/unicode.hpp"
  8#include "common/windows/util.hpp"
  9
 10#include <initguid.h>
 11#include <mfapi.h>
 12#include <mfidl.h>
 13
 14extern "C" const char* ffDetectCamera([[maybe_unused]] FFlist* result) {
 15    FF_LIBRARY_LOAD_MESSAGE(mfplat, "mfplat" FF_LIBRARY_EXTENSION, 1)
 16    FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mfplat, MFCreateAttributes)
 17    FF_LIBRARY_LOAD_MESSAGE(mf, "mf" FF_LIBRARY_EXTENSION, 1)
 18    FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mf, MFEnumDeviceSources)
 19
 20    const char* error = ffInitCom();
 21    if (error) {
 22        return error;
 23    }
 24
 25    FF_AUTO_RELEASE_COM_OBJECT IMFAttributes* attrs = nullptr;
 26    HRESULT hr = ffMFCreateAttributes(&attrs, 1);
 27    if (FAILED(hr)) {
 28        FF_DEBUG("MFCreateAttributes() failed: %s", ffDebugHResult(hr));
 29        return "MFCreateAttributes() failed";
 30    }
 31
 32    hr = attrs->SetGUID(
 33            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
 34            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
 35    if (FAILED(hr)) {
 36        FF_DEBUG("SetGUID(MF_*) failed: %s", ffDebugHResult(hr));
 37        return "SetGUID(MF_*) failed";
 38    }
 39
 40    IMFActivate** devices = nullptr;
 41    uint32_t count;
 42
 43    hr = ffMFEnumDeviceSources(attrs, &devices, &count);
 44    if (FAILED(hr)) {
 45        FF_DEBUG("MFEnumDeviceSources() failed: %s", ffDebugHResult(hr));
 46        return "MFEnumDeviceSources() failed";
 47    }
 48
 49    for (uint32_t i = 0; i < count; i++) {
 50        FF_AUTO_RELEASE_COM_OBJECT IMFActivate* device = devices[i];
 51
 52        wchar_t buffer[256];
 53        uint32_t length = 0;
 54        if (FAILED(device->GetString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, buffer, ARRAY_SIZE(buffer), &length)) || length == 0) {
 55            continue;
 56        }
 57
 58        FFCameraResult* camera = FF_LIST_ADD(FFCameraResult, *result);
 59        ffStrbufInitNWS(&camera->name, length, buffer);
 60        ffStrbufInit(&camera->colorspace);
 61        ffStrbufInit(&camera->vendor);
 62        ffStrbufInit(&camera->id);
 63        camera->width = 0;
 64        camera->height = 0;
 65
 66        if (SUCCEEDED(device->GetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, buffer, ARRAY_SIZE(buffer), &length)) && length > 0) {
 67            ffStrbufSetNWS(&camera->id, length, buffer);
 68        }
 69
 70        FF_AUTO_RELEASE_COM_OBJECT IMFMediaSource* source = nullptr;
 71        if (FAILED(device->ActivateObject(IID_PPV_ARGS(&source)))) {
 72            continue;
 73        }
 74
 75        on_scope_exit destroySource([&] { source->Shutdown(); });
 76
 77        FF_AUTO_RELEASE_COM_OBJECT IMFPresentationDescriptor* pd = nullptr;
 78        if (FAILED(source->CreatePresentationDescriptor(&pd))) {
 79            continue;
 80        }
 81
 82        FF_AUTO_RELEASE_COM_OBJECT IMFStreamDescriptor* sd = nullptr;
 83        BOOL selected;
 84        if (FAILED(pd->GetStreamDescriptorByIndex(0, &selected, &sd))) {
 85            continue;
 86        }
 87
 88        FF_AUTO_RELEASE_COM_OBJECT IMFMediaTypeHandler* handler = nullptr;
 89        if (FAILED(sd->GetMediaTypeHandler(&handler))) {
 90            continue;
 91        }
 92
 93        DWORD mediaTypeCount;
 94        if (FAILED(handler->GetMediaTypeCount(&mediaTypeCount))) {
 95            continue;
 96        }
 97
 98        // Assume first type is the maximum resolution
 99        IMFMediaType* type = nullptr;
100        for (DWORD idx = 0; SUCCEEDED(handler->GetMediaTypeByIndex(idx, &type)); ++idx) {
101            on_scope_exit destroyType([=] { type->Release(); });
102
103            GUID majorType;
104            if (FAILED(type->GetMajorType(&majorType)) || majorType != MFMediaType_Video) {
105                continue;
106            }
107
108            MFVideoPrimaries primaries;
109            static_assert(sizeof(primaries) == sizeof(uint32_t), "");
110            if (SUCCEEDED(type->GetUINT32(MF_MT_VIDEO_PRIMARIES, (uint32_t*) &primaries))) {
111                switch (primaries) {
112                    case MFVideoPrimaries_BT709:
113                        ffStrbufSetStatic(&camera->colorspace, "sRGB");
114                        break;
115                    case MFVideoPrimaries_BT470_2_SysM:
116                    case MFVideoPrimaries_BT470_2_SysBG:
117                        ffStrbufSetStatic(&camera->colorspace, "NTSC");
118                        break;
119                    case MFVideoPrimaries_SMPTE170M:
120                        ffStrbufSetStatic(&camera->colorspace, "SMPTE 170M");
121                        break;
122                    case MFVideoPrimaries_SMPTE240M:
123                        ffStrbufSetStatic(&camera->colorspace, "SMPTE 240M");
124                        break;
125                    case MFVideoPrimaries_EBU3213:
126                        ffStrbufSetStatic(&camera->colorspace, "EBU 3213");
127                        break;
128                    case MFVideoPrimaries_SMPTE_C:
129                        ffStrbufSetStatic(&camera->colorspace, "SMPTE C");
130                        break;
131                    case MFVideoPrimaries_BT2020:
132                        ffStrbufSetStatic(&camera->colorspace, "BT.2020");
133                        break;
134                    case MFVideoPrimaries_XYZ:
135                        ffStrbufSetStatic(&camera->colorspace, "XYZ");
136                        break;
137                    case MFVideoPrimaries_DCI_P3:
138                        ffStrbufSetStatic(&camera->colorspace, "DCI-P3");
139                        break;
140                    case MFVideoPrimaries_ACES:
141                        ffStrbufSetStatic(&camera->colorspace, "ACES");
142                        break;
143                    case (MFVideoPrimaries) 13: // MFVideoPrimaries_Display_P3
144                        ffStrbufSetStatic(&camera->colorspace, "Display P3");
145                        break;
146                    default:
147                        break;
148                }
149            }
150
151            MFGetAttributeSize(type, MF_MT_FRAME_SIZE, &camera->width, &camera->height);
152            break;
153        }
154    }
155
156    if (devices) {
157        CoTaskMemFree(devices);
158    }
159
160    return nullptr;
161}