MythTV master
v4l2util.cpp
Go to the documentation of this file.
1#include "v4l2util.h"
3
4#include <sys/ioctl.h>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <algorithm>
8#include <climits>
9#include <fcntl.h>
10#include <unistd.h>
11
12#include <array>
13
14#include <QRegularExpression>
15
16#define LOC QString("V4L2(%1): ").arg(m_deviceName)
17
18V4L2util::V4L2util(const QString& dev_name)
19{
20 Open(dev_name);
21}
22
23V4L2util::V4L2util(const QString& dev_name, const QString& vbi_dev_name)
24 : m_fd(0)
25{
26 Open(dev_name, vbi_dev_name);
27}
28
30{
31 Close();
32}
33
34bool V4L2util::Open(const QString& dev_name, const QString& vbi_dev_name)
35{
36 if (m_fd >= 0 && dev_name == m_deviceName)
37 return true;
38
39 Close();
40
41 m_fd = open(dev_name.toLatin1().constData(), O_RDWR);
42 if (m_fd < 0)
43 {
44 LOG(VB_CHANNEL, LOG_INFO, LOC +
45 QString("Could not open '%1': ").arg(dev_name) + ENO);
46 return false;
47 }
48 m_deviceName = dev_name;
49
50 struct v4l2_query_ext_ctrl qc {};
51 qc.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
52 m_haveQueryExtCtrl = (ioctl(m_fd, VIDIOC_QUERY_EXT_CTRL, &qc) == 0);
53
54 m_cardName.clear();
55 m_driverName.clear();
56 m_version = 0;
58
59 struct v4l2_capability capability {};
60 if (ioctl(m_fd, VIDIOC_QUERYCAP, &capability) >= 0)
61 {
62 m_cardName = QString::fromLatin1((const char*)capability.card);
63 m_driverName = QString::fromLatin1((const char*)capability.driver);
64 m_version = capability.version;
65 m_capabilities = capability.capabilities;
66 }
67 else
68 {
69 Close();
70 return false;
71 }
72
73 static const QRegularExpression kDigitsRE { R"(\[[0-9]\]$)" };
74 if (!m_driverName.isEmpty())
75 m_driverName.remove( kDigitsRE );
76
77 OpenVBI(vbi_dev_name);
78
79 LOG(VB_CHANNEL, LOG_INFO, LOC + "Opened");
80 return true;
81}
82
84{
85 if (m_fd >= 0)
86 {
87 close(m_fd);
88 LOG(VB_CHANNEL, LOG_INFO, LOC + "Closed");
89 }
90 m_fd = -1;
91 m_options.clear();
92}
93
94bool V4L2util::HasStreaming(void) const
95{
96 if (m_capabilities ^ V4L2_CAP_STREAMING)
97 return false;
98
99 struct v4l2_requestbuffers reqbuf {};
100
101 if (-1 == ioctl (m_fd, VIDIOC_REQBUFS, &reqbuf))
102 {
103 if (errno == EINVAL)
104 {
105 LOG(VB_CHANNEL, LOG_INFO, LOC +
106 "Video capturing or mmap-streaming is not supported");
107 }
108 else
109 {
110 LOG(VB_CHANNEL, LOG_WARNING, LOC + "VIDIOC_REQBUFS" + ENO);
111 }
112 return false;
113 }
114
115 return true;
116}
117
119{
120 return (m_capabilities & V4L2_CAP_SLICED_VBI_CAPTURE) != 0U;
121}
122
123void V4L2util::bitmask_toString(QString& result, uint32_t flags,
124 uint32_t mask, const QString& desc)
125{
126 if (flags& mask)
127 {
128 if (!result.isEmpty())
129 result += '|';
130 result += desc;
131 }
132}
133
134QString V4L2util::ctrlflags_toString(uint32_t flags)
135{
136 QString result;
137
138 bitmask_toString(result, flags, V4L2_CTRL_FLAG_DISABLED,
139 "disabled");
140 bitmask_toString(result, flags, V4L2_CTRL_FLAG_GRABBED,
141 "grabbed");
142 bitmask_toString(result, flags, V4L2_CTRL_FLAG_READ_ONLY,
143 "read-only");
144 bitmask_toString(result, flags, V4L2_CTRL_FLAG_UPDATE,
145 "update");
146 bitmask_toString(result, flags, V4L2_CTRL_FLAG_INACTIVE,
147 "inactive");
148 bitmask_toString(result, flags, V4L2_CTRL_FLAG_SLIDER,
149 "slider");
150 bitmask_toString(result, flags, V4L2_CTRL_FLAG_WRITE_ONLY,
151 "write-only");
152 bitmask_toString(result, flags, V4L2_CTRL_FLAG_VOLATILE,
153 "volatile");
154 bitmask_toString(result, flags, V4L2_CTRL_FLAG_HAS_PAYLOAD,
155 "has-payload");
156 bitmask_toString(result, flags, V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
157 "execute-on-write");
158
159 return result;
160}
161
163{
164 switch (type)
165 {
166 case V4L2_CTRL_TYPE_INTEGER:
167 return "int";
168 case V4L2_CTRL_TYPE_INTEGER64:
169 return "int64";
170 case V4L2_CTRL_TYPE_STRING:
171 return "str";
172 case V4L2_CTRL_TYPE_BOOLEAN:
173 return "bool";
174 case V4L2_CTRL_TYPE_MENU:
175 return "menu";
176 case V4L2_CTRL_TYPE_INTEGER_MENU:
177 return "intmenu";
178 case V4L2_CTRL_TYPE_BUTTON:
179 return "button";
180 case V4L2_CTRL_TYPE_BITMASK:
181 return "bitmask";
182 case V4L2_CTRL_TYPE_U8:
183 return "u8";
184 case V4L2_CTRL_TYPE_U16:
185 return "u16";
186 case V4L2_CTRL_TYPE_U32:
187 return "u32";
188 default:
189 return "unknown";
190 }
191}
192
193void V4L2util::log_qctrl(struct v4l2_queryctrl& queryctrl,
194 DriverOption& drv_opt, QString& msg)
195{
196 struct v4l2_querymenu qmenu {};
197 QString nameStr((char *)queryctrl.name);
198
199 qmenu.id = queryctrl.id;
200
201 // Replace non-printable with _
202 static const QRegularExpression kNonPrintableRE { "[^a-zA-Z\\d\\s]" };
203 nameStr.replace(kNonPrintableRE, "_");
204
205 drv_opt.m_name = nameStr;
206 drv_opt.m_minimum = queryctrl.minimum;
207 drv_opt.m_maximum = queryctrl.maximum;
208 drv_opt.m_step = queryctrl.step;
209 drv_opt.m_defaultValue = queryctrl.default_value;;
210
211 if (nameStr == "Stream Type")
213 else if (nameStr == "Video Encoding")
215 else if (nameStr == "Video Aspect")
217 else if (nameStr == "Video B Frames")
219 else if (nameStr == "Video GOP Size")
221 else if (nameStr == "Video Bitrate Mode")
223 else if (nameStr == "Video Bitrate")
225 else if (nameStr == "Video Peak Bitrate")
227 else if (nameStr == "Audio Encoding")
229 else if (nameStr == "Audio Bitrate Mode")
231 else if (nameStr == "Audio Bitrate")
233 else if (nameStr == "Brightness")
235 else if (nameStr == "Contrast")
237 else if (nameStr == "Saturation")
239 else if (nameStr == "Hue")
241 else if (nameStr == "Sharpness")
243 else if (nameStr == "Volume")
245 else
247
248 switch (queryctrl.type)
249 {
250 case V4L2_CTRL_TYPE_INTEGER:
251 case V4L2_CTRL_TYPE_INTEGER64:
252 case V4L2_CTRL_TYPE_U8:
253 case V4L2_CTRL_TYPE_U16:
254 case V4L2_CTRL_TYPE_U32:
255 msg = QString("%1 : min=%2 max=%3 step=%4 default=%5")
256 .arg(QString("%1 (%2)").arg(nameStr, queryctrl_toString(queryctrl.type)), 31, QChar(' '))
257 .arg(queryctrl.minimum)
258 .arg(queryctrl.maximum)
259 .arg(queryctrl.step)
260 .arg(queryctrl.default_value);
262 break;
263 case V4L2_CTRL_TYPE_STRING:
264 msg = QString("%1 : min=%2 max=%3 step=%4")
265 .arg(QString("%1 (%2)").arg(nameStr, queryctrl_toString(queryctrl.type)), 31, QChar(' '))
266 .arg(queryctrl.minimum)
267 .arg(queryctrl.maximum)
268 .arg(queryctrl.step);
270 break;
271 case V4L2_CTRL_TYPE_BOOLEAN:
272 msg = QString("%1 : default=%2")
273 .arg(QString("%1 (%2)").arg(nameStr, queryctrl_toString(queryctrl.type)), 31, QChar(' '))
274 .arg(queryctrl.default_value);
276 break;
277 case V4L2_CTRL_TYPE_MENU:
278 case V4L2_CTRL_TYPE_INTEGER_MENU:
279 {
280 msg = QString("%1 : min=%3 max=%4 default=%5")
281 .arg(QString("%1 (%2)").arg(nameStr, queryctrl_toString(queryctrl.type)), 31, QChar(' '))
282 .arg(queryctrl.minimum)
283 .arg(queryctrl.maximum)
284 .arg(queryctrl.default_value);
285#if 0
286 struct v4l2_querymenu querymenu = { 0, };
287 memset (&querymenu, 0, sizeof (querymenu));
288 querymenu.id = queryctrl.id;
289
290 for (querymenu.index = queryctrl.minimum;
291 static_cast<int>(querymenu.index) <= queryctrl.maximum;
292 ++querymenu.index)
293 {
294 drv_opt.menu.clear();
295 if (0 == ioctl(m_fd, VIDIOC_QUERYMENU, &querymenu))
296 {
297 msg += QString(" menu>%1").arg((char *)querymenu.name);
298 drv_opt.menu[querymenu.index] =
299 QString((char *)querymenu.name);
300 }
301 }
302#endif
303 drv_opt.m_type = DriverOption::MENU;
304 break;
305 }
306 case V4L2_CTRL_TYPE_BUTTON:
307 msg = QString("%1 :")
308 .arg(QString("%1 (%2)").arg(nameStr, queryctrl_toString(queryctrl.type)), 31, QChar(' '));
310 break;
311 case V4L2_CTRL_TYPE_BITMASK:
312 msg = QString("%1 : max=0x%2 default=0x%3")
313 .arg(QString("%1 (%2)").arg(nameStr, queryctrl_toString(queryctrl.type)), 31, QChar(' '))
314 .arg(queryctrl.maximum, 8, 16, QChar(' '))
315 .arg(queryctrl.default_value, 8, 16, QChar(' '));
317 break;
318
319 default:
320 msg = QString("%1 : type=%2")
321 .arg(QString("%1 (%2)").arg(nameStr, queryctrl_toString(queryctrl.type)), 31, QChar(' '))
322 .arg(queryctrl.type);
324 break;
325 }
326
327 if (queryctrl.flags)
328 msg += QString(" flags=%1").arg(ctrlflags_toString(queryctrl.flags));
329
330 if (queryctrl.type == V4L2_CTRL_TYPE_MENU ||
331 queryctrl.type == V4L2_CTRL_TYPE_INTEGER_MENU)
332 {
333 for (int idx = queryctrl.minimum; idx <= queryctrl.maximum; ++idx)
334 {
335 qmenu.index = idx;
336 if (ioctl(m_fd, VIDIOC_QUERYMENU, &qmenu))
337 continue;
338
339 drv_opt.m_menu[idx] = QString((char *)qmenu.name);
340 if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
341 msg += QString("\t\t%1: %2").arg(idx).arg((char *)qmenu.name);
342 else
343 {
344 msg += QString("\t\t%1: %2 (0x%3)")
345 .arg(idx).arg(qmenu.value)
346 .arg(qmenu.value, 0, 16, QChar('0'));
347 }
348 }
349 }
350
351 LOG(VB_CHANNEL, LOG_INFO, LOC + msg);
352}
353
354bool V4L2util::log_control(struct v4l2_queryctrl& qctrl, DriverOption& drv_opt,
355 QString& msg)
356{
357 struct v4l2_control ctrl {};
358 struct v4l2_ext_control ext_ctrl {};
359 struct v4l2_ext_controls ctrls {};
360
361 if (qctrl.flags& V4L2_CTRL_FLAG_DISABLED)
362 {
363 msg += QString("'%1' Disabled").arg((char *)qctrl.name);
364 return true;
365 }
366
367 if (qctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS)
368 {
369 msg += QString("'%1' V4L2_CTRL_TYPE_CTRL_CLASS").arg((char *)qctrl.name);
370 return true;
371 }
372
373 ext_ctrl.id = qctrl.id;
374 if ((qctrl.flags& V4L2_CTRL_FLAG_WRITE_ONLY) ||
375 qctrl.type == V4L2_CTRL_TYPE_BUTTON)
376 {
377 log_qctrl(qctrl, drv_opt, msg);
378 return true;
379 }
380
381 if (qctrl.type >= V4L2_CTRL_COMPOUND_TYPES)
382 {
383 log_qctrl(qctrl, drv_opt, msg);
384 return true;
385 }
386
387 ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(qctrl.id);
388 ctrls.count = 1;
389 ctrls.controls = &ext_ctrl;
390 if (qctrl.type == V4L2_CTRL_TYPE_INTEGER64 ||
391 qctrl.type == V4L2_CTRL_TYPE_STRING ||
392 (V4L2_CTRL_ID2CLASS(qctrl.id) != V4L2_CTRL_CLASS_USER &&
393 qctrl.id < V4L2_CID_PRIVATE_BASE))
394 {
395 if (qctrl.type == V4L2_CTRL_TYPE_STRING)
396 {
397 ext_ctrl.size = qctrl.maximum + 1;
398 // C library structure. NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
399 ext_ctrl.string = (char *)malloc(ext_ctrl.size);
400 ext_ctrl.string[0] = 0;
401 }
402 if (ioctl(m_fd, VIDIOC_G_EXT_CTRLS, &ctrls))
403 {
404 LOG(VB_CHANNEL, LOG_WARNING, LOC +
405 QString("Failed to get ext_ctr %1: ")
406 .arg((char *)qctrl.name) + ENO);
407 return false;
408 }
409 }
410 else {
411 ctrl.id = qctrl.id;
412 if (ioctl(m_fd, VIDIOC_G_CTRL, &ctrl))
413 {
414 LOG(VB_CHANNEL, LOG_WARNING, LOC +
415 QString("Failed to get ctrl %1: ")
416 .arg((char *)qctrl.name) + ENO);
417 return false;
418 }
419 ext_ctrl.value = ctrl.value;
420 }
421 log_qctrl(qctrl, drv_opt, msg);
422
423 if (qctrl.type == V4L2_CTRL_TYPE_STRING)
424 free(ext_ctrl.string); // NOLINT(cppcoreguidelines-no-malloc)
425 return true;
426}
427
428// Some drivers don't set 'default' options, so make some assumptions
430{
432 {
433 DriverOption drv_opt;
435 drv_opt.m_name = "Video Encoding";
436 drv_opt.m_minimum = drv_opt.m_maximum = drv_opt.m_defaultValue =
437 V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
438 drv_opt.m_menu[drv_opt.m_defaultValue] = "MPEG-2 Video";
439 options[drv_opt.m_category] = drv_opt;
440 }
441
443 {
444 DriverOption drv_opt;
445
446 // V4L2_CID_MPEG_AUDIO_ENCODING
448 drv_opt.m_name = "Audio Encoding";
449 drv_opt.m_minimum = drv_opt.m_maximum = drv_opt.m_defaultValue =
450 V4L2_MPEG_AUDIO_ENCODING_LAYER_2;
451 drv_opt.m_menu[drv_opt.m_defaultValue] = "MPEG-1/2 Layer II encoding";
452 options[drv_opt.m_category] = drv_opt;
453
455 drv_opt.m_name = "Audio Bitrate";
456 drv_opt.m_minimum = drv_opt.m_maximum = drv_opt.m_defaultValue =
457 V4L2_MPEG_AUDIO_ENCODING_LAYER_2;
458 drv_opt.m_menu[drv_opt.m_defaultValue] = "MPEG-1/2 Layer II encoding";
459 options[drv_opt.m_category] = drv_opt;
460
461 // V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ
463 drv_opt.m_name = "MPEG Audio sampling frequency";
464 drv_opt.m_minimum = drv_opt.m_maximum = drv_opt.m_defaultValue =
465 V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
466 drv_opt.m_menu[drv_opt.m_defaultValue] = "48 kHz";
467 options[drv_opt.m_category] = drv_opt;
468
469 // VIDIOC_S_TUNER
471 drv_opt.m_name = "Tuner Audio Modes";
472 drv_opt.m_minimum = drv_opt.m_maximum = drv_opt.m_defaultValue =
473 V4L2_TUNER_MODE_STEREO;
474 drv_opt.m_menu[drv_opt.m_defaultValue] = "Play stereo audio";
475 options[drv_opt.m_category] = drv_opt;
476 }
477
478 DriverOption::Options::iterator Iopt = options.begin();
479 for ( ; Iopt != options.end(); ++Iopt)
480 {
481 // If the driver provides a menu of options, use it to set limits
482 if (!(*Iopt).m_menu.isEmpty())
483 {
484 int minimum = INT_MAX;
485 int maximum = -1;
486
487 DriverOption::menu_t::iterator Imenu = (*Iopt).m_menu.begin();
488 for ( ; Imenu != (*Iopt).m_menu.end(); ++Imenu)
489 {
490 minimum = std::min(Imenu.key(), minimum);
491 maximum = std::max(Imenu.key(), maximum);
492 }
493 if ((*Iopt).m_minimum != minimum)
494 {
495 LOG(VB_CHANNEL, LOG_INFO, LOC +
496 QString("%1 menu options overrides minimum from %2 to %3")
497 .arg((*Iopt).m_name).arg((*Iopt).m_minimum).arg(minimum));
498 (*Iopt).m_minimum = minimum;
499 }
500 if ((*Iopt).m_maximum != maximum)
501 {
502 LOG(VB_CHANNEL, LOG_INFO, LOC +
503 QString("%1 menu options overrides maximum from %2 to %3")
504 .arg((*Iopt).m_name).arg((*Iopt).m_maximum).arg(maximum));
505 (*Iopt).m_maximum = maximum;
506 }
507 }
508 }
509}
510
512{
513 struct v4l2_fmtdesc vid_fmtdesc {};
514 const std::array<const QString,2> flags {"uncompressed", "compressed"};
515
516 vid_fmtdesc.index = 0;
517 vid_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
518 while(ioctl(m_fd, VIDIOC_ENUM_FMT, &vid_fmtdesc) == 0)
519 {
520 formats << QString("%1 (%2)").arg((char *)vid_fmtdesc.description,
521 flags[vid_fmtdesc.flags]);
522
523 /* Convert the pixelformat attributes from FourCC into 'human readab
524 fprintf(stdout, " pixelformat :%c%c%c%c\\n",
525 vid_fmtdesc.pixelformat& 0xFF, (vid_fmtdesc.pixelformat >>
526 (vid_fmtdesc.pixelformat >> 16)& 0xFF, (vid_fmtdesc.pixelfo
527 */
528
529 vid_fmtdesc.index++;
530 }
531
532 LOG(VB_CHANNEL, LOG_DEBUG, LOC + QString("GetFormats: %1")
533 .arg(formats.join(",")));
534
535 return true;
536}
537
539{
540 LOG(VB_CHANNEL, LOG_INFO, LOC + "Options");
541
542 if (!m_options.isEmpty())
543 {
545 return true;
546 }
547
548 struct v4l2_queryctrl qctrl {};
549 qctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
550 while (0 == ioctl (m_fd, VIDIOC_QUERYCTRL, &qctrl))
551 {
552 QString msg;
553 DriverOption drv_opt;
554
555 log_control(qctrl, drv_opt, msg);
556 m_options[drv_opt.m_category] = drv_opt;
557
558 qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
559 }
560
563 return true;
564}
565
567{
568 if (m_options.isEmpty())
570
571 if (!m_options.contains(cat))
572 {
573 LOG(VB_CHANNEL, LOG_WARNING, LOC +
574 QString("Driver does not support option."));
575 return -1;
576 }
577
578 DriverOption drv_opt = m_options.value(cat);
579 DriverOption::menu_t::iterator Imenu = drv_opt.m_menu.begin();
580 for ( ; Imenu != drv_opt.m_menu.end(); ++Imenu)
581 {
582 if ((*Imenu) == desc)
583 {
584 LOG(VB_CHANNEL, LOG_INFO, LOC + QString("GetOptionValue '%1' = %2")
585 .arg(desc).arg(Imenu.key()));
586 return Imenu.key();
587 }
588 }
589
590 LOG(VB_CHANNEL, LOG_WARNING, LOC +
591 QString("'%1' not found in driver options menu.").arg(desc));
592 return -1;
593}
594
595bool V4L2util::GetVideoStandard(QString& name) const
596{
597 v4l2_std_id std_id = 0;
598 struct v4l2_standard standard {};
599
600 if (-1 == ioctl (m_fd, VIDIOC_G_STD, &std_id))
601 {
602 /* Note when VIDIOC_ENUMSTD always returns EINVAL this
603 is no video device or it falls under the USB exception,
604 and VIDIOC_G_STD returning EINVAL is no error. */
605 LOG(VB_CHANNEL, LOG_WARNING, LOC +
606 "GetVideoStandard: Failed to detect signal." + ENO);
607 return false;
608 }
609
610 standard.index = 0;
611
612 while (0 == ioctl (m_fd, VIDIOC_ENUMSTD, &standard))
613 {
614 if (standard.id & std_id)
615 {
616 name = (char *)standard.name;
617 return true;
618 }
619
620 ++standard.index;
621 }
622
623 /* EINVAL indicates the end of the enumeration, which cannot be
624 empty unless this device falls under the USB exception. */
625 if (errno == EINVAL || standard.index == 0)
626 {
627 LOG(VB_CHANNEL, LOG_WARNING, LOC +
628 "GetVideoStandard: Failed to find signal." + ENO);
629 }
630
631 return false;
632}
633
635{
636 return -1; // Does not work
637
638 struct v4l2_tuner tuner {};
639
640 if (ioctl(m_fd, VIDIOC_G_TUNER, &tuner, 0) != 0)
641 {
642 LOG(VB_GENERAL, LOG_ERR, "GetSignalStrength() : "
643 "Failed to probe signal (v4l2)" + ENO);
644 return -1;
645 }
646
647 tuner.signal /= 655.35; // Set to 0-100 range
648
649 LOG(VB_RECORD, LOG_INFO, LOC + QString("GetSignalStrength() : "
650 "(%1\%)")
651 .arg(tuner.signal));
652 return tuner.signal;
653}
654
655bool V4L2util::GetResolution(int& width, int& height) const
656{
657 struct v4l2_format vfmt {};
658
659 vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
660 if (ioctl(m_fd, VIDIOC_G_FMT, &vfmt) != 0)
661 {
662 LOG(VB_CHANNEL, LOG_WARNING, LOC +
663 "Failed to determine resolution: " + ENO);
664 width = height = -1;
665 return false;
666 }
667
668 width = vfmt.fmt.pix.width;
669 height = vfmt.fmt.pix.height;
670 LOG(VB_CHANNEL, LOG_INFO, LOC +
671 QString("Resolution: %1x%2").arg(width).arg(height));
672 return true;
673}
674
675uint32_t V4L2util::GetCapabilities(void) const
676{
677 return m_capabilities;
678}
679
680QString V4L2util::GetDeviceName(void) const
681{
682 return m_deviceName;
683}
684
685QString V4L2util::GetDriverName(void) const
686{
687 return m_driverName;
688}
689
690bool V4L2util::HasTuner(void) const
691{
692 return (m_capabilities & V4L2_CAP_TUNER) != 0U;
693}
694
696{
697 return (m_capabilities & V4L2_CAP_AUDIO) != 0U;
698}
699
700bool V4L2util::IsEncoder(void) const
701{
702 struct v4l2_queryctrl qctrl {};
703
704 qctrl.id = V4L2_CTRL_CLASS_MPEG | V4L2_CTRL_FLAG_NEXT_CTRL;
705 return (0 == ioctl (m_fd, VIDIOC_QUERYCTRL, &qctrl) &&
706 V4L2_CTRL_ID2CLASS (qctrl.id) == V4L2_CTRL_CLASS_MPEG);
707}
708
710{
711 // I have not been able to come up with a way of querying the
712 // driver to answer this question.
713
714 return m_driverName != "hdpvr";
715}
716
717int V4L2util::GetExtControl(int request, const QString& ctrl_desc) const
718{
719 struct v4l2_ext_control ctrl {};
720 struct v4l2_ext_controls ctrls {};
721
722 ctrl.id = request;
723
724 ctrls.count = 1;
725 ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
726 ctrls.controls = &ctrl;
727
728 if (ioctl(m_fd, VIDIOC_G_EXT_CTRLS, &ctrls) != 0)
729 {
730 LOG(VB_GENERAL, LOG_ERR, LOC +
731 QString("Failed to retrieve current %1 value.")
732 .arg(ctrl_desc) + ENO);
733 return -1;
734 }
735
736 return ctrls.controls->value;
737}
738
739
740bool V4L2util::SetExtControl(int request, int value, const QString& ctrl_desc,
741 const QString& value_desc)
742{
743 int current_value = GetExtControl(request, ctrl_desc);
744
745 if (current_value < 0)
746 return false;
747 if (current_value == value)
748 {
749 LOG(VB_CHANNEL, LOG_INFO, LOC +
750 QString("%1 value is already %2 (%3).")
751 .arg(ctrl_desc, value_desc, QString::number(value)));
752 return true;
753 }
754
755 struct v4l2_ext_control ctrl {};
756 struct v4l2_ext_controls ctrls {};
757
758 ctrl.id = request;
759 ctrl.value = value;
760
761 ctrls.count = 1;
762 ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
763 ctrls.controls = &ctrl;
764
765 if (ioctl(m_fd, VIDIOC_S_EXT_CTRLS, &ctrls) < 0)
766 {
767 LOG(VB_GENERAL, LOG_ERR, LOC +
768 QString("Failed to set %1 value to %2 (%3).")
769 .arg(ctrl_desc, value_desc, QString::number(value)) + ENO);
770 return false;
771 }
772
773 LOG(VB_CHANNEL, LOG_INFO, LOC +
774 QString("%1 value set to %2 (%3).")
775 .arg(ctrl_desc, value_desc, QString::number(value)));
776
777 return true;
778}
779
780QString V4L2util::StreamTypeDesc(int value)
781{
782 switch (value)
783 {
784 case V4L2_MPEG_STREAM_TYPE_MPEG2_PS:
785 return "MPEG-2 program stream";
786 case V4L2_MPEG_STREAM_TYPE_MPEG2_TS:
787 return "MPEG-2 transport stream";
788 case V4L2_MPEG_STREAM_TYPE_MPEG1_SS:
789 return "MPEG-1 system stream";
790 case V4L2_MPEG_STREAM_TYPE_MPEG2_DVD:
791 return "MPEG-2 DVD-compatible stream";
792 case V4L2_MPEG_STREAM_TYPE_MPEG1_VCD:
793 return "MPEG-1 VCD-compatible stream";
794 case V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD:
795 return "MPEG-2 SVCD-compatible stream";
796 }
797 return "Unknown";
798}
799
801{
802 int type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS;
803
804 if (DriverName().startsWith("saa7164"))
805 {
806 // The saa7164 driver reports that it can do TS, but it doesn't work!
807 type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS;
808 }
809 else
810 {
811 type = GetExtControl(V4L2_CID_MPEG_STREAM_TYPE, "Stream Type");
812 }
813
814 LOG(VB_CHANNEL, LOG_INFO, LOC +
815 QString("MPEG Stream Type is currently set to %1 (%2)")
816 .arg(StreamTypeDesc(type)).arg(type));
817
818 return type;
819}
820
822{
823 if (DriverName().startsWith("saa7164") ||
824 DriverName().startsWith("ivtv"))
825 {
826 // The saa7164 driver reports that it can do TS, but it doesn't work!
827 value = V4L2_MPEG_STREAM_TYPE_MPEG2_PS;
828 }
829
830 return SetExtControl(V4L2_CID_MPEG_STREAM_TYPE, value,
831 "MPEG Stream type", StreamTypeDesc(value));
832}
833
834// Video controls
836{
837 QString desc;
838 switch (value)
839 {
840 case V4L2_MPEG_VIDEO_ASPECT_1x1:
841 desc = "Square";
842 break;
843 case V4L2_MPEG_VIDEO_ASPECT_4x3:
844 desc = "4x3";
845 break;
846 case V4L2_MPEG_VIDEO_ASPECT_16x9:
847 desc = "16x9";
848 break;
849 case V4L2_MPEG_VIDEO_ASPECT_221x100:
850 desc = "221x100";
851 break;
852 default:
853 desc = "Unknown";
854 }
855
856 return SetExtControl(V4L2_CID_MPEG_VIDEO_ASPECT, value,
857 "Video Aspect ratio", desc);
858}
859
861{
862 QString desc;
863 switch (value)
864 {
865 case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR:
866 desc = "VBR";
867 break;
868 case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR:
869 desc = "CBR";
870 break;
871 }
872
873 return SetExtControl(V4L2_CID_MPEG_VIDEO_BITRATE_MODE, value,
874 "Video Bitrate Mode", desc);
875}
876
878{
879 QString desc = QString("%1").arg(value);
880 return SetExtControl(V4L2_CID_MPEG_VIDEO_BITRATE, value,
881 "Video Average Bitrate", desc);
882}
883
885{
886 QString desc = QString("%1").arg(value);
887 return SetExtControl(V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, value,
888 "Video Peak Bitrate", desc);
889}
890
891bool V4L2util::SetResolution(uint32_t width, uint32_t height)
892{
893 struct v4l2_format vfmt {};
894
895 vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
896
897 if (ioctl(m_fd, VIDIOC_G_FMT, &vfmt) < 0)
898 {
899 LOG(VB_GENERAL, LOG_ERR, LOC +
900 "SetResolution() -- Error getting format" + ENO);
901 return false;
902 }
903
904 if ((vfmt.fmt.pix.width == width) && (vfmt.fmt.pix.height == height))
905 {
906 LOG(VB_RECORD, LOG_INFO, LOC + QString("Resolution is already %1x%2")
907 .arg(width).arg(height));
908 return true;
909 }
910
911 vfmt.fmt.pix.width = width;
912 vfmt.fmt.pix.height = height;
913
914 if (ioctl(m_fd, VIDIOC_S_FMT, &vfmt) < 0)
915 {
916 LOG(VB_GENERAL, LOG_ERR, LOC +
917 "SetResolution() -- Error setting format" + ENO);
918 return false;
919 }
920
921 LOG(VB_RECORD, LOG_INFO, LOC + QString("Resolution set to %1x%2")
922 .arg(width).arg(height));
923 return true;
924}
925
926// Audio controls
928{
929 struct v4l2_audio ain {};
930
931 ain.index = value;
932 if (ioctl(m_fd, VIDIOC_ENUMAUDIO, &ain) < 0)
933 {
934 LOG(VB_GENERAL, LOG_WARNING, LOC +
935 QString("Failed to retrieve audio input.") + ENO);
936 return false;
937 }
938
939 ain.index = value;
940 if (ioctl(m_fd, VIDIOC_S_AUDIO, &ain) < 0)
941 {
942 LOG(VB_GENERAL, LOG_WARNING,
943 LOC + QString("Failed to set audio input to %1.").arg(value) + ENO);
944 return false;
945 }
946
947 LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Audio input set to %1.")
948 .arg(value));
949 return true;
950}
951
953{
954#if 0
955 if (DriverName().startsWith("ivtv"))
956 value = V4L2_MPEG_AUDIO_ENCODING_LAYER_2;
957#endif
958
959 QString desc;
960 switch (value)
961 {
962 case V4L2_MPEG_AUDIO_ENCODING_LAYER_1:
963 desc = "Layer I";
964 break;
965 case V4L2_MPEG_AUDIO_ENCODING_LAYER_2:
966 desc = "Layer II";
967 break;
968 case V4L2_MPEG_AUDIO_ENCODING_LAYER_3:
969 desc = "Layer III";
970 break;
971 case V4L2_MPEG_AUDIO_ENCODING_AAC:
972 desc = "AAC";
973 break;
974 case V4L2_MPEG_AUDIO_ENCODING_AC3:
975 desc = "AC3";
976 break;
977 default:
978 desc = "Unknown";
979 break;
980 }
981
982#if 0
983 if (DriverName().startsWith("ivtv"))
984 {
985 LOG(VB_CHANNEL, LOG_INFO, LOC +
986 QString("Overriding AudioCodec for %1 to %2")
987 .arg(DriverName()).arg(desc));
988 }
989#endif
990
991 return SetExtControl(V4L2_CID_MPEG_AUDIO_ENCODING, value,
992 "Audio Codec", desc);
993}
994
995
996bool V4L2util::SetVolume(int volume)
997{
998 // Get volume min/max values
999 struct v4l2_queryctrl qctrl {};
1000 qctrl.id = V4L2_CID_AUDIO_VOLUME;
1001 if ((ioctl(m_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) ||
1002 (qctrl.flags & V4L2_CTRL_FLAG_DISABLED))
1003 {
1004 LOG(VB_CHANNEL, LOG_WARNING,
1005 LOC + "SetRecordingVolume() -- Audio volume control not supported.");
1006 return false;
1007 }
1008
1009 // calculate volume in card units.
1010 int range = qctrl.maximum - qctrl.minimum;
1011 int value = (int) ((range * volume * 0.01F) + qctrl.minimum);
1012 int ctrl_volume = std::clamp(value, qctrl.minimum, qctrl.maximum);
1013
1014 // Set recording volume
1015 struct v4l2_control ctrl {};
1016 ctrl.id = V4L2_CID_AUDIO_VOLUME;
1017 ctrl.value = ctrl_volume;
1018
1019 if (ioctl(m_fd, VIDIOC_S_CTRL, &ctrl) < 0)
1020 {
1021 LOG(VB_GENERAL, LOG_WARNING, LOC +
1022 "SetRecordingVolume() -- Failed to set recording volume" + ENO);
1023// "If you are using an AverMedia M179 card this is normal."
1024 return false;
1025 }
1026
1027 LOG(VB_RECORD, LOG_INFO, LOC + "SetRecordingVolume() -- volume set.");
1028 return true;
1029}
1030
1032{
1033 struct v4l2_tuner vt {};
1034
1035 if (ioctl(m_fd, VIDIOC_G_TUNER, &vt) < 0)
1036 {
1037 LOG(VB_CHANNEL, LOG_WARNING, LOC +
1038 "SetLanguageMode() -- Failed to retrieve audio mode" + ENO);
1039 return false;
1040 }
1041
1042 vt.audmode = mode;
1043
1044 if (ioctl(m_fd, VIDIOC_S_TUNER, &vt) < 0)
1045 {
1046 LOG(VB_CHANNEL, LOG_WARNING, LOC +
1047 "SetLanguageMode -- Failed to set audio mode" + ENO);
1048 return false;
1049 }
1050
1051 QString desc;
1052 switch (mode)
1053 {
1054 case V4L2_TUNER_MODE_MONO:
1055 desc = "Mono";
1056 break;
1057 case V4L2_TUNER_MODE_STEREO:
1058 desc = "Stereo";
1059 break;
1060#if 0
1061 case V4L2_TUNER_MODE_LANG2:
1062 desc = "Lang2";
1063 break;
1064#endif
1065 case V4L2_TUNER_MODE_SAP:
1066 desc = "SAP";
1067 break;
1068 case V4L2_TUNER_MODE_LANG1:
1069 desc = "LANG1";
1070 break;
1071 case V4L2_TUNER_MODE_LANG1_LANG2:
1072 desc = "LANG1&Lang2";
1073 break;
1074 default:
1075 desc = "Unknown";
1076 break;
1077 }
1078
1079 LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Language Mode set to %1 (%2)")
1080 .arg(desc).arg(mode));
1081 return true;
1082}
1083
1085{
1086 QString desc;
1087
1088#if 0
1089 if (DriverName().startsWith("ivtv"))
1090 value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
1091#endif
1092
1093 switch (value)
1094 {
1095 case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100:
1096 desc = "44.1kHz";
1097 break;
1098 case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000:
1099 desc = "48kHz";
1100 break;
1101 case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000:
1102 desc = "32kHz";
1103 break;
1104 default:
1105 desc = "Unknown";
1106 }
1107
1108#if 0
1109 if (DriverName().startsWith("ivtv"))
1110 {
1111 LOG(VB_CHANNEL, LOG_INFO, LOC +
1112 QString("Overriding sampling frequence for %1 to %2")
1113 .arg(DriverName()).arg(desc));
1114 }
1115#endif
1116
1117 return SetExtControl(V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, value,
1118 "Audio Sample Rate", desc);
1119}
1120
1122{
1123 QString desc;
1124 switch (value)
1125 {
1126 case V4L2_MPEG_AUDIO_L2_BITRATE_32K:
1127 desc = "32K";
1128 break;
1129 case V4L2_MPEG_AUDIO_L2_BITRATE_48K:
1130 desc = "48K";
1131 break;
1132 case V4L2_MPEG_AUDIO_L2_BITRATE_56K:
1133 desc = "56K";
1134 break;
1135 case V4L2_MPEG_AUDIO_L2_BITRATE_64K:
1136 desc = "64K";
1137 break;
1138 case V4L2_MPEG_AUDIO_L2_BITRATE_80K:
1139 desc = "80K";
1140 break;
1141 case V4L2_MPEG_AUDIO_L2_BITRATE_96K:
1142 desc = "96K";
1143 break;
1144 case V4L2_MPEG_AUDIO_L2_BITRATE_112K:
1145 desc = "112K";
1146 break;
1147 case V4L2_MPEG_AUDIO_L2_BITRATE_128K:
1148 desc = "128K";
1149 break;
1150 case V4L2_MPEG_AUDIO_L2_BITRATE_160K:
1151 desc = "160K";
1152 break;
1153 case V4L2_MPEG_AUDIO_L2_BITRATE_192K:
1154 desc = "192K";
1155 break;
1156 case V4L2_MPEG_AUDIO_L2_BITRATE_224K:
1157 desc = "224K";
1158 break;
1159 case V4L2_MPEG_AUDIO_L2_BITRATE_256K:
1160 desc = "256K";
1161 break;
1162 case V4L2_MPEG_AUDIO_L2_BITRATE_320K:
1163 desc = "320K";
1164 break;
1165 case V4L2_MPEG_AUDIO_L2_BITRATE_384K:
1166 desc = "384K";
1167 break;
1168 default:
1169 desc = "Unknown";
1170 }
1171
1172 return SetExtControl(V4L2_CID_MPEG_AUDIO_L2_BITRATE, value,
1173 "Audio L2 Bitrate", desc);
1174}
1175
1176// Actions
1177bool V4L2util::SetEncoderState(int mode, const QString& desc)
1178{
1179 struct v4l2_encoder_cmd command {};
1180
1181 command.cmd = mode;
1182 if (ioctl(m_fd, VIDIOC_ENCODER_CMD, &command) != 0 && errno != ENOTTY)
1183 {
1184 // Some drivers do not support this ioctl at all. It is marked as
1185 // "experimental" in the V4L2 API spec. These drivers return EINVAL
1186 // in older kernels and ENOTTY in 3.1+
1187 LOG(VB_CHANNEL, LOG_WARNING, LOC +
1188 QString("SetEncoderState(%1) -- failed").arg(desc) + ENO);
1189 return false;
1190 }
1191 LOG(VB_CHANNEL, LOG_INFO, LOC +
1192 QString("SetEncoderState(%1) -- success").arg(desc));
1193 return true;
1194}
1195
1197{
1198 return SetEncoderState(V4L2_ENC_CMD_START, "Start");
1199}
1200
1202{
1203 return SetEncoderState(V4L2_ENC_CMD_STOP, "Stop");
1204}
1205
1207{
1208 return SetEncoderState(V4L2_ENC_CMD_PAUSE, "Pause");
1209}
1210
1212{
1213 return SetEncoderState(V4L2_ENC_CMD_RESUME, "Resume");
1214}
1215
1216bool V4L2util::OpenVBI(const QString& /*vbi_dev_name*/)
1217{
1218 return false;
1219}
1220
1222{
1223 struct v4l2_format vbifmt {};
1224
1225 vbifmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
1226 vbifmt.fmt.sliced.service_set |= (VBIMode::PAL_TT == vbimode) ?
1227 V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
1228
1229 int fd = m_vbiFd < 0 ? m_fd : m_vbiFd;
1230
1231 if (ioctl(fd, VIDIOC_S_FMT, &vbifmt) < 0)
1232 {
1233 LOG(VB_CHANNEL, LOG_WARNING, LOC + "ConfigureVBI() -- " +
1234 "Failed to enable VBI embedding (/dev/videoX)" + ENO);
1235 return false;
1236 }
1237
1238 if (ioctl(fd, VIDIOC_G_FMT, &vbifmt) >= 0)
1239 {
1240 LOG(VB_RECORD, LOG_INFO,
1241 LOC + QString("VBI service: %1, io size: %2")
1242 .arg(vbifmt.fmt.sliced.service_set)
1243 .arg(vbifmt.fmt.sliced.io_size));
1244
1245 // V4L2_MPEG_STREAM_VBI_FMT_NONE = 0, /* No VBI in the MPEG stream */
1246 // V4L2_MPEG_STREAM_VBI_FMT_IVTV = 1, /* VBI in private packets, IVTV form
1247 return SetExtControl(V4L2_CID_MPEG_STREAM_VBI_FMT,
1248 V4L2_MPEG_STREAM_VBI_FMT_IVTV,
1249 "MPEG Stream VBI format",
1250 "VBI in private packets, IVTV form");
1251
1252 }
1253
1254 return false;
1255}
static const std::array< const std::string, 8 > formats
bool GetFormats(QStringList &formats)
Definition: v4l2util.cpp:511
bool GetVideoStandard(QString &name) const
Definition: v4l2util.cpp:595
QString m_deviceName
Definition: v4l2util.h:104
bool HasTuner(void) const
Definition: v4l2util.cpp:690
bool ResumeEncoding(void)
Definition: v4l2util.cpp:1211
static bool OpenVBI(const QString &vbi_dev_name)
Definition: v4l2util.cpp:1216
bool Open(const QString &dev_name, const QString &vbi_dev_name="")
Definition: v4l2util.cpp:34
bool SetVideoBitrate(int value)
Definition: v4l2util.cpp:877
DriverOption::Options m_options
Definition: v4l2util.h:103
bool StopEncoding(void)
Definition: v4l2util.cpp:1201
QString GetDriverName(void) const
Definition: v4l2util.cpp:685
bool GetResolution(int &width, int &height) const
Definition: v4l2util.cpp:655
bool log_control(struct v4l2_queryctrl &qctrl, DriverOption &drv_opt, QString &msg)
Definition: v4l2util.cpp:354
bool IsEncoder(void) const
Definition: v4l2util.cpp:700
~V4L2util(void)
Definition: v4l2util.cpp:29
bool StartEncoding(void)
Definition: v4l2util.cpp:1196
void log_qctrl(struct v4l2_queryctrl &queryctrl, DriverOption &drv_opt, QString &msg)
Definition: v4l2util.cpp:193
V4L2util(void)=default
int m_version
Definition: v4l2util.h:107
bool PauseEncoding(void)
Definition: v4l2util.cpp:1206
bool SetLanguageMode(int mode)
Definition: v4l2util.cpp:1031
bool SetAudioSamplingRate(int value)
Definition: v4l2util.cpp:1084
int GetOptionValue(DriverOption::category_t cat, const QString &desc)
Definition: v4l2util.cpp:566
bool SetExtControl(int request, int value, const QString &ctrl_desc, const QString &value_desc)
Definition: v4l2util.cpp:740
static QString ctrlflags_toString(uint32_t flags)
Definition: v4l2util.cpp:134
bool SetSlicedVBI(VBIMode::vbimode_t vbimode)
Definition: v4l2util.cpp:1221
bool SetEncoderState(int mode, const QString &desc)
Definition: v4l2util.cpp:1177
bool SetVideoAspect(int value)
Definition: v4l2util.cpp:835
bool UserAdjustableResolution(void) const
Definition: v4l2util.cpp:709
QString DriverName(void) const
Definition: v4l2util.h:50
QString GetDeviceName(void) const
Definition: v4l2util.cpp:680
static QString queryctrl_toString(int type)
Definition: v4l2util.cpp:162
bool HasSlicedVBI(void) const
Definition: v4l2util.cpp:118
bool SetVolume(int volume)
Definition: v4l2util.cpp:996
bool HasAudioSupport(void) const
Definition: v4l2util.cpp:695
bool SetStreamType(int value)
Definition: v4l2util.cpp:821
uint32_t m_capabilities
Definition: v4l2util.h:108
int m_fd
Definition: v4l2util.h:101
bool HasStreaming(void) const
Definition: v4l2util.cpp:94
static void bitmask_toString(QString &result, uint32_t flags, uint32_t mask, const QString &desc)
Definition: v4l2util.cpp:123
void SetDefaultOptions(DriverOption::Options &options)
Definition: v4l2util.cpp:429
int GetStreamType(void) const
Definition: v4l2util.cpp:800
bool GetOptions(DriverOption::Options &options)
Definition: v4l2util.cpp:538
QString m_cardName
Definition: v4l2util.h:106
uint32_t GetCapabilities(void) const
Definition: v4l2util.cpp:675
int GetExtControl(int request, const QString &ctrl_desc="") const
Definition: v4l2util.cpp:717
bool SetAudioInput(int value)
Definition: v4l2util.cpp:927
bool SetResolution(uint32_t width, uint32_t height)
Definition: v4l2util.cpp:891
static QString StreamTypeDesc(int value)
Definition: v4l2util.cpp:780
bool SetVideoBitrateMode(int value)
Definition: v4l2util.cpp:860
QString m_driverName
Definition: v4l2util.h:105
bool SetVideoBitratePeak(int value)
Definition: v4l2util.cpp:884
int m_vbiFd
Definition: v4l2util.h:102
void Close(void)
Definition: v4l2util.cpp:83
bool SetAudioBitrateL2(int value)
Definition: v4l2util.cpp:1121
int GetSignalStrength(void) const
Definition: v4l2util.cpp:634
bool m_haveQueryExtCtrl
Definition: v4l2util.h:109
bool SetAudioCodec(int value)
Definition: v4l2util.cpp:952
vbimode_t
Definition: tv.h:11
@ PAL_TT
Definition: tv.h:13
#define close
Definition: compat.h:28
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:74
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
static eu8 clamp(eu8 value, eu8 low, eu8 high)
Definition: pxsup2dast.c:206
uint32_t m_step
Definition: driveroption.h:33
menu_t m_menu
Definition: driveroption.h:35
QMap< category_t, DriverOption > Options
Definition: driveroption.h:22
int32_t m_minimum
Definition: driveroption.h:29
int32_t m_maximum
Definition: driveroption.h:30
QString m_name
Definition: driveroption.h:27
int32_t m_defaultValue
Definition: driveroption.h:31
category_t m_category
Definition: driveroption.h:28
type_t m_type
Definition: driveroption.h:36
#define LOC
Definition: v4l2util.cpp:16
vbimode
Definition: vbilut.h:7