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 using namespace std;
18 
19 #include <linux/videodev2.h>
20 
21 // MythTV headers
22 #include "v4lchannel.h"
23 #include "frequencies.h"
24 #include "tv_rec.h"
25 #include "mythdb.h"
26 #include "channelutil.h"
27 #include "cardutil.h"
28 
29 #define DEBUG_ATTRIB 1
30 
31 #define LOC QString("V4LChannel[%1](%2): ") \
32  .arg(m_inputid).arg(GetDevice())
33 
34 static int format_to_mode(const QString &fmt);
35 static QString mode_to_format(int mode);
36 
38 {
40 }
41 
42 bool V4LChannel::Init(QString &startchannel, bool setchan)
43 {
44  if (setchan)
45  {
46  SetFormat(gCoreContext->GetSetting("TVFormat"));
47  SetDefaultFreqTable(gCoreContext->GetSetting("FreqTable"));
48  }
49  return ChannelBase::Init(startchannel, setchan);
50 }
51 
52 bool V4LChannel::Open(void)
53 {
54 #if FAKE_VIDEO
55  return true;
56 #endif
57  if (m_videofd >= 0)
58  return true;
59 
60  QByteArray ascii_device = m_device.toLatin1();
61  m_videofd = open(ascii_device.constData(), O_RDWR);
62  if (m_videofd < 0)
63  {
64  LOG(VB_GENERAL, LOG_ERR, LOC + "Can't open video device." + ENO);
65  return false;
66  }
67 
68  uint32_t version, capabilities;
69  if (!CardUtil::GetV4LInfo(m_videofd, m_device_name, m_driver_name,
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_has_stream_io = ((capabilities & V4L2_CAP_STREAMING) != 0U);
78  m_has_std_io = ((capabilities & V4L2_CAP_READWRITE) != 0U);
79  m_has_async_io = ((capabilities & V4L2_CAP_ASYNCIO) != 0U);
80  m_has_tuner = ((capabilities & V4L2_CAP_TUNER) != 0U);
81  m_has_sliced_vbi = ((capabilities & V4L2_CAP_SLICED_VBI_CAPTURE) != 0U);
82 
83  if (m_driver_name == "bttv" || m_driver_name == "cx8800" || m_driver_name == "cx88_blackbird"
84  || m_driver_name == "saa7164")
85  m_has_stream_io = false; // driver workaround, see #9825, #10519 and #12336
86 
87  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Device name '%1' driver '%2'.")
88  .arg(m_device_name).arg(m_driver_name));
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")
93  .arg(m_has_stream_io).arg(m_has_std_io).arg(m_has_async_io)
94  .arg(m_has_tuner).arg(m_has_sliced_vbi));
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;
237  InputNames v4l_inputs = CardUtil::ProbeV4LVideoInputs(m_videofd, ok);
238 
239  // Insert info from hardware
240  uint valid_cnt = 0;
241  InputNames::const_iterator v4l_it = v4l_inputs.begin();
242  for (; v4l_it != v4l_inputs.end(); ++v4l_it)
243  {
244  if (*v4l_it == m_name)
245  {
246  m_inputNumV4L = v4l_it.key();
247  m_videoModeV4L2 = videomode_v4l2;
248  valid_cnt++;
249  }
250  }
251 
252  // print it
253  LOG(VB_CHANNEL, LOG_INFO, LOC +
254  QString("Input #%1: '%2' schan(%3) tun(%4) v4l2(%6)")
255  .arg(m_inputid).arg(m_name).arg(m_startChanNum)
256  .arg(m_tuneToChannel)
257  .arg(mode_to_format(m_videoModeV4L2)));
258 
259  return valid_cnt != 0U;
260 }
261 
271 void V4LChannel::SetFormat(const QString &format)
272 {
273  if (!Open())
274  return;
275 
276  int inputNum = m_inputid;
277 
278  QString fmt = format;
279  if ((fmt == "Default") || format.isEmpty())
280  {
281  if (m_inputid)
282  fmt = mode_to_format(m_videoModeV4L2);
283  }
284 
285  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("SetFormat(%1) fmt(%2) input(%3)")
286  .arg(format).arg(fmt).arg(inputNum));
287 
288  if (!SetInputAndFormat(inputNum, fmt))
289  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to set format." + ENO);
290 
291 }
292 
294 {
295  m_defaultFreqTable = SetFreqTable(name);
296  return m_defaultFreqTable;
297 }
298 
299 void V4LChannel::SetFreqTable(const int index)
300 {
301  m_curList = chanlists[index].list;
302  m_totalChannels = chanlists[index].count;
303 }
304 
305 int V4LChannel::SetFreqTable(const QString &tablename)
306 {
307  const QString& name = tablename;
308  bool use_default = (name.toLower() == "default" || name.isEmpty());
309 
310  int i = 0;
311  char *listname = (char *)chanlists[i].name;
312 
313  m_curList = nullptr;
314  while (listname != nullptr)
315  {
316  if (use_default)
317  {
318  if (i == 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  i++;
330  listname = (char *)chanlists[i].name;
331  }
332 
333  LOG(VB_CHANNEL, LOG_ERR,
334  QString("Channel(%1)::SetFreqTable(): Invalid "
335  "frequency table name %2, using %3.").
336  arg(m_device).arg(name).arg((char *)chanlists[1].name));
337  SetFreqTable(1);
338  return 1;
339 }
340 
341 int V4LChannel::GetCurrentChannelNum(const QString &channame)
342 {
343  for (int i = 0; i < m_totalChannels; i++)
344  {
345  if (channame == m_curList[i].name)
346  return i;
347  }
348 
349  LOG(VB_GENERAL, LOG_ERR, LOC +
350  QString("GetCurrentChannelNum(%1): Failed to find Channel")
351  .arg(channame));
352 
353  return -1;
354 }
355 
356 bool V4LChannel::Tune(const QString &freqid, int finetune)
357 {
358  int i = GetCurrentChannelNum(freqid);
359  LOG(VB_CHANNEL, LOG_INFO,
360  QString("Channel(%1)::Tune(%2): curList[%3].freq(%4)")
361  .arg(m_device).arg(freqid).arg(i)
362  .arg((i != -1) ? m_curList[i].freq : -1));
363 
364  if (i == -1)
365  {
366  LOG(VB_GENERAL, LOG_ERR,
367  QString("Channel(%1)::Tune(%2): Error, failed to find channel.")
368  .arg(m_device).arg(freqid));
369  return false;
370  }
371 
372  int frequency = (m_curList[i].freq + finetune) * 1000;
373 
374  return Tune(frequency);
375 }
376 
377 bool V4LChannel::Tune(const DTVMultiplex &tuning)
378 {
379  return Tune(tuning.m_frequency - 1750000); // to visual carrier
380 }
381 
391 bool V4LChannel::Tune(uint64_t frequency)
392 {
393  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Tune(%1)").arg(frequency));
394 
395  int ioctlval = 0;
396 
397  uint mplexid_restriction;
398  uint chanid_restriction;
399  if (!IsInputAvailable(mplexid_restriction, chanid_restriction))
400  return false;
401 
402  // Video4Linux version 2 tuning
403  bool isTunerCapLow = false;
404  struct v4l2_modulator mod;
405  memset(&mod, 0, sizeof(mod));
406  mod.index = 0;
407  ioctlval = ioctl(m_videofd, VIDIOC_G_MODULATOR, &mod);
408  if (ioctlval >= 0)
409  {
410  isTunerCapLow = ((mod.capability & V4L2_TUNER_CAP_LOW) != 0U);
411  LOG(VB_CHANNEL, LOG_INFO,
412  QString(" name: %1").arg((char *)mod.name));
413  LOG(VB_CHANNEL, LOG_INFO, QString("CapLow: %1").arg(isTunerCapLow));
414  }
415 
416  struct v4l2_frequency vf;
417  memset(&vf, 0, sizeof(vf));
418 
419  vf.tuner = 0; // use first tuner
420  vf.frequency = (isTunerCapLow) ?
421  ((int)(frequency / 62.5)) : (frequency / 62500);
422 
423  vf.type = V4L2_TUNER_ANALOG_TV;
424 
425  ioctlval = ioctl(m_videofd, VIDIOC_S_FREQUENCY, &vf);
426  if (ioctlval < 0)
427  {
428  LOG(VB_GENERAL, LOG_ERR,
429  QString("Channel(%1)::Tune(): Error %2 "
430  "while setting frequency (v2): %3")
431  .arg(m_device).arg(ioctlval).arg(strerror(errno)));
432  return false;
433  }
434  ioctlval = ioctl(m_videofd, VIDIOC_G_FREQUENCY, &vf);
435 
436  if (ioctlval >= 0)
437  {
438  LOG(VB_CHANNEL, LOG_INFO,
439  QString("Channel(%1)::Tune(): Frequency is now %2")
440  .arg(m_device).arg(vf.frequency * 62500));
441  }
442 
443  return true;
444 }
445 
452 {
453  struct v4l2_frequency vf;
454  memset(&vf, 0, sizeof(vf));
455 
456  vf.tuner = 0; // use first tuner
457  vf.type = V4L2_TUNER_ANALOG_TV;
458 
459  // Get the last tuned frequency
460  int ioctlval = ioctl(m_videofd, VIDIOC_G_FREQUENCY, &vf);
461  if (ioctlval < 0)
462  {
463  LOG(VB_GENERAL, LOG_ERR, LOC + "Retune failed (1)" + ENO);
464  return false;
465  }
466 
467  // Set the last tuned frequency again...
468  ioctlval = ioctl(m_videofd, VIDIOC_S_FREQUENCY, &vf);
469  if (ioctlval < 0)
470  {
471  LOG(VB_GENERAL, LOG_ERR, LOC + "Retune failed (2)" + ENO);
472  return false;
473  }
474 
475  return true;
476 }
477 
478 QString V4LChannel::GetFormatForChannel(const QString& channum, const QString& inputname)
479 {
480  MSqlQuery query(MSqlQuery::InitCon());
481  query.prepare(
482  "SELECT tvformat "
483  "FROM channel, capturecard "
484  "WHERE channum = :CHANNUM AND "
485  " inputname = :INPUTNAME AND "
486  " capturecard.cardid = :INPUTID AND "
487  " capturecard.sourceid = channel.sourceid");
488  query.bindValue(":CHANNUM", channum);
489  query.bindValue(":INPUTNAME", inputname);
490  query.bindValue(":INPUTID", m_inputid);
491 
492  QString fmt;
493  if (!query.exec() || !query.isActive())
494  MythDB::DBError("GetFormatForChannel:find format", query);
495  else if (query.next())
496  fmt = query.value(0).toString();
497  return fmt;
498 }
499 
500 bool V4LChannel::SetInputAndFormat(int inputNum, const QString& newFmt)
501 {
502  if (!m_inputid || m_inputNumV4L < 0)
503  return false;
504 
505  int inputNumV4L = m_inputNumV4L;
506  bool ok = true;
507 
508  QString msg =
509  QString("SetInputAndFormat(%1, %2) ").arg(inputNum).arg(newFmt);
510 
511  struct v4l2_input input;
512  int ioctlval = ioctl(m_videofd, VIDIOC_G_INPUT, &input);
513  bool input_switch = (0 != ioctlval || (uint)inputNumV4L != input.index);
514 
515  const v4l2_std_id new_vid_mode = format_to_mode(newFmt);
516  v4l2_std_id cur_vid_mode;
517  ioctlval = ioctl(m_videofd, VIDIOC_G_STD, &cur_vid_mode);
518  bool mode_switch = (0 != ioctlval || new_vid_mode != cur_vid_mode);
519  bool needs_switch = input_switch || mode_switch;
520 
521  LOG(VB_GENERAL, LOG_INFO, LOC + msg + "(v4l v2) " +
522  QString("input_switch: %1 mode_switch: %2")
523  .arg(input_switch).arg(mode_switch));
524 
525  // ConvertX (wis-go7007) requires streaming to be disabled
526  // before an input switch, do this if CAP_STREAMING is set.
527  bool streamingDisabled = false;
528  int streamType = V4L2_BUF_TYPE_VIDEO_CAPTURE;
529  if (needs_switch && m_has_stream_io)
530  {
531  ioctlval = ioctl(m_videofd, VIDIOC_STREAMOFF, &streamType);
532  if (ioctlval < 0)
533  {
534  LOG(VB_GENERAL, LOG_ERR, LOC + msg +
535  "\n\t\t\twhile disabling streaming (v4l v2)" + ENO);
536  ok = false;
537  }
538  else
539  {
540  streamingDisabled = true;
541  }
542  }
543 
544  if (input_switch)
545  {
546  // Send the input switch ioctl.
547  ioctlval = ioctl(m_videofd, VIDIOC_S_INPUT, &inputNumV4L);
548  if (ioctlval < 0)
549  {
550  LOG(VB_GENERAL, LOG_ERR, LOC + msg +
551  "\n\t\t\twhile setting input (v4l v2)" + ENO);
552 
553  ok = false;
554  }
555  }
556 
557  if (mode_switch)
558  {
559  ioctlval = ioctl(m_videofd, VIDIOC_S_STD, &new_vid_mode);
560  if (ioctlval < 0)
561  {
562  LOG(VB_GENERAL, LOG_ERR, LOC + msg +
563  "\n\t\t\twhile setting format (v4l v2)" + ENO);
564 
565  ok = false;
566  }
567  }
568 
569  if (streamingDisabled)
570  {
571  ioctlval = ioctl(m_videofd, VIDIOC_STREAMON, &streamType);
572  if (ioctlval < 0)
573  {
574  LOG(VB_GENERAL, LOG_ERR, LOC + msg +
575  "\n\t\t\twhile reenabling streaming (v4l v2)" + ENO);
576 
577  ok = false;
578  }
579  }
580 
581  return ok;
582 }
583 
584 static int get_v4l2_attribute(const QString &db_col_name)
585 {
586  if ("brightness" == db_col_name)
587  return V4L2_CID_BRIGHTNESS;
588  if ("contrast" == db_col_name)
589  return V4L2_CID_CONTRAST;
590  if ("colour" == db_col_name)
591  return V4L2_CID_SATURATION;
592  if ("hue" == db_col_name)
593  return V4L2_CID_HUE;
594  return -1;
595 }
596 
597 bool V4LChannel::InitPictureAttribute(const QString &db_col_name)
598 {
599  if (!m_pParent)
600  return false;
601 
602  int v4l2_attrib = get_v4l2_attribute(db_col_name);
603  if (v4l2_attrib == -1)
604  return false;
605 
606  int cfield = ChannelUtil::GetChannelValueInt(
607  db_col_name, GetSourceID(), m_curchannelname);
608  int sfield = CardUtil::GetValueInt(
609  db_col_name, m_inputid);
610 
611  if ((cfield == -1) || (sfield == -1))
612  return false;
613 
614  QString loc = LOC +
615  QString("InitPictureAttribute(%1): ").arg(db_col_name, 10);
616 
617  struct v4l2_control ctrl;
618  struct v4l2_queryctrl qctrl;
619  memset(&ctrl, 0, sizeof(ctrl));
620  memset(&qctrl, 0, sizeof(qctrl));
621 
622  ctrl.id = qctrl.id = v4l2_attrib;
623  if (ioctl(m_videofd, VIDIOC_QUERYCTRL, &qctrl) < 0)
624  {
625  LOG(VB_GENERAL, LOG_ERR, loc + "failed to query controls." + ENO);
626  return false;
627  }
628 
629  float new_range = qctrl.maximum - qctrl.minimum;
630  float old_range = 65535 - 0;
631  float scl_range = new_range / old_range;
632  float dfl = (qctrl.default_value - qctrl.minimum) / new_range;
633  int norm_dfl = (0x10000 + (int)(dfl * old_range) - 32768) & 0xFFFF;
634 
635  if (m_pict_attr_default.find(db_col_name) == m_pict_attr_default.end())
636  {
637  if (m_device_name == "pcHDTV HD3000 HDTV")
638  {
639  m_pict_attr_default["brightness"] = 9830;
640  m_pict_attr_default["contrast"] = 39322;
641  m_pict_attr_default["colour"] = 45875;
642  m_pict_attr_default["hue"] = 0;
643  }
644  else
645  {
646  m_pict_attr_default[db_col_name] = norm_dfl;
647  }
648  }
649 
650  int dfield = m_pict_attr_default[db_col_name];
651  int field = (cfield + sfield + dfield) & 0xFFFF;
652  int value0 = (int) ((scl_range * field) + qctrl.minimum);
653  int value1 = min(value0, qctrl.maximum);
654  ctrl.value = max(value1, qctrl.minimum);
655 
656 #if DEBUG_ATTRIB
657  LOG(VB_CHANNEL, LOG_DEBUG, loc + QString(" %1\n\t\t\t"
658  "[%2,%3] dflt(%4, %5, %6)")
659  .arg(value0).arg(qctrl.minimum, 5).arg(qctrl.maximum, 5)
660  .arg(qctrl.default_value, 5).arg(dfl, 4, 'f', 2)
661  .arg(norm_dfl));
662 #endif
663 
664  if (ioctl(m_videofd, VIDIOC_S_CTRL, &ctrl) < 0)
665  {
666  LOG(VB_GENERAL, LOG_ERR, loc + "failed to set controls" + ENO);
667  return false;
668  }
669 
670  return true;
671 }
672 
674 {
675  return (InitPictureAttribute("brightness") &&
676  InitPictureAttribute("contrast") &&
677  InitPictureAttribute("colour") &&
678  InitPictureAttribute("hue"));
679 }
680 
682 {
683  QString db_col_name = toDBString(attr);
684  if (db_col_name.isEmpty())
685  return -1;
686 
687  int cfield = ChannelUtil::GetChannelValueInt(
688  db_col_name, GetSourceID(), m_curchannelname);
689  int sfield = CardUtil::GetValueInt(
690  db_col_name, m_inputid);
691  int dfield = 0;
692 
693  if (m_pict_attr_default.find(db_col_name) != m_pict_attr_default.end())
694  dfield = m_pict_attr_default[db_col_name];
695 
696  int val = (cfield + sfield + dfield) & 0xFFFF;
697 
698 #if DEBUG_ATTRIB
699  LOG(VB_CHANNEL, LOG_DEBUG,
700  QString("GetPictureAttribute(%1) -> cdb %2 rdb %3 d %4 -> %5")
701  .arg(db_col_name).arg(cfield).arg(sfield)
702  .arg(dfield).arg(val));
703 #endif
704 
705  return val;
706 }
707 
708 static int get_v4l2_attribute_value(int videofd, int v4l2_attrib)
709 {
710  struct v4l2_control ctrl;
711  struct v4l2_queryctrl qctrl;
712  memset(&ctrl, 0, sizeof(ctrl));
713  memset(&qctrl, 0, sizeof(qctrl));
714 
715  ctrl.id = qctrl.id = v4l2_attrib;
716  if (ioctl(videofd, VIDIOC_QUERYCTRL, &qctrl) < 0)
717  {
718  LOG(VB_GENERAL, LOG_ERR,
719  "get_v4l2_attribute_value: failed to query controls (1)" + ENO);
720  return -1;
721  }
722 
723  if (ioctl(videofd, VIDIOC_G_CTRL, &ctrl) < 0)
724  {
725  LOG(VB_GENERAL, LOG_ERR,
726  "get_v4l2_attribute_value: failed to get controls (2)" + ENO);
727  return -1;
728  }
729 
730  float mult = 65535.0 / (qctrl.maximum - qctrl.minimum);
731  return min(max((int)(mult * (ctrl.value - qctrl.minimum)), 0), 65525);
732 }
733 
734 static int set_v4l2_attribute_value(int videofd, int v4l2_attrib, int newvalue)
735 {
736  struct v4l2_control ctrl;
737  struct v4l2_queryctrl qctrl;
738  memset(&ctrl, 0, sizeof(ctrl));
739  memset(&qctrl, 0, sizeof(qctrl));
740 
741  ctrl.id = qctrl.id = v4l2_attrib;
742  if (ioctl(videofd, VIDIOC_QUERYCTRL, &qctrl) < 0)
743  {
744  LOG(VB_GENERAL, LOG_ERR,
745  "set_v4l2_attribute_value: failed to query control" + ENO);
746  return -1;
747  }
748 
749  float mult = (qctrl.maximum - qctrl.minimum) / 65535.0;
750  ctrl.value = (int)(mult * newvalue + qctrl.minimum);
751  ctrl.value = min(ctrl.value, qctrl.maximum);
752  ctrl.value = max(ctrl.value, qctrl.minimum);
753 
754  if (ioctl(videofd, VIDIOC_S_CTRL, &ctrl) < 0)
755  {
756  LOG(VB_GENERAL, LOG_ERR,
757  "set_v4l2_attribute_value: failed to set control" + ENO);
758  return -1;
759  }
760 
761  return 0;
762 }
763 
765  PictureAdjustType type, PictureAttribute attr, bool up)
766 {
767  if (!m_pParent)
768  return -1;
769 
770  QString db_col_name = toDBString(attr);
771  if (db_col_name.isEmpty())
772  return -1;
773 
774  int v4l2_attrib = get_v4l2_attribute(db_col_name);
775  if (v4l2_attrib == -1)
776  return -1;
777 
778  // get the old attribute value from the hardware, this is
779  // just a sanity check on whether this attribute exists
780  if (get_v4l2_attribute_value(m_videofd, v4l2_attrib) < 0)
781  return -1;
782 
783  int old_value = GetPictureAttribute(attr);
784  int new_value = old_value + ((up) ? 655 : -655);
785 
786  // make sure we are within bounds (wrap around for hue)
787  if (V4L2_CID_HUE == v4l2_attrib)
788  new_value &= 0xffff;
789  new_value = min(max(new_value, 0), 65535);
790 
791 #if DEBUG_ATTRIB
792  LOG(VB_CHANNEL, LOG_DEBUG,
793  QString("ChangePictureAttribute(%1,%2,%3) cur %4 -> new %5")
794  .arg(type).arg(db_col_name).arg(up)
795  .arg(old_value).arg(new_value));
796 #endif
797 
798  // actually set the new attribute value on the hardware
799  if (set_v4l2_attribute_value(m_videofd, v4l2_attrib, new_value) < 0)
800  return -1;
801 
802  // tell the DB about the new attribute value
804  {
805  int adj_value = ChannelUtil::GetChannelValueInt(
806  db_col_name, GetSourceID(), m_curchannelname);
807 
808  int tmp = new_value - old_value + adj_value;
809  tmp = (tmp < 0) ? tmp + 0x10000 : tmp;
810  tmp = (tmp > 0xffff) ? tmp - 0x10000 : tmp;
811  ChannelUtil::SetChannelValue(db_col_name, QString::number(tmp),
812  GetSourceID(), m_curchannelname);
813  }
814  else if (kAdjustingPicture_Recording == type)
815  {
816  int adj_value = CardUtil::GetValueInt(
817  db_col_name, m_inputid);
818 
819  int tmp = new_value - old_value + adj_value;
820  tmp = (tmp < 0) ? tmp + 0x10000 : tmp;
821  tmp = (tmp > 0xffff) ? tmp - 0x10000 : tmp;
822  CardUtil::SetValue(db_col_name, m_inputid, tmp);
823  }
824 
825  return new_value;
826 }
void SetFreqTable(const int index)
Definition: v4lchannel.cpp:299
static int get_v4l2_attribute_value(int videofd, int v4l2_attrib)
Definition: v4lchannel.cpp:708
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:782
static bool SetValue(const QString &col, uint inputid, int val)
Definition: cardutil.h:287
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:863
static int set_v4l2_attribute_value(int videofd, int v4l2_attrib, int newvalue)
Definition: v4lchannel.cpp:734
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
virtual bool Init(QString &startchannel, bool setchan)
Definition: channelbase.cpp:57
bool SetInputAndFormat(int inputNum, const QString &newFmt)
Definition: v4lchannel.cpp:500
struct CHANLIST * list
Definition: frequencies.h:103
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
uint32_t freq[4]
Definition: element.c:44
int SetDefaultFreqTable(const QString &name)
Definition: v4lchannel.cpp:293
void SetFd(int fd) override
Sets file descriptor.
Definition: v4lchannel.cpp:114
bool Retune(void) override
Retunes to last tuned frequency.
Definition: v4lchannel.cpp:451
static guint32 * tmp
Definition: goom_core.c:35
bool InitPictureAttributes(void) override
Definition: v4lchannel.cpp:673
bool Init(QString &startchannel, bool setchan) override
Definition: v4lchannel.cpp:42
static bool SetChannelValue(const QString &field_name, const QString &value, uint sourceid, const QString &channum)
static bool GetV4LInfo(int videofd, QString &input, QString &driver, uint32_t &version, uint32_t &capabilities)
Definition: cardutil.cpp:2123
bool InitPictureAttribute(const QString &db_col_name)
Definition: v4lchannel.cpp:597
QVariant value(int i) const
Definition: mythdbcon.h:198
static int get_v4l2_attribute(const QString &db_col_name)
Definition: v4lchannel.cpp:584
struct CHANLISTS chanlists[]
bool InitializeInputs(void)
This enumerates the inputs, converts the format string to something the hardware understands,...
Definition: v4lchannel.cpp:225
#define close
Definition: compat.h:16
void SetFormat(const QString &format) override
Initializes tuner and modulator variables.
Definition: v4lchannel.cpp:271
static int GetValueInt(const QString &col, uint inputid)
Definition: cardutil.h:285
QString GetSetting(const QString &key, const QString &defaultval="")
bool Tune(const DTVMultiplex &tuning) override
This performs the actual frequency tuning and in some cases input switching.
Definition: v4lchannel.cpp:377
bool isActive(void) const
Definition: mythdbcon.h:204
PictureAttribute
Definition: videoouttypes.h:89
static int GetChannelValueInt(const QString &channel_field, uint sourceid, const QString &channum)
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
void Close(void) override
Closes the channel changing hardware to use.
Definition: v4lchannel.cpp:107
static int format_to_mode(const QString &fmt)
Definition: v4lchannel.cpp:121
const char * name
Definition: ParseText.cpp:328
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:99
QString GetFormatForChannel(const QString &channum, const QString &inputname)
Definition: v4lchannel.cpp:478
static QString mode_to_format(int mode)
Definition: v4lchannel.cpp:157
int GetPictureAttribute(PictureAttribute) const override
Definition: v4lchannel.cpp:681
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:807
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
PictureAdjustType
Definition: tv.h:120
QMap< int, QString > InputNames
Definition: cardutil.h:20
bool Open(void) override
Opens the channel changing hardware for use.
Definition: v4lchannel.cpp:52
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
virtual ~V4LChannel(void)
Definition: v4lchannel.cpp:37
int GetCurrentChannelNum(const QString &channame)
Definition: v4lchannel.cpp:341
#define LOC
Definition: v4lchannel.cpp:31
QString toDBString(PictureAttribute pictureattribute)
virtual bool InitializeInput(void)
Fills in input map from DB.
int ChangePictureAttribute(PictureAdjustType, PictureAttribute, bool up) override
Definition: v4lchannel.cpp:764
uint64_t m_frequency
Definition: dtvmultiplex.h:94
static InputNames ProbeV4LVideoInputs(int videofd, bool &ok)