cscore: Separate platform-specific sources (#1387)

This commit is contained in:
Peter Johnson
2018-10-23 22:59:47 -07:00
committed by GitHub
parent 349e273ecc
commit 8ff81f5a2a
22 changed files with 333 additions and 180 deletions

View File

@@ -53,15 +53,6 @@ void HttpCameraImpl::Start() {
m_settingsThread = std::thread(&HttpCameraImpl::SettingsThreadMain, this);
}
#ifdef __linux__
static inline void DoFdSet(int fd, fd_set* set, int* nfds) {
if (fd >= 0) {
FD_SET(fd, set);
if ((fd + 1) > *nfds) *nfds = fd + 1;
}
}
#endif
void HttpCameraImpl::StreamThreadMain() {
while (m_active) {
SetConnected(false);

View File

@@ -1,136 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "NetworkListener.h"
#ifdef __linux__
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/eventfd.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <cerrno>
#endif
#include "Log.h"
#include "Notifier.h"
using namespace cs;
class NetworkListener::Thread : public wpi::SafeThread {
public:
void Main();
#ifdef __linux__
int m_command_fd = -1;
#endif
};
NetworkListener::~NetworkListener() { Stop(); }
void NetworkListener::Start() {
auto thr = m_owner.GetThread();
if (!thr) m_owner.Start();
}
void NetworkListener::Stop() {
// Wake up thread
if (auto thr = m_owner.GetThread()) {
thr->m_active = false;
#ifdef __linux__
if (thr->m_command_fd >= 0) eventfd_write(thr->m_command_fd, 1);
#endif
}
m_owner.Stop();
}
void NetworkListener::Thread::Main() {
#ifdef __linux__
// Create event socket so we can be shut down
m_command_fd = ::eventfd(0, 0);
if (m_command_fd < 0) {
ERROR(
"NetworkListener: could not create eventfd: " << std::strerror(errno));
return;
}
// Create netlink socket
int sd = ::socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (sd < 0) {
ERROR("NetworkListener: could not create socket: " << std::strerror(errno));
::close(m_command_fd);
m_command_fd = -1;
return;
}
// Bind to netlink socket
struct sockaddr_nl addr;
std::memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
if (bind(sd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) < 0) {
ERROR("NetworkListener: could not create socket: " << std::strerror(errno));
::close(sd);
::close(m_command_fd);
m_command_fd = -1;
return;
}
char buf[4096];
while (m_active) {
// select timeout
struct timeval tv;
tv.tv_sec = 10;
tv.tv_usec = 0;
// select on applicable read descriptors
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(m_command_fd, &readfds);
FD_SET(sd, &readfds);
int nfds = std::max(m_command_fd, sd) + 1;
if (::select(nfds, &readfds, nullptr, nullptr, &tv) < 0) {
ERROR("NetworkListener: select(): " << std::strerror(errno));
break; // XXX: is this the right thing to do here?
}
// Double-check to see if we're shutting down
if (!m_active) break;
if (!FD_ISSET(sd, &readfds)) continue;
std::memset(&addr, 0, sizeof(addr));
struct iovec iov = {buf, sizeof(buf)};
struct msghdr msg = {&addr, sizeof(addr), &iov, 1, nullptr, 0, 0};
int len = ::recvmsg(sd, &msg, 0);
if (len < 0) {
if (errno == EWOULDBLOCK || errno == EAGAIN) continue;
ERROR(
"NetworkListener: could not read netlink: " << std::strerror(errno));
break; // XXX: is this the right thing to do here?
}
if (len == 0) continue; // EOF?
for (struct nlmsghdr* nh = reinterpret_cast<struct nlmsghdr*>(buf);
NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
if (nh->nlmsg_type == NLMSG_DONE) break;
if (nh->nlmsg_type == RTM_NEWLINK || nh->nlmsg_type == RTM_DELLINK ||
nh->nlmsg_type == RTM_NEWADDR || nh->nlmsg_type == RTM_DELADDR) {
Notifier::GetInstance().NotifyNetworkInterfacesChanged();
}
}
}
::close(sd);
::close(m_command_fd);
m_command_fd = -1;
#endif
}

View File

@@ -1,60 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#ifndef CSCORE_USBCAMERABUFFER_H_
#define CSCORE_USBCAMERABUFFER_H_
#ifdef __linux__
#include <sys/mman.h>
#endif
#include <utility>
namespace cs {
class UsbCameraBuffer {
public:
UsbCameraBuffer() noexcept : m_data{nullptr}, m_length{0} {}
UsbCameraBuffer(UsbCameraBuffer&& other) noexcept : UsbCameraBuffer() {
swap(*this, other);
}
UsbCameraBuffer& operator=(UsbCameraBuffer&& other) noexcept {
swap(*this, other);
return *this;
}
UsbCameraBuffer(const UsbCameraBuffer&) = delete;
UsbCameraBuffer& operator=(const UsbCameraBuffer&) = delete;
#ifdef __linux__
UsbCameraBuffer(int fd, size_t length, off_t offset) noexcept
: m_length{length} {
m_data =
mmap(nullptr, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
if (m_data == MAP_FAILED) {
m_data = nullptr;
m_length = 0;
}
}
~UsbCameraBuffer() {
if (m_data) munmap(m_data, m_length);
}
#endif
friend void swap(UsbCameraBuffer& first, UsbCameraBuffer& second) noexcept {
using std::swap;
swap(first.m_data, second.m_data);
swap(first.m_length, second.m_length);
}
void* m_data;
size_t m_length;
};
} // namespace cs
#endif // CSCORE_USBCAMERABUFFER_H_

File diff suppressed because it is too large Load Diff

View File

@@ -1,185 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#ifndef CSCORE_USBCAMERAIMPL_H_
#define CSCORE_USBCAMERAIMPL_H_
#ifdef __linux__
#include <linux/videodev2.h>
#endif
#include <atomic>
#include <memory>
#include <string>
#include <thread>
#include <utility>
#include <vector>
#include <wpi/STLExtras.h>
#include <wpi/SmallVector.h>
#include <wpi/Twine.h>
#include <wpi/condition_variable.h>
#include <wpi/mutex.h>
#include <wpi/raw_istream.h>
#include <wpi/raw_ostream.h>
#include "SourceImpl.h"
#include "UsbCameraBuffer.h"
#include "UsbCameraProperty.h"
namespace cs {
class UsbCameraImpl : public SourceImpl {
public:
UsbCameraImpl(const wpi::Twine& name, const wpi::Twine& path);
~UsbCameraImpl() override;
void Start();
// Property functions
void SetProperty(int property, int value, CS_Status* status) override;
void SetStringProperty(int property, const wpi::Twine& value,
CS_Status* status) override;
// Standard common camera properties
void SetBrightness(int brightness, CS_Status* status) override;
int GetBrightness(CS_Status* status) const override;
void SetWhiteBalanceAuto(CS_Status* status) override;
void SetWhiteBalanceHoldCurrent(CS_Status* status) override;
void SetWhiteBalanceManual(int value, CS_Status* status) override;
void SetExposureAuto(CS_Status* status) override;
void SetExposureHoldCurrent(CS_Status* status) override;
void SetExposureManual(int value, CS_Status* status) 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;
void NumSinksChanged() override;
void NumSinksEnabledChanged() override;
std::string GetPath() { return m_path; }
// Messages passed to/from camera thread
struct Message {
enum Kind {
kNone = 0,
kCmdSetMode,
kCmdSetPixelFormat,
kCmdSetResolution,
kCmdSetFPS,
kCmdSetProperty,
kCmdSetPropertyStr,
kNumSinksChanged, // no response
kNumSinksEnabledChanged, // no response
// Responses
kOk,
kError
};
explicit Message(Kind kind_)
: kind(kind_), from(std::this_thread::get_id()) {}
Kind kind;
int data[4];
std::string dataStr;
std::thread::id from;
};
protected:
std::unique_ptr<PropertyImpl> CreateEmptyProperty(
const wpi::Twine& name) const override;
// 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:
// Send a message to the camera thread and wait for a response (generic)
CS_StatusValue SendAndWait(Message&& msg) const;
// Send a message to the camera thread with no response
void Send(Message&& msg) const;
// The camera processing thread
void CameraThreadMain();
// Functions used by CameraThreadMain()
void DeviceDisconnect();
void DeviceConnect();
bool DeviceStreamOn();
bool DeviceStreamOff();
void DeviceProcessCommands();
void DeviceSetMode();
void DeviceSetFPS();
void DeviceCacheMode();
void DeviceCacheProperty(std::unique_ptr<UsbCameraProperty> rawProp);
void DeviceCacheProperties();
void DeviceCacheVideoModes();
// Command helper functions
CS_StatusValue DeviceProcessCommand(std::unique_lock<wpi::mutex>& lock,
const Message& msg);
CS_StatusValue DeviceCmdSetMode(std::unique_lock<wpi::mutex>& lock,
const Message& msg);
CS_StatusValue DeviceCmdSetProperty(std::unique_lock<wpi::mutex>& lock,
const Message& msg);
// Property helper functions
int RawToPercentage(const UsbCameraProperty& rawProp, int rawValue);
int PercentageToRaw(const UsbCameraProperty& rawProp, int percentValue);
void SetQuirks();
//
// Variables only used within camera thread
//
bool m_streaming;
bool m_modeSetPixelFormat{false};
bool m_modeSetResolution{false};
bool m_modeSetFPS{false};
int m_connectVerbose{1};
#ifdef __linux__
unsigned m_capabilities = 0;
#endif
// Number of buffers to ask OS for
static constexpr int kNumBuffers = 4;
#ifdef __linux__
std::array<UsbCameraBuffer, kNumBuffers> m_buffers;
#endif
//
// Path never changes, so not protected by mutex.
//
std::string m_path;
#ifdef __linux__
std::atomic_int m_fd;
std::atomic_int m_command_fd; // for command eventfd
#endif
std::atomic_bool m_active; // set to false to terminate thread
std::thread m_cameraThread;
// Quirks
bool m_lifecam_exposure{false}; // Microsoft LifeCam exposure
//
// Variables protected by m_mutex
//
// Message queues
mutable std::vector<Message> m_commands;
mutable std::vector<std::pair<std::thread::id, CS_StatusValue>> m_responses;
mutable wpi::condition_variable m_responseCv;
};
} // namespace cs
#endif // CSCORE_USBCAMERAIMPL_H_

View File

@@ -0,0 +1,52 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "cscore_c.h" // NOLINT(build/include_order)
#include "c_util.h"
#include "cscore_cpp.h"
using namespace cs;
extern "C" {
CS_Source CS_CreateUsbCameraDev(const char* name, int dev, CS_Status* status) {
return cs::CreateUsbCameraDev(name, dev, status);
}
CS_Source CS_CreateUsbCameraPath(const char* name, const char* path,
CS_Status* status) {
return cs::CreateUsbCameraPath(name, path, status);
}
char* CS_GetUsbCameraPath(CS_Source source, CS_Status* status) {
return ConvertToC(cs::GetUsbCameraPath(source, status));
}
CS_UsbCameraInfo* CS_EnumerateUsbCameras(int* count, CS_Status* status) {
auto cameras = cs::EnumerateUsbCameras(status);
CS_UsbCameraInfo* out = static_cast<CS_UsbCameraInfo*>(
wpi::CheckedMalloc(cameras.size() * sizeof(CS_UsbCameraInfo)));
*count = cameras.size();
for (size_t i = 0; i < cameras.size(); ++i) {
out[i].dev = cameras[i].dev;
out[i].path = ConvertToC(cameras[i].path);
out[i].name = ConvertToC(cameras[i].name);
}
return out;
}
void CS_FreeEnumeratedUsbCameras(CS_UsbCameraInfo* cameras, int count) {
if (!cameras) return;
for (int i = 0; i < count; ++i) {
std::free(cameras[i].path);
std::free(cameras[i].name);
}
std::free(cameras);
}
} // extern "C"

View File

@@ -1,326 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "UsbCameraProperty.h"
#include <wpi/STLExtras.h>
#include <wpi/SmallString.h>
#include "UsbUtil.h"
using namespace cs;
#ifdef __linux__
static int GetIntCtrlIoctl(int fd, unsigned id, int type, int64_t* value) {
unsigned ctrl_class = V4L2_CTRL_ID2CLASS(id);
if (type == V4L2_CTRL_TYPE_INTEGER64 || V4L2_CTRL_DRIVER_PRIV(id) ||
(ctrl_class != V4L2_CTRL_CLASS_USER &&
ctrl_class != V4L2_CID_PRIVATE_BASE)) {
// Use extended control
struct v4l2_ext_control ctrl;
struct v4l2_ext_controls ctrls;
std::memset(&ctrl, 0, sizeof(ctrl));
std::memset(&ctrls, 0, sizeof(ctrls));
ctrl.id = id;
ctrls.ctrl_class = ctrl_class;
ctrls.count = 1;
ctrls.controls = &ctrl;
int rc = DoIoctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls);
if (rc < 0) return rc;
*value = ctrl.value;
} else {
// Use normal control
struct v4l2_control ctrl;
std::memset(&ctrl, 0, sizeof(ctrl));
ctrl.id = id;
int rc = DoIoctl(fd, VIDIOC_G_CTRL, &ctrl);
if (rc < 0) return rc;
*value = ctrl.value;
}
return 0;
}
static int SetIntCtrlIoctl(int fd, unsigned id, int type, int64_t value) {
unsigned ctrl_class = V4L2_CTRL_ID2CLASS(id);
if (type == V4L2_CTRL_TYPE_INTEGER64 || V4L2_CTRL_DRIVER_PRIV(id) ||
(ctrl_class != V4L2_CTRL_CLASS_USER &&
ctrl_class != V4L2_CID_PRIVATE_BASE)) {
// Use extended control
struct v4l2_ext_control ctrl;
struct v4l2_ext_controls ctrls;
std::memset(&ctrl, 0, sizeof(ctrl));
std::memset(&ctrls, 0, sizeof(ctrls));
ctrl.id = id;
if (type == V4L2_CTRL_TYPE_INTEGER64)
ctrl.value64 = value;
else
ctrl.value = static_cast<__s32>(value);
ctrls.ctrl_class = ctrl_class;
ctrls.count = 1;
ctrls.controls = &ctrl;
return DoIoctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls);
} else {
// Use normal control
struct v4l2_control ctrl;
ctrl.id = id;
ctrl.value = static_cast<__s32>(value);
return DoIoctl(fd, VIDIOC_S_CTRL, &ctrl);
}
}
static int GetStringCtrlIoctl(int fd, int id, int maximum, std::string* value) {
struct v4l2_ext_control ctrl;
struct v4l2_ext_controls ctrls;
std::memset(&ctrl, 0, sizeof(ctrl));
std::memset(&ctrls, 0, sizeof(ctrls));
ctrl.id = id;
ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(id);
ctrls.count = 1;
ctrls.controls = &ctrl;
int rc = DoIoctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls);
if (rc < 0) {
value->clear();
return rc;
}
value->assign(ctrl.string, std::strlen(ctrl.string));
return 0;
}
static int SetStringCtrlIoctl(int fd, int id, int maximum,
const wpi::Twine& value) {
wpi::SmallString<64> strBuf, strBuf2;
wpi::StringRef str = value.toNullTerminatedStringRef(strBuf);
if (str.size() > static_cast<size_t>(maximum)) {
// don't know if strBuf was used, just recopy
strBuf2 = str.take_front(maximum);
str = strBuf2;
strBuf2.push_back('\0'); // null terminate
}
struct v4l2_ext_control ctrl;
struct v4l2_ext_controls ctrls;
std::memset(&ctrl, 0, sizeof(ctrl));
std::memset(&ctrls, 0, sizeof(ctrls));
ctrl.id = id;
ctrl.size = str.size();
ctrl.string = const_cast<char*>(str.data());
ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(id);
ctrls.count = 1;
ctrls.controls = &ctrl;
return DoIoctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls);
}
// Removes non-alphanumeric characters and replaces spaces with underscores.
// e.g. "Zoom, Absolute" -> "zoom_absolute", "Pan (Absolute)" -> "pan_absolute"
static wpi::StringRef NormalizeName(wpi::StringRef name,
wpi::SmallVectorImpl<char>& buf) {
bool newWord = false;
for (auto ch : name) {
if (std::isalnum(ch)) {
if (newWord) buf.push_back('_');
newWord = false;
buf.push_back(std::tolower(ch));
} else if (!buf.empty()) {
newWord = true;
}
}
return wpi::StringRef(buf.data(), buf.size());
}
#ifdef VIDIOC_QUERY_EXT_CTRL
UsbCameraProperty::UsbCameraProperty(const struct v4l2_query_ext_ctrl& ctrl)
: PropertyImpl(wpi::StringRef{}, CS_PROP_NONE, ctrl.step,
ctrl.default_value, 0),
id(ctrl.id & V4L2_CTRL_ID_MASK),
type(ctrl.type) {
hasMinimum = true;
minimum = ctrl.minimum;
hasMaximum = true;
maximum = ctrl.maximum;
// propKind
switch (ctrl.type) {
case V4L2_CTRL_TYPE_INTEGER:
case V4L2_CTRL_TYPE_INTEGER64:
propKind = CS_PROP_INTEGER;
break;
case V4L2_CTRL_TYPE_BOOLEAN:
propKind = CS_PROP_BOOLEAN;
break;
case V4L2_CTRL_TYPE_INTEGER_MENU:
case V4L2_CTRL_TYPE_MENU:
propKind = CS_PROP_ENUM;
break;
case V4L2_CTRL_TYPE_STRING:
propKind = CS_PROP_STRING;
break;
default:
return; // others unsupported
}
// name
size_t len = 0;
while (len < sizeof(ctrl.name) && ctrl.name[len] != '\0') ++len;
wpi::SmallString<64> name_buf;
name = NormalizeName(wpi::StringRef(ctrl.name, len), name_buf);
}
#endif
UsbCameraProperty::UsbCameraProperty(const struct v4l2_queryctrl& ctrl)
: PropertyImpl(wpi::StringRef{}, CS_PROP_NONE, ctrl.step,
ctrl.default_value, 0),
id(ctrl.id & V4L2_CTRL_ID_MASK),
type(ctrl.type) {
hasMinimum = true;
minimum = ctrl.minimum;
hasMaximum = true;
maximum = ctrl.maximum;
// propKind
switch (ctrl.type) {
case V4L2_CTRL_TYPE_INTEGER:
case V4L2_CTRL_TYPE_INTEGER64:
propKind = CS_PROP_INTEGER;
break;
case V4L2_CTRL_TYPE_BOOLEAN:
propKind = CS_PROP_BOOLEAN;
break;
case V4L2_CTRL_TYPE_INTEGER_MENU:
case V4L2_CTRL_TYPE_MENU:
propKind = CS_PROP_ENUM;
break;
case V4L2_CTRL_TYPE_STRING:
propKind = CS_PROP_STRING;
break;
default:
return; // others unsupported
}
// name
size_t len = 0;
while (len < sizeof(ctrl.name) && ctrl.name[len] != '\0') ++len;
wpi::SmallString<64> name_buf;
name = NormalizeName(
wpi::StringRef(reinterpret_cast<const char*>(ctrl.name), len), name_buf);
}
std::unique_ptr<UsbCameraProperty> UsbCameraProperty::DeviceQuery(int fd,
__u32* id) {
int rc;
std::unique_ptr<UsbCameraProperty> prop;
#ifdef VIDIOC_QUERY_EXT_CTRL
v4l2_query_ext_ctrl qc_ext;
std::memset(&qc_ext, 0, sizeof(qc_ext));
qc_ext.id = *id;
rc = TryIoctl(fd, VIDIOC_QUERY_EXT_CTRL, &qc_ext);
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 nullptr;
prop = wpi::make_unique<UsbCameraProperty>(qc_ext);
}
#endif
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 nullptr;
prop = wpi::make_unique<UsbCameraProperty>(qc);
}
// Cache enum property choices
if (prop->propKind == 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<const char*>(qmenu.name);
}
}
return prop;
}
bool UsbCameraProperty::DeviceGet(std::unique_lock<wpi::mutex>& lock, int fd) {
if (fd < 0) return true;
unsigned idCopy = id;
int rv = 0;
switch (propKind) {
case CS_PROP_BOOLEAN:
case CS_PROP_INTEGER:
case CS_PROP_ENUM: {
int typeCopy = type;
int64_t newValue = 0;
lock.unlock();
rv = GetIntCtrlIoctl(fd, idCopy, typeCopy, &newValue);
lock.lock();
if (rv >= 0) value = newValue;
break;
}
case CS_PROP_STRING: {
int maximumCopy = maximum;
std::string newValueStr;
lock.unlock();
rv = GetStringCtrlIoctl(fd, idCopy, maximumCopy, &newValueStr);
lock.lock();
if (rv >= 0) valueStr = std::move(newValueStr);
break;
}
default:
break;
}
return rv >= 0;
}
bool UsbCameraProperty::DeviceSet(std::unique_lock<wpi::mutex>& lock,
int fd) const {
// Make a copy of the string as we're about to release the lock
wpi::SmallString<128> valueStrCopy{valueStr};
return DeviceSet(lock, fd, value, valueStrCopy);
}
bool UsbCameraProperty::DeviceSet(std::unique_lock<wpi::mutex>& lock, int fd,
int newValue,
const wpi::Twine& newValueStr) const {
if (!device || fd < 0) return true;
unsigned idCopy = id;
int rv = 0;
switch (propKind) {
case CS_PROP_BOOLEAN:
case CS_PROP_INTEGER:
case CS_PROP_ENUM: {
int typeCopy = type;
lock.unlock();
rv = SetIntCtrlIoctl(fd, idCopy, typeCopy, newValue);
lock.lock();
break;
}
case CS_PROP_STRING: {
int maximumCopy = maximum;
lock.unlock();
rv = SetStringCtrlIoctl(fd, idCopy, maximumCopy, newValueStr);
lock.lock();
break;
}
default:
break;
}
return rv >= 0;
}
#endif // __linux__

