Commit b019155c authored by Nicolas Michon's avatar Nicolas Michon

Initial commit

parents
SmartWireless GmbH & Co. KG
\ No newline at end of file
cmake_minimum_required(VERSION 3.4)
project(mselph264
LANGUAGES CXX
VERSION 0.4.0
)
find_program(CLANG_TIDY_BIN clang-tidy HINTS)
if(CLANG_TIDY_BIN)
message(STATUS "Use clang-tidy")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
endif()
option(ENABLE_TEST "Enable test programs using the plugin" OFF)
option(ENABLE_TOOLS "Enable test tools for manual checking" OFF)
option(ENABLE_DOC "Enable generating documentation" OFF)
add_subdirectory(src)
if(ENABLE_TOOLS)
add_subdirectory(tools)
endif()
if(ENABLE_DOC)
add_subdirectory(docs)
endif()
\ No newline at end of file
This diff is collapsed.
find_package(Doxygen REQUIRED)
# set input and output files
set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY)
add_custom_target(doc_doxygen ALL
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating API documentation with Doxygen"
VERBATIM
)
\ No newline at end of file
PROJECT_NAME = "@PROJECT_NAME@"
OUTPUT_DIRECTORY = "@CMAKE_CURRENT_BINARY_DIR@"
INPUT = "@PROJECT_SOURCE_DIR@/src"
EXCLUDE_PATTERNS = "*/test/*"
FULL_PATH_NAMES = NO
TAB_SIZE = 2
MARKDOWN_SUPPORT = NO
BUILTIN_STL_SUPPORT = YES
EXTRACT_ALL = YES
CASE_SENSE_NAMES = YES
GENERATE_TODOLIST = NO
GENERATE_TESTLIST = NO
GENERATE_BUGLIST = NO
RECURSIVE = YES
GENERATE_HTML = YES
HTML_OUTPUT = html
SEARCHENGINE = NO
GENERATE_LATEX = NO
GENERATE_XML = YES
XML_OUTPUT = xml
ENABLE_PREPROCESSING = NO
HAVE_DOT = YES
INTERACTIVE_SVG = YES
add_subdirectory(camera)
add_subdirectory(plugin)
project(h264camera
VERSION 0.2.0
LANGUAGES CXX
)
find_package(PkgConfig REQUIRED)
pkg_check_modules(V4L REQUIRED IMPORTED_TARGET libv4l2 libv4l1 libv4lconvert)
include(GNUInstallDirs)
add_library(elph264 SHARED
include/h264camera/elp_usb100w04h.hpp
include/h264camera/types.hpp
include/h264camera/v4l2_device.hpp
src/data_helper.hpp
src/elp_usb100w04h.cpp
src/v4l2_device.cpp
)
add_library(mselph264::camera ALIAS elph264)
target_compile_options(elph264 PRIVATE "-Wall;-Wextra;-Werror;-pedantic")
target_compile_features(elph264 PUBLIC cxx_std_17)
target_include_directories(elph264
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
PUBLIC $<INSTALL_INTERFACE:include>
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src
)
target_link_libraries(elph264 PRIVATE PkgConfig::V4L)
set_target_properties(elph264 PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
)
if(CLANG_TIDY_BIN)
set_target_properties(elph264 PROPERTIES
CXX_CLANG_TIDY "${CLANG_TIDY_BIN};-p;${CMAKE_BINARY_DIR};-checks='*'"
)
endif()
install(TARGETS elph264 EXPORT elph264Config
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
install(DIRECTORY include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
install(FILES elp-camera.rules
DESTINATION ${CMAKE_INSTALL_LIBDIR}/udev/rules.d
)
install(EXPORT elph264Config
DESTINATION share/elph264/cmake
)
export(TARGETS elph264 FILE elph264Config.cmake)
if(ENABLE_TEST)
find_package(Catch2 REQUIRED)
enable_testing()
add_executable(h264camera_test
test/main.cpp
test/tc_elp_usb100w04h.cpp
test/tc_v4l2_device.cpp
)
target_link_libraries(h264camera_test
PRIVATE Catch2::Catch2
PRIVATE mselph264::camera
)
add_test(NAME h264camera_test COMMAND ${CMAKE_CURRENT_BINARY_DIR}/h264camera_test)
find_package(fmt REQUIRED)
add_executable(capture_tester test/capture_tester.cpp)
target_link_libraries(capture_tester
PRIVATE mselph264::camera
PRIVATE fmt::fmt-header-only
)
endif(ENABLE_TEST)
\ No newline at end of file
SUBSYSTEMS=="usb", ATTRS{idProduct}=="9420", ATTRS{idVendor}=="05a3", GOTO="elp_camera"
SUBSYSTEM=="video4linux", ATTRS{index}=="0", SYMLINK+="elp-mjpeg", LABEL="elp_camera"
SUBSYSTEM=="video4linux", ATTRS{index}=="1", SYMLINK+="elp-h264", LABEL="elp_camera"
\ No newline at end of file
// Copyright (C) 2019 SmartWireless GmbH & Co. KG
//
// This file is part of mselph264.
//
// mselph264 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// mselph264 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with mselph264. If not, see <http://www.gnu.org/licenses/>.
#ifndef USB100W04H_HPP__
#define USB100W04H_HPP__
#include <array>
#include "v4l2_device.hpp"
#include "types.hpp"
namespace h264camera {
/// UVC interface extensions for a ELP USB100W04H
class Usb100W04H : public Device {
public:
using Device::Device;
/// Read vendor chip id
int xuReadChipId();
/// Connecting the extended controls, has to be called at least once
/// while the camera is plugged.
void addXuCtrl();
/// Get bitrate
double xuBitrate() const;
/// Set bitrate
void xuSetBitrate(double br);
/// Get mode (CBR, VBR)
Mode xuMode() const;
/// Set mode
void xuSetMode(Mode mode);
/// Check H.264 SEI header settings
bool xuSeiHeaderEnabled() const;
/// Set H.264 SEI header
void xuEnableSeiHeader(bool enable);
/// This method returns the register value for the color mode, but this does
/// not alwyas represent the applied color. To ensure color settings, apply
/// while the stream is running.
bool xuColor() const;
/// Set the color mode. If set to false, the output is in gray scale.
void xuSetColor(bool enable);
/// Request I-frame
void xuResetIFrame();
/// Set camera RTC to local time
void xuUpdateOsdRtc();
/// Set the flip state
///
/// Setting false is normal orientation and setting true will flip the image
/// on the H.264 stream.
void xuSetFlip(bool flip);
/// Get the flip state
bool xuFlip();
private:
template <typename CTRL> auto uvcGetCur() const;
template <typename CTRL>
void uvcSetCur(typename CTRL::value_type value) const;
};
} // namespace h264camera
#endif // USB100W04H_HPP__
// Copyright (C) 2019 SmartWireless GmbH & Co. KG
//
// This file is part of mselph264.
//
// mselph264 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// mselph264 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with mselph264. If not, see <http://www.gnu.org/licenses/>.
#ifndef H264_CAMERA_HPP__
#define H264_CAMERA_HPP__
#include <array>
#include <chrono>
#include <cstdint>
#include <ctime>
namespace h264camera {
// Convert register values into or from structurs for ease of use
enum class Mode : uint8_t { CBR = 1, VBR = 2 };
struct ChipId {
int id;
};
struct TimeRTC {
std::chrono::system_clock::time_point time;
};
template <std::size_t SIZE, typename TYPE>
constexpr auto convert_to(const std::array<uint8_t, SIZE> &data) -> TYPE;
template <>
constexpr auto convert_to(const std::array<uint8_t, 11> &data) -> int {
return (data[0] << 16) | (data[1] << 8) | data[2];
}
template <>
constexpr auto convert_to(const std::array<uint8_t, 11> &data) -> bool {
return data[0] == 1;
}
template <>
constexpr auto convert_to(const std::array<uint8_t, 4> &data) -> ChipId {
return {data[2]};
}
template <>
constexpr auto convert_to(const std::array<uint8_t, 11> &data) -> Mode {
return static_cast<Mode>(data[0]);
}
template <>
inline auto convert_to(const std::array<uint8_t, 11> &data) -> TimeRTC {
tm cam_rtc;
cam_rtc.tm_sec = data[0];
cam_rtc.tm_min = data[1];
cam_rtc.tm_hour = data[2];
cam_rtc.tm_mday = data[3];
cam_rtc.tm_mon = data[4] - 1;
cam_rtc.tm_year = ((data[5] << 8) | data[6]) - 1900;
return TimeRTC{std::chrono::system_clock::from_time_t(mktime(&cam_rtc))};
}
template <std::size_t SIZE, typename TYPE>
constexpr void convert_from(std::array<uint8_t, SIZE> &dest, TYPE value);
template <>
constexpr void convert_from(std::array<uint8_t, 11> &dest, int value) {
dest = {{static_cast<uint8_t>((value & 0x00FF0000) >> 16),
static_cast<uint8_t>((value & 0x0000FF00) >> 8),
static_cast<uint8_t>(value & 0x000000FF)}};
}
template <>
constexpr void convert_from(std::array<uint8_t, 11> &dest, bool value) {
dest = {{(value) ? static_cast<uint8_t>(0x01) : static_cast<uint8_t>(0x00)}};
}
template <>
constexpr void convert_from(std::array<uint8_t, 11> &dest, Mode value) {
dest[0] = static_cast<uint8_t>(value);
}
template <>
inline void convert_from(std::array<uint8_t, 11> &dest, TimeRTC value) {
auto tt = std::chrono::system_clock::to_time_t(value.time);
tm cam_rtc = *std::localtime(&tt);
dest[0] = cam_rtc.tm_sec;
dest[1] = cam_rtc.tm_min;
dest[2] = cam_rtc.tm_hour;
dest[3] = cam_rtc.tm_mday;
dest[4] = cam_rtc.tm_mon + 1;
int year = cam_rtc.tm_year + 1900;
dest[5] = (year & 0xFF00) >> 8;
dest[6] = (year & 0x00FF);
}
} // namespace h264camera
#endif
\ No newline at end of file
// Copyright (C) 2019 SmartWireless GmbH & Co. KG
//
// This file is part of mselph264.
//
// mselph264 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// mselph264 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with mselph264. If not, see <http://www.gnu.org/licenses/>.
#ifndef V4L2_DEVICE_HPP__
#define V4L2_DEVICE_HPP__
#include <chrono>
#include <linux/uvcvideo.h>
#include <linux/videodev2.h>
#include <string>
#include <vector>
namespace h264camera {
struct VideoSize {
unsigned int width{0};
unsigned int height{0};
};
constexpr inline bool operator==(const VideoSize &a, const VideoSize &b) {
return (a.width == b.width && a.height == b.height);
}
constexpr VideoSize VIDEO_SIZE_720P{1280, 720};
constexpr VideoSize VIDEO_SIZE_SVGA{800, 600};
constexpr VideoSize VIDEO_SIZE_VGA{640, 480};
/// This class will handle the camera device descriptor and wrap v4l2
/// calls.
///
/// https://linuxtv.org/downloads/v4l-dvb-apis/uapi/v4l/user-func.html
class Device {
public:
/// Constructor opening the device using v4l2_open
/// @param dev Device path, e.g., /dev/video0
Device(const std::string &dev_path);
/// Destructor closing the device using v4l2_close
~Device();
/// Open device
void open();
/// Close device
void close();
/// Check if device is open
bool isOpen() const;
/// Open the device, after closing when necessary
void reopen();
/// @see v4l2_ioctl
int ioctl(unsigned long int request, void *argp) const;
/// Create memory map
void mmap();
/// Wait for new data to be ready
bool ready(std::chrono::milliseconds timeout) const;
/// Return the device path
inline const std::string &path() const { return mPath; }
// Some convenience functions
void setFormat(uint32_t width, uint32_t height, uint32_t format);
void setFramerate(uint32_t framerate);
VideoSize vsize();
/// Enable capture stream
int streamOn();
/// Disable capture stream
int streamOff();
struct Mem {
Mem(std::uint32_t index, void *ptr, std::size_t len);
~Mem();
Mem(Mem &&);
/// - UNUSED : Ready to be queued again
/// - READY : Dequeud and has data to be processed
/// - QUEUED : Wait for new data
enum class State { UNUSED, READY, QUEUED } state{State::UNUSED};
/// The index within the vector
const std::uint32_t index;
/// Pointer to the mapped memory
void *ptr{nullptr};
/// Length of the buffer
std::uint32_t len{0};
/// Count of bytes with data in the buffer
v4l2_buffer video_buffer;
std::uint32_t used() const { return video_buffer.bytesused; }
/// Call this when done with the buffered data so it might be
/// requeued
inline void done() { state = State::UNUSED; }
inline bool isUnused() const { return state == State::UNUSED; }
inline bool isReady() const { return state == State::READY; }
inline bool isQueued() const { return state == State::QUEUED; }
};
/// Check if there are still queued buffers
bool queued() const { return mQueuedBuffers > 0; }
/// Indicate if there a buffers ready for queuing.
bool freeSlots() const { return mQueuedBuffers < mMap.size(); }
/// Try and queue all unqueued buffer
int queue();
/// Queue a given frame
int queue(std::size_t index);
/// Dequeue a buffer a ready buffer
Mem *dequeue(std::chrono::milliseconds timeout);
private:
uint32_t requestBuffer(uint32_t count);
v4l2_buffer bufferRequest(unsigned long int request, uint32_t index);
int queue(Mem &mem);
static const uint32_t V4L2_DEFAULT_BUFFER_COUNT{6};
/// Device path string
const std::string mPath;
/// File descriptor
int fd{-1};
/// The buffers
std::vector<Mem> mMap;
/// Count and track queued buffers
std::size_t mQueuedBuffers{0};
};
} // namespace h264camera
#endif // V4L2_DEVICE_HPP__
// Copyright (C) 2019 SmartWireless GmbH & Co. KG
//
// This file is part of mselph264.
//
// mselph264 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// mselph264 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with mselph264. If not, see <http://www.gnu.org/licenses/>.
#ifndef ELPH264_DATA_HELPER_HPP__
#define ELPH264_DATA_HELPER_HPP__
#include <array>
namespace h264camera {
// NOTE: The int conversion uses only 24bit
template <std::size_t size = 11>
constexpr double data_to_int(const std::array<uint8_t, size> &data) {
static_assert(size >= 3, "Array is too small");
return (data[0] << 16) | (data[1] << 8) | data[2];
}
template <std::size_t size = 11>
constexpr std::array<uint8_t, size> data_from_int(int32_t val) {
static_assert(size >= 3, "Array is too small");
return {{static_cast<uint8_t>((val & 0x00FF0000) >> 16),
static_cast<uint8_t>((val & 0x0000FF00) >> 8),
static_cast<uint8_t>(val & 0x000000FF)}};
}
template <std::size_t size = 11>
constexpr bool data_to_bool(const std::array<uint8_t, size> &data) {
static_assert(size >= 1, "Array is too small");
return data[0] == 1;
}
template <std::size_t size = 11>
constexpr std::array<uint8_t, size> data_from_bool(bool val) {
static_assert(size >= 1, "Array is too small");
return {{(val) ? static_cast<uint8_t>(0x01) : static_cast<uint8_t>(0x00)}};
}
}
#endif
\ No newline at end of file
// Copyright (C) 2019 SmartWireless GmbH & Co. KG
//
// This file is part of mselph264.
//
// mselph264 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// mselph264 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with mselph264. If not, see <http://www.gnu.org/licenses/>.
#include <h264camera/elp_usb100w04h.hpp>
#include <chrono>
#include <cstring>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <system_error>
#include <linux/usb/video.h>
#include <linux/uvcvideo.h>
#include "data_helper.hpp"
namespace h264camera {
// All sorts of constant values as defined in the ELP USB100W04H Linux
// SDK.
#define UVC_GUID_RERVISION_SYS_HW_CTRL \
{ \
0x70, 0x33, 0xf0, 0x28, 0x11, 0x63, 0x2e, 0x4a, 0xba, 0x2c, 0x68, 0x90, \
0xeb, 0x33, 0x40, 0x16 \
}
#define UVC_GUID_RERVISION_USR_HW_CTRL \
{ \
0x94, 0x73, 0xDF, 0xDD, 0x3E, 0x97, 0x27, 0x47, 0xBE, 0xD9, 0x04, 0xED, \
0x64, 0x26, 0xDC, 0x67 \
}
constexpr uint32_t V4L2_CID_BASE_EXTCTR_RERVISION = 0x0A0c4501;
constexpr uint32_t V4L2_CID_BASE_RERVISION = V4L2_CID_BASE_EXTCTR_RERVISION;
constexpr uint32_t V4L2_CID_ASIC_RW_RERVISION = V4L2_CID_BASE_RERVISION + 1;
constexpr uint32_t V4L2_CID_H264_CTRL_RERVISION = V4L2_CID_BASE_RERVISION + 4;
enum class XUUnit : uint8_t {
RERVISION_SYS_ID = 0x03,
RERVISION_USR_ID = 0x04
};
// ----- XU Control Selector -----
enum class XUSelector : uint8_t {
SYS_ASIC_RW = 0x01,
SYS_H264_CTRL = 0x07,
USR_H264_CTRL = 0x02,
USR_OSD_CTRL = 0x04,
USR_IMG_SETTING = 0x06
};
template <XUUnit XUUNIT, XUSelector XUSELECTOR, std::uint8_t TAG,
std::uint8_t REG, std::size_t XU_SIZE, typename TYPE>
struct Ctrl {
static constexpr XUUnit unit{XUUNIT};
static constexpr XUSelector selector{XUSELECTOR};
static constexpr uint8_t tag{TAG};
static constexpr uint8_t reg{REG};
static constexpr std::size_t xu_size{XU_SIZE};
typedef TYPE value_type;
};
using SysChipId = Ctrl<XUUnit::RERVISION_SYS_ID, XUSelector::SYS_ASIC_RW, 0x1F,
0x10, 4, ChipId>;
using CtrlBitRate = Ctrl<XUUnit::RERVISION_USR_ID, XUSelector::USR_H264_CTRL,
0x9A, 0x02, 11, int>;
using CtrlIFrame = Ctrl<XUUnit::RERVISION_USR_ID, XUSelector::USR_H264_CTRL,
0x9A, 0x04, 11, bool>;
using CtrlSEIHeader = Ctrl<XUUnit::RERVISION_USR_ID, XUSelector::USR_H264_CTRL,
0x9A, 0x05, 11, bool>;
using CtrlMode = Ctrl<XUUnit::RERVISION_USR_ID, XUSelector::USR_H264_CTRL, 0x9A,
0x06, 11, Mode>;
using SettingImgFlip = Ctrl<XUUnit::RERVISION_USR_ID,
XUSelector::USR_IMG_SETTING, 0x9A, 0x02, 11, bool>;
using SettingImgColor = Ctrl<XUUnit::RERVISION_USR_ID,
XUSelector::USR_IMG_SETTING, 0x9A, 0x03, 11, bool>;
using OsdCtrlRTC = Ctrl<XUUnit::RERVISION_USR_ID, XUSelector::USR_OSD_CTRL,
0x9A, 0x01, 11, TimeRTC>;
/// XU Controller access
template <typename CTRL> uvc_xu_control_query create_query(uint8_t *data) {
struct uvc_xu_control_query xctrl;
xctrl.unit = static_cast<uint8_t>(CTRL::unit);
xctrl.selector = static_cast<uint8_t>(CTRL::selector);
data[0] = CTRL::tag;
data[1] = CTRL::reg;
xctrl.size = CTRL::xu_size;
xctrl.data = data;
return xctrl;
}
template <typename CTRL> auto Usb100W04H::uvcGetCur() const {
std::array<uint8_t, CTRL::xu_size> data{{0}};
auto xctrl = create_query<CTRL>(data.data());
xctrl.query = UVC_SET_CUR;
if (-1 == ioctl(UVCIOC_CTRL_QUERY, &xctrl)) {
throw std::system_error(errno, std::system_category(),
"UVCIOC_CTRL_QUERY failed");
}
data.fill(0);
xctrl.query = UVC_GET_CUR;
if (-1 == ioctl(UVCIOC_CTRL_QUERY, &xctrl)) {
throw std::system_error(errno, std::system_category(),
"UVCIOC_CTRL_QUERY failed");
}
return convert_to<CTRL::xu_size, typename CTRL::value_type>(data);
}
template <typename CTRL>
void Usb100W04H::uvcSetCur(typename CTRL::value_type value) const {
std::array<uint8_t, CTRL::xu_size> data{{0}};
auto xctrl = create_query<CTRL>(data.data());
xctrl.query = UVC_SET_CUR;
if (-1 == ioctl(UVCIOC_CTRL_QUERY, &xctrl)) {
throw std::system_error(errno, std::system_category(),
"UVCIOC_CTRL_QUERY failed");
}
convert_from<CTRL::xu_size, typename CTRL::value_type>(data, value);
xctrl.query = UVC_SET_CUR;
if (-1 == ioctl(UVCIOC_CTRL_QUERY, &xctrl)) {
throw std::system_error(errno, std::system_category(),
"UVCIOC_CTRL_QUERY failed");
}
}
// We do not have the C way of initializing structs :(
// NOTE: This mapping is incomplete, but suffices for now.
constexpr std::array<uvc_xu_control_mapping, 2> control_mapping = {
{uvc_xu_control_mapping{V4L2_CID_ASIC_RW_RERVISION,
"RERVISION: Asic Read",
UVC_GUID_RERVISION_SYS_HW_CTRL,
static_cast<uint8_t>(XUSelector::SYS_ASIC_RW),
4,
0,
V4L2_CTRL_TYPE_INTEGER,
UVC_CTRL_DATA_TYPE_SIGNED,
nullptr,
0,
{0, 0, 0, 0}},
uvc_xu_control_mapping{V4L2_CID_H264_CTRL_RERVISION,
"RERVISION: H264 Control",
UVC_GUID_RERVISION_USR_HW_CTRL,
static_cast<uint8_t>(XUSelector::USR_H264_CTRL),
11,
0,
V4L2_CTRL_TYPE_INTEGER,
UVC_CTRL_DATA_TYPE_UNSIGNED,
nullptr,
0,
{0, 0, 0, 0}}}};
void Usb100W04H::addXuCtrl() {
for (auto mapping : control_mapping) {
if (-1 == ioctl(UVCIOC_CTRL_MAP, &mapping)) {
// The control need only to be set once, the if they are already
// set for the device the ioctl call will fail with EEXIST and
// everything is fine.