MythTV master
v4lchannel.cpp
Go to the documentation of this file.
1// Std C headers
2#include <cstdio>
3#include <cstdlib>
4#include <cerrno>
5
6// POSIX headers
7#include <unistd.h>
8#include <fcntl.h>
9#include <sys/ioctl.h>
10#include <sys/types.h>
11#include <sys/stat.h>
12#include <sys/wait.h>
13
14// C++ headers
15#include <algorithm>
16#include <iostream>
17
18#include <linux/videodev2.h>
19
20// MythTV headers
22#include "libmythbase/mythdb.h"
24
25#include "cardutil.h"
26#include "channelutil.h"
27#include "frequencies.h"
28#include "tv_rec.h"
29#include "v4lchannel.h"
30
31#define DEBUG_ATTRIB 1
32
33#define LOC QString("V4LChannel[%1](%2): ") \
34 .arg(m_inputId).arg(GetDevice())
35
36static int format_to_mode(const QString &fmt);
37static QString mode_to_format(int mode);
38
40{
42}
43
44bool V4LChannel::Init(QString &startchannel, bool setchan)
45{
46 if (setchan)
47 {
48 SetFormat(gCoreContext->GetSetting("TVFormat"));
50 }
51 return ChannelBase::Init(startchannel, setchan);
52}
53
55{
56#if FAKE_VIDEO
57 return true;
58#endif
59 if (m_videoFd >= 0)
60 return true;
61
62 QByteArray ascii_device = m_device.toLatin1();
63 m_videoFd = open(ascii_device.constData(), O_RDWR);
64 if (m_videoFd < 0)
65 {
66 LOG(VB_GENERAL, LOG_ERR, LOC + "Can't open video device." + ENO);
67 return false;
68 }
69
70 uint32_t version = 0;
71 uint32_t capabilities = 0;
73 version, capabilities))
74 {
75 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to query capabilities." + ENO);
76 Close();
77 return false;
78 }
79
80 m_hasStreamIO = ((capabilities & V4L2_CAP_STREAMING) != 0U);
81 m_hasStdIO = ((capabilities & V4L2_CAP_READWRITE) != 0U);
82 m_hasAsyncIO = ((capabilities & V4L2_CAP_ASYNCIO) != 0U);
83 m_hasTuner = ((capabilities & V4L2_CAP_TUNER) != 0U);
84 m_hasSlicedVbi = ((capabilities & V4L2_CAP_SLICED_VBI_CAPTURE) != 0U);
85
86 if (m_driverName == "bttv" || m_driverName == "cx8800" || m_driverName == "cx88_blackbird"
87 || m_driverName == "saa7164")
88 m_hasStreamIO = false; // driver workaround, see #9825, #10519 and #12336
89
90 LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Device name '%1' driver '%2'.")
92
93 LOG(VB_CHANNEL, LOG_INFO, LOC +
94 QString("v4l2: stream io: %2 std io: %3 async io: %4 "
95 "tuner %5 sliced vbi %6")
97 .arg(m_hasTuner).arg(m_hasSlicedVbi));
98
99 if (!InitializeInputs())
100 {
101 Close();
102 return false;
103 }
104
105 SetFormat("Default");
106
107 return true;
108}
109
111{
112 if (m_videoFd >= 0)
114 m_videoFd = -1;
115}
116
118{
119 if (fd != m_videoFd)
120 Close();
121 m_videoFd = (fd >= 0) ? fd : -1;
122}
123
124static int format_to_mode(const QString &fmt)
125{
126 if (fmt == "PAL-BG")
127 return V4L2_STD_PAL_BG;
128 if (fmt == "PAL-D")
129 return V4L2_STD_PAL_D;
130 if (fmt == "PAL-DK")
131 return V4L2_STD_PAL_DK;
132 if (fmt == "PAL-I")
133 return V4L2_STD_PAL_I;
134 if (fmt == "PAL-60")
135 return V4L2_STD_PAL_60;
136 if (fmt == "SECAM")
137 return V4L2_STD_SECAM;
138 if (fmt == "SECAM-D")
139 return V4L2_STD_SECAM_D;
140 if (fmt == "SECAM-DK")
141 return V4L2_STD_SECAM_DK;
142 if (fmt == "PAL-NC")
143 return V4L2_STD_PAL_Nc;
144 if (fmt == "PAL-M")
145 return V4L2_STD_PAL_M;
146 if (fmt == "PAL-N")
147 return V4L2_STD_PAL_N;
148 if (fmt == "NTSC-JP")
149 return V4L2_STD_NTSC_M_JP;
150 // generics...
151 if (fmt.startsWith("NTSC"))
152 return V4L2_STD_NTSC;
153 if (fmt.startsWith("ATSC"))
154 return V4L2_STD_NTSC; // We've dropped V4L ATSC support...
155 if (fmt.startsWith("PAL"))
156 return V4L2_STD_PAL;
157 return V4L2_STD_NTSC;
158}
159
160static QString mode_to_format(int mode)
161{
162 if (mode == V4L2_STD_NTSC)
163 return "NTSC";
164 if (mode == V4L2_STD_NTSC_M_JP)
165 return "NTSC-JP";
166 if (mode == V4L2_STD_PAL)
167 return "PAL";
168 if (mode == V4L2_STD_PAL_60)
169 return "PAL-60";
170 if (mode == V4L2_STD_PAL_BG)
171 return "PAL-BG";
172 if (mode == V4L2_STD_PAL_D)
173 return "PAL-D";
174 if (mode == V4L2_STD_PAL_DK)
175 return "PAL-DK";
176 if (mode == V4L2_STD_PAL_I)
177 return "PAL-I";
178 if (mode == V4L2_STD_PAL_M)
179 return "PAL-M";
180 if (mode == V4L2_STD_PAL_N)
181 return "PAL-N";
182 if (mode == V4L2_STD_PAL_Nc)
183 return "PAL-NC";
184 if (mode == V4L2_STD_SECAM)
185 return "SECAM";
186 if (mode == V4L2_STD_SECAM_D)
187 return "SECAM-D";
188 // generic..
189 if ((V4L2_STD_NTSC_M == mode) ||
190 (V4L2_STD_NTSC_443 == mode) ||
191 (V4L2_STD_NTSC_M_KR == mode))
192 return "NTSC";
193 if ((V4L2_STD_PAL_B == mode) ||
194 (V4L2_STD_PAL_B1 == mode) ||
195 (V4L2_STD_PAL_G == mode) ||
196 (V4L2_STD_PAL_H == mode) ||
197 (V4L2_STD_PAL_D1 == mode) ||
198 (V4L2_STD_PAL_K == mode))
199 return "PAL";
200 if ((V4L2_STD_SECAM_B == mode) ||
201 (V4L2_STD_SECAM_DK == mode) ||
202 (V4L2_STD_SECAM_G == mode) ||
203 (V4L2_STD_SECAM_H == mode) ||
204 (V4L2_STD_SECAM_K == mode) ||
205 (V4L2_STD_SECAM_K1 == mode) ||
206 (V4L2_STD_SECAM_L == mode) ||
207 (V4L2_STD_SECAM_LC == mode))
208 return "SECAM";
209 if ((V4L2_STD_ATSC == mode) ||
210 (V4L2_STD_ATSC_8_VSB == mode) ||
211 (V4L2_STD_ATSC_16_VSB == mode))
212 {
213 // We've dropped V4L ATSC support, but this still needs to be
214 // returned here so we will change the mode if the device is
215 // in ATSC mode already.
216 return "ATSC";
217 }
218
219 return "Unknown";
220}
221
229{
230 // Get Inputs from DB
232 return false;
233
234 // Get global TVFormat setting
235 QString fmt = gCoreContext->GetSetting("TVFormat");
236 LOG(VB_CHANNEL, LOG_INFO, QString("Global TVFormat Setting '%1'").arg(fmt));
237 int videomode_v4l2 = format_to_mode(fmt.toUpper());
238
239 bool ok = false;
241
242 // Insert info from hardware
243 uint valid_cnt = 0;
244 for (auto v4l_it = v4l_inputs.cbegin(); v4l_it != v4l_inputs.cend(); ++v4l_it)
245 {
246 if (*v4l_it == m_name)
247 {
248 m_inputNumV4L = v4l_it.key();
249 m_videoModeV4L2 = videomode_v4l2;
250 valid_cnt++;
251 }
252 }
253
254 // print it
255 LOG(VB_CHANNEL, LOG_INFO, LOC +
256 QString("Input #%1: '%2' schan(%3) tun(%4) v4l2(%6)")
257 .arg(QString::number(m_inputId), m_name, m_startChanNum,
260
261 return valid_cnt != 0U;
262}
263
273void V4LChannel::SetFormat(const QString &format)
274{
275 if (!Open())
276 return;
277
278 int inputNum = m_inputId;
279
280 QString fmt = format;
281 if ((fmt == "Default") || format.isEmpty())
282 {
283 if (m_inputId)
285 }
286
287 LOG(VB_CHANNEL, LOG_INFO, LOC + QString("SetFormat(%1) fmt(%2) input(%3)")
288 .arg(format, fmt, QString::number(inputNum)));
289
290 if (!SetInputAndFormat(inputNum, fmt))
291 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to set format." + ENO);
292
293}
294
295int V4LChannel::SetDefaultFreqTable(const QString &name)
296{
298 return m_defaultFreqTable;
299}
300
301void V4LChannel::SetFreqTable(const int index)
302{
303 m_curList = gChanLists[index].list;
304}
305
306int V4LChannel::SetFreqTable(const QString &tablename)
307{
308 const QString& name = tablename;
309 bool use_default = (name.toLower() == "default" || name.isEmpty());
310
311 m_curList.clear();
312 for (size_t i = 0; i < gChanLists.size(); i++)
313 {
314 char *listname = (char *)gChanLists[i].name;
315
316 if (use_default)
317 {
318 if (i == static_cast<size_t>(m_defaultFreqTable))
319 {
320 SetFreqTable(i);
321 return i;
322 }
323 }
324 else if (name == listname)
325 {
326 SetFreqTable(i);
327 return i;
328 }
329 }
330
331 LOG(VB_CHANNEL, LOG_ERR,
332 QString("Channel(%1)::SetFreqTable(): Invalid "
333 "frequency table name %2, using %3.").
334 arg(m_device, name, (char *)gChanLists[1].name));
335 SetFreqTable(1);
336 return 1;
337}
338
339int V4LChannel::GetCurrentChannelNum(const QString &channame)
340{
341 for (size_t i = 0; i < m_curList.size(); i++)
342 {
343 if (channame == m_curList[i].name)
344 return i;
345 }
346
347 LOG(VB_GENERAL, LOG_ERR, LOC +
348 QString("GetCurrentChannelNum(%1): Failed to find Channel")
349 .arg(channame));
350
351 return -1;
352}
353
354bool V4LChannel::Tune(const QString &freqid, int finetune)
355{
356 int i = GetCurrentChannelNum(freqid);
357 LOG(VB_CHANNEL, LOG_INFO,
358 QString("Channel(%1)::Tune(%2): curList[%3].freq(%4)")
359 .arg(m_device, freqid, QString::number(i))
360 .arg((i != -1) ? m_curList[i].freq : -1));
361
362 if (i == -1)
363 {
364 LOG(VB_GENERAL, LOG_ERR,
365 QString("Channel(%1)::Tune(%2): Error, failed to find channel.")
366 .arg(m_device, freqid));
367 return false;
368 }
369
370 int frequency = (m_curList[i].freq + finetune) * 1000;
371
372 return Tune(frequency);
373}
374
376{
377 return Tune(tuning.m_frequency - 1750000); // to visual carrier
378}
379
389bool V4LChannel::Tune(uint64_t frequency)
390{
391 LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Tune(%1)").arg(frequency));
392
393 int ioctlval = 0;
394
395 uint mplexid_restriction = 0;
396 uint chanid_restriction = 0;
397 if (!IsInputAvailable(mplexid_restriction, chanid_restriction))
398 return false;
399
400 // Video4Linux version 2 tuning
401 bool isTunerCapLow = false;
402 struct v4l2_modulator mod {};
403 mod.index = 0;
404 ioctlval = ioctl(m_videoFd, VIDIOC_G_MODULATOR, &mod);
405 if (ioctlval >= 0)
406 {
407 isTunerCapLow = ((mod.capability & V4L2_TUNER_CAP_LOW) != 0U);
408 LOG(VB_CHANNEL, LOG_INFO,
409 QString(" name: %1").arg((char *)mod.name));
410 LOG(VB_CHANNEL, LOG_INFO, QString("CapLow: %1").arg(isTunerCapLow));
411 }
412
413 struct v4l2_frequency vf {};
414 vf.tuner = 0; // use first tuner
415 vf.frequency = (isTunerCapLow) ?
416 ((int)(frequency / 62.5)) : (frequency / 62500);
417
418 vf.type = V4L2_TUNER_ANALOG_TV;
419
420 ioctlval = ioctl(m_videoFd, VIDIOC_S_FREQUENCY, &vf);
421 if (ioctlval < 0)
422 {
423 LOG(VB_GENERAL, LOG_ERR,
424 QString("Channel(%1)::Tune(): Error %2 "
425 "while setting frequency (v2): %3")
426 .arg(m_device).arg(ioctlval).arg(strerror(errno)));
427 return false;
428 }
429 ioctlval = ioctl(m_videoFd, VIDIOC_G_FREQUENCY, &vf);
430
431 if (ioctlval >= 0)
432 {
433 LOG(VB_CHANNEL, LOG_INFO,
434 QString("Channel(%1)::Tune(): Frequency is now %2")
435 .arg(m_device).arg(vf.frequency * 62500));
436 }
437
438 return true;
439}
440
447{
448 struct v4l2_frequency vf {};
449 vf.tuner = 0; // use first tuner
450 vf.type = V4L2_TUNER_ANALOG_TV;
451
452 // Get the last tuned frequency
453 int ioctlval = ioctl(m_videoFd, VIDIOC_G_FREQUENCY, &vf);
454 if (ioctlval < 0)
455 {
456 LOG(VB_GENERAL, LOG_ERR, LOC + "Retune failed (1)" + ENO);
457 return false;
458 }
459
460 // Set the last tuned frequency again...
461 ioctlval = ioctl(m_videoFd, VIDIOC_S_FREQUENCY, &vf);
462 if (ioctlval < 0)
463 {
464 LOG(VB_GENERAL, LOG_ERR, LOC + "Retune failed (2)" + ENO);
465 return false;
466 }
467
468 return true;
469}
470
471QString V4LChannel::GetFormatForChannel(const QString& channum, const QString& inputname)
472{
474 query.prepare(
475 "SELECT tvformat "
476 "FROM channel, capturecard "
477 "WHERE deleted IS NULL AND "
478 " channum = :CHANNUM AND "
479 " inputname = :INPUTNAME AND "
480 " capturecard.cardid = :INPUTID AND "
481 " capturecard.sourceid = channel.sourceid");
482 query.bindValue(":CHANNUM", channum);
483 query.bindValue(":INPUTNAME", inputname);
484 query.bindValue(":INPUTID", m_inputId);
485
486 QString fmt;
487 if (!query.exec() || !query.isActive())
488 MythDB::DBError("GetFormatForChannel:find format", query);
489 else if (query.next())
490 fmt = query.value(0).toString();
491 return fmt;
492}
493
494bool V4LChannel::SetInputAndFormat(int inputNum, const QString& newFmt)
495{
496 if (!m_inputId || m_inputNumV4L < 0)
497 return false;
498
499 int inputNumV4L = m_inputNumV4L;
500 bool ok = true;
501
502 QString msg =
503 QString("SetInputAndFormat(%1, %2) ").arg(inputNum).arg(newFmt);
504
505 struct v4l2_input input {};
506 int ioctlval = ioctl(m_videoFd, VIDIOC_G_INPUT, &input);
507 bool input_switch = (0 != ioctlval || (uint)inputNumV4L != input.index);
508
509 const v4l2_std_id new_vid_mode = format_to_mode(newFmt);
510 v4l2_std_id cur_vid_mode = 0;
511 ioctlval = ioctl(m_videoFd, VIDIOC_G_STD, &cur_vid_mode);
512 bool mode_switch = (0 != ioctlval || new_vid_mode != cur_vid_mode);
513 bool needs_switch = input_switch || mode_switch;
514
515 LOG(VB_GENERAL, LOG_INFO, LOC + msg + "(v4l v2) " +
516 QString("input_switch: %1 mode_switch: %2")
517 .arg(input_switch).arg(mode_switch));
518
519 // ConvertX (wis-go7007) requires streaming to be disabled
520 // before an input switch, do this if CAP_STREAMING is set.
521 bool streamingDisabled = false;
522 int streamType = V4L2_BUF_TYPE_VIDEO_CAPTURE;
523 if (needs_switch && m_hasStreamIO)
524 {
525 ioctlval = ioctl(m_videoFd, VIDIOC_STREAMOFF, &streamType);
526 if (ioctlval < 0)
527 {
528 LOG(VB_GENERAL, LOG_ERR, LOC + msg +
529 "\n\t\t\twhile disabling streaming (v4l v2)" + ENO);
530 ok = false;
531 }
532 else
533 {
534 streamingDisabled = true;
535 }
536 }
537
538 if (input_switch)
539 {
540 // Send the input switch ioctl.
541 ioctlval = ioctl(m_videoFd, VIDIOC_S_INPUT, &inputNumV4L);
542 if (ioctlval < 0)
543 {
544 LOG(VB_GENERAL, LOG_ERR, LOC + msg +
545 "\n\t\t\twhile setting input (v4l v2)" + ENO);
546
547 ok = false;
548 }
549 }
550
551 if (mode_switch)
552 {
553 ioctlval = ioctl(m_videoFd, VIDIOC_S_STD, &new_vid_mode);
554 if (ioctlval < 0)
555 {
556 LOG(VB_GENERAL, LOG_ERR, LOC + msg +
557 "\n\t\t\twhile setting format (v4l v2)" + ENO);
558
559 ok = false;
560 }
561 }
562
563 if (streamingDisabled)
564 {
565 ioctlval = ioctl(m_videoFd, VIDIOC_STREAMON, &streamType);
566 if (ioctlval < 0)
567 {
568 LOG(VB_GENERAL, LOG_ERR, LOC + msg +
569 "\n\t\t\twhile reenabling streaming (v4l v2)" + ENO);
570
571 ok = false;
572 }
573 }
574
575 return ok;
576}
577
578static int get_v4l2_attribute(const QString &db_col_name)
579{
580 if ("brightness" == db_col_name)
581 return V4L2_CID_BRIGHTNESS;
582 if ("contrast" == db_col_name)
583 return V4L2_CID_CONTRAST;
584 if ("colour" == db_col_name)
585 return V4L2_CID_SATURATION;
586 if ("hue" == db_col_name)
587 return V4L2_CID_HUE;
588 return -1;
589}
590
591bool V4LChannel::InitPictureAttribute(const QString &db_col_name)
592{
593 if (!m_pParent)
594 return false;
595
596 int v4l2_attrib = get_v4l2_attribute(db_col_name);
597 if (v4l2_attrib == -1)
598 return false;
599
601 db_col_name, GetSourceID(), m_curChannelName);
602 int sfield = CardUtil::GetValueInt(
603 db_col_name, m_inputId);
604
605 if ((cfield == -1) || (sfield == -1))
606 return false;
607
608 QString loc = LOC +
609 QString("InitPictureAttribute(%1): ").arg(db_col_name, 10);
610
611 struct v4l2_control ctrl {};
612 struct v4l2_queryctrl qctrl {};
613
614 ctrl.id = qctrl.id = v4l2_attrib;
615 if (ioctl(m_videoFd, VIDIOC_QUERYCTRL, &qctrl) < 0)
616 {
617 LOG(VB_GENERAL, LOG_ERR, loc + "failed to query controls." + ENO);
618 return false;
619 }
620
621 float new_range = qctrl.maximum - qctrl.minimum;
622 float old_range = 65535 - 0;
623 float scl_range = new_range / old_range;
624 float dfl = (qctrl.default_value - qctrl.minimum) / new_range;
625 int norm_dfl = (0x10000 + (int)(dfl * old_range) - 32768) & 0xFFFF;
626
627 if (!m_pictAttrDefault.contains(db_col_name))
628 {
629 if (m_deviceName == "pcHDTV HD3000 HDTV")
630 {
631 m_pictAttrDefault["brightness"] = 9830;
632 m_pictAttrDefault["contrast"] = 39322;
633 m_pictAttrDefault["colour"] = 45875;
634 m_pictAttrDefault["hue"] = 0;
635 }
636 else
637 {
638 m_pictAttrDefault[db_col_name] = norm_dfl;
639 }
640 }
641
642 int dfield = m_pictAttrDefault[db_col_name];
643 int field = (cfield + sfield + dfield) & 0xFFFF;
644 int value0 = (int) ((scl_range * field) + qctrl.minimum);
645 int value1 = std::min(value0, qctrl.maximum);
646 ctrl.value = std::max(value1, qctrl.minimum);
647
648#if DEBUG_ATTRIB
649 LOG(VB_CHANNEL, LOG_DEBUG, loc + QString(" %1\n\t\t\t"
650 "[%2,%3] dflt(%4, %5, %6)")
651 .arg(value0).arg(qctrl.minimum, 5).arg(qctrl.maximum, 5)
652 .arg(qctrl.default_value, 5).arg(dfl, 4, 'f', 2)
653 .arg(norm_dfl));
654#endif
655
656 if (ioctl(m_videoFd, VIDIOC_S_CTRL, &ctrl) < 0)
657 {
658 LOG(VB_GENERAL, LOG_ERR, loc + "failed to set controls" + ENO);
659 return false;
660 }
661
662 return true;
663}
664
666{
667 return (InitPictureAttribute("brightness") &&
668 InitPictureAttribute("contrast") &&
669 InitPictureAttribute("colour") &&
670 InitPictureAttribute("hue"));
671}
672
674{
675 QString db_col_name = toDBString(attr);
676 if (db_col_name.isEmpty())
677 return -1;
678
680 db_col_name, GetSourceID(), m_curChannelName);
681 int sfield = CardUtil::GetValueInt(
682 db_col_name, m_inputId);
683 int dfield = 0;
684
685 if (m_pictAttrDefault.contains(db_col_name))
686 dfield = m_pictAttrDefault[db_col_name];
687
688 int val = (cfield + sfield + dfield) & 0xFFFF;
689
690#if DEBUG_ATTRIB
691 LOG(VB_CHANNEL, LOG_DEBUG,
692 QString("GetPictureAttribute(%1) -> cdb %2 rdb %3 d %4 -> %5")
693 .arg(db_col_name).arg(cfield).arg(sfield)
694 .arg(dfield).arg(val));
695#endif
696
697 return val;
698}
699
700static int get_v4l2_attribute_value(int videofd, int v4l2_attrib)
701{
702 struct v4l2_control ctrl {};
703 struct v4l2_queryctrl qctrl {};
704
705 ctrl.id = qctrl.id = v4l2_attrib;
706 if (ioctl(videofd, VIDIOC_QUERYCTRL, &qctrl) < 0)
707 {
708 LOG(VB_GENERAL, LOG_ERR,
709 "get_v4l2_attribute_value: failed to query controls (1)" + ENO);
710 return -1;
711 }
712
713 if (ioctl(videofd, VIDIOC_G_CTRL, &ctrl) < 0)
714 {
715 LOG(VB_GENERAL, LOG_ERR,
716 "get_v4l2_attribute_value: failed to get controls (2)" + ENO);
717 return -1;
718 }
719
720 float mult = 65535.0F / (qctrl.maximum - qctrl.minimum);
721 return std::clamp((int)(mult * (ctrl.value - qctrl.minimum)), 0, 65525);
722}
723
724static int set_v4l2_attribute_value(int videofd, int v4l2_attrib, int newvalue)
725{
726 struct v4l2_control ctrl {};
727 struct v4l2_queryctrl qctrl {};
728
729 ctrl.id = qctrl.id = v4l2_attrib;
730 if (ioctl(videofd, VIDIOC_QUERYCTRL, &qctrl) < 0)
731 {
732 LOG(VB_GENERAL, LOG_ERR,
733 "set_v4l2_attribute_value: failed to query control" + ENO);
734 return -1;
735 }
736
737 float mult = (qctrl.maximum - qctrl.minimum) / 65535.0F;
738 ctrl.value = (int)((mult * newvalue) + qctrl.minimum);
739 ctrl.value = std::min(ctrl.value, qctrl.maximum);
740 ctrl.value = std::max(ctrl.value, qctrl.minimum);
741
742 if (ioctl(videofd, VIDIOC_S_CTRL, &ctrl) < 0)
743 {
744 LOG(VB_GENERAL, LOG_ERR,
745 "set_v4l2_attribute_value: failed to set control" + ENO);
746 return -1;
747 }
748
749 return 0;
750}
751
754{
755 if (!m_pParent)
756 return -1;
757
758 QString db_col_name = toDBString(attr);
759 if (db_col_name.isEmpty())
760 return -1;
761
762 int v4l2_attrib = get_v4l2_attribute(db_col_name);
763 if (v4l2_attrib == -1)
764 return -1;
765
766 // get the old attribute value from the hardware, this is
767 // just a sanity check on whether this attribute exists
768 if (get_v4l2_attribute_value(m_videoFd, v4l2_attrib) < 0)
769 return -1;
770
771 int old_value = GetPictureAttribute(attr);
772 int new_value = old_value + ((up) ? 655 : -655);
773
774 // make sure we are within bounds (wrap around for hue)
775 if (V4L2_CID_HUE == v4l2_attrib)
776 new_value &= 0xffff;
777 new_value = std::clamp(new_value, 0, 65535);
778
779#if DEBUG_ATTRIB
780 LOG(VB_CHANNEL, LOG_DEBUG,
781 QString("ChangePictureAttribute(%1,%2,%3) cur %4 -> new %5")
782 .arg(type).arg(db_col_name).arg(up)
783 .arg(old_value).arg(new_value));
784#endif
785
786 // actually set the new attribute value on the hardware
787 if (set_v4l2_attribute_value(m_videoFd, v4l2_attrib, new_value) < 0)
788 return -1;
789
790 // tell the DB about the new attribute value
792 {
793 int adj_value = ChannelUtil::GetChannelValueInt(
794 db_col_name, GetSourceID(), m_curChannelName);
795
796 int tmp = new_value - old_value + adj_value;
797 tmp = (tmp < 0) ? tmp + 0x10000 : tmp;
798 tmp = (tmp > 0xffff) ? tmp - 0x10000 : tmp;
799 ChannelUtil::SetChannelValue(db_col_name, QString::number(tmp),
801 }
803 {
804 int adj_value = CardUtil::GetValueInt(
805 db_col_name, m_inputId);
806
807 int tmp = new_value - old_value + adj_value;
808 tmp = (tmp < 0) ? tmp + 0x10000 : tmp;
809 tmp = (tmp > 0xffff) ? tmp - 0x10000 : tmp;
810 CardUtil::SetValue(db_col_name, m_inputId, tmp);
811 }
812
813 return new_value;
814}
QMap< int, QString > InputNames
Definition: cardutil.h:22
static InputNames ProbeV4LVideoInputs(int videofd, bool &ok)
Definition: cardutil.cpp:2385
static bool SetValue(const QString &col, uint inputid, int val)
Definition: cardutil.h:310
static int GetValueInt(const QString &col, uint inputid)
Definition: cardutil.h:308
static bool GetV4LInfo(int videofd, QString &input, QString &driver, uint32_t &version, uint32_t &capabilities)
Definition: cardutil.cpp:2355
QString m_name
Definition: channelbase.h:139
virtual uint GetSourceID(void) const
Definition: channelbase.h:71
virtual bool IsInputAvailable(uint &mplexid_restriction, uint &chanid_restriction) const
Switches to another input on hardware, and sets the channel is setstarting is true.
virtual bool Init(QString &startchannel, bool setchan)
Definition: channelbase.cpp:67
QString m_curChannelName
Definition: channelbase.h:135
TVRec * m_pParent
Definition: channelbase.h:134
uint m_inputId
Definition: channelbase.h:137
virtual bool InitializeInput(void)
Fills in input map from DB.
QString m_startChanNum
Definition: channelbase.h:140
QString m_tuneToChannel
Definition: channelbase.h:142
static bool SetChannelValue(const QString &field_name, const QString &value, uint sourceid, const QString &channum)
static int GetChannelValueInt(const QString &channel_field, uint sourceid, const QString &channum)
uint64_t m_frequency
Definition: dtvmultiplex.h:94
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837
QVariant value(int i) const
Definition: mythdbcon.h:204
bool isActive(void) const
Definition: mythdbcon.h:215
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
QString GetSetting(const QString &key, const QString &defaultval="")
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
bool m_hasAsyncIO
Definition: v4lchannel.h:104
bool m_hasSlicedVbi
Definition: v4lchannel.h:106
bool m_hasStdIO
Definition: v4lchannel.h:103
int GetCurrentChannelNum(const QString &channame)
Definition: v4lchannel.cpp:339
~V4LChannel(void) override
Definition: v4lchannel.cpp:39
int m_videoFd
Definition: v4lchannel.h:95
bool SetInputAndFormat(int inputNum, const QString &newFmt)
Definition: v4lchannel.cpp:494
int ChangePictureAttribute(PictureAdjustType type, PictureAttribute attr, bool up) override
Definition: v4lchannel.cpp:752
int GetPictureAttribute(PictureAttribute attr) const override
Definition: v4lchannel.cpp:673
bool m_hasTuner
Definition: v4lchannel.h:105
CHANLIST_vec m_curList
Definition: v4lchannel.h:100
QString m_deviceName
Definition: v4lchannel.h:96
QString GetFormatForChannel(const QString &channum, const QString &inputname)
Definition: v4lchannel.cpp:471
QMap< QString, int > m_pictAttrDefault
Definition: v4lchannel.h:98
bool m_hasStreamIO
Definition: v4lchannel.h:102
bool InitializeInputs(void)
This enumerates the inputs, converts the format string to something the hardware understands,...
Definition: v4lchannel.cpp:228
int SetDefaultFreqTable(const QString &name)
Definition: v4lchannel.cpp:295
bool InitPictureAttribute(const QString &db_col_name)
Definition: v4lchannel.cpp:591
void Close(void) override
Closes the channel changing hardware to use.
Definition: v4lchannel.cpp:110
QString m_device
Definition: v4lchannel.h:93
bool Retune(void) override
Retunes to last tuned frequency.
Definition: v4lchannel.cpp:446
bool InitPictureAttributes(void) override
Definition: v4lchannel.cpp:665
int m_videoModeV4L2
Definition: v4lchannel.h:110
bool Open(void) override
Opens the channel changing hardware for use.
Definition: v4lchannel.cpp:54
QString m_driverName
Definition: v4lchannel.h:97
int m_inputNumV4L
Definition: v4lchannel.h:109
bool Init(QString &startchannel, bool setchan) override
Definition: v4lchannel.cpp:44
void SetFreqTable(int index)
Definition: v4lchannel.cpp:301
void SetFormat(const QString &format) override
Initializes tuner and modulator variables.
Definition: v4lchannel.cpp:273
void SetFd(int fd) override
Sets file descriptor.
Definition: v4lchannel.cpp:117
int m_defaultFreqTable
Definition: v4lchannel.h:108
bool Tune(const DTVMultiplex &tuning) override
This performs the actual frequency tuning and in some cases input switching.
Definition: v4lchannel.cpp:375
#define close
Definition: compat.h:39
static const std::array< const uint32_t, 4 > freq
Definition: element.cpp:45
unsigned int uint
Definition: freesurround.h:24
const CHANLISTS_vec gChanLists
static guint32 * tmp
Definition: goom_core.cpp:26
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:74
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
string version
Definition: giantbomb.py:185
static eu8 clamp(eu8 value, eu8 low, eu8 high)
Definition: pxsup2dast.c:206
PictureAdjustType
Definition: tv.h:124
@ kAdjustingPicture_Recording
Definition: tv.h:128
@ kAdjustingPicture_Channel
Definition: tv.h:127
#define LOC
Definition: v4lchannel.cpp:33
static QString mode_to_format(int mode)
Definition: v4lchannel.cpp:160
static int get_v4l2_attribute_value(int videofd, int v4l2_attrib)
Definition: v4lchannel.cpp:700
static int set_v4l2_attribute_value(int videofd, int v4l2_attrib, int newvalue)
Definition: v4lchannel.cpp:724
static int get_v4l2_attribute(const QString &db_col_name)
Definition: v4lchannel.cpp:578
static int format_to_mode(const QString &fmt)
Definition: v4lchannel.cpp:124
QString toDBString(PrimariesMode Mode)
PictureAttribute