diff --git a/pkg/driver/camera/camera_windows.cpp b/pkg/driver/camera/camera_windows.cpp index 5520cd5..0f3b933 100644 --- a/pkg/driver/camera/camera_windows.cpp +++ b/pkg/driver/camera/camera_windows.cpp @@ -33,6 +33,11 @@ char* getName(cameraList* list, int i) return list->name[i]; } +char* getFriendlyName(cameraList* list, int i) +{ + return list->friendlyName[i]; +} + // printErr shows string representation of HRESULT. // This is for debugging. @@ -43,7 +48,7 @@ void printErr(HRESULT hr) fprintf(stderr, "%s\n", buf); } -// getCameraName returns name of the device. +// getCameraName returns the display name (device path) of the device. // returned pointer must be released by free() after use. char* getCameraName(IMoniker* moniker) { @@ -62,6 +67,40 @@ char* getCameraName(IMoniker* moniker) return ret; } +// getDeviceFriendlyName returns the human-readable name of the device via IPropertyBag. +// Returns nullptr if the friendly name is not available. +// returned pointer must be released by free() after use. +static char* getDeviceFriendlyName(IMoniker* moniker) +{ + IPropertyBag* propBag = nullptr; + if (FAILED(moniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&propBag))) + return nullptr; + + VARIANT varName; + VariantInit(&varName); + if (FAILED(propBag->Read(L"FriendlyName", &varName, 0))) + { + VariantClear(&varName); + propBag->Release(); + return nullptr; + } + + if (varName.vt != VT_BSTR || varName.bstrVal == nullptr) + { + VariantClear(&varName); + propBag->Release(); + return nullptr; + } + + std::string nameStr = utf16Decode(varName.bstrVal); + VariantClear(&varName); + propBag->Release(); + + char* ret = (char*)malloc(nameStr.size() + 1); + memcpy(ret, nameStr.c_str(), nameStr.size() + 1); + return ret; +} + // listCamera stores information of the devices to cameraList*. int listCamera(cameraList* list, const char** errstr) { @@ -89,6 +128,7 @@ int listCamera(cameraList* list, const char** errstr) { list->num = 0; list->name = nullptr; + list->friendlyName = nullptr; return 0; } @@ -102,15 +142,18 @@ int listCamera(cameraList* list, const char** errstr) } enumMon->Reset(); - list->name = new char*[list->num]; + list->name = new char*[list->num](); + list->friendlyName = new char*[list->num](); int i = 0; while (enumMon->Next(1, &moniker, nullptr) == S_OK) { list->name[i] = getCameraName(moniker); + list->friendlyName[i] = getDeviceFriendlyName(moniker); moniker->Release(); i++; } + list->num = i; } safeRelease(&enumMon); @@ -129,9 +172,17 @@ int freeCameraList(cameraList* list, const char** errstr) { for (int i = 0; i < list->num; ++i) { - delete list->name[i]; + free(list->name[i]); } - delete list->name; + delete[] list->name; + } + if (list->friendlyName != nullptr) + { + for (int i = 0; i < list->num; ++i) + { + free(list->friendlyName[i]); + } + delete[] list->friendlyName; } return 1; } @@ -247,7 +298,10 @@ int listResolution(camera* cam, const char** errstr) if (mediaType->majortype != MEDIATYPE_Video || mediaType->pbFormat == nullptr) + { + freeMediaType(mediaType); continue; + } BITMAPINFOHEADER* bmi = nullptr; if (mediaType->formattype == FORMAT_VideoInfo) @@ -260,12 +314,15 @@ int listResolution(camera* cam, const char** errstr) } else { + freeMediaType(mediaType); continue; } cam->props[iProp].width = bmi->biWidth; cam->props[iProp].height = bmi->biHeight; - cam->props[iProp].fcc = bmi->biCompression; + // Use subtype.Data1 for the FourCC; some drivers leave biCompression as 0. + cam->props[iProp].fcc = mediaType->subtype.Data1; + freeMediaType(mediaType); iProp++; } cam->numProps = iProp; @@ -367,7 +424,7 @@ int openCamera(camera* cam, const char** errstr) if (bmi != nullptr && bmi->biWidth == cam->width && bmi->biHeight == cam->height && - bmi->biCompression == cam->fcc) + mt->subtype.Data1 == cam->fcc) { streamConfig->SetFormat(mt); freeMediaType(mt); diff --git a/pkg/driver/camera/camera_windows.go b/pkg/driver/camera/camera_windows.go index 0038b9c..18f0fa2 100644 --- a/pkg/driver/camera/camera_windows.go +++ b/pkg/driver/camera/camera_windows.go @@ -1,6 +1,6 @@ package camera -// #cgo LDFLAGS: -lstrmiids -lole32 -lquartz +// #cgo LDFLAGS: -lstrmiids -lole32 -loleaut32 -lquartz // #include // #include "camera_windows.hpp" import "C" @@ -49,11 +49,19 @@ func Initialize() { } for i := 0; i < int(list.num); i++ { - name := C.GoString(C.getName(&list, C.int(i))) - driver.GetManager().Register(&camera{name: name}, driver.Info{ - Label: name, + cName := C.getName(&list, C.int(i)) + if cName == nil { + continue + } + label := C.GoString(cName) + info := driver.Info{ + Label: label, DeviceType: driver.Camera, - }) + } + if fn := C.getFriendlyName(&list, C.int(i)); fn != nil { + info.Name = C.GoString(fn) + } + driver.GetManager().Register(&camera{name: label}, info) } C.freeCameraList(&list, &errStr) diff --git a/pkg/driver/camera/camera_windows.hpp b/pkg/driver/camera/camera_windows.hpp index 06a21f2..6b669ff 100644 --- a/pkg/driver/camera/camera_windows.hpp +++ b/pkg/driver/camera/camera_windows.hpp @@ -33,6 +33,7 @@ typedef struct { int num; char** name; + char** friendlyName; } cameraList; int openCamera(camera* cam, const char** errstr); @@ -44,6 +45,7 @@ int freeCameraList(cameraList* list, const char** errstr); imageProp* getProp(camera* cam, int i); char* getName(cameraList* list, int i); +char* getFriendlyName(cameraList* list, int i); #ifdef __cplusplus }