10 #include <sys/types.h>
18 #include <linux/videodev2.h>
28 #define DEBUG_ATTRIB 1
30 #define LOC QString("V4LChannel[%1](%2): ") \
31 .arg(m_inputId).arg(GetDevice())
59 QByteArray ascii_device =
m_device.toLatin1();
60 m_videoFd = open(ascii_device.constData(), O_RDWR);
63 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Can't open video device." +
ENO);
68 uint32_t capabilities = 0;
72 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to query capabilities." +
ENO);
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);
87 LOG(VB_CHANNEL, LOG_INFO,
LOC + QString(
"Device name '%1' driver '%2'.")
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")
124 return V4L2_STD_PAL_BG;
126 return V4L2_STD_PAL_D;
128 return V4L2_STD_PAL_DK;
130 return V4L2_STD_PAL_I;
132 return V4L2_STD_PAL_60;
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;
140 return V4L2_STD_PAL_Nc;
142 return V4L2_STD_PAL_M;
144 return V4L2_STD_PAL_N;
145 if (fmt ==
"NTSC-JP")
146 return V4L2_STD_NTSC_M_JP;
148 if (fmt.startsWith(
"NTSC"))
149 return V4L2_STD_NTSC;
150 if (fmt.startsWith(
"ATSC"))
151 return V4L2_STD_NTSC;
152 if (fmt.startsWith(
"PAL"))
154 return V4L2_STD_NTSC;
159 if (mode == V4L2_STD_NTSC)
161 if (mode == V4L2_STD_NTSC_M_JP)
163 if (mode == V4L2_STD_PAL)
165 if (mode == V4L2_STD_PAL_60)
167 if (mode == V4L2_STD_PAL_BG)
169 if (mode == V4L2_STD_PAL_D)
171 if (mode == V4L2_STD_PAL_DK)
173 if (mode == V4L2_STD_PAL_I)
175 if (mode == V4L2_STD_PAL_M)
177 if (mode == V4L2_STD_PAL_N)
179 if (mode == V4L2_STD_PAL_Nc)
181 if (mode == V4L2_STD_SECAM)
183 if (mode == V4L2_STD_SECAM_D)
186 if ((V4L2_STD_NTSC_M == mode) ||
187 (V4L2_STD_NTSC_443 == mode) ||
188 (V4L2_STD_NTSC_M_KR == mode))
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))
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))
206 if ((V4L2_STD_ATSC == mode) ||
207 (V4L2_STD_ATSC_8_VSB == mode) ||
208 (V4L2_STD_ATSC_16_VSB == mode))
233 LOG(VB_CHANNEL, LOG_INFO, QString(
"Global TVFormat Setting '%1'").
arg(fmt));
241 for (
auto v4l_it = v4l_inputs.cbegin(); v4l_it != v4l_inputs.cend(); ++v4l_it)
252 LOG(VB_CHANNEL, LOG_INFO,
LOC +
253 QString(
"Input #%1: '%2' schan(%3) tun(%4) v4l2(%6)")
258 return valid_cnt != 0U;
277 QString fmt = format;
278 if ((fmt ==
"Default") || format.isEmpty())
284 LOG(VB_CHANNEL, LOG_INFO,
LOC + QString(
"SetFormat(%1) fmt(%2) input(%3)")
288 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to set format." +
ENO);
305 const QString& name = tablename;
306 bool use_default = (name.toLower() ==
"default" || name.isEmpty());
309 for (
size_t i = 0; i <
gChanLists.size(); i++)
321 else if (name == listname)
328 LOG(VB_CHANNEL, LOG_ERR,
329 QString(
"Channel(%1)::SetFreqTable(): Invalid "
330 "frequency table name %2, using %3.").
338 for (
size_t i = 0; i <
m_curList.size(); i++)
344 LOG(VB_GENERAL, LOG_ERR,
LOC +
345 QString(
"GetCurrentChannelNum(%1): Failed to find Channel")
354 LOG(VB_CHANNEL, LOG_INFO,
355 QString(
"Channel(%1)::Tune(%2): curList[%3].freq(%4)")
361 LOG(VB_GENERAL, LOG_ERR,
362 QString(
"Channel(%1)::Tune(%2): Error, failed to find channel.")
367 int frequency = (
m_curList[i].freq + finetune) * 1000;
369 return Tune(frequency);
388 LOG(VB_CHANNEL, LOG_INFO,
LOC + QString(
"Tune(%1)").
arg(frequency));
392 uint mplexid_restriction = 0;
393 uint chanid_restriction = 0;
398 bool isTunerCapLow =
false;
399 struct v4l2_modulator mod {};
401 ioctlval = ioctl(
m_videoFd, VIDIOC_G_MODULATOR, &mod);
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));
410 struct v4l2_frequency vf {};
412 vf.frequency = (isTunerCapLow) ?
413 ((
int)(frequency / 62.5)) : (frequency / 62500);
415 vf.type = V4L2_TUNER_ANALOG_TV;
417 ioctlval = ioctl(
m_videoFd, VIDIOC_S_FREQUENCY, &vf);
420 LOG(VB_GENERAL, LOG_ERR,
421 QString(
"Channel(%1)::Tune(): Error %2 "
422 "while setting frequency (v2): %3")
426 ioctlval = ioctl(
m_videoFd, VIDIOC_G_FREQUENCY, &vf);
430 LOG(VB_CHANNEL, LOG_INFO,
431 QString(
"Channel(%1)::Tune(): Frequency is now %2")
445 struct v4l2_frequency vf {};
447 vf.type = V4L2_TUNER_ANALOG_TV;
450 int ioctlval = ioctl(
m_videoFd, VIDIOC_G_FREQUENCY, &vf);
453 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Retune failed (1)" +
ENO);
458 ioctlval = ioctl(
m_videoFd, VIDIOC_S_FREQUENCY, &vf);
461 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Retune failed (2)" +
ENO);
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");
500 QString(
"SetInputAndFormat(%1, %2) ").arg(inputNum).arg(newFmt);
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);
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;
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));
518 bool streamingDisabled =
false;
519 int streamType = V4L2_BUF_TYPE_VIDEO_CAPTURE;
522 ioctlval = ioctl(
m_videoFd, VIDIOC_STREAMOFF, &streamType);
525 LOG(VB_GENERAL, LOG_ERR,
LOC + msg +
526 "\n\t\t\twhile disabling streaming (v4l v2)" +
ENO);
531 streamingDisabled =
true;
538 ioctlval = ioctl(
m_videoFd, VIDIOC_S_INPUT, &inputNumV4L);
541 LOG(VB_GENERAL, LOG_ERR,
LOC + msg +
542 "\n\t\t\twhile setting input (v4l v2)" +
ENO);
550 ioctlval = ioctl(
m_videoFd, VIDIOC_S_STD, &new_vid_mode);
553 LOG(VB_GENERAL, LOG_ERR,
LOC + msg +
554 "\n\t\t\twhile setting format (v4l v2)" +
ENO);
560 if (streamingDisabled)
562 ioctlval = ioctl(
m_videoFd, VIDIOC_STREAMON, &streamType);
565 LOG(VB_GENERAL, LOG_ERR,
LOC + msg +
566 "\n\t\t\twhile reenabling streaming (v4l v2)" +
ENO);
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)
594 if (v4l2_attrib == -1)
602 if ((cfield == -1) || (sfield == -1))
606 QString(
"InitPictureAttribute(%1): ").arg(db_col_name, 10);
608 struct v4l2_control ctrl {};
609 struct v4l2_queryctrl qctrl {};
611 ctrl.id = qctrl.id = v4l2_attrib;
612 if (ioctl(
m_videoFd, VIDIOC_QUERYCTRL, &qctrl) < 0)
614 LOG(VB_GENERAL, LOG_ERR, loc +
"failed to query controls." +
ENO);
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;
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);
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)
653 if (ioctl(
m_videoFd, VIDIOC_S_CTRL, &ctrl) < 0)
655 LOG(VB_GENERAL, LOG_ERR, loc +
"failed to set controls" +
ENO);
673 if (db_col_name.isEmpty())
685 int val = (cfield + sfield + dfield) & 0xFFFF;
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)
699 struct v4l2_control ctrl {};
700 struct v4l2_queryctrl qctrl {};
702 ctrl.id = qctrl.id = v4l2_attrib;
703 if (ioctl(videofd, VIDIOC_QUERYCTRL, &qctrl) < 0)
705 LOG(VB_GENERAL, LOG_ERR,
706 "get_v4l2_attribute_value: failed to query controls (1)" +
ENO);
710 if (ioctl(videofd, VIDIOC_G_CTRL, &ctrl) < 0)
712 LOG(VB_GENERAL, LOG_ERR,
713 "get_v4l2_attribute_value: failed to get controls (2)" +
ENO);
717 float mult = 65535.0 / (qctrl.maximum - qctrl.minimum);
718 return std::min(std::max((
int)(mult * (ctrl.value - qctrl.minimum)), 0), 65525);
723 struct v4l2_control ctrl {};
724 struct v4l2_queryctrl qctrl {};
726 ctrl.id = qctrl.id = v4l2_attrib;
727 if (ioctl(videofd, VIDIOC_QUERYCTRL, &qctrl) < 0)
729 LOG(VB_GENERAL, LOG_ERR,
730 "set_v4l2_attribute_value: failed to query control" +
ENO);
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);
739 if (ioctl(videofd, VIDIOC_S_CTRL, &ctrl) < 0)
741 LOG(VB_GENERAL, LOG_ERR,
742 "set_v4l2_attribute_value: failed to set control" +
ENO);
756 if (db_col_name.isEmpty())
760 if (v4l2_attrib == -1)
769 int new_value = old_value + ((up) ? 655 : -655);
772 if (V4L2_CID_HUE == v4l2_attrib)
774 new_value = std::min(std::max(new_value, 0), 65535);
777 LOG(VB_CHANNEL, LOG_DEBUG,
778 QString(
"ChangePictureAttribute(%1,%2,%3) cur %4 -> new %5")
780 .
arg(old_value).
arg(new_value));
793 int tmp = new_value - old_value + adj_value;
804 int tmp = new_value - old_value + adj_value;