00001
00002 #include <cstdio>
00003 #include <cstdlib>
00004 #include <cerrno>
00005
00006
00007 #include <unistd.h>
00008 #include <fcntl.h>
00009 #include <sys/ioctl.h>
00010 #include <sys/types.h>
00011 #include <sys/stat.h>
00012 #include <sys/wait.h>
00013
00014
00015 #include <algorithm>
00016 #include <iostream>
00017 using namespace std;
00018
00019 #ifdef USING_V4L1
00020 #include <linux/videodev.h>
00021 #endif // USING_V4L1
00022
00023 #include <linux/videodev2.h>
00024
00025
00026 #include "v4lchannel.h"
00027 #include "frequencies.h"
00028 #include "tv_rec.h"
00029 #include "mythdb.h"
00030 #include "channelutil.h"
00031 #include "cardutil.h"
00032
00033 #define DEBUG_ATTRIB 1
00034
00035 #define LOC QString("V4LChannel(%1): ").arg(device)
00036
00037 static int format_to_mode(const QString& fmt, int v4l_version);
00038 static QString mode_to_format(int mode, int v4l_version);
00039
00040 V4LChannel::V4LChannel(TVRec *parent, const QString &videodevice)
00041 : DTVChannel(parent),
00042 device(videodevice), videofd(-1),
00043 device_name(), driver_name(),
00044 curList(NULL), totalChannels(0),
00045 currentFormat(),
00046 usingv4l2(false),
00047 has_stream_io(false), has_std_io(false),
00048 has_async_io(false),
00049 has_tuner(false), has_sliced_vbi(false),
00050
00051 defaultFreqTable(1)
00052 {
00053 }
00054
00055 V4LChannel::~V4LChannel(void)
00056 {
00057 Close();
00058 }
00059
00060 bool V4LChannel::Init(QString &inputname, QString &startchannel, bool setchan)
00061 {
00062 if (setchan)
00063 {
00064 SetFormat(gCoreContext->GetSetting("TVFormat"));
00065 SetDefaultFreqTable(gCoreContext->GetSetting("FreqTable"));
00066 }
00067 return ChannelBase::Init(inputname, startchannel, setchan);
00068 }
00069
00070 bool V4LChannel::Open(void)
00071 {
00072 #if FAKE_VIDEO
00073 return true;
00074 #endif
00075 if (videofd >= 0)
00076 return true;
00077
00078 QByteArray ascii_device = device.toAscii();
00079 videofd = open(ascii_device.constData(), O_RDWR);
00080 if (videofd < 0)
00081 {
00082 LOG(VB_GENERAL, LOG_ERR, LOC + "Can't open video device." + ENO);
00083 return false;
00084 }
00085
00086 uint32_t version, capabilities;
00087 if (!CardUtil::GetV4LInfo(videofd, device_name, driver_name,
00088 version, capabilities))
00089 {
00090 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to query capabilities." + ENO);
00091 Close();
00092 return false;
00093 }
00094
00095 usingv4l2 = !!(capabilities & V4L2_CAP_VIDEO_CAPTURE);
00096 has_stream_io = !!(capabilities & V4L2_CAP_STREAMING);
00097 has_std_io = !!(capabilities & V4L2_CAP_READWRITE);
00098 has_async_io = !!(capabilities & V4L2_CAP_ASYNCIO);
00099 has_tuner = !!(capabilities & V4L2_CAP_TUNER);
00100 has_sliced_vbi = !!(capabilities & V4L2_CAP_SLICED_VBI_CAPTURE);
00101
00102 if (driver_name == "bttv" || driver_name == "cx8800")
00103 has_stream_io = false;
00104
00105 LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Device name '%1' driver '%2'.")
00106 .arg(device_name).arg(driver_name));
00107
00108 LOG(VB_CHANNEL, LOG_INFO, LOC +
00109 QString("v4l2: %1 stream io: %2 std io: %3 async io: %4 "
00110 "tuner %5 sliced vbi %6")
00111 .arg(usingv4l2)
00112 .arg(has_stream_io).arg(has_std_io).arg(has_async_io)
00113 .arg(has_tuner).arg(has_sliced_vbi));
00114
00115 if (!InitializeInputs())
00116 {
00117 Close();
00118 return false;
00119 }
00120
00121 SetFormat("Default");
00122
00123 return true;
00124 }
00125
00126 void V4LChannel::Close(void)
00127 {
00128 if (videofd >= 0)
00129 close(videofd);
00130 videofd = -1;
00131 }
00132
00133 void V4LChannel::SetFd(int fd)
00134 {
00135 if (fd != videofd)
00136 Close();
00137 videofd = (fd >= 0) ? fd : -1;
00138 }
00139
00140 static int format_to_mode(const QString &fmt, int v4l_version)
00141 {
00142 if (2 == v4l_version)
00143 {
00144 if (fmt == "PAL-BG")
00145 return V4L2_STD_PAL_BG;
00146 else if (fmt == "PAL-D")
00147 return V4L2_STD_PAL_D;
00148 else if (fmt == "PAL-DK")
00149 return V4L2_STD_PAL_DK;
00150 else if (fmt == "PAL-I")
00151 return V4L2_STD_PAL_I;
00152 else if (fmt == "PAL-60")
00153 return V4L2_STD_PAL_60;
00154 else if (fmt == "SECAM")
00155 return V4L2_STD_SECAM;
00156 else if (fmt == "SECAM-D")
00157 return V4L2_STD_SECAM_D;
00158 else if (fmt == "SECAM-DK")
00159 return V4L2_STD_SECAM_DK;
00160 else if (fmt == "PAL-NC")
00161 return V4L2_STD_PAL_Nc;
00162 else if (fmt == "PAL-M")
00163 return V4L2_STD_PAL_M;
00164 else if (fmt == "PAL-N")
00165 return V4L2_STD_PAL_N;
00166 else if (fmt == "NTSC-JP")
00167 return V4L2_STD_NTSC_M_JP;
00168
00169 else if (fmt.left(4) == "NTSC")
00170 return V4L2_STD_NTSC;
00171 else if (fmt.left(4) == "ATSC")
00172 return V4L2_STD_NTSC;
00173 else if (fmt.left(3) == "PAL")
00174 return V4L2_STD_PAL;
00175 return V4L2_STD_NTSC;
00176 }
00177 #ifdef USING_V4L1
00178 else if (1 == v4l_version)
00179 {
00180 if (fmt == "NTSC-JP")
00181 return 6;
00182 else if (fmt.left(5) == "SECAM")
00183 return VIDEO_MODE_SECAM;
00184 else if (fmt == "PAL-NC")
00185 return 3;
00186 else if (fmt == "PAL-M")
00187 return 4;
00188 else if (fmt == "PAL-N")
00189 return 5;
00190
00191 else if (fmt.left(3) == "PAL")
00192 return VIDEO_MODE_PAL;
00193 else if (fmt.left(4) == "NTSC")
00194 return VIDEO_MODE_NTSC;
00195 else if (fmt.left(4) == "ATSC")
00196 return VIDEO_MODE_NTSC;
00197 return VIDEO_MODE_NTSC;
00198 }
00199 #else
00200 else if (v4l_version == 1)
00201 {
00202 return V4L2_STD_NTSC;
00203 }
00204 #endif
00205
00206 LOG(VB_GENERAL, LOG_ERR,
00207 QString("format_to_mode() does not recognize V4L") + v4l_version);
00208
00209 return V4L2_STD_NTSC;
00210 }
00211
00212 static QString mode_to_format(int mode, int v4l_version)
00213 {
00214 if (2 == v4l_version)
00215 {
00216 if (mode == V4L2_STD_NTSC)
00217 return "NTSC";
00218 else if (mode == V4L2_STD_NTSC_M_JP)
00219 return "NTSC-JP";
00220 else if (mode == V4L2_STD_PAL)
00221 return "PAL";
00222 else if (mode == V4L2_STD_PAL_60)
00223 return "PAL-60";
00224 else if (mode == V4L2_STD_PAL_BG)
00225 return "PAL-BG";
00226 else if (mode == V4L2_STD_PAL_D)
00227 return "PAL-D";
00228 else if (mode == V4L2_STD_PAL_DK)
00229 return "PAL-DK";
00230 else if (mode == V4L2_STD_PAL_I)
00231 return "PAL-I";
00232 else if (mode == V4L2_STD_PAL_M)
00233 return "PAL-M";
00234 else if (mode == V4L2_STD_PAL_N)
00235 return "PAL-N";
00236 else if (mode == V4L2_STD_PAL_Nc)
00237 return "PAL-NC";
00238 else if (mode == V4L2_STD_SECAM)
00239 return "SECAM";
00240 else if (mode == V4L2_STD_SECAM_D)
00241 return "SECAM-D";
00242
00243 else if ((V4L2_STD_NTSC_M == mode) ||
00244 (V4L2_STD_NTSC_443 == mode) ||
00245 (V4L2_STD_NTSC_M_KR == mode))
00246 return "NTSC";
00247 else if ((V4L2_STD_PAL_B == mode) ||
00248 (V4L2_STD_PAL_B1 == mode) ||
00249 (V4L2_STD_PAL_G == mode) ||
00250 (V4L2_STD_PAL_H == mode) ||
00251 (V4L2_STD_PAL_D1 == mode) ||
00252 (V4L2_STD_PAL_K == mode))
00253 return "PAL";
00254 else if ((V4L2_STD_SECAM_B == mode) ||
00255 (V4L2_STD_SECAM_DK == mode) ||
00256 (V4L2_STD_SECAM_G == mode) ||
00257 (V4L2_STD_SECAM_H == mode) ||
00258 (V4L2_STD_SECAM_K == mode) ||
00259 (V4L2_STD_SECAM_K1 == mode) ||
00260 (V4L2_STD_SECAM_L == mode) ||
00261 (V4L2_STD_SECAM_LC == mode))
00262 return "SECAM";
00263 else if ((V4L2_STD_ATSC == mode) ||
00264 (V4L2_STD_ATSC_8_VSB == mode) ||
00265 (V4L2_STD_ATSC_16_VSB == mode))
00266 {
00267
00268
00269
00270 return "ATSC";
00271 }
00272 }
00273 #ifdef USING_V4L1
00274 else if (1 == v4l_version)
00275 {
00276 if (mode == VIDEO_MODE_NTSC)
00277 return "NTSC";
00278 else if (mode == VIDEO_MODE_PAL)
00279 return "PAL";
00280 else if (mode == VIDEO_MODE_SECAM)
00281 return "SECAM";
00282 else if (mode == 3)
00283 return "PAL-NC";
00284 else if (mode == 5)
00285 return "PAL-N";
00286 else if (mode == 6)
00287 return "NTSC-JP";
00288 }
00289 #else
00290 if (1 == v4l_version)
00291 {
00292 return "Unknown";
00293 }
00294 #endif
00295 else
00296 {
00297 LOG(VB_GENERAL, LOG_ERR,
00298 QString("mode_to_format() does not recognize V4L") + v4l_version);
00299 }
00300
00301 return "Unknown";
00302 }
00303
00310 bool V4LChannel::InitializeInputs(void)
00311 {
00312
00313 if (!ChannelBase::InitializeInputs())
00314 return false;
00315
00316
00317 QString fmt = gCoreContext->GetSetting("TVFormat");
00318 LOG(VB_CHANNEL, LOG_INFO, QString("Global TVFormat Setting '%1'").arg(fmt));
00319 int videomode_v4l1 = format_to_mode(fmt.toUpper(), 1);
00320 int videomode_v4l2 = format_to_mode(fmt.toUpper(), 2);
00321
00322 bool ok = false;
00323 InputNames v4l_inputs = CardUtil::ProbeV4LVideoInputs(videofd, ok);
00324
00325
00326 uint valid_cnt = 0;
00327 InputMap::const_iterator it;
00328 for (it = m_inputs.begin(); it != m_inputs.end(); ++it)
00329 {
00330 InputNames::const_iterator v4l_it = v4l_inputs.begin();
00331 for (; v4l_it != v4l_inputs.end(); ++v4l_it)
00332 {
00333 if (*v4l_it == (*it)->name)
00334 {
00335 (*it)->inputNumV4L = v4l_it.key();
00336 (*it)->videoModeV4L1 = videomode_v4l1;
00337 (*it)->videoModeV4L2 = videomode_v4l2;
00338 valid_cnt++;
00339 }
00340 }
00341 }
00342
00343
00344 for (it = m_inputs.begin(); it != m_inputs.end(); ++it)
00345 {
00346 LOG(VB_CHANNEL, LOG_INFO, LOC +
00347 QString("Input #%1: '%2' schan(%3) tun(%4) v4l1(%5) v4l2(%6)")
00348 .arg(it.key()).arg((*it)->name).arg((*it)->startChanNum)
00349 .arg((*it)->tuneToChannel)
00350 .arg(mode_to_format((*it)->videoModeV4L1,1))
00351 .arg(mode_to_format((*it)->videoModeV4L2,2)));
00352 }
00353
00354 return valid_cnt;
00355 }
00356
00366 void V4LChannel::SetFormat(const QString &format)
00367 {
00368 if (!Open())
00369 return;
00370
00371 int inputNum = m_currentInputID;
00372 if (m_currentInputID < 0)
00373 inputNum = GetNextInputNum();
00374
00375 QString fmt = format;
00376 if ((fmt == "Default") || format.isEmpty())
00377 {
00378 InputMap::const_iterator it = m_inputs.find(inputNum);
00379 if (it != m_inputs.end())
00380 fmt = mode_to_format((*it)->videoModeV4L2, 2);
00381 }
00382
00383 LOG(VB_CHANNEL, LOG_INFO, LOC + QString("SetFormat(%1) fmt(%2) input(%3)")
00384 .arg(format).arg(fmt).arg(inputNum));
00385
00386 if ((fmt == currentFormat) || SetInputAndFormat(inputNum, fmt))
00387 {
00388 currentFormat = fmt;
00389 }
00390 }
00391
00392 int V4LChannel::SetDefaultFreqTable(const QString &name)
00393 {
00394 defaultFreqTable = SetFreqTable(name);
00395 return defaultFreqTable;
00396 }
00397
00398 void V4LChannel::SetFreqTable(const int index)
00399 {
00400 curList = chanlists[index].list;
00401 totalChannels = chanlists[index].count;
00402 }
00403
00404 int V4LChannel::SetFreqTable(const QString &tablename)
00405 {
00406 QString name = tablename;
00407 bool use_default = (name.toLower() == "default" || name.isEmpty());
00408
00409 int i = 0;
00410 char *listname = (char *)chanlists[i].name;
00411
00412 curList = NULL;
00413 while (listname != NULL)
00414 {
00415 if (use_default)
00416 {
00417 if (i == defaultFreqTable)
00418 {
00419 SetFreqTable(i);
00420 return i;
00421 }
00422 }
00423 else if (name == listname)
00424 {
00425 SetFreqTable(i);
00426 return i;
00427 }
00428 i++;
00429 listname = (char *)chanlists[i].name;
00430 }
00431
00432 LOG(VB_CHANNEL, LOG_ERR,
00433 QString("Channel(%1)::SetFreqTable(): Invalid "
00434 "frequency table name %2, using %3.").
00435 arg(device).arg(name).arg((char *)chanlists[1].name));
00436 SetFreqTable(1);
00437 return 1;
00438 }
00439
00440 int V4LChannel::GetCurrentChannelNum(const QString &channame)
00441 {
00442 for (int i = 0; i < totalChannels; i++)
00443 {
00444 if (channame == curList[i].name)
00445 return i;
00446 }
00447
00448 LOG(VB_GENERAL, LOG_ERR, LOC +
00449 QString("GetCurrentChannelNum(%1): Failed to find Channel")
00450 .arg(channame));
00451
00452 return -1;
00453 }
00454
00455 bool V4LChannel::Tune(const QString &freqid, int finetune)
00456 {
00457 int i = GetCurrentChannelNum(freqid);
00458 LOG(VB_CHANNEL, LOG_INFO,
00459 QString("Channel(%1)::Tune(%2): curList[%3].freq(%4)")
00460 .arg(device).arg(freqid).arg(i)
00461 .arg((i != -1) ? curList[i].freq : -1));
00462
00463 if (i == -1)
00464 {
00465 LOG(VB_GENERAL, LOG_ERR,
00466 QString("Channel(%1)::Tune(%2): Error, failed to find channel.")
00467 .arg(device).arg(freqid));
00468 return false;
00469 }
00470
00471 int frequency = (curList[i].freq + finetune) * 1000;
00472
00473 return Tune(frequency, "");
00474 }
00475
00476 bool V4LChannel::Tune(const DTVMultiplex &tuning, QString inputname)
00477 {
00478 return Tune(tuning.frequency - 1750000,
00479 inputname);
00480 }
00481
00493 bool V4LChannel::Tune(uint64_t frequency, QString inputname)
00494 {
00495 LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Tune(%1, %2)")
00496 .arg(frequency).arg(inputname));
00497
00498 int ioctlval = 0;
00499
00500 int inputnum = GetInputByName(inputname);
00501
00502 bool ok = true;
00503 if ((inputnum >= 0) && (GetCurrentInputNum() != inputnum))
00504 ok = SwitchToInput(inputnum, false);
00505 else if (GetCurrentInputNum() < 0)
00506 ok = SwitchToInput(0, false);
00507
00508 if (!ok)
00509 return false;
00510
00511
00512 if (usingv4l2)
00513 {
00514 bool isTunerCapLow = false;
00515 struct v4l2_modulator mod;
00516 memset(&mod, 0, sizeof(mod));
00517 mod.index = 0;
00518 ioctlval = ioctl(videofd, VIDIOC_G_MODULATOR, &mod);
00519 if (ioctlval >= 0)
00520 {
00521 isTunerCapLow = (mod.capability & V4L2_TUNER_CAP_LOW);
00522 LOG(VB_CHANNEL, LOG_INFO,
00523 QString(" name: %1").arg((char *)mod.name));
00524 LOG(VB_CHANNEL, LOG_INFO, QString("CapLow: %1").arg(isTunerCapLow));
00525 }
00526
00527 struct v4l2_frequency vf;
00528 memset(&vf, 0, sizeof(vf));
00529
00530 vf.tuner = 0;
00531 vf.frequency = (isTunerCapLow) ?
00532 ((int)(frequency / 62.5)) : (frequency / 62500);
00533
00534 vf.type = V4L2_TUNER_ANALOG_TV;
00535
00536 ioctlval = ioctl(videofd, VIDIOC_S_FREQUENCY, &vf);
00537 if (ioctlval < 0)
00538 {
00539 LOG(VB_GENERAL, LOG_ERR,
00540 QString("Channel(%1)::Tune(): Error %2 "
00541 "while setting frequency (v2): %3")
00542 .arg(device).arg(ioctlval).arg(strerror(errno)));
00543 return false;
00544 }
00545 ioctlval = ioctl(videofd, VIDIOC_G_FREQUENCY, &vf);
00546
00547 if (ioctlval >= 0)
00548 {
00549 LOG(VB_CHANNEL, LOG_INFO,
00550 QString("Channel(%1)::Tune(): Frequency is now %2")
00551 .arg(device).arg(vf.frequency * 62500));
00552 }
00553
00554 return true;
00555 }
00556
00557 #ifdef USING_V4L1
00558
00559 uint freq = frequency / 62500;
00560 ioctlval = ioctl(videofd, VIDIOCSFREQ, &freq);
00561 if (ioctlval < 0)
00562 {
00563 LOG(VB_GENERAL, LOG_ERR,
00564 QString("Channel(%1)::Tune(): Error %2 "
00565 "while setting frequency (v1): %3")
00566 .arg(device).arg(ioctlval).arg(strerror(errno)));
00567 return false;
00568 }
00569 return true;
00570 #else
00571 return false;
00572 #endif
00573 }
00574
00580 bool V4LChannel::Retune(void)
00581 {
00582 if (usingv4l2)
00583 {
00584 struct v4l2_frequency vf;
00585 memset(&vf, 0, sizeof(vf));
00586
00587 vf.tuner = 0;
00588 vf.type = V4L2_TUNER_ANALOG_TV;
00589
00590
00591 int ioctlval = ioctl(videofd, VIDIOC_G_FREQUENCY, &vf);
00592 if (ioctlval < 0)
00593 {
00594 LOG(VB_GENERAL, LOG_ERR, LOC + "Retune failed (1)" + ENO);
00595 return false;
00596 }
00597
00598
00599 ioctlval = ioctl(videofd, VIDIOC_S_FREQUENCY, &vf);
00600 if (ioctlval < 0)
00601 {
00602 LOG(VB_GENERAL, LOG_ERR, LOC + "Retune failed (2)" + ENO);
00603 return false;
00604 }
00605
00606 return true;
00607 }
00608
00609 return false;
00610 }
00611
00612 QString V4LChannel::GetFormatForChannel(QString channum, QString inputname)
00613 {
00614 MSqlQuery query(MSqlQuery::InitCon());
00615 query.prepare(
00616 "SELECT tvformat "
00617 "FROM channel, cardinput "
00618 "WHERE channum = :CHANNUM AND "
00619 " inputname = :INPUTNAME AND "
00620 " cardinput.cardid = :CARDID AND "
00621 " cardinput.sourceid = channel.sourceid");
00622 query.bindValue(":CHANNUM", channum);
00623 query.bindValue(":INPUTNAME", inputname);
00624 query.bindValue(":CARDID", GetCardID());
00625
00626 QString fmt = QString::null;
00627 if (!query.exec() || !query.isActive())
00628 MythDB::DBError("SwitchToInput:find format", query);
00629 else if (query.next())
00630 fmt = query.value(0).toString();
00631 return fmt;
00632 }
00633
00634 bool V4LChannel::SetInputAndFormat(int inputNum, QString newFmt)
00635 {
00636 InputMap::const_iterator it = m_inputs.find(inputNum);
00637 if (it == m_inputs.end() || (*it)->inputNumV4L < 0)
00638 return false;
00639
00640 int inputNumV4L = (*it)->inputNumV4L;
00641 bool usingv4l1 = !usingv4l2;
00642 bool ok = true;
00643
00644 QString msg =
00645 QString("SetInputAndFormat(%1, %2) ").arg(inputNum).arg(newFmt);
00646
00647 if (usingv4l2)
00648 {
00649 struct v4l2_input input;
00650 int ioctlval = ioctl(videofd, VIDIOC_G_INPUT, &input);
00651 bool input_switch = (0 != ioctlval || (uint)inputNumV4L != input.index);
00652
00653 const v4l2_std_id new_vid_mode = format_to_mode(newFmt, 2);
00654 v4l2_std_id cur_vid_mode;
00655 ioctlval = ioctl(videofd, VIDIOC_G_STD, &cur_vid_mode);
00656 bool mode_switch = (0 != ioctlval || new_vid_mode != cur_vid_mode);
00657 bool needs_switch = input_switch || mode_switch;
00658
00659 LOG(VB_GENERAL, LOG_INFO, LOC + msg + "(v4l v2) " +
00660 QString("input_switch: %1 mode_switch: %2")
00661 .arg(input_switch).arg(mode_switch));
00662
00663
00664
00665 bool streamingDisabled = false;
00666 int streamType = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00667 if (needs_switch && has_stream_io)
00668 {
00669 ioctlval = ioctl(videofd, VIDIOC_STREAMOFF, &streamType);
00670 if (ioctlval < 0)
00671 {
00672 LOG(VB_GENERAL, LOG_ERR, LOC + msg +
00673 "\n\t\t\twhile disabling streaming (v4l v2)" + ENO);
00674 ok = false;
00675 }
00676 else
00677 {
00678 streamingDisabled = true;
00679 }
00680 }
00681
00682 if (input_switch)
00683 {
00684
00685 ioctlval = ioctl(videofd, VIDIOC_S_INPUT, &inputNumV4L);
00686 if (ioctlval < 0)
00687 {
00688 LOG(VB_GENERAL, LOG_ERR, LOC + msg +
00689 "\n\t\t\twhile setting input (v4l v2)" + ENO);
00690
00691 ok = false;
00692 }
00693 }
00694
00695 if (mode_switch)
00696 {
00697 ioctlval = ioctl(videofd, VIDIOC_S_STD, &new_vid_mode);
00698 if (ioctlval < 0)
00699 {
00700 LOG(VB_GENERAL, LOG_ERR, LOC + msg +
00701 "\n\t\t\twhile setting format (v4l v2)" + ENO);
00702
00703 ok = false;
00704 }
00705 }
00706
00707 if (streamingDisabled)
00708 {
00709 ioctlval = ioctl(videofd, VIDIOC_STREAMON, &streamType);
00710 if (ioctlval < 0)
00711 {
00712 LOG(VB_GENERAL, LOG_ERR, LOC + msg +
00713 "\n\t\t\twhile reenabling streaming (v4l v2)" + ENO);
00714
00715 ok = false;
00716 }
00717 }
00718 }
00719
00720 (void) usingv4l1;
00721 #ifdef USING_V4L1
00722 if (usingv4l1)
00723 {
00724 LOG(VB_CHANNEL, LOG_INFO, LOC + msg + "(v4l v1)");
00725
00726
00727 struct video_channel set;
00728 memset(&set, 0, sizeof(set));
00729 ioctl(videofd, VIDIOCGCHAN, &set);
00730
00731
00732 set.channel = inputNumV4L;
00733 set.norm = format_to_mode(newFmt, 1);
00734 int ioctlval = ioctl(videofd, VIDIOCSCHAN, &set);
00735
00736 ok = (ioctlval >= 0);
00737 if (!ok)
00738 {
00739 LOG(VB_GENERAL, LOG_ERR, LOC + msg +
00740 "\n\t\t\twhile setting format (v4l v1)" + ENO);
00741 }
00742 else if (usingv4l2)
00743 {
00744 LOG(VB_GENERAL, LOG_INFO, LOC + msg +
00745 "\n\t\t\tSetting video mode with v4l version 1 worked");
00746 }
00747 }
00748 #endif // USING_V4L1
00749
00750 return ok;
00751 }
00752
00753 bool V4LChannel::SwitchToInput(int inputnum, bool setstarting)
00754 {
00755 InputMap::const_iterator it = m_inputs.find(inputnum);
00756 if (it == m_inputs.end())
00757 return false;
00758
00759 QString tuneFreqId = (*it)->tuneToChannel;
00760 QString channum = (*it)->startChanNum;
00761 QString inputname = (*it)->name;
00762
00763 LOG(VB_CHANNEL, LOG_INFO, QString("Channel(%1)::SwitchToInput(in %2, '%3')")
00764 .arg(device).arg(inputnum)
00765 .arg(setstarting ? channum : QString("")));
00766
00767 uint mplexid_restriction;
00768 if (!IsInputAvailable(inputnum, mplexid_restriction))
00769 return false;
00770
00771 QString newFmt = mode_to_format((*it)->videoModeV4L2, 2);
00772
00773
00774 bool chanValid = (channum != "Undefined") && !channum.isEmpty();
00775 if (setstarting && chanValid)
00776 {
00777 QString tmp = GetFormatForChannel(channum, inputname);
00778 if (tmp != "Default" && !tmp.isEmpty())
00779 newFmt = tmp;
00780 }
00781
00782 bool ok = SetInputAndFormat(inputnum, newFmt);
00783
00784 if (!ok)
00785 {
00786 LOG(VB_GENERAL, LOG_ERR, LOC + "SetInputAndFormat() failed");
00787 return false;
00788 }
00789
00790 currentFormat = newFmt;
00791 m_currentInputID = inputnum;
00792 m_curchannelname = "";
00793
00794 if (!tuneFreqId.isEmpty() && tuneFreqId != "Undefined")
00795 ok = Tune(tuneFreqId, 0);
00796
00797 if (!ok)
00798 return false;
00799
00800 if (setstarting && chanValid)
00801 ok = SetChannelByString(channum);
00802 else if (setstarting && !chanValid)
00803 {
00804 LOG(VB_GENERAL, LOG_ERR, LOC +
00805 QString("SwitchToInput(in %2, set ch): ").arg(inputnum) +
00806 QString("\n\t\t\tDefault channel '%1' is not valid.").arg(channum));
00807 ok = false;
00808 }
00809
00810 return ok;
00811 }
00812
00813 #ifdef USING_V4L1
00814 static unsigned short *get_v4l1_field(
00815 int v4l2_attrib, struct video_picture &vid_pic)
00816 {
00817 switch (v4l2_attrib)
00818 {
00819 case V4L2_CID_CONTRAST:
00820 return &vid_pic.contrast;
00821 case V4L2_CID_BRIGHTNESS:
00822 return &vid_pic.brightness;
00823 case V4L2_CID_SATURATION:
00824 return &vid_pic.colour;
00825 case V4L2_CID_HUE:
00826 return &vid_pic.hue;
00827 default:
00828 LOG(VB_GENERAL, LOG_ERR,
00829 QString("get_v4l1_field: invalid attribute argument %1")
00830 .arg(v4l2_attrib));
00831 }
00832 return NULL;
00833 }
00834 #endif
00835
00836 static int get_v4l2_attribute(const QString &db_col_name)
00837 {
00838 if ("brightness" == db_col_name)
00839 return V4L2_CID_BRIGHTNESS;
00840 else if ("contrast" == db_col_name)
00841 return V4L2_CID_CONTRAST;
00842 else if ("colour" == db_col_name)
00843 return V4L2_CID_SATURATION;
00844 else if ("hue" == db_col_name)
00845 return V4L2_CID_HUE;
00846 return -1;
00847 }
00848
00849 bool V4LChannel::InitPictureAttribute(const QString db_col_name)
00850 {
00851 if (!m_pParent)
00852 return false;
00853
00854 int v4l2_attrib = get_v4l2_attribute(db_col_name);
00855 if (v4l2_attrib == -1)
00856 return false;
00857
00858 int cfield = ChannelUtil::GetChannelValueInt(
00859 db_col_name, GetCurrentSourceID(), m_curchannelname);
00860 int sfield = CardUtil::GetValueInt(
00861 db_col_name, GetCardID());
00862
00863 if ((cfield == -1) || (sfield == -1))
00864 return false;
00865
00866 int field = (cfield + sfield) & 0xFFFF;
00867
00868 QString loc = LOC +
00869 QString("InitPictureAttribute(%1): ").arg(db_col_name, 10);
00870
00871 if (usingv4l2)
00872 {
00873 struct v4l2_control ctrl;
00874 struct v4l2_queryctrl qctrl;
00875 memset(&ctrl, 0, sizeof(ctrl));
00876 memset(&qctrl, 0, sizeof(qctrl));
00877
00878 ctrl.id = qctrl.id = v4l2_attrib;
00879 if (ioctl(videofd, VIDIOC_QUERYCTRL, &qctrl) < 0)
00880 {
00881 LOG(VB_GENERAL, LOG_ERR, loc + "failed to query controls." + ENO);
00882 return false;
00883 }
00884
00885 float new_range = qctrl.maximum - qctrl.minimum;
00886 float old_range = 65535 - 0;
00887 float scl_range = new_range / old_range;
00888 float dfl = (qctrl.default_value - qctrl.minimum) / new_range;
00889 int norm_dfl = (0x10000 + (int)(dfl * old_range) - 32768) & 0xFFFF;
00890
00891 if (pict_attr_default.find(db_col_name) == pict_attr_default.end())
00892 {
00893 if (device_name == "pcHDTV HD3000 HDTV")
00894 {
00895 pict_attr_default["brightness"] = 9830;
00896 pict_attr_default["contrast"] = 39322;
00897 pict_attr_default["colour"] = 45875;
00898 pict_attr_default["hue"] = 0;
00899 }
00900 else
00901 {
00902 pict_attr_default[db_col_name] = norm_dfl;
00903 }
00904 }
00905
00906 int dfield = pict_attr_default[db_col_name];
00907 field = (cfield + sfield + dfield) & 0xFFFF;
00908 int value0 = (int) ((scl_range * field) + qctrl.minimum);
00909 int value1 = min(value0, (int)qctrl.maximum);
00910 ctrl.value = max(value1, (int)qctrl.minimum);
00911
00912 #if DEBUG_ATTRIB
00913 LOG(VB_CHANNEL, LOG_DEBUG, loc + QString(" %1\n\t\t\t"
00914 "[%2,%3] dflt(%4, %5, %6)")
00915 .arg(value0).arg(qctrl.minimum, 5).arg(qctrl.maximum, 5)
00916 .arg(qctrl.default_value, 5).arg(dfl, 4, 'f', 2)
00917 .arg(norm_dfl));
00918 #endif
00919
00920 if (ioctl(videofd, VIDIOC_S_CTRL, &ctrl) < 0)
00921 {
00922 LOG(VB_GENERAL, LOG_ERR, loc + "failed to set controls" + ENO);
00923 return false;
00924 }
00925
00926 return true;
00927 }
00928
00929 #ifdef USING_V4L1
00930
00931 unsigned short *setfield;
00932 struct video_picture vid_pic;
00933 memset(&vid_pic, 0, sizeof(vid_pic));
00934
00935 if (ioctl(videofd, VIDIOCGPICT, &vid_pic) < 0)
00936 {
00937 LOG(VB_GENERAL, LOG_ERR, loc + "failed to query controls." + ENO);
00938 return false;
00939 }
00940 setfield = get_v4l1_field(v4l2_attrib, vid_pic);
00941
00942 if (!setfield)
00943 return false;
00944
00945 *setfield = field;
00946 if (ioctl(videofd, VIDIOCSPICT, &vid_pic) < 0)
00947 {
00948 LOG(VB_GENERAL, LOG_ERR, loc + "failed to set controls." + ENO);
00949 return false;
00950 }
00951
00952 return true;
00953 #else
00954 return false;
00955 #endif
00956 }
00957
00958 bool V4LChannel::InitPictureAttributes(void)
00959 {
00960 return (InitPictureAttribute("brightness") &&
00961 InitPictureAttribute("contrast") &&
00962 InitPictureAttribute("colour") &&
00963 InitPictureAttribute("hue"));
00964 }
00965
00966 int V4LChannel::GetPictureAttribute(PictureAttribute attr) const
00967 {
00968 QString db_col_name = toDBString(attr);
00969 if (db_col_name.isEmpty())
00970 return -1;
00971
00972 int cfield = ChannelUtil::GetChannelValueInt(
00973 db_col_name, GetCurrentSourceID(), m_curchannelname);
00974 int sfield = CardUtil::GetValueInt(
00975 db_col_name, GetCardID());
00976 int dfield = 0;
00977
00978 if (pict_attr_default.find(db_col_name) != pict_attr_default.end())
00979 dfield = pict_attr_default[db_col_name];
00980
00981 int val = (cfield + sfield + dfield) & 0xFFFF;
00982
00983 #if DEBUG_ATTRIB
00984 LOG(VB_CHANNEL, LOG_DEBUG,
00985 QString("GetPictureAttribute(%1) -> cdb %2 rdb %3 d %4 -> %5")
00986 .arg(db_col_name).arg(cfield).arg(sfield)
00987 .arg(dfield).arg(val));
00988 #endif
00989
00990 return val;
00991 }
00992
00993 static int get_v4l2_attribute_value(int videofd, int v4l2_attrib)
00994 {
00995 struct v4l2_control ctrl;
00996 struct v4l2_queryctrl qctrl;
00997 memset(&ctrl, 0, sizeof(ctrl));
00998 memset(&qctrl, 0, sizeof(qctrl));
00999
01000 ctrl.id = qctrl.id = v4l2_attrib;
01001 if (ioctl(videofd, VIDIOC_QUERYCTRL, &qctrl) < 0)
01002 {
01003 LOG(VB_GENERAL, LOG_ERR,
01004 "get_v4l2_attribute_value: failed to query controls (1)" + ENO);
01005 return -1;
01006 }
01007
01008 if (ioctl(videofd, VIDIOC_G_CTRL, &ctrl) < 0)
01009 {
01010 LOG(VB_GENERAL, LOG_ERR,
01011 "get_v4l2_attribute_value: failed to get controls (2)" + ENO);
01012 return -1;
01013 }
01014
01015 float mult = 65535.0 / (qctrl.maximum - qctrl.minimum);
01016 return min(max((int)(mult * (ctrl.value - qctrl.minimum)), 0), 65525);
01017 }
01018
01019 static int get_v4l1_attribute_value(int videofd, int v4l2_attrib)
01020 {
01021 (void) videofd;
01022 (void) v4l2_attrib;
01023 #ifdef USING_V4L1
01024 struct video_picture vid_pic;
01025 memset(&vid_pic, 0, sizeof(vid_pic));
01026
01027 if (ioctl(videofd, VIDIOCGPICT, &vid_pic) < 0)
01028 {
01029 LOG(VB_GENERAL, LOG_ERR, "get_v4l1_attribute_value: failed to get "
01030 "picture control (1)" + ENO);
01031 return -1;
01032 }
01033
01034 unsigned short *setfield = get_v4l1_field(v4l2_attrib, vid_pic);
01035 if (setfield)
01036 return *setfield;
01037 #endif
01038 return -1;
01039 }
01040
01041 static int get_attribute_value(bool usingv4l2, int videofd, int v4l2_attrib)
01042 {
01043 if (usingv4l2)
01044 return get_v4l2_attribute_value(videofd, v4l2_attrib);
01045 return get_v4l1_attribute_value(videofd, v4l2_attrib);
01046 }
01047
01048 static int set_v4l2_attribute_value(int videofd, int v4l2_attrib, int newvalue)
01049 {
01050 struct v4l2_control ctrl;
01051 struct v4l2_queryctrl qctrl;
01052 memset(&ctrl, 0, sizeof(ctrl));
01053 memset(&qctrl, 0, sizeof(qctrl));
01054
01055 ctrl.id = qctrl.id = v4l2_attrib;
01056 if (ioctl(videofd, VIDIOC_QUERYCTRL, &qctrl) < 0)
01057 {
01058 LOG(VB_GENERAL, LOG_ERR,
01059 "set_v4l2_attribute_value: failed to query control" + ENO);
01060 return -1;
01061 }
01062
01063 float mult = (qctrl.maximum - qctrl.minimum) / 65535.0;
01064 ctrl.value = (int)(mult * newvalue + qctrl.minimum);
01065 ctrl.value = min(ctrl.value, qctrl.maximum);
01066 ctrl.value = max(ctrl.value, qctrl.minimum);
01067
01068 if (ioctl(videofd, VIDIOC_S_CTRL, &ctrl) < 0)
01069 {
01070 LOG(VB_GENERAL, LOG_ERR,
01071 "set_v4l2_attribute_value: failed to set control" + ENO);
01072 return -1;
01073 }
01074
01075 return 0;
01076 }
01077
01078 static int set_v4l1_attribute_value(int videofd, int v4l2_attrib, int newvalue)
01079 {
01080 #ifdef USING_V4L1
01081 unsigned short *setfield;
01082 struct video_picture vid_pic;
01083 memset(&vid_pic, 0, sizeof(vid_pic));
01084
01085 if (ioctl(videofd, VIDIOCGPICT, &vid_pic) < 0)
01086 {
01087 LOG(VB_GENERAL, LOG_ERR,
01088 "set_v4l1_attribute_value: failed to get picture control." + ENO);
01089 return -1;
01090 }
01091 setfield = get_v4l1_field(v4l2_attrib, vid_pic);
01092 if (newvalue != -1 && setfield)
01093 {
01094 *setfield = newvalue;
01095 if (ioctl(videofd, VIDIOCSPICT, &vid_pic) < 0)
01096 {
01097 LOG(VB_GENERAL, LOG_ERR, "set_v4l1_attribute_value: failed to set "
01098 "picture control." + ENO);
01099 return -1;
01100 }
01101 }
01102 else
01103 {
01104
01105 return -1;
01106 }
01107
01108 return 0;
01109 #else
01110 return -1;
01111 #endif
01112 }
01113
01114 static int set_attribute_value(bool usingv4l2, int videofd,
01115 int v4l2_attrib, int newvalue)
01116 {
01117 if (usingv4l2)
01118 return set_v4l2_attribute_value(videofd, v4l2_attrib, newvalue);
01119 return set_v4l1_attribute_value(videofd, v4l2_attrib, newvalue);
01120 }
01121
01122 int V4LChannel::ChangePictureAttribute(
01123 PictureAdjustType type, PictureAttribute attr, bool up)
01124 {
01125 if (!m_pParent)
01126 return -1;
01127
01128 QString db_col_name = toDBString(attr);
01129 if (db_col_name.isEmpty())
01130 return -1;
01131
01132 int v4l2_attrib = get_v4l2_attribute(db_col_name);
01133 if (v4l2_attrib == -1)
01134 return -1;
01135
01136
01137
01138 if (get_attribute_value(usingv4l2, videofd, v4l2_attrib) < 0)
01139 return -1;
01140
01141 int old_value = GetPictureAttribute(attr);
01142 int new_value = old_value + ((up) ? 655 : -655);
01143
01144
01145 if (V4L2_CID_HUE == v4l2_attrib)
01146 new_value &= 0xffff;
01147 new_value = min(max(new_value, 0), 65535);
01148
01149 #if DEBUG_ATTRIB
01150 LOG(VB_CHANNEL, LOG_DEBUG,
01151 QString("ChangePictureAttribute(%1,%2,%3) cur %4 -> new %5")
01152 .arg(type).arg(db_col_name).arg(up)
01153 .arg(old_value).arg(new_value));
01154 #endif
01155
01156
01157 if (set_attribute_value(usingv4l2, videofd, v4l2_attrib, new_value) < 0)
01158 return -1;
01159
01160
01161 if (kAdjustingPicture_Channel == type)
01162 {
01163 int adj_value = ChannelUtil::GetChannelValueInt(
01164 db_col_name, GetCurrentSourceID(), m_curchannelname);
01165
01166 int tmp = new_value - old_value + adj_value;
01167 tmp = (tmp < 0) ? tmp + 0x10000 : tmp;
01168 tmp = (tmp > 0xffff) ? tmp - 0x10000 : tmp;
01169 ChannelUtil::SetChannelValue(db_col_name, QString::number(tmp),
01170 GetCurrentSourceID(), m_curchannelname);
01171 }
01172 else if (kAdjustingPicture_Recording == type)
01173 {
01174 int adj_value = CardUtil::GetValueInt(
01175 db_col_name, GetCardID());
01176
01177 int tmp = new_value - old_value + adj_value;
01178 tmp = (tmp < 0) ? tmp + 0x10000 : tmp;
01179 tmp = (tmp > 0xffff) ? tmp - 0x10000 : tmp;
01180 CardUtil::SetValue(db_col_name, GetCardID(),
01181 GetCurrentSourceID(), tmp);
01182 }
01183
01184 return new_value;
01185 }