From 7ea13f7e03dc2d87e19d844f1fcc4d1037f88e6d Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Sun, 23 Oct 2016 18:20:56 -0700 Subject: [PATCH] Refactor properties from USBCameraImpl to SourceImpl. --- src/SourceImpl.cpp | 175 ++++++++++++++++++++++++++- src/SourceImpl.h | 112 +++++++++++++---- src/USBCameraImpl.cpp | 271 ++++++++---------------------------------- src/USBCameraImpl.h | 74 ++---------- 4 files changed, 321 insertions(+), 311 deletions(-) diff --git a/src/SourceImpl.cpp b/src/SourceImpl.cpp index 30e8041de3..106960120f 100644 --- a/src/SourceImpl.cpp +++ b/src/SourceImpl.cpp @@ -32,6 +32,18 @@ SourceImpl::~SourceImpl() { // Everything else can clean up itself. } +void SourceImpl::SetDescription(llvm::StringRef description) { + std::lock_guard lock(m_mutex); + m_description = description; +} + +llvm::StringRef SourceImpl::GetDescription( + llvm::SmallVectorImpl& buf) const { + std::lock_guard lock(m_mutex); + buf.append(m_description.begin(), m_description.end()); + return llvm::StringRef{buf.data(), buf.size()}; +} + uint64_t SourceImpl::GetCurFrameTime() { std::unique_lock lock{m_frameMutex}; return m_frame.time(); @@ -57,6 +69,157 @@ void SourceImpl::Wakeup() { m_frameCv.notify_all(); } +int SourceImpl::GetPropertyIndex(llvm::StringRef name) const { + // We can't fail, so instead we create a new index if caching fails. + CS_Status status = 0; + if (!m_properties_cached) CacheProperties(&status); + std::lock_guard lock(m_mutex); + int& ndx = m_properties[name]; + if (ndx == 0) { + // create a new index + ndx = m_propertyData.size() + 1; + m_propertyData.emplace_back(); + } + return ndx; +} + +llvm::ArrayRef SourceImpl::EnumerateProperties( + llvm::SmallVectorImpl& vec, CS_Status* status) const { + if (!m_properties_cached && !CacheProperties(status)) + return llvm::ArrayRef{}; + std::lock_guard lock(m_mutex); + for (int i = 0; i < static_cast(m_propertyData.size()); ++i) + vec.push_back(i + 1); + return vec; +} + +CS_PropertyType SourceImpl::GetPropertyType(int property) const { + CS_Status status = 0; + if (!m_properties_cached && !CacheProperties(&status)) return CS_PROP_NONE; + std::lock_guard lock(m_mutex); + auto prop = GetProperty(property); + if (!prop) return CS_PROP_NONE; + return prop->propType; +} + +llvm::StringRef SourceImpl::GetPropertyName(int property, + llvm::SmallVectorImpl& buf, + CS_Status* status) const { + if (!m_properties_cached && !CacheProperties(status)) + return llvm::StringRef{}; + std::lock_guard lock(m_mutex); + auto prop = GetProperty(property); + if (!prop) { + *status = CS_INVALID_PROPERTY; + return llvm::StringRef{}; + } + // safe to not copy because we never modify it after caching + return prop->name; +} + +int SourceImpl::GetProperty(int property, CS_Status* status) const { + if (!m_properties_cached && !CacheProperties(status)) return 0; + std::lock_guard lock(m_mutex); + auto prop = GetProperty(property); + if (!prop) { + *status = CS_INVALID_PROPERTY; + return 0; + } + if ((prop->propType & (CS_PROP_BOOLEAN | CS_PROP_INTEGER | CS_PROP_ENUM)) == + 0) { + *status = CS_WRONG_PROPERTY_TYPE; + return 0; + } + return prop->value; +} + +int SourceImpl::GetPropertyMin(int property, CS_Status* status) const { + if (!m_properties_cached && !CacheProperties(status)) return 0; + std::lock_guard lock(m_mutex); + auto prop = GetProperty(property); + if (!prop) { + *status = CS_INVALID_PROPERTY; + return 0; + } + return prop->minimum; +} + +int SourceImpl::GetPropertyMax(int property, CS_Status* status) const { + if (!m_properties_cached && !CacheProperties(status)) return 0; + std::lock_guard lock(m_mutex); + auto prop = GetProperty(property); + if (!prop) { + *status = CS_INVALID_PROPERTY; + return 0; + } + return prop->maximum; +} + +int SourceImpl::GetPropertyStep(int property, CS_Status* status) const { + if (!m_properties_cached && !CacheProperties(status)) return 0; + std::lock_guard lock(m_mutex); + auto prop = GetProperty(property); + if (!prop) { + *status = CS_INVALID_PROPERTY; + return 0; + } + return prop->step; +} + +int SourceImpl::GetPropertyDefault(int property, CS_Status* status) const { + if (!m_properties_cached && !CacheProperties(status)) return 0; + std::lock_guard lock(m_mutex); + auto prop = GetProperty(property); + if (!prop) { + *status = CS_INVALID_PROPERTY; + return 0; + } + return prop->defaultValue; +} + +llvm::StringRef SourceImpl::GetStringProperty( + int property, llvm::SmallVectorImpl& buf, CS_Status* status) const { + if (!m_properties_cached && !CacheProperties(status)) + return llvm::StringRef{}; + std::lock_guard lock(m_mutex); + auto prop = GetProperty(property); + if (!prop) { + *status = CS_INVALID_PROPERTY; + return llvm::StringRef{}; + } + if (prop->propType != CS_PROP_STRING) { + *status = CS_WRONG_PROPERTY_TYPE; + return llvm::StringRef{}; + } + buf.clear(); + buf.append(prop->valueStr.begin(), prop->valueStr.end()); + return llvm::StringRef(buf.data(), buf.size()); +} + +std::vector SourceImpl::GetEnumPropertyChoices( + int property, CS_Status* status) const { + if (!m_properties_cached && !CacheProperties(status)) + return std::vector{}; + std::lock_guard lock(m_mutex); + auto prop = GetProperty(property); + if (!prop) { + *status = CS_INVALID_PROPERTY; + return std::vector{}; + } + if (prop->propType != CS_PROP_ENUM) { + *status = CS_WRONG_PROPERTY_TYPE; + return std::vector{}; + } + return prop->enumChoices; +} + +VideoMode SourceImpl::GetVideoMode(CS_Status* status) const { + if (!m_properties_cached && !CacheProperties(status)) + return VideoMode{}; + std::lock_guard lock(m_mutex); + return m_mode; +} + bool SourceImpl::SetPixelFormat(VideoMode::PixelFormat pixelFormat, CS_Status* status) { auto mode = GetVideoMode(status); @@ -80,11 +243,19 @@ bool SourceImpl::SetFPS(int fps, CS_Status* status) { return SetVideoMode(mode, status); } +std::vector SourceImpl::EnumerateVideoModes( + CS_Status* status) const { + if (!m_properties_cached && !CacheProperties(status)) + return std::vector{}; + std::lock_guard lock(m_mutex); + return m_videoModes; +} + void SourceImpl::PutFrame(VideoMode::PixelFormat pixelFormat, llvm::StringRef data, Frame::Time time) { std::unique_ptr frameData; { - std::lock_guard lock{m_mutex}; + std::lock_guard lock{m_poolMutex}; // find the smallest existing frame that is at least big enough. int found = -1; for (std::size_t i = 0; i < m_framesAvail.size(); ++i) { @@ -129,7 +300,7 @@ void SourceImpl::PutFrame(VideoMode::PixelFormat pixelFormat, } void SourceImpl::ReleaseFrame(std::unique_ptr data) { - std::lock_guard lock{m_mutex}; + std::lock_guard lock{m_poolMutex}; if (m_destroyFrames) return; // Return the frame to the pool. First try to find an empty slot, otherwise // add it to the end. diff --git a/src/SourceImpl.h b/src/SourceImpl.h index 0b710a7154..166f5beb66 100644 --- a/src/SourceImpl.h +++ b/src/SourceImpl.h @@ -16,6 +16,7 @@ #include #include "llvm/ArrayRef.h" +#include "llvm/StringMap.h" #include "llvm/StringRef.h" #include "cameraserver_cpp.h" #include "Frame.h" @@ -28,12 +29,14 @@ class SourceImpl { public: SourceImpl(llvm::StringRef name); virtual ~SourceImpl(); - SourceImpl(const SourceImpl& queue) = delete; - SourceImpl& operator=(const SourceImpl& queue) = delete; + SourceImpl(const SourceImpl& oth) = delete; + SourceImpl& operator=(const SourceImpl& oth) = delete; llvm::StringRef GetName() const { return m_name; } - virtual llvm::StringRef GetDescription( - llvm::SmallVectorImpl& buf) const = 0; + + void SetDescription(llvm::StringRef description); + llvm::StringRef GetDescription(llvm::SmallVectorImpl& buf) const; + virtual bool IsConnected() const = 0; // Functions to keep track of the overall number of sinks connected to this @@ -78,29 +81,29 @@ class SourceImpl { void Wakeup(); // Property functions - virtual int GetPropertyIndex(llvm::StringRef name) const = 0; - virtual llvm::ArrayRef EnumerateProperties( - llvm::SmallVectorImpl& vec, CS_Status* status) const = 0; - virtual CS_PropertyType GetPropertyType(int property) const = 0; - virtual llvm::StringRef GetPropertyName(int property, - llvm::SmallVectorImpl& buf, - CS_Status* status) const = 0; - virtual int GetProperty(int property, CS_Status* status) const = 0; + int GetPropertyIndex(llvm::StringRef name) const; + llvm::ArrayRef EnumerateProperties(llvm::SmallVectorImpl& vec, + CS_Status* status) const; + CS_PropertyType GetPropertyType(int property) const; + llvm::StringRef GetPropertyName(int property, + llvm::SmallVectorImpl& buf, + CS_Status* status) const; + int GetProperty(int property, CS_Status* status) const; virtual void SetProperty(int property, int value, CS_Status* status) = 0; - virtual int GetPropertyMin(int property, CS_Status* status) const = 0; - virtual int GetPropertyMax(int property, CS_Status* status) const = 0; - virtual int GetPropertyStep(int property, CS_Status* status) const = 0; - virtual int GetPropertyDefault(int property, CS_Status* status) const = 0; - virtual llvm::StringRef GetStringProperty(int property, - llvm::SmallVectorImpl& buf, - CS_Status* status) const = 0; + int GetPropertyMin(int property, CS_Status* status) const; + int GetPropertyMax(int property, CS_Status* status) const; + int GetPropertyStep(int property, CS_Status* status) const; + int GetPropertyDefault(int property, CS_Status* status) const; + llvm::StringRef GetStringProperty(int property, + llvm::SmallVectorImpl& buf, + CS_Status* status) const; virtual void SetStringProperty(int property, llvm::StringRef value, CS_Status* status) = 0; - virtual std::vector GetEnumPropertyChoices( - int property, CS_Status* status) const = 0; + std::vector GetEnumPropertyChoices(int property, + CS_Status* status) const; // Video mode functions - virtual VideoMode GetVideoMode(CS_Status* status) const = 0; + VideoMode GetVideoMode(CS_Status* status) const; virtual bool SetVideoMode(const VideoMode& mode, CS_Status* status) = 0; // These have default implementations but can be overridden for custom @@ -110,8 +113,7 @@ class SourceImpl { virtual bool SetResolution(int width, int height, CS_Status* status); virtual bool SetFPS(int fps, CS_Status* status); - virtual std::vector EnumerateVideoModes( - CS_Status* status) const = 0; + std::vector EnumerateVideoModes(CS_Status* status) const; protected: void PutFrame(VideoMode::PixelFormat pixelFormat, llvm::StringRef data, @@ -124,12 +126,69 @@ class SourceImpl { std::atomic_int m_numSinks{0}; std::atomic_int m_numSinksEnabled{0}; + protected: + // Property data + class PropertyBase { + public: + PropertyBase() = default; + PropertyBase(llvm::StringRef name_, CS_PropertyType type_, int minimum_, + int maximum_, int step_, int defaultValue_, int value_) + : name{name_}, + propType{type_}, + minimum{minimum_}, + maximum{maximum_}, + step{step_}, + defaultValue{defaultValue_}, + value{value_} {} + virtual ~PropertyBase() = default; + PropertyBase(const PropertyBase& oth) = delete; + PropertyBase& operator=(const PropertyBase& oth) = delete; + + std::string name; + CS_PropertyType propType{CS_PROP_NONE}; + int minimum; + int maximum; + int step; + int defaultValue; + int value{0}; + std::string valueStr; + std::vector enumChoices; + bool valueSet{false}; + }; + + // Get a property; must be called with m_mutex held. + PropertyBase* GetProperty(int property) { + if (property <= 0 || static_cast(property) > m_propertyData.size()) + return nullptr; + return m_propertyData[property - 1].get(); + } + const PropertyBase* GetProperty(int property) const { + if (property <= 0 || static_cast(property) > m_propertyData.size()) + return nullptr; + return m_propertyData[property - 1].get(); + } + + // Cache properties. Implementations must return false and set status to + // CS_SOURCE_IS_DISCONNECTED if not possible to cache. + virtual bool CacheProperties(CS_Status* status) const = 0; + + // Cached properties and video modes (protected with m_mutex) + mutable std::vector> m_propertyData; + mutable llvm::StringMap m_properties; + mutable std::vector m_videoModes; + // Current video mode + mutable VideoMode m_mode; + // Whether CacheProperties() has been successful at least once (and thus + // should not be called again) + mutable std::atomic_bool m_properties_cached{false}; + + mutable std::mutex m_mutex; + private: void ReleaseFrame(std::unique_ptr data); std::string m_name; - - std::mutex m_mutex; + std::string m_description; std::mutex m_frameMutex; std::condition_variable m_frameCv; @@ -141,6 +200,7 @@ class SourceImpl { bool m_destroyFrames{false}; // Pool of frame data to reduce malloc traffic. + std::mutex m_poolMutex; std::vector> m_framesAvail; }; diff --git a/src/USBCameraImpl.cpp b/src/USBCameraImpl.cpp index b65a42c272..18052d6d16 100644 --- a/src/USBCameraImpl.cpp +++ b/src/USBCameraImpl.cpp @@ -89,12 +89,10 @@ static llvm::StringRef NormalizeName(llvm::StringRef name, #ifdef VIDIOC_QUERY_EXT_CTRL USBCameraImpl::PropertyData::PropertyData( const struct v4l2_query_ext_ctrl& ctrl) - : id(ctrl.id & V4L2_CTRL_ID_MASK), - type(ctrl.type), - minimum(ctrl.minimum), - maximum(ctrl.maximum), - step(ctrl.step), - defaultValue(ctrl.default_value) { + : PropertyBase(llvm::StringRef{}, CS_PROP_NONE, ctrl.minimum, ctrl.maximum, + ctrl.step, ctrl.default_value, 0), + id(ctrl.id & V4L2_CTRL_ID_MASK), + type(ctrl.type) { // propType switch (ctrl.type) { case V4L2_CTRL_TYPE_INTEGER: @@ -124,12 +122,10 @@ USBCameraImpl::PropertyData::PropertyData( #endif USBCameraImpl::PropertyData::PropertyData(const struct v4l2_queryctrl& ctrl) - : id(ctrl.id & V4L2_CTRL_ID_MASK), - type(ctrl.type), - minimum(ctrl.minimum), - maximum(ctrl.maximum), - step(ctrl.step), - defaultValue(ctrl.default_value) { + : PropertyBase(llvm::StringRef{}, CS_PROP_NONE, ctrl.minimum, ctrl.maximum, + ctrl.step, ctrl.default_value, 0), + id(ctrl.id & V4L2_CTRL_ID_MASK), + type(ctrl.type) { // propType switch (ctrl.type) { case V4L2_CTRL_TYPE_INTEGER: @@ -176,9 +172,10 @@ static inline int CheckedIoctl(int fd, unsigned long req, void* data, #define TryIoctl(fd, req, data) \ CheckedIoctl(fd, req, data, #req, __FILE__, __LINE__, true) -static int ExtCtrlIoctl(int fd, __u32* id, USBCameraImpl::PropertyData* prop) { +static std::unique_ptr ExtCtrlIoctl(int fd, + __u32* id) { int rc; - bool done = false; + std::unique_ptr prop; #ifdef VIDIOC_QUERY_EXT_CTRL v4l2_query_ext_ctrl qc_ext; std::memset(&qc_ext, 0, sizeof(qc_ext)); @@ -187,34 +184,35 @@ static int ExtCtrlIoctl(int fd, __u32* id, USBCameraImpl::PropertyData* prop) { if (rc == 0) { *id = qc_ext.id; // copy back // We don't support array types - if (qc_ext.elems > 1 || qc_ext.nr_of_dims > 0) return 0; - *prop = qc_ext; - done = true; + if (qc_ext.elems > 1 || qc_ext.nr_of_dims > 0) return nullptr; + prop = llvm::make_unique(qc_ext); } #endif - if (!done) { + if (!prop) { // Fall back to normal QUERYCTRL struct v4l2_queryctrl qc; std::memset(&qc, 0, sizeof(qc)); qc.id = *id; rc = TryIoctl(fd, VIDIOC_QUERYCTRL, &qc); *id = qc.id; // copy back - if (rc != 0) return rc; - *prop = qc; + if (rc != 0) return nullptr; + prop = llvm::make_unique(qc); } // Cache enum property choices - if (prop->propType != CS_PROP_ENUM) return 0; - prop->enumChoices.resize(prop->maximum + 1); - v4l2_querymenu qmenu; - std::memset(&qmenu, 0, sizeof(qmenu)); - qmenu.id = *id; - for (int i = prop->minimum; i <= prop->maximum; ++i) { - qmenu.index = static_cast<__u32>(i); - if (TryIoctl(fd, VIDIOC_QUERYMENU, &qmenu) != 0) continue; - prop->enumChoices[i] = reinterpret_cast(qmenu.name); + if (prop->propType == CS_PROP_ENUM) { + prop->enumChoices.resize(prop->maximum + 1); + v4l2_querymenu qmenu; + std::memset(&qmenu, 0, sizeof(qmenu)); + qmenu.id = *id; + for (int i = prop->minimum; i <= prop->maximum; ++i) { + qmenu.index = static_cast<__u32>(i); + if (TryIoctl(fd, VIDIOC_QUERYMENU, &qmenu) != 0) continue; + prop->enumChoices[i] = reinterpret_cast(qmenu.name); + } } - return 0; + + return prop; } static int GetIntCtrlIoctl(int fd, unsigned id, int type, int64_t* value) { @@ -376,10 +374,10 @@ static std::string GetDescriptionImpl(const char* cpath) { USBCameraImpl::USBCameraImpl(llvm::StringRef name, llvm::StringRef path) : SourceImpl{name}, m_path{path}, - m_description{GetDescriptionImpl(m_path.c_str())}, m_fd{-1}, m_command_fd{eventfd(0, 0)}, m_active{true} { + SetDescription(GetDescriptionImpl(m_path.c_str())); // Kick off the camera thread m_cameraThread = std::thread(&USBCameraImpl::CameraThreadMain, this); } @@ -632,9 +630,9 @@ void USBCameraImpl::DeviceConnect() { std::unique_lock lock2(m_mutex); for (std::size_t i = 0; i < m_propertyData.size(); ++i) { const auto& prop = m_propertyData[i]; - if (!prop.valueSet) continue; - if (!DeviceSetProperty(lock2, prop)) - WARNING("USB " << m_path << ": failed to set property " << prop.name); + if (!prop->valueSet) continue; + if (!DeviceSetProperty(lock2, static_cast(*prop))) + WARNING("USB " << m_path << ": failed to set property " << prop->name); } } @@ -782,7 +780,7 @@ void USBCameraImpl::DeviceProcessCommands() { int property = msg->data[0]; // Look up - auto prop = GetProperty(property); + auto prop = static_cast(GetProperty(property)); if (!prop) { msg->type = Message::kError; msg->data[0] = CS_INVALID_PROPERTY; @@ -827,7 +825,7 @@ void USBCameraImpl::DeviceProcessCommands() { // Cache the set value. We need to re-get the pointer due to // releasing the lock. - prop = GetProperty(property); + prop = static_cast(GetProperty(property)); if (msg->type == Message::kCmdSetPropertyStr) prop->valueStr = msg->dataStr; else @@ -1019,37 +1017,36 @@ void USBCameraImpl::DeviceCacheMode() { if (fpsChanged) DeviceSetFPS(); } -void USBCameraImpl::DeviceCacheProperty(PropertyData&& prop) { +void USBCameraImpl::DeviceCacheProperty(std::unique_ptr prop) { std::unique_lock lock(m_mutex); - int& ndx = m_properties[prop.name]; + int& ndx = m_properties[prop->name]; if (ndx == 0) { // get the value lock.unlock(); - if (!DeviceGetProperty(&prop)) - WARNING("USB " << m_path << ": failed to get property " << prop.name); + if (!DeviceGetProperty(prop.get())) + WARNING("USB " << m_path << ": failed to get property " << prop->name); lock.lock(); // create a new index ndx = m_propertyData.size() + 1; m_propertyData.emplace_back(std::move(prop)); } else { // merge with existing settings - auto* prop2 = GetProperty(ndx); - prop.valueSet = prop2->valueSet; - prop.value = prop2->value; - prop.valueStr = std::move(prop2->valueStr); + auto prop2 = static_cast(GetProperty(ndx)); + prop->valueSet = prop2->valueSet; + prop->value = prop2->value; + prop->valueStr = std::move(prop2->valueStr); lock.unlock(); - if (prop.valueSet) { + if (prop->valueSet) { // set the value if it was previously set - if (!DeviceSetProperty(lock, prop)) - WARNING("USB " << m_path << ": failed to set property " << prop.name); + if (!DeviceSetProperty(lock, *prop)) + WARNING("USB " << m_path << ": failed to set property " << prop->name); } else { // otherwise get the value - if (!DeviceGetProperty(&prop)) - WARNING("USB " << m_path << ": failed to get property " << prop.name); + if (!DeviceGetProperty(prop.get())) + WARNING("USB " << m_path << ": failed to get property " << prop->name); } lock.lock(); - // need to re-get as we unlocked - *GetProperty(ndx) = std::move(prop); + m_propertyData[ndx - 1] = std::move(prop); } } @@ -1063,9 +1060,8 @@ void USBCameraImpl::DeviceCacheProperties() { #endif ; __u32 id = nextFlags; - PropertyData prop; - while (ExtCtrlIoctl(fd, &id, &prop) == 0) { + while (auto prop = ExtCtrlIoctl(fd, &id)) { DeviceCacheProperty(std::move(prop)); id |= nextFlags; } @@ -1073,11 +1069,12 @@ void USBCameraImpl::DeviceCacheProperties() { if (id == nextFlags) { // try just enumerating standard... for (id = V4L2_CID_BASE; id < V4L2_CID_LASTP1; ++id) { - if (ExtCtrlIoctl(fd, &id, &prop) == 0) + if (auto prop = ExtCtrlIoctl(fd, &id)) DeviceCacheProperty(std::move(prop)); } // ... and custom controls - for (id = V4L2_CID_PRIVATE_BASE; ExtCtrlIoctl(fd, &id, &prop) == 0; ++id) + std::unique_ptr prop; + for (id = V4L2_CID_PRIVATE_BASE; (prop = ExtCtrlIoctl(fd, &id)); ++id) DeviceCacheProperty(std::move(prop)); } } @@ -1260,77 +1257,8 @@ bool USBCameraImpl::CacheProperties(CS_Status* status) const { return true; } -llvm::StringRef USBCameraImpl::GetDescription( - llvm::SmallVectorImpl& buf) const { - return m_description; -} - bool USBCameraImpl::IsConnected() const { return m_fd >= 0; } -int USBCameraImpl::GetPropertyIndex(llvm::StringRef name) const { - // We can't fail, so instead we create a new index if caching fails. - CS_Status status = 0; - if (!m_properties_cached) CacheProperties(&status); - std::lock_guard lock(m_mutex); - int& ndx = m_properties[name]; - if (ndx == 0) { - // create a new index - ndx = m_propertyData.size() + 1; - m_propertyData.emplace_back(); - } - return ndx; -} - -llvm::ArrayRef USBCameraImpl::EnumerateProperties( - llvm::SmallVectorImpl& vec, CS_Status* status) const { - if (!m_properties_cached && !CacheProperties(status)) - return llvm::ArrayRef{}; - std::lock_guard lock(m_mutex); - for (int i = 0; i < static_cast(m_propertyData.size()); ++i) - vec.push_back(i + 1); - return vec; -} - -CS_PropertyType USBCameraImpl::GetPropertyType(int property) const { - CS_Status status = 0; - if (!m_properties_cached && !CacheProperties(&status)) return CS_PROP_NONE; - std::lock_guard lock(m_mutex); - auto prop = GetProperty(property); - if (!prop) return CS_PROP_NONE; - return prop->propType; -} - -llvm::StringRef USBCameraImpl::GetPropertyName(int property, - llvm::SmallVectorImpl& buf, - CS_Status* status) const { - if (!m_properties_cached && !CacheProperties(status)) - return llvm::StringRef{}; - std::lock_guard lock(m_mutex); - auto prop = GetProperty(property); - if (!prop) { - *status = CS_INVALID_PROPERTY; - return llvm::StringRef{}; - } - // safe to not copy because we never modify it after caching - return prop->name; -} - -int USBCameraImpl::GetProperty(int property, CS_Status* status) const { - if (!m_properties_cached && !CacheProperties(status)) return 0; - std::lock_guard lock(m_mutex); - auto prop = GetProperty(property); - if (!prop) { - *status = CS_INVALID_PROPERTY; - return 0; - } - if ((prop->propType & (CS_PROP_BOOLEAN | CS_PROP_INTEGER | CS_PROP_ENUM)) == - 0) { - *status = CS_WRONG_PROPERTY_TYPE; - return 0; - } - return prop->value; -} - void USBCameraImpl::SetProperty(int property, int value, CS_Status* status) { auto msg = CreateMessage(Message::kCmdSetProperty); msg->data[0] = property; @@ -1341,69 +1269,6 @@ void USBCameraImpl::SetProperty(int property, int value, CS_Status* status) { DestroyMessage(std::move(msg)); } -int USBCameraImpl::GetPropertyMin(int property, CS_Status* status) const { - if (!m_properties_cached && !CacheProperties(status)) return 0; - std::lock_guard lock(m_mutex); - auto prop = GetProperty(property); - if (!prop) { - *status = CS_INVALID_PROPERTY; - return 0; - } - return prop->minimum; -} - -int USBCameraImpl::GetPropertyMax(int property, CS_Status* status) const { - if (!m_properties_cached && !CacheProperties(status)) return 0; - std::lock_guard lock(m_mutex); - auto prop = GetProperty(property); - if (!prop) { - *status = CS_INVALID_PROPERTY; - return 0; - } - return prop->maximum; -} - -int USBCameraImpl::GetPropertyStep(int property, CS_Status* status) const { - if (!m_properties_cached && !CacheProperties(status)) return 0; - std::lock_guard lock(m_mutex); - auto prop = GetProperty(property); - if (!prop) { - *status = CS_INVALID_PROPERTY; - return 0; - } - return prop->step; -} - -int USBCameraImpl::GetPropertyDefault(int property, CS_Status* status) const { - if (!m_properties_cached && !CacheProperties(status)) return 0; - std::lock_guard lock(m_mutex); - auto prop = GetProperty(property); - if (!prop) { - *status = CS_INVALID_PROPERTY; - return 0; - } - return prop->defaultValue; -} - -llvm::StringRef USBCameraImpl::GetStringProperty( - int property, llvm::SmallVectorImpl& buf, CS_Status* status) const { - if (!m_properties_cached && !CacheProperties(status)) - return llvm::StringRef{}; - std::lock_guard lock(m_mutex); - auto prop = GetProperty(property); - if (!prop) { - *status = CS_INVALID_PROPERTY; - return llvm::StringRef{}; - } - if (prop->propType != CS_PROP_STRING) { - *status = CS_WRONG_PROPERTY_TYPE; - return llvm::StringRef{}; - } - buf.clear(); - buf.append(prop->valueStr.begin(), prop->valueStr.end()); - return llvm::StringRef(buf.data(), buf.size()); -} - void USBCameraImpl::SetStringProperty(int property, llvm::StringRef value, CS_Status* status) { auto msg = CreateMessage(Message::kCmdSetPropertyStr); @@ -1415,30 +1280,6 @@ void USBCameraImpl::SetStringProperty(int property, llvm::StringRef value, DestroyMessage(std::move(msg)); } -std::vector USBCameraImpl::GetEnumPropertyChoices( - int property, CS_Status* status) const { - if (!m_properties_cached && !CacheProperties(status)) - return std::vector{}; - std::lock_guard lock(m_mutex); - auto prop = GetProperty(property); - if (!prop) { - *status = CS_INVALID_PROPERTY; - return std::vector{}; - } - if (prop->propType != CS_PROP_ENUM) { - *status = CS_WRONG_PROPERTY_TYPE; - return std::vector{}; - } - return prop->enumChoices; -} - -VideoMode USBCameraImpl::GetVideoMode(CS_Status* status) const { - if (!m_properties_cached && !CacheProperties(status)) - return VideoMode{}; - std::lock_guard lock(m_mutex); - return m_mode; -} - bool USBCameraImpl::SetVideoMode(const VideoMode& mode, CS_Status* status) { auto msg = CreateMessage(Message::kCmdSetMode); msg->data[0] = mode.pixelFormat; @@ -1500,14 +1341,6 @@ bool USBCameraImpl::SetFPS(int fps, CS_Status* status) { return rv; } -std::vector USBCameraImpl::EnumerateVideoModes( - CS_Status* status) const { - if (!m_properties_cached && !CacheProperties(status)) - return std::vector{}; - std::lock_guard lock(m_mutex); - return m_videoModes; -} - void USBCameraImpl::NumSinksChanged() { Send(CreateMessage(Message::kNumSinksChanged)); } diff --git a/src/USBCameraImpl.h b/src/USBCameraImpl.h index 9a28dfdebb..5c928c0f0d 100644 --- a/src/USBCameraImpl.h +++ b/src/USBCameraImpl.h @@ -18,7 +18,6 @@ #include "llvm/raw_ostream.h" #include "llvm/SmallVector.h" -#include "llvm/StringMap.h" #include "llvm/STLExtras.h" #include "support/raw_istream.h" @@ -32,45 +31,25 @@ class USBCameraImpl : public SourceImpl { USBCameraImpl(llvm::StringRef name, llvm::StringRef path); ~USBCameraImpl() override; - llvm::StringRef GetDescription( - llvm::SmallVectorImpl& buf) const override; bool IsConnected() const override; // Property functions - int GetPropertyIndex(llvm::StringRef name) const override; - llvm::ArrayRef EnumerateProperties(llvm::SmallVectorImpl& vec, - CS_Status* status) const override; - CS_PropertyType GetPropertyType(int property) const override; - llvm::StringRef GetPropertyName(int property, - llvm::SmallVectorImpl& buf, - CS_Status* status) const override; - int GetProperty(int property, CS_Status* status) const override; void SetProperty(int property, int value, CS_Status* status) override; - int GetPropertyMin(int property, CS_Status* status) const override; - int GetPropertyMax(int property, CS_Status* status) const override; - int GetPropertyStep(int property, CS_Status* status) const override; - int GetPropertyDefault(int property, CS_Status* status) const override; - llvm::StringRef GetStringProperty(int property, - llvm::SmallVectorImpl& buf, - CS_Status* status) const override; void SetStringProperty(int property, llvm::StringRef value, CS_Status* status) override; - std::vector GetEnumPropertyChoices( - int property, CS_Status* status) const override; - VideoMode GetVideoMode(CS_Status* status) const override; bool SetVideoMode(const VideoMode& mode, CS_Status* status) override; bool SetPixelFormat(VideoMode::PixelFormat pixelFormat, CS_Status* status) override; bool SetResolution(int width, int height, CS_Status* status) override; bool SetFPS(int fps, CS_Status* status) override; - std::vector EnumerateVideoModes(CS_Status* status) const override; void NumSinksChanged() override; void NumSinksEnabledChanged() override; // Property data - struct PropertyData { + class PropertyData : public PropertyBase { + public: PropertyData() = default; #ifdef __linux__ #ifdef VIDIOC_QUERY_EXT_CTRL @@ -79,18 +58,8 @@ class USBCameraImpl : public SourceImpl { PropertyData(const struct v4l2_queryctrl& ctrl); #endif - std::string name; unsigned id; // implementation-level id int type; // implementation type, not CS_PropertyType! - CS_PropertyType propType{CS_PROP_NONE}; - int minimum; - int maximum; - int step; - int defaultValue; - int value{0}; - std::string valueStr; - std::vector enumChoices; - bool valueSet{false}; }; // Messages passed to/from camera thread @@ -117,6 +86,12 @@ class USBCameraImpl : public SourceImpl { std::string dataStr; }; + protected: + // Cache properties. Immediately successful if properties are already cached. + // If they are not, tries to connect to the camera to do so; returns false and + // sets status to CS_SOURCE_IS_DISCONNECTED if that too fails. + bool CacheProperties(CS_Status* status) const override; + private: // Message pool access std::unique_ptr CreateMessage(Message::Type type) const { @@ -137,11 +112,6 @@ class USBCameraImpl : public SourceImpl { // Send a message to the camera thread with no response void Send(std::unique_ptr msg) const; - // Cache properties. Immediately successful if properties are already cached. - // If they are not, tries to connect to the camera to do so; returns false and - // sets status to CS_SOURCE_IS_DISCONNECTED if that too fails. - bool CacheProperties(CS_Status* status) const; - // The camera processing thread void CameraThreadMain(); @@ -154,7 +124,7 @@ class USBCameraImpl : public SourceImpl { void DeviceSetMode(); void DeviceSetFPS(); void DeviceCacheMode(); - void DeviceCacheProperty(PropertyData&& prop); + void DeviceCacheProperty(std::unique_ptr prop); void DeviceCacheProperties(); void DeviceCacheVideoModes(); bool DeviceGetProperty(PropertyData* prop); @@ -176,10 +146,9 @@ class USBCameraImpl : public SourceImpl { std::array m_buffers; // - // Path and description: These never change, so not protected by mutex. + // Path never changes, so not protected by mutex. // std::string m_path; - std::string m_description; #ifdef __linux__ std::atomic_int m_fd; @@ -193,34 +162,11 @@ class USBCameraImpl : public SourceImpl { // Variables protected by m_mutex // - // Cached camera information (properties and video modes) - mutable std::vector m_propertyData; - mutable llvm::StringMap m_properties; - std::vector m_videoModes; - std::atomic_bool m_properties_cached{false}; - - // Get a property; must be called with m_mutex held. - PropertyData* GetProperty(int property) { - if (property <= 0 || static_cast(property) > m_propertyData.size()) - return nullptr; - return &m_propertyData[property - 1]; - } - const PropertyData* GetProperty(int property) const { - if (property <= 0 || static_cast(property) > m_propertyData.size()) - return nullptr; - return &m_propertyData[property - 1]; - } - - // Current video mode (updated by camera thread) - VideoMode m_mode; - // Message pool and queues mutable std::vector> m_messagePool; mutable std::vector> m_commands; mutable std::vector> m_responses; mutable std::condition_variable m_responseCv; - - mutable std::mutex m_mutex; }; } // namespace cs