View File

@@ -1,82 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#ifndef CSCORE_USBCAMERAPROPERTY_H_
#define CSCORE_USBCAMERAPROPERTY_H_
#ifdef __linux__
#include <linux/videodev2.h>
#endif
#include <memory>
#include <wpi/mutex.h>
#include "PropertyImpl.h"
namespace cs {
// Property data
class UsbCameraProperty : public PropertyImpl {
public:
UsbCameraProperty() = default;
explicit UsbCameraProperty(const wpi::Twine& name_) : PropertyImpl{name_} {}
// Software property constructor
UsbCameraProperty(const wpi::Twine& name_, unsigned id_,
CS_PropertyKind kind_, int minimum_, int maximum_,
int step_, int defaultValue_, int value_)
: PropertyImpl(name_, kind_, minimum_, maximum_, step_, defaultValue_,
value_),
device{false},
id{id_} {}
// Normalized property constructor
UsbCameraProperty(const wpi::Twine& name_, int rawIndex_,
const UsbCameraProperty& rawProp, int defaultValue_,
int value_)
: PropertyImpl(name_, rawProp.propKind, 1, defaultValue_, value_),
percentage{true},
propPair{rawIndex_},
id{rawProp.id},
type{rawProp.type} {
hasMinimum = true;
minimum = 0;
hasMaximum = true;
maximum = 100;
}
#ifdef __linux__
#ifdef VIDIOC_QUERY_EXT_CTRL
explicit UsbCameraProperty(const struct v4l2_query_ext_ctrl& ctrl);
#endif
explicit UsbCameraProperty(const struct v4l2_queryctrl& ctrl);
static std::unique_ptr<UsbCameraProperty> DeviceQuery(int fd, __u32* id);
bool DeviceGet(std::unique_lock<wpi::mutex>& lock, int fd);
bool DeviceSet(std::unique_lock<wpi::mutex>& lock, int fd) const;
bool DeviceSet(std::unique_lock<wpi::mutex>& lock, int fd, int newValue,
const wpi::Twine& newValueStr) const;
#endif
// If this is a device (rather than software) property
bool device{true};
// If this is a percentage (rather than raw) property
bool percentage{false};
// If not 0, index of corresponding raw/percentage property
int propPair{0};
unsigned id{0}; // implementation-level id
int type{0}; // implementation type, not CS_PropertyKind!
};
} // namespace cs
#endif // CSCORE_USBCAMERAPROPERTY_H_

View File

@@ -1,166 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "UsbUtil.h"
#include <fcntl.h>
#ifdef __linux__
#include <libgen.h>
#include <sys/ioctl.h>
#endif
#include <wpi/Format.h>
#include <wpi/SmallString.h>
#include <wpi/raw_istream.h>
#include <wpi/raw_ostream.h>
#include "Log.h"
namespace cs {
#ifdef __linux__
static wpi::StringRef GetUsbNameFromFile(int vendor, int product,
wpi::SmallVectorImpl<char>& buf) {
int fd = open("/var/lib/usbutils/usb.ids", O_RDONLY);
if (fd < 0) return wpi::StringRef{};
wpi::raw_svector_ostream os{buf};
wpi::raw_fd_istream is{fd, true};
// build vendor and product 4-char hex strings
wpi::SmallString<16> vendorStr, productStr;
wpi::raw_svector_ostream vendorOs{vendorStr}, productOs{productStr};
vendorOs << wpi::format_hex_no_prefix(vendor, 4);
productOs << wpi::format_hex_no_prefix(product, 4);
// scan file
wpi::SmallString<128> lineBuf;
bool foundVendor = false;
for (;;) {
auto line = is.getline(lineBuf, 4096);
if (is.has_error()) break;
if (line.empty()) continue;
// look for vendor at start of line
if (line.startswith(vendorStr)) {
foundVendor = true;
os << line.substr(5).trim() << ' ';
continue;
}
if (foundVendor) {
// next vendor, but didn't match product?
if (line[0] != '\t') {
os << "Unknown";
return os.str();
}
// look for product
if (line.substr(1).startswith(productStr)) {
os << line.substr(6).trim();
return os.str();
}
}
}
return wpi::StringRef{};
}
wpi::StringRef GetUsbNameFromId(int vendor, int product,
wpi::SmallVectorImpl<char>& buf) {
// try reading usb.ids
wpi::StringRef rv = GetUsbNameFromFile(vendor, product, buf);
if (!rv.empty()) return rv;
// Fall back to internal database
wpi::raw_svector_ostream os{buf};
switch (vendor) {
case 0x046d:
os << "Logitech, Inc. ";
switch (product) {
case 0x0802:
os << "Webcam C200";
break;
case 0x0804:
os << "Webcam C250";
break;
case 0x0805:
os << "Webcam C300";
break;
case 0x0807:
os << "Webcam B500";
break;
case 0x0808:
os << "Webcam C600";
break;
case 0x0809:
os << "Webcam Pro 9000";
break;
case 0x080a:
os << "Portable Webcam C905";
break;
case 0x080f:
os << "Webcam C120";
break;
case 0x0819:
os << "Webcam C210";
break;
case 0x081b:
os << "Webcam C310";
break;
case 0x081d:
os << "HD Webcam C510";
break;
case 0x0821:
os << "HD Webcam C910";
break;
case 0x0825:
os << "Webcam C270";
break;
case 0x0826:
os << "HD Webcam C525";
break;
case 0x0828:
os << "HD Webcam B990";
break;
case 0x082b:
os << "Webcam C170";
break;
case 0x082d:
os << "HD Pro Webcam C920";
break;
case 0x0836:
os << "B525 HD Webcam";
break;
case 0x0843:
os << "Webcam C930e";
break;
}
break;
}
return os.str();
}
int CheckedIoctl(int fd, unsigned long req, void* data, // NOLINT(runtime/int)
const char* name, const char* file, int line, bool quiet) {
int retval = ioctl(fd, req, data);
if (!quiet && retval < 0) {
wpi::SmallString<64> localfile{file};
localfile.push_back('\0');
ERROR("ioctl " << name << " failed at " << basename(localfile.data()) << ":"
<< line << ": " << std::strerror(errno));
}
return retval;
}
#endif // __linux__
} // namespace cs

View File

@@ -1,35 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#ifndef CSCORE_USBUTIL_H_
#define CSCORE_USBUTIL_H_
#include <stdint.h>
#include <wpi/SmallVector.h>
#include <wpi/StringRef.h>
namespace cs {
#ifdef __linux__
wpi::StringRef GetUsbNameFromId(int vendor, int product,
wpi::SmallVectorImpl<char>& buf);
int CheckedIoctl(int fd, unsigned long req, void* data, // NOLINT(runtime/int)
const char* name, const char* file, int line, bool quiet);
#define DoIoctl(fd, req, data) \
CheckedIoctl(fd, req, data, #req, __FILE__, __LINE__, false)
#define TryIoctl(fd, req, data) \
CheckedIoctl(fd, req, data, #req, __FILE__, __LINE__, true)
#endif // __linux__
} // namespace cs
#endif // CSCORE_USBUTIL_H_

View File

@@ -7,13 +7,6 @@
#include "cscore_cpp.h"
#if defined(__linux__)
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <sys/types.h>
#include <unistd.h>
#endif
#include <wpi/SmallString.h>
#include "Handle.h"
@@ -693,39 +686,4 @@ wpi::ArrayRef<CS_Sink> EnumerateSinkHandles(wpi::SmallVectorImpl<CS_Sink>& vec,
return Sinks::GetInstance().GetAll(vec);
}
std::string GetHostname() {
#ifdef __linux__
char name[256];
if (::gethostname(name, sizeof(name)) != 0) return "";
name[255] = '\0'; // Per POSIX, may not be null terminated if too long
return name;
#else
return ""; // TODO
#endif
}
std::vector<std::string> GetNetworkInterfaces() {
#ifdef __linux__
struct ifaddrs* ifa;
if (::getifaddrs(&ifa) != 0) return std::vector<std::string>{};
std::vector<std::string> rv;
char buf[256];
for (struct ifaddrs* i = ifa; i; i = i->ifa_next) {
if (!i->ifa_addr) continue; // no address
if (i->ifa_addr->sa_family != AF_INET) continue; // only return IPv4
struct sockaddr_in* addr_in = reinterpret_cast<sockaddr_in*>(i->ifa_addr);
const char* addr =
::inet_ntop(addr_in->sin_family, &addr_in->sin_addr, buf, sizeof(buf));
if (!addr) continue; // error converting address
rv.emplace_back(addr);
}
::freeifaddrs(ifa);
return rv;
#else
return std::vector<std::string>{}; // TODO
#endif
}
} // namespace cs

View File

@@ -181,7 +181,6 @@ static inline bool CheckStatus(JNIEnv* env, CS_Status status) {
return status == CS_OK;
}
#ifdef __linux__
static jobject MakeJObject(JNIEnv* env, const cs::UsbCameraInfo& info) {
static jmethodID constructor = env->GetMethodID(
usbCameraInfoCls, "<init>", "(ILjava/lang/String;Ljava/lang/String;)V");
@@ -190,7 +189,6 @@ static jobject MakeJObject(JNIEnv* env, const cs::UsbCameraInfo& info) {
return env->NewObject(usbCameraInfoCls, constructor,
static_cast<jint>(info.dev), path.obj(), name.obj());
}
#endif
static jobject MakeJObject(JNIEnv* env, const cs::VideoMode& videoMode) {
static jmethodID constructor =
@@ -406,10 +404,6 @@ JNIEXPORT jint JNICALL
Java_edu_wpi_cscore_CameraServerJNI_createUsbCameraDev
(JNIEnv* env, jclass, jstring name, jint dev)
{
#ifndef __linux__
unsupportedEx.Throw(env, "USB is not supported yet");
return 0;
#else
if (!name) {
nullPointerEx.Throw(env, "name cannot be null");
return 0;
@@ -418,7 +412,6 @@ Java_edu_wpi_cscore_CameraServerJNI_createUsbCameraDev
auto val = cs::CreateUsbCameraDev(JStringRef{env, name}.str(), dev, &status);
CheckStatus(env, status);
return val;
#endif
}
/*
@@ -430,10 +423,6 @@ JNIEXPORT jint JNICALL
Java_edu_wpi_cscore_CameraServerJNI_createUsbCameraPath
(JNIEnv* env, jclass, jstring name, jstring path)
{
#ifndef __linux__
unsupportedEx.Throw(env, "USB is not supported yet");
return 0;
#else
if (!name) {
nullPointerEx.Throw(env, "name cannot be null");
return 0;
@@ -447,7 +436,6 @@ Java_edu_wpi_cscore_CameraServerJNI_createUsbCameraPath
JStringRef{env, path}.str(), &status);
CheckStatus(env, status);
return val;
#endif
}
/*
@@ -949,15 +937,10 @@ JNIEXPORT jstring JNICALL
Java_edu_wpi_cscore_CameraServerJNI_getUsbCameraPath
(JNIEnv* env, jclass, jint source)
{
#ifndef __linux__
unsupportedEx.Throw(env, "USB is not supported yet");
return 0;
#else
CS_Status status = 0;
auto str = cs::GetUsbCameraPath(source, &status);
if (!CheckStatus(env, status)) return nullptr;
return MakeJString(env, str);
#endif
}
/*
@@ -1582,10 +1565,6 @@ JNIEXPORT jobjectArray JNICALL
Java_edu_wpi_cscore_CameraServerJNI_enumerateUsbCameras
(JNIEnv* env, jclass)
{
#ifndef __linux__
unsupportedEx.Throw(env, "USB is not supported yet");
return 0;
#else
CS_Status status = 0;
auto arr = cs::EnumerateUsbCameras(&status);
if (!CheckStatus(env, status)) return nullptr;
@@ -1597,7 +1576,6 @@ Java_edu_wpi_cscore_CameraServerJNI_enumerateUsbCameras
env->SetObjectArrayElement(jarr, i, jelem);
}
return jarr;
#endif
}
/*