Camera (Windows): init support

This commit is contained in:
李通洲
2024-02-02 16:42:47 +08:00
committed by 李通洲
parent 246ad6d288
commit cba22b7155
4 changed files with 122 additions and 17 deletions
+3 -1
View File
@@ -662,7 +662,7 @@ elseif(WIN32)
src/detection/wm/wm_windows.cpp
src/detection/de/de_nosupport.c
src/detection/wmtheme/wmtheme_windows.c
src/detection/camera/camera_windows.c
src/detection/camera/camera_windows.cpp
src/util/windows/getline.c
src/util/windows/com.cpp
src/util/windows/registry.c
@@ -944,6 +944,8 @@ elseif(WIN32)
PRIVATE "dwmapi"
PRIVATE "gdi32"
PRIVATE "iphlpapi"
PRIVATE "mf"
PRIVATE "mfplat"
PRIVATE "ole32"
PRIVATE "oleaut32"
PRIVATE "ws2_32"
-6
View File
@@ -1,6 +0,0 @@
#include "camera.h"
const char* ffDetectCamera(FF_MAYBE_UNUSED FFlist* result)
{
return "Not supported on this platform";
}
+95
View File
@@ -0,0 +1,95 @@
extern "C" {
#include "camera.h"
#include "common/library.h"
}
#include "util/windows/com.hpp"
#include "util/windows/unicode.hpp"
#include <initguid.h>
#include <mfapi.h>
#include <mfidl.h>
template <typename Fn>
struct on_scope_exit {
on_scope_exit(Fn &&fn): _fn(std::move(fn)) {}
~on_scope_exit() { this->_fn(); }
private:
Fn _fn;
};
extern "C"
const char* ffDetectCamera(FF_MAYBE_UNUSED FFlist* result)
{
// TODO: check if supported by Windows Server Core
const char* error = ffInitCom();
if (error)
return error;
IMFAttributes* FF_AUTO_RELEASE_COM_OBJECT attrs = nullptr;
if (FAILED(MFCreateAttributes(&attrs, 1)))
return "MFCreateAttributes() failed";
if (FAILED(attrs->SetGUID(
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
)))
return "SetGUID(MF_*) failed";
IMFActivate** devices = NULL;
uint32_t count;
if (FAILED(MFEnumDeviceSources(attrs, &devices, &count)))
return "MFEnumDeviceSources() failed";
for (uint32_t i = 0; i < count; i++)
{
IMFActivate* device = devices[i];
wchar_t buffer[256];
uint32_t length = 0;
if (FAILED(device->GetString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, buffer, sizeof(buffer), &length)) || length == 0)
continue;
FFCameraResult* camera = (FFCameraResult*) ffListAdd(result);
ffStrbufInitNWS(&camera->name, length, buffer);
ffStrbufInit(&camera->vendor);
ffStrbufInit(&camera->id);
camera->width = 0;
camera->height = 0;
if (SUCCEEDED(device->GetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, buffer, sizeof(buffer), &length)) && length > 0)
ffStrbufSetNWS(&camera->id, length, buffer);
IMFMediaSource* FF_AUTO_RELEASE_COM_OBJECT source = nullptr;
if (FAILED(device->ActivateObject(IID_PPV_ARGS(&source))))
continue;
on_scope_exit destroySource([&] { source->Shutdown(); });
IMFPresentationDescriptor* FF_AUTO_RELEASE_COM_OBJECT pd = nullptr;
if (FAILED(source->CreatePresentationDescriptor(&pd)))
continue;
IMFStreamDescriptor* FF_AUTO_RELEASE_COM_OBJECT sd = NULL;
BOOL selected;
if (FAILED(pd->GetStreamDescriptorByIndex(0, &selected, &sd)))
continue;
IMFMediaTypeHandler* FF_AUTO_RELEASE_COM_OBJECT handler = NULL;
if (FAILED(sd->GetMediaTypeHandler(&handler)))
continue;
// Assume first type is the maximum resolution
IMFMediaType* FF_AUTO_RELEASE_COM_OBJECT type = NULL;
if (FAILED(handler->GetMediaTypeByIndex(0, &type)))
continue;
MFGetAttributeSize(type, MF_MT_FRAME_SIZE, &camera->width, &camera->height);
}
CoTaskMemFree(devices);
return nullptr;
}
+24 -10
View File
@@ -1,16 +1,12 @@
#include <oaidl.h>
#include <propidl.h>
#include <type_traits>
#include <utility>
#include <string_view>
struct FFWmiVariant: VARIANT
template <typename TVariant>
struct FFBaseVariant: TVariant
{
explicit FFWmiVariant() { VariantInit(this); }
~FFWmiVariant() { VariantClear(this); }
FFWmiVariant(const FFWmiVariant&) = delete;
FFWmiVariant(FFWmiVariant&&); // don't define it to enforce NRVO optimization
bool hasValue() {
return this->vt != VT_EMPTY;
}
@@ -33,11 +29,11 @@ struct FFWmiVariant: VARIANT
return this->cVal;
}
else if constexpr (std::is_same_v<T, int16_t>) {
assert(vt == VT_I2);
assert(this->vt == VT_I2);
return this->iVal;
}
else if constexpr (std::is_same_v<T, int32_t>) {
assert(this->vt == VT_I4 || vt == VT_INT);
assert(this->vt == VT_I4 || this->vt == VT_INT);
return this->intVal;
}
else if constexpr (std::is_same_v<T, int64_t>) {
@@ -55,7 +51,7 @@ struct FFWmiVariant: VARIANT
return this->uiVal;
}
else if constexpr (std::is_same_v<T, uint32_t>) {
assert(this->vt == VT_UI4 || vt == VT_UINT);
assert(this->vt == VT_UI4 || this->vt == VT_UINT);
return this->uintVal;
}
else if constexpr (std::is_same_v<T, uint64_t>) {
@@ -135,3 +131,21 @@ struct FFWmiVariant: VARIANT
}
}
};
struct FFWmiVariant: FFBaseVariant<VARIANT>
{
FFWmiVariant(const FFWmiVariant&) = delete;
FFWmiVariant(FFWmiVariant&&); // don't define it to enforce NRVO optimization
explicit FFWmiVariant() { VariantInit(this); }
~FFWmiVariant() { VariantClear(this); }
};
static_assert(sizeof(FFWmiVariant) == sizeof(VARIANT), "");
struct FFPropVariant: FFBaseVariant<PROPVARIANT>
{
FFPropVariant(const FFPropVariant&) = delete;
FFPropVariant(FFPropVariant&&); // don't define it to enforce NRVO optimization
explicit FFPropVariant() { PropVariantInit(this); }
~FFPropVariant() { PropVariantClear(this); }
};
static_assert(sizeof(FFPropVariant) == sizeof(PROPVARIANT), "");