34 inline void debugCtrlReq(
struct usb_ctrlrequest
const & ctrl)
38 LDEBUG(std::showbase << std::hex <<
"bRequestType " << ctrl.bRequestType <<
" bRequest " << ctrl.bRequest
39 <<
" wValue " << ctrl.wValue <<
" wIndex " << ctrl.wIndex <<
" wLength " << ctrl.wLength);
42 inline void debugStreamingCtrl(std::string
const & msg,
struct uvc_streaming_control
const & ctrl)
46 LDEBUG(msg <<
": " << std::showbase << std::hex <<
"bmHint=" << ctrl.bmHint <<
", bFormatIndex=" <<
47 ctrl.bFormatIndex <<
", bFrameIndex=" << ctrl.bFrameIndex <<
", dwFrameInterval=" << ctrl.dwFrameInterval <<
48 ", wKeyFrameRate=" << ctrl.wKeyFrameRate <<
", wPFrameRate=" << ctrl.wPFrameRate <<
49 ", wCompQuality=" << ctrl.wCompQuality <<
", wCompWindowSize=" << ctrl.wCompWindowSize <<
50 ", wDelay=" << ctrl.wDelay <<
", dwMaxVideoFrameSize=" << ctrl.dwMaxVideoFrameSize <<
51 ", dwMaxPayloadTransferSize=" << ctrl.dwMaxPayloadTransferSize <<
", dwClockFrequency=" <<
52 ctrl.dwClockFrequency <<
", bmFramingInfo=" << ctrl.bmFramingInfo <<
", bPreferedVersion=" <<
53 ctrl.bPreferedVersion <<
", bMinVersion=" << ctrl.bMinVersion <<
", bMaxVersion=" << ctrl.bMaxVersion);
56 unsigned int uvcToV4Lcontrol(
unsigned int entity,
unsigned int cs)
85 case UVC_CT_AE_MODE_CONTROL:
return V4L2_CID_EXPOSURE_AUTO;
86 case UVC_CT_AE_PRIORITY_CONTROL:
return V4L2_CID_EXPOSURE_AUTO_PRIORITY;
87 case UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL:
return V4L2_CID_EXPOSURE_ABSOLUTE;
118 case UVC_PU_BACKLIGHT_COMPENSATION_CONTROL:
return V4L2_CID_BACKLIGHT_COMPENSATION;
119 case UVC_PU_BRIGHTNESS_CONTROL:
return V4L2_CID_BRIGHTNESS;
120 case UVC_PU_CONTRAST_CONTROL:
return V4L2_CID_CONTRAST;
121 case UVC_PU_GAIN_CONTROL:
return V4L2_CID_GAIN;
122 case UVC_PU_POWER_LINE_FREQUENCY_CONTROL:
return V4L2_CID_POWER_LINE_FREQUENCY;
123 case UVC_PU_HUE_CONTROL:
return V4L2_CID_HUE;
124 case UVC_PU_SATURATION_CONTROL:
return V4L2_CID_SATURATION;
125 case UVC_PU_SHARPNESS_CONTROL:
return V4L2_CID_SHARPNESS;
126 case UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL:
return V4L2_CID_RED_BALANCE;
127 case UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL:
return V4L2_CID_AUTO_WHITE_BALANCE;
133 LFATAL(
"Request to access unsupported control " << cs <<
" on entity " << entity);
140 size_t const nbufs,
bool multicam) :
141 itsFd(-1), itsMulticam(multicam), itsNbufs(nbufs), itsBuffers(nullptr), itsCamera(camera), itsEngine(engine),
142 itsRunning(false), itsFormat(), itsFps(0.0F), itsStreaming(false), itsErrorCode(0), itsControl(0), itsEntity(0)
146 if (itsCamera ==
nullptr)
LFATAL(
"Gadget requires a valid camera to work");
149 fillStreamingControl(&itsProbe, m);
150 fillStreamingControl(&itsCommit, m);
154 while (itsRunning.load() ==
false) std::this_thread::sleep_for(std::chrono::milliseconds(5));
157 itsFd = open(devname.c_str(), O_RDWR | O_NONBLOCK);
158 if (itsFd == -1)
PLFATAL(
"Gadget device open failed for " << devname);
161 struct v4l2_event_subscription sub = { };
164 XIOCTL(itsFd, VIDIOC_SUBSCRIBE_EVENT, &sub);
167 XIOCTL(itsFd, VIDIOC_SUBSCRIBE_EVENT, &sub);
170 XIOCTL(itsFd, VIDIOC_SUBSCRIBE_EVENT, &sub);
173 XIOCTL(itsFd, VIDIOC_SUBSCRIBE_EVENT, &sub);
176 struct v4l2_capability cap = { };
177 XIOCTL(itsFd, VIDIOC_QUERYCAP, &cap);
179 LINFO(
'[' << itsFd <<
"] UVC gadget " << devname <<
" card " << cap.card <<
" bus " << cap.bus_info);
180 if ((cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) == 0)
LFATAL(devname <<
" is not a video output device");
181 if ((cap.capabilities & V4L2_CAP_STREAMING) == 0)
LFATAL(devname <<
" does not support streaming");
192 itsRunning.store(
false);
197 if (close(itsFd) == -1)
PLERROR(
"Error closing UVC gadget -- IGNORED");
208 memset(&itsFormat, 0,
sizeof(
struct v4l2_format));
210 itsFormat.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
211 itsFormat.fmt.pix.width = m.
ow;
212 itsFormat.fmt.pix.height = m.
oh;
213 itsFormat.fmt.pix.pixelformat = m.
ofmt;
214 itsFormat.fmt.pix.field = V4L2_FIELD_NONE;
215 itsFormat.fmt.pix.sizeimage = m.
osize();
219 if (m.
ofmt == 0) {
LINFO(
"USB Gadget set video format to NONE");
return; }
222 XIOCTL(itsFd, VIDIOC_S_FMT, &itsFormat);
228 struct v4l2_streamparm sparm = { };
229 sparm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
230 sparm.parm.output.outputmode = 2;
235 LINFO(
"USB Gadget set video format to " << itsFormat.fmt.pix.width <<
'x' << itsFormat.fmt.pix.height <<
' ' <<
240void jevois::Gadget::run()
249 itsRunning.store(
true);
252 while (itsFd == -1) std::this_thread::sleep_for(std::chrono::milliseconds(1));
255 while (itsRunning.load())
258 FD_ZERO(&wfds); FD_ZERO(&efds); FD_SET(itsFd, &wfds); FD_SET(itsFd, &efds);
259 tv.tv_sec = 0; tv.tv_usec = 10000;
261 int ret = select(itsFd + 1,
nullptr, &wfds, &efds, &tv);
263 if (ret == -1) {
PLERROR(
"Select error");
if (errno == EINTR)
continue;
else break; }
267 if (FD_ISSET(itsFd, &efds))
273 while (
true)
try { processEvents(); }
catch (...) {
break; }
283 while (
true)
try { processEvents(); }
catch (...) {
break; }
289 if (itsDoneImgs.size())
291 LDEBUG(
"Queuing image " << itsDoneImgs.front() <<
" for sending over USB");
294 struct v4l2_buffer buf = { };
296 buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
297 buf.memory = V4L2_MEMORY_MMAP;
298 buf.index = itsDoneImgs.front();
299 buf.length = itsBuffers->get(buf.index)->length();
301 if (itsFormat.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
302 buf.bytesused = itsBuffers->get(buf.index)->bytesUsed();
304 buf.bytesused = buf.length;
306 buf.field = V4L2_FIELD_NONE;
308 gettimeofday(&buf.timestamp,
nullptr);
311 itsBuffers->qbuf(buf);
314 itsDoneImgs.pop_front();
320 itsRunning.store(
false);
324void jevois::Gadget::processEvents()
329 struct v4l2_event v4l2ev = { };
353void jevois::Gadget::processVideo()
361 if (itsStreaming.load() ==
false)
LFATAL(
"Aborted while not streaming");
365 struct v4l2_buffer buf;
366 itsBuffers->dqbuf(buf);
369 img.
width = itsFormat.fmt.pix.width;
370 img.
height = itsFormat.fmt.pix.height;
371 img.
fmt = itsFormat.fmt.pix.pixelformat;
373 img.
buf = itsBuffers->get(buf.index);
377 itsImageQueue.push_back(img);
378 LDEBUG(
"Empty image " << img.
bufindex <<
" ready for filling in by application code");
382void jevois::Gadget::processEventSetup(
struct usb_ctrlrequest
const & ctrl,
struct uvc_request_data & resp)
386 itsControl = 0; itsEntity = 0;
390 switch (ctrl.bRequestType & USB_TYPE_MASK)
392 case USB_TYPE_STANDARD: processEventStandard(ctrl, resp);
break;
393 case USB_TYPE_CLASS: processEventClass(ctrl, resp);
break;
394 default:
LERROR(
"Unsupported setup event type " << std::showbase << std::hex <<
395 (ctrl.bRequestType & USB_TYPE_MASK) <<
" -- IGNORED");
401void jevois::Gadget::processEventStandard(
struct usb_ctrlrequest
const & ctrl,
struct uvc_request_data &)
405 LDEBUG(
"UVC standard setup event ignored:");
410void jevois::Gadget::processEventClass(
struct usb_ctrlrequest
const & ctrl,
struct uvc_request_data & resp)
414 if ((ctrl.bRequestType & USB_RECIP_MASK) != USB_RECIP_INTERFACE)
return;
416 switch (ctrl.wIndex & 0xff)
419 processEventControl(ctrl.bRequest, ctrl.wValue >> 8, ctrl.wIndex >> 8, ctrl.wLength, resp);
423 processEventStreaming(ctrl.bRequest, ctrl.wValue >> 8, resp);
427 LERROR(
"Unsupported setup event class " << std::showbase << std::hex << (ctrl.wIndex & 0xff) <<
" -- IGNORED");
432void jevois::Gadget::processEventControl(uint8_t req, uint8_t cs, uint8_t entity_id, uint8_t len,
438#define success() { itsErrorCode = 0; }
441#define failure(code) { resp.length = -EL2HLT; itsErrorCode = code; }
444#define byteresponse(val) { resp.data[0] = val; resp.length = 1; itsErrorCode = 0; }
447#define wordresponse(val) { resp.data[0] = val & 0xff; resp.data[1] = (val >> 8) & 0xff; \
448 resp.length = 2; itsErrorCode = 0; }
451#define intresponse(val) { resp.data[0] = val & 0xff; resp.data[1] = (val >> 8) & 0xff; \
452 resp.data[2] = (val >> 16) & 0xff; resp.data[3] = (val >> 24) & 0xff; \
453 resp.length = 4; itsErrorCode = 0; }
456#define arrayblankresponse(len) { memset(resp.data, 0, len); resp.length = len; itsErrorCode = 0; }
466 case UVC_VC_REQUEST_ERROR_CODE_CONTROL:
byteresponse(itsErrorCode);
return;
467 default:
failure(0x06);
return;
472 if (req == UVC_SET_CUR)
475 itsEntity = entity_id; itsControl = cs;
477 LDEBUG(
"SET_CUR ent " << itsEntity <<
" ctrl "<< itsControl <<
" len "<< len);
479 else if (req == UVC_GET_INFO)
482 byteresponse(UVC_CONTROL_CAP_GET | UVC_CONTROL_CAP_SET);
484 else if (req == UVC_GET_CUR)
489 struct v4l2_control ctrl = { };
490 try { ctrl.id = uvcToV4Lcontrol(entity_id, cs); itsCamera->getControl(ctrl); }
catch (...) { ctrl.id = 0; }
493 if (ctrl.id == V4L2_CID_RED_BALANCE)
495 unsigned int redval = (ctrl.value & 0xffff) << 16;
498 ctrl.id = V4L2_CID_BLUE_BALANCE;
499 itsCamera->getControl(ctrl);
502 ctrl.value = (ctrl.value & 0xffff) | redval;
505 else if (ctrl.id == V4L2_CID_EXPOSURE_AUTO)
507 if (ctrl.value == V4L2_EXPOSURE_MANUAL) ctrl.value = 0x01;
508 else if (ctrl.value == V4L2_EXPOSURE_AUTO) ctrl.value = 0x02;
509 else ctrl.value = 0x03;
513 else if (ctrl.id == 0) ctrl.value = 0;
520 default:
LERROR(
"Unsupported control with length " << len <<
" -- SENDING BLANK RESPONSE");
529 struct v4l2_queryctrl qc = { };
530 try { qc.id = uvcToV4Lcontrol(entity_id, cs); itsCamera->queryControl(qc); }
catch (...) { qc.id = 0; }
533 if (qc.id == V4L2_CID_RED_BALANCE)
536 struct v4l2_queryctrl qc2 = { };
537 qc2.id = V4L2_CID_BLUE_BALANCE;
538 itsCamera->queryControl(qc2);
541 qc.default_value = (qc.default_value << 16) | qc2.default_value;
542 qc.step = (qc.step << 16) | qc2.step;
543 qc.minimum = (qc.minimum << 16) | qc2.minimum;
544 qc.maximum = (qc.maximum << 16) | qc2.maximum;
547 else if (qc.id == V4L2_CID_EXPOSURE_AUTO)
552 qc.minimum = 0; qc.step = 3; qc.maximum = 3; qc.default_value = 1;
556 { qc.minimum = 0; qc.step = 1; qc.maximum = 1; qc.default_value = 0; }
561 case UVC_GET_DEF: val = qc.default_value;
break;
562 case UVC_GET_RES: val = qc.step;
break;
563 case UVC_GET_MIN: val = qc.minimum;
break;
564 case UVC_GET_MAX: val = qc.maximum;
break;
565 default:
failure(0x07);
return;
573 default:
LERROR(
"Unsupported control with length " << len <<
" -- SENDING BLANK RESPONSE");
580 LERROR(
"FAILED entity " << entity_id <<
" cs " << cs <<
" len " << len);
586void jevois::Gadget::fillStreamingControl(
struct uvc_streaming_control * ctrl,
jevois::VideoMapping const & m)
590 memset(ctrl, 0,
sizeof(
struct uvc_streaming_control));
595 ctrl->dwMaxVideoFrameSize = m.
osize();
596 ctrl->dwMaxPayloadTransferSize = itsMulticam ? 1024 : 3072;
597 ctrl->bmFramingInfo = 3;
598 ctrl->bPreferedVersion = 1;
599 ctrl->bMaxVersion = 1;
603void jevois::Gadget::processEventStreaming(uint8_t req, uint8_t cs,
struct uvc_request_data & resp)
607 int const datalen = 26;
608 if (cs != UVC_VS_PROBE_CONTROL && cs != UVC_VS_COMMIT_CONTROL)
return;
610 struct uvc_streaming_control * ctrl =
reinterpret_cast<struct uvc_streaming_control *
>(&resp.
data);
611 struct uvc_streaming_control * target = (cs == UVC_VS_PROBE_CONTROL) ? &itsProbe : &itsCommit;
616 case UVC_SET_CUR: itsControl = cs; resp.
length = datalen;
break;
621 memcpy(ctrl, target, datalen);
628 size_t idx = itsEngine->getDefaultVideoMappingIdx();
629 try { idx = itsEngine->getVideoMappingIdx(ctrl->bFormatIndex, ctrl->bFrameIndex, ctrl->dwFrameInterval); }
631 fillStreamingControl(target, itsEngine->getVideoMapping(idx));
632 memcpy(ctrl, target, datalen);
636 case UVC_GET_RES: memset(ctrl, 0, datalen);
break;
638 case UVC_GET_LEN: resp.
data[0] = 0x00; resp.
data[1] = datalen; resp.
length = 2;
break;
640 case UVC_GET_INFO: resp.
data[0] = 0x03; resp.
length = 1;
break;
649 struct uvc_streaming_control * target;
652 if (itsEntity == 2 || itsEntity == 1) { processEventControlData(data);
return; }
656 case UVC_VS_PROBE_CONTROL: target = &itsProbe;
break;
657 case UVC_VS_COMMIT_CONTROL: target = &itsCommit;
break;
658 default: processEventControlData(data);
return;
662 struct uvc_streaming_control * ctrl =
reinterpret_cast<struct uvc_streaming_control *
>(&data.
data);
664 size_t idx = itsEngine->getVideoMappingIdx(ctrl->bFormatIndex, ctrl->bFrameIndex, ctrl->dwFrameInterval);
666 fillStreamingControl(target, itsEngine->getVideoMapping(idx));
668 LDEBUG(
"Host requested " << ctrl->bFormatIndex <<
'/' << ctrl->bFrameIndex <<
'/' << ctrl->dwFrameInterval <<
669 ", " << ((itsControl == UVC_VS_COMMIT_CONTROL) ?
"setting " :
"returning ") <<
670 itsEngine->getVideoMapping(idx).str());
673 if (itsControl == UVC_VS_COMMIT_CONTROL) itsEngine->setFormat(idx);
681 struct v4l2_control ctrl;
684 ctrl.id = uvcToV4Lcontrol(itsEntity, itsControl);
689 case 1: ctrl.value =
static_cast<int>(data.
data[0]);
break;
690 case 2: ctrl.value =
static_cast<int>(__s16(data.
data[0] | (
static_cast<short>(data.
data[1]) << 8)));
break;
691 case 4: ctrl.value = data.
data[0] | (data.
data[1] << 8) | (data.
data[2] << 16) | (data.
data[3] << 24);
break;
700 case V4L2_CID_RED_BALANCE:
703 int blue = ctrl.value & 0xffff;
704 ctrl.value >>= 16; itsCamera->setControl(ctrl);
705 ctrl.id = V4L2_CID_BLUE_BALANCE; ctrl.value = blue; itsCamera->setControl(ctrl);
709 case V4L2_CID_EXPOSURE_AUTO:
710 if (ctrl.value & 0x01) ctrl.value = V4L2_EXPOSURE_MANUAL;
711 else if (ctrl.value & 0x02) ctrl.value = V4L2_EXPOSURE_AUTO;
713 itsCamera->setControl(ctrl);
716 default: itsCamera->setControl(ctrl);
725 LDEBUG(
"Turning on UVC stream");
729 if (itsStreaming.load() || itsBuffers) {
LERROR(
"Stream is already on -- IGNORED");
return; }
730 if (itsFormat.fmt.pix.pixelformat == 0) {
LINFO(
"Gadget output format is NONE");
return; }
733 unsigned int nbuf = itsNbufs;
736 unsigned int framesize =
jevois::v4l2ImageSize(itsFormat.fmt.pix.pixelformat, itsFormat.fmt.pix.width,
737 itsFormat.fmt.pix.height);
740 nbuf = (4U * 1024U * 1024U) / framesize;
741 if (nbuf > 4) nbuf = 4;
745 if (nbuf < 3) nbuf = 3;
else if (nbuf > 16) nbuf = 16;
749 LINFO(itsBuffers->size() <<
" buffers of " << itsBuffers->get(0)->length() <<
" bytes allocated");
752 for (
size_t i = 0; i < nbuf; ++i)
755 img.
width = itsFormat.fmt.pix.width;
756 img.
height = itsFormat.fmt.pix.height;
757 img.
fmt = itsFormat.fmt.pix.pixelformat;
759 img.
buf = itsBuffers->get(i);
763 itsImageQueue.push_back(img);
764 LDEBUG(
"Empty image " << img.
bufindex <<
" ready for filling in by application code");
768 int type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
769 XIOCTL(itsFd, VIDIOC_STREAMON, &type);
770 LDEBUG(
"Device stream on");
772 itsStreaming.store(
true);
781 itsStreaming.store(
false);
792 LDEBUG(
"Turning off gadget stream");
801 int type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
802 try {
XIOCTL_QUIET(itsFd, VIDIOC_STREAMOFF, &type); }
catch (...) { }
805 if (itsBuffers) {
delete itsBuffers; itsBuffers =
nullptr; }
806 itsImageQueue.clear();
809 LDEBUG(
"Gadget stream is off");
820 if (itsStreaming.load() ==
false)
821 {
LDEBUG(
"Not streaming");
throw std::runtime_error(
"Gadget get() rejected while not streaming"); }
823 if (itsMtx.try_lock_for(std::chrono::milliseconds(100)))
825 if (itsStreaming.load() ==
false)
829 throw std::runtime_error(
"Gadget get() rejected while not streaming");
832 if (itsImageQueue.size())
834 img = itsImageQueue.front();
835 itsImageQueue.pop_front();
837 LDEBUG(
"Empty image " << img.
bufindex <<
" handed over to application code for filling");
843 LDEBUG(
"Waiting for blank UVC image...");
844 std::this_thread::sleep_for(std::chrono::milliseconds(5));
848 LDEBUG(
"Waiting for lock");
849 std::this_thread::sleep_for(std::chrono::milliseconds(5));
852 LFATAL(
"Giving up waiting for blank UVC image");
863 if (itsStreaming.load() ==
false)
864 {
LDEBUG(
"Not streaming");
throw std::runtime_error(
"Gadget send() rejected while not streaming"); }
866 if (itsMtx.try_lock_for(std::chrono::milliseconds(100)))
868 if (itsStreaming.load() ==
false)
872 throw std::runtime_error(
"Gadget send() rejected while not streaming");
877 if (img.
width != itsFormat.fmt.pix.width ||
878 img.
height != itsFormat.fmt.pix.height ||
879 img.
fmt != itsFormat.fmt.pix.pixelformat)
881 LDEBUG(
"Dropping image to send out as format just changed");
888 itsDoneImgs.push_back(img.
bufindex);
890 LDEBUG(
"Filled image " << img.
bufindex <<
" received from application code");
895 LDEBUG(
"Waiting for lock");
896 std::this_thread::sleep_for(std::chrono::milliseconds(5));
899 LFATAL(
"Giving up waiting for lock");
#define arrayblankresponse(len)
#define byteresponse(val)
#define wordresponse(val)
JeVois processing engine - gets images from camera sensor, processes them, and sends results over USB...
VideoMapping const & getDefaultVideoMapping() const
Allow access to the default video mapping.
void streamOff() override
Stop streaming.
void abortStream() override
Abort streaming.
void get(RawImage &img) override
Get a pre-allocated image so that we can fill the pixel data and later send out over USB using send()
Gadget(std::string const &devname, VideoInput *camera, Engine *engine, size_t const nbufs=0, bool multicam=false)
Construct and open the device.
virtual ~Gadget()
Close the device and free all resources.
void setFormat(jevois::VideoMapping const &m) override
Set the video format and frame rate.
void streamOn() override
Start streaming.
void send(RawImage const &img) override
Send an image out over USB to the host computer.
A raw image as coming from a V4L2 Camera and/or being sent out to a USB Gadget.
float fps
Programmed frames/s as given by current video mapping, may not be actual.
unsigned int fmt
Pixel format as a V4L2_PIX_FMT_XXX.
size_t bufindex
The index of the data buffer in the kernel driver.
unsigned int width
Image width in pixels.
unsigned int height
Image height in pixels.
std::shared_ptr< VideoBuf > buf
The pixel data buffer.
Collection of buffers for V4L2 video frames (Camera or Gadget) with hooks to the MMAP'd areas.
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level.
#define LDEBUG(msg)
Convenience macro for users to print out console or syslog messages, DEBUG level.
#define JEVOIS_TIMED_LOCK(mtx)
Helper macro to create a timed_lock_guard object.
#define PLERROR(msg)
Like LERROR but appends errno and strerror(errno), to be used when some system call fails.
std::string warnAndIgnoreException(std::string const &prefix="")
Convenience function to catch an exception, issue some LERROR (depending on type),...
#define PLFATAL(msg)
Like LDEBUG but appends errno and strerror(errno), to be used when some system call fails.
#define JEVOIS_TRACE(level)
Trace object.
#define LERROR(msg)
Convenience macro for users to print out console or syslog messages, ERROR level.
#define LINFO(msg)
Convenience macro for users to print out console or syslog messages, INFO level.
#define XIOCTL_QUIET(dev, req, mem)
Helper macro to execute an ioctl, ignore interruptions, and, if error throw quietly.
std::string fccstr(unsigned int fcc)
Convert a V4L2 four-cc code (V4L2_PIX_FMT_...) to a 4-char string.
std::future< std::invoke_result_t< std::decay_t< Function >, std::decay_t< Args >... > > async_little(Function &&f, Args &&... args)
Async execution using a thread pool.
#define XIOCTL(dev, req, mem)
Helper macro to execute an ioctl, ignore interruptions, and, if error, issue a fatal message and thro...
unsigned int v4l2ImageSize(unsigned int fcc, unsigned int width, unsigned int height)
Return the image size in bytes for a given V4L2_PIX_FMT_..., width, height.
Simple struct to hold video mapping definitions for the processing Engine.
static struct v4l2_fract fpsToV4l2(float fps)
Convert from fps to V4L2 interval.
unsigned int ow
output width
static unsigned int fpsToUvc(float fps)
Convert from fps to USB/UVC interval.
unsigned int osize() const
Return the size in bytes of an output image.
float ofps
output frame rate in frames/sec
unsigned int oh
output height
unsigned int uvcformat
USB-UVC format number (1-based)
unsigned int uvcframe
USB UVC frame number (1-based)
unsigned int ofmt
output pixel format, or 0 for no output over USB
struct usb_ctrlrequest req
struct uvc_request_data data
__u8 data[UVC_MAX_REQUEST_SIZE - sizeof(__s32)]
#define UVCIOC_SEND_RESPONSE
#define UVC_EVENT_STREAMOFF
#define UVC_EVENT_CONNECT
#define UVC_EVENT_STREAMON
#define UVC_INTF_STREAMING
#define UVC_EVENT_DISCONNECT