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