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
00020 #include <qsqldatabase.h>
00021
00022
00023 #include "videodev_myth.h"
00024 #include "channel.h"
00025 #include "frequencies.h"
00026 #include "tv_rec.h"
00027 #include "mythcontext.h"
00028 #include "mythdbcon.h"
00029 #include "channelutil.h"
00030 #include "cardutil.h"
00031
00032 #define DEBUG_ATTRIB 1
00033
00034 #define LOC QString("Channel(%1): ").arg(device)
00035 #define LOC_WARN QString("Channel(%1) Warning: ").arg(device)
00036 #define LOC_ERR QString("Channel(%1) Error: ").arg(device)
00037
00038 static int format_to_mode(const QString& fmt, int v4l_version);
00039 static QString mode_to_format(int mode, int v4l_version);
00040
00046 Channel::Channel(TVRec *parent, const QString &videodevice)
00047 : DTVChannel(parent),
00048 device(videodevice), videofd(-1),
00049 device_name(QString::null), driver_name(QString::null),
00050 curList(NULL), totalChannels(0),
00051 currentFormat(""), is_dtv(false),
00052 usingv4l2(false), defaultFreqTable(1)
00053 {
00054 }
00055
00056 Channel::~Channel(void)
00057 {
00058 Close();
00059 }
00060
00061 bool Channel::Init(QString &inputname, QString &startchannel, bool setchan)
00062 {
00063 if (setchan)
00064 {
00065 SetFormat(gContext->GetSetting("TVFormat"));
00066 SetDefaultFreqTable(gContext->GetSetting("FreqTable"));
00067 }
00068 return ChannelBase::Init(inputname, startchannel, setchan);
00069 }
00070
00071 bool Channel::Open(void)
00072 {
00073 #if FAKE_VIDEO
00074 return true;
00075 #endif
00076 if (videofd >= 0)
00077 return true;
00078
00079 videofd = open(device.ascii(), O_RDWR);
00080 if (videofd < 0)
00081 {
00082 VERBOSE(VB_IMPORTANT,
00083 QString("Channel(%1)::Open(): Can't open video device, "
00084 "error \"%2\"").arg(device).arg(strerror(errno)));
00085 return false;
00086 }
00087
00088 usingv4l2 = CardUtil::hasV4L2(videofd);
00089 CardUtil::GetV4LInfo(videofd, device_name, driver_name);
00090 VERBOSE(VB_CHANNEL, LOC + QString("Device name '%1' driver '%2'.")
00091 .arg(device_name).arg(driver_name));
00092
00093 if (!InitializeInputs())
00094 {
00095 Close();
00096 return false;
00097 }
00098
00099 SetFormat("Default");
00100
00101 return true;
00102 }
00103
00104 void Channel::Close(void)
00105 {
00106 if (videofd >= 0)
00107 close(videofd);
00108 videofd = -1;
00109 }
00110
00111 void Channel::SetFd(int fd)
00112 {
00113 if (fd != videofd)
00114 Close();
00115 videofd = (fd >= 0) ? fd : -1;
00116 }
00117
00118 static int format_to_mode(const QString &fmt, int v4l_version)
00119 {
00120 if (2 == v4l_version)
00121 {
00122 if (fmt == "PAL-BG")
00123 return V4L2_STD_PAL_BG;
00124 else if (fmt == "PAL-D")
00125 return V4L2_STD_PAL_D;
00126 else if (fmt == "PAL-DK")
00127 return V4L2_STD_PAL_DK;
00128 else if (fmt == "PAL-I")
00129 return V4L2_STD_PAL_I;
00130 else if (fmt == "PAL-60")
00131 return V4L2_STD_PAL_60;
00132 else if (fmt == "SECAM")
00133 return V4L2_STD_SECAM;
00134 else if (fmt == "SECAM-D")
00135 return V4L2_STD_SECAM_D;
00136 else if (fmt == "PAL-NC")
00137 return V4L2_STD_PAL_Nc;
00138 else if (fmt == "PAL-M")
00139 return V4L2_STD_PAL_M;
00140 else if (fmt == "PAL-N")
00141 return V4L2_STD_PAL_N;
00142 else if (fmt == "NTSC-JP")
00143 return V4L2_STD_NTSC_M_JP;
00144
00145 else if (fmt.left(4) == "NTSC")
00146 return V4L2_STD_NTSC;
00147 else if (fmt.left(4) == "ATSC")
00148 return V4L2_STD_NTSC;
00149 else if (fmt.left(3) == "PAL")
00150 return V4L2_STD_PAL;
00151 return V4L2_STD_NTSC;
00152 }
00153 else if (1 == v4l_version)
00154 {
00155 if (fmt == "NTSC-JP")
00156 return 6;
00157 else if (fmt.left(5) == "SECAM")
00158 return VIDEO_MODE_SECAM;
00159 else if (fmt == "PAL-NC")
00160 return 3;
00161 else if (fmt == "PAL-M")
00162 return 4;
00163 else if (fmt == "PAL-N")
00164 return 5;
00165
00166 else if (fmt.left(3) == "PAL")
00167 return VIDEO_MODE_PAL;
00168 else if (fmt.left(4) == "NTSC")
00169 return VIDEO_MODE_NTSC;
00170 else if (fmt.left(4) == "ATSC")
00171 return VIDEO_MODE_NTSC;
00172 return VIDEO_MODE_NTSC;
00173 }
00174
00175 VERBOSE(VB_IMPORTANT,
00176 "format_to_mode() does not recognize V4L" << v4l_version);
00177
00178 return V4L2_STD_NTSC;
00179 }
00180
00181 static QString mode_to_format(int mode, int v4l_version)
00182 {
00183 if (2 == v4l_version)
00184 {
00185 if (mode == V4L2_STD_NTSC)
00186 return "NTSC";
00187 else if (mode == V4L2_STD_NTSC_M_JP)
00188 return "NTSC-JP";
00189 else if (mode == V4L2_STD_PAL)
00190 return "PAL";
00191 else if (mode == V4L2_STD_PAL_60)
00192 return "PAL-60";
00193 else if (mode == V4L2_STD_PAL_BG)
00194 return "PAL-BG";
00195 else if (mode == V4L2_STD_PAL_D)
00196 return "PAL-D";
00197 else if (mode == V4L2_STD_PAL_DK)
00198 return "PAL-DK";
00199 else if (mode == V4L2_STD_PAL_I)
00200 return "PAL-I";
00201 else if (mode == V4L2_STD_PAL_M)
00202 return "PAL-M";
00203 else if (mode == V4L2_STD_PAL_N)
00204 return "PAL-N";
00205 else if (mode == V4L2_STD_PAL_Nc)
00206 return "PAL-NC";
00207 else if (mode == V4L2_STD_SECAM)
00208 return "SECAM";
00209 else if (mode == V4L2_STD_SECAM_D)
00210 return "SECAM-D";
00211
00212 else if ((V4L2_STD_NTSC_M == mode) ||
00213 (V4L2_STD_NTSC_443 == mode) ||
00214 (V4L2_STD_NTSC_M_KR == mode))
00215 return "NTSC";
00216 else if ((V4L2_STD_PAL_B == mode) ||
00217 (V4L2_STD_PAL_B1 == mode) ||
00218 (V4L2_STD_PAL_G == mode) ||
00219 (V4L2_STD_PAL_H == mode) ||
00220 (V4L2_STD_PAL_D1 == mode) ||
00221 (V4L2_STD_PAL_K == mode))
00222 return "PAL";
00223 else if ((V4L2_STD_SECAM_B == mode) ||
00224 (V4L2_STD_SECAM_DK == mode) ||
00225 (V4L2_STD_SECAM_G == mode) ||
00226 (V4L2_STD_SECAM_H == mode) ||
00227 (V4L2_STD_SECAM_K == mode) ||
00228 (V4L2_STD_SECAM_K1 == mode) ||
00229 (V4L2_STD_SECAM_L == mode) ||
00230 (V4L2_STD_SECAM_LC == mode))
00231 return "SECAM";
00232 else if ((V4L2_STD_ATSC == mode) ||
00233 (V4L2_STD_ATSC_8_VSB == mode) ||
00234 (V4L2_STD_ATSC_16_VSB == mode))
00235 {
00236
00237
00238
00239 return "ATSC";
00240 }
00241 }
00242 else if (1 == v4l_version)
00243 {
00244 if (mode == VIDEO_MODE_NTSC)
00245 return "NTSC";
00246 else if (mode == VIDEO_MODE_ATSC)
00247 return "ATSC";
00248 else if (mode == VIDEO_MODE_PAL)
00249 return "PAL";
00250 else if (mode == VIDEO_MODE_SECAM)
00251 return "SECAM";
00252 else if (mode == 3)
00253 return "PAL-NC";
00254 else if (mode == 4)
00255 return "PAL-M";
00256 else if (mode == 5)
00257 return "PAL-N";
00258 else if (mode == 6)
00259 return "NTSC-JP";
00260 }
00261 else
00262 {
00263 VERBOSE(VB_IMPORTANT,
00264 "mode_to_format() does not recognize V4L" << v4l_version);
00265 }
00266
00267 return "Unknown";
00268 }
00269
00276 bool Channel::InitializeInputs(void)
00277 {
00278
00279 if (!ChannelBase::InitializeInputs())
00280 return false;
00281
00282
00283 QString fmt = gContext->GetSetting("TVFormat");
00284 VERBOSE(VB_CHANNEL, QString("Global TVFormat Setting '%1'").arg(fmt));
00285 int videomode_v4l1 = format_to_mode(fmt.upper(), 1);
00286 int videomode_v4l2 = format_to_mode(fmt.upper(), 2);
00287
00288 bool ok = false;
00289 InputNames v4l_inputs = CardUtil::probeV4LInputs(videofd, ok);
00290
00291
00292 uint valid_cnt = 0;
00293 InputMap::const_iterator it;
00294 for (it = inputs.begin(); it != inputs.end(); ++it)
00295 {
00296 InputNames::const_iterator v4l_it = v4l_inputs.begin();
00297 for (; v4l_it != v4l_inputs.end(); ++v4l_it)
00298 {
00299 if (*v4l_it == (*it)->name)
00300 {
00301 (*it)->inputNumV4L = v4l_it.key();
00302 (*it)->videoModeV4L1 = videomode_v4l1;
00303 (*it)->videoModeV4L2 = videomode_v4l2;
00304 valid_cnt++;
00305 }
00306 }
00307 }
00308
00309
00310 for (it = inputs.begin(); it != inputs.end(); ++it)
00311 {
00312 VERBOSE(VB_CHANNEL, LOC + QString("Input #%1: '%2' schan(%3) "
00313 "tun(%4) v4l1(%5) v4l2(%6)")
00314 .arg(it.key()).arg((*it)->name).arg((*it)->startChanNum)
00315 .arg((*it)->tuneToChannel)
00316 .arg(mode_to_format((*it)->videoModeV4L1,1))
00317 .arg(mode_to_format((*it)->videoModeV4L2,2)));
00318 }
00319
00320 return valid_cnt;
00321 }
00322
00332 void Channel::SetFormat(const QString &format)
00333 {
00334 if (!Open())
00335 return;
00336
00337 int inputNum = currentInputID;
00338 if (currentInputID < 0)
00339 inputNum = GetNextInputNum();
00340
00341 QString fmt = format;
00342 if ((fmt == "Default") || format.isEmpty())
00343 {
00344 InputMap::const_iterator it = inputs.find(inputNum);
00345 if (it != inputs.end())
00346 fmt = mode_to_format((*it)->videoModeV4L2, 2);
00347 }
00348
00349 VERBOSE(VB_CHANNEL, LOC + QString("SetFormat(%1) fmt(%2) input(%3)")
00350 .arg(format).arg(fmt).arg(inputNum));
00351
00352 if ((fmt == currentFormat) || SetInputAndFormat(inputNum, fmt))
00353 {
00354 currentFormat = fmt;
00355 is_dtv = (fmt == "ATSC");
00356 }
00357 }
00358
00359 int Channel::SetDefaultFreqTable(const QString &name)
00360 {
00361 defaultFreqTable = SetFreqTable(name);
00362 return defaultFreqTable;
00363 }
00364
00365 void Channel::SetFreqTable(const int index)
00366 {
00367 curList = chanlists[index].list;
00368 totalChannels = chanlists[index].count;
00369 }
00370
00371 int Channel::SetFreqTable(const QString &name)
00372 {
00373 int i = 0;
00374 char *listname = (char *)chanlists[i].name;
00375
00376 curList = NULL;
00377 while (listname != NULL)
00378 {
00379 if (name == listname)
00380 {
00381 SetFreqTable(i);
00382 return i;
00383 }
00384 i++;
00385 listname = (char *)chanlists[i].name;
00386 }
00387
00388 VERBOSE(VB_CHANNEL, QString("Channel(%1)::SetFreqTable(): Invalid "
00389 "frequency table name %2, using %3.").
00390 arg(device).arg(name).arg((char *)chanlists[1].name));
00391 SetFreqTable(1);
00392 return 1;
00393 }
00394
00395 int Channel::GetCurrentChannelNum(const QString &channame)
00396 {
00397 for (int i = 0; i < totalChannels; i++)
00398 {
00399 if (channame == curList[i].name)
00400 return i;
00401 }
00402
00403 VERBOSE(VB_IMPORTANT, LOC_ERR +
00404 QString("GetCurrentChannelNum(%1): "
00405 "Failed to find Channel").arg(channame));
00406
00407 return -1;
00408 }
00409
00410 void Channel::SaveCachedPids(const pid_cache_t &pid_cache) const
00411 {
00412 int chanid = GetChanID();
00413 if (chanid > 0)
00414 DTVChannel::SaveCachedPids(chanid, pid_cache);
00415 }
00416
00417 void Channel::GetCachedPids(pid_cache_t &pid_cache) const
00418 {
00419 int chanid = GetChanID();
00420 if (chanid > 0)
00421 DTVChannel::GetCachedPids(chanid, pid_cache);
00422 }
00423
00424 bool Channel::SetChannelByString(const QString &channum)
00425 {
00426 QString loc = LOC + QString("SetChannelByString(%1)").arg(channum);
00427 QString loc_err = loc + ", Error: ";
00428 VERBOSE(VB_CHANNEL, loc);
00429
00430 if (!Open())
00431 {
00432 VERBOSE(VB_IMPORTANT, loc_err + "Channel object "
00433 "will not open, can not change channels.");
00434
00435 return false;
00436 }
00437
00438 QString inputName;
00439 if (!CheckChannel(channum, inputName))
00440 {
00441 VERBOSE(VB_IMPORTANT, loc_err +
00442 "CheckChannel failed.\n\t\t\tPlease verify the channel "
00443 "in the 'mythtv-setup' Channel Editor.");
00444
00445 return false;
00446 }
00447
00448
00449
00450
00451 if (!inputName.isEmpty())
00452 return ChannelBase::SwitchToInput(inputName, channum);
00453
00454 ClearDTVInfo();
00455
00456 InputMap::const_iterator it = inputs.find(currentInputID);
00457 if (it == inputs.end())
00458 return false;
00459
00460 uint mplexid_restriction;
00461 if (!IsInputAvailable(currentInputID, mplexid_restriction))
00462 return false;
00463
00464
00465 QString tvformat, modulation, freqtable, freqid, dtv_si_std;
00466 int finetune;
00467 uint64_t frequency;
00468 int mpeg_prog_num;
00469 uint atsc_major, atsc_minor, mplexid, tsid, netid;
00470
00471 if (!ChannelUtil::GetChannelData(
00472 (*it)->sourceid, channum,
00473 tvformat, modulation, freqtable, freqid,
00474 finetune, frequency,
00475 dtv_si_std, mpeg_prog_num, atsc_major, atsc_minor, tsid, netid,
00476 mplexid, commfree))
00477 {
00478 return false;
00479 }
00480
00481 if (mplexid_restriction && (mplexid != mplexid_restriction))
00482 return false;
00483
00484
00485 bool ok = (frequency > 0);
00486
00487 if (!ok)
00488 {
00489 frequency = (freqid.toInt(&ok) + finetune) * 1000;
00490 mplexid = 0;
00491 }
00492 bool isFrequency = ok && (frequency > 10000000);
00493
00494
00495
00496 if (!isFrequency)
00497 {
00498 if (freqtable == "default" || freqtable.isEmpty())
00499 SetFreqTable(defaultFreqTable);
00500 else
00501 SetFreqTable(freqtable);
00502 }
00503
00504
00505 SetFormat(tvformat);
00506
00507
00508 if (!(*it)->tuneToChannel.isEmpty() && (*it)->tuneToChannel != "Undefined")
00509 TuneTo((*it)->tuneToChannel, 0);
00510
00511
00512 if ((*it)->externalChanger.isEmpty())
00513 {
00514 if ((*it)->name.contains("composite", false) ||
00515 (*it)->name.contains("s-video", false))
00516 {
00517 VERBOSE(VB_GENERAL, LOC_WARN + "You have not set "
00518 "an external channel changing"
00519 "\n\t\t\tscript for a composite or s-video "
00520 "input. Channel changing will do nothing.");
00521 }
00522 else if (isFrequency)
00523 {
00524 if (!Tune(frequency, "", (is_dtv) ? "8vsb" : "analog", dtv_si_std))
00525 {
00526 return false;
00527 }
00528 }
00529 else
00530 {
00531 if (!TuneTo(freqid, finetune))
00532 return false;
00533 }
00534 }
00535 else if (!ChangeExternalChannel(freqid))
00536 return false;
00537
00538
00539 curchannelname = QDeepCopy<QString>(channum);
00540
00541
00542
00543 if (pParent)
00544 pParent->SetVideoFiltersForChannel(GetCurrentSourceID(), channum);
00545 InitPictureAttributes();
00546
00547
00548 SetDTVInfo(atsc_major, atsc_minor, netid, tsid, mpeg_prog_num);
00549
00550
00551 inputs[currentInputID]->startChanNum = QDeepCopy<QString>(curchannelname);
00552
00553 return true;
00554 }
00555
00556 bool Channel::TuneTo(const QString &channum, int finetune)
00557 {
00558 int i = GetCurrentChannelNum(channum);
00559 VERBOSE(VB_CHANNEL, QString("Channel(%1)::TuneTo(%2): "
00560 "curList[%3].freq(%4)")
00561 .arg(device).arg(channum).arg(i)
00562 .arg((i != -1) ? curList[i].freq : -1));
00563
00564 if (i == -1)
00565 {
00566 VERBOSE(VB_IMPORTANT, QString("Channel(%1)::TuneTo(%2): Error, "
00567 "failed to find channel.")
00568 .arg(device).arg(channum));
00569 return false;
00570 }
00571
00572 int frequency = (curList[i].freq + finetune) * 1000;
00573
00574 return Tune(frequency, "", "analog", "analog");
00575 }
00576
00577 bool Channel::Tune(const DTVMultiplex &tuning, QString inputname)
00578 {
00579 return Tune(tuning.frequency - 1750000,
00580 inputname, tuning.modulation.toString(), tuning.sistandard);
00581 }
00582
00594 bool Channel::Tune(uint frequency, QString inputname,
00595 QString modulation, QString si_std)
00596 {
00597 VERBOSE(VB_CHANNEL, LOC + QString("Tune(%1, %2, %3, %4)")
00598 .arg(frequency).arg(inputname).arg(modulation).arg(si_std));
00599
00600 int ioctlval = 0;
00601
00602 if (modulation == "8vsb")
00603 SetFormat("ATSC");
00604 modulation = (is_dtv) ? "digital" : modulation;
00605
00606 int inputnum = GetInputByName(inputname);
00607
00608 bool ok = true;
00609 if ((inputnum >= 0) && (GetCurrentInputNum() != inputnum))
00610 ok = SwitchToInput(inputnum, false);
00611 else if (GetCurrentInputNum() < 0)
00612 ok = SwitchToInput(0, false);
00613
00614 if (!ok)
00615 return false;
00616
00617
00618
00619 int offset = frequency % 1000000;
00620 offset = (offset > 500000) ? 1000000 - offset : offset;
00621 bool is_visual_carrier = (offset > 150000) && (offset < 350000);
00622 if (!is_visual_carrier && currentFormat == "ATSC")
00623 {
00624 VERBOSE(VB_CHANNEL, QString("Channel(%1): ").arg(device) +
00625 QString("Converting frequency from center frequency "
00626 "(%1 Hz) to visual carrier frequency (%2 Hz).")
00627 .arg(frequency).arg(frequency - 1750000));
00628 frequency -= 1750000;
00629 }
00630
00631
00632 if (usingv4l2)
00633 {
00634 bool isTunerCapLow = false;
00635 struct v4l2_modulator mod;
00636 bzero(&mod, sizeof(mod));
00637 mod.index = 0;
00638 ioctlval = ioctl(videofd, VIDIOC_G_MODULATOR, &mod);
00639 if (ioctlval >= 0)
00640 {
00641 isTunerCapLow = (mod.capability & V4L2_TUNER_CAP_LOW);
00642 VERBOSE(VB_CHANNEL, " name: "<<mod.name);
00643 VERBOSE(VB_CHANNEL, "CapLow: "<<isTunerCapLow);
00644 }
00645
00646 struct v4l2_frequency vf;
00647 bzero(&vf, sizeof(vf));
00648
00649 vf.tuner = 0;
00650 vf.frequency = (isTunerCapLow) ?
00651 ((int)(frequency / 62.5)) : (frequency / 62500);
00652
00653 if (modulation.lower() == "digital")
00654 {
00655 VERBOSE(VB_CHANNEL, "using digital modulation");
00656 vf.type = V4L2_TUNER_DIGITAL_TV;
00657 if (ioctl(videofd, VIDIOC_S_FREQUENCY, &vf)>=0)
00658 return true;
00659 VERBOSE(VB_CHANNEL, "digital modulation failed");
00660 }
00661
00662 vf.type = V4L2_TUNER_ANALOG_TV;
00663
00664 ioctlval = ioctl(videofd, VIDIOC_S_FREQUENCY, &vf);
00665 if (ioctlval < 0)
00666 {
00667 VERBOSE(VB_IMPORTANT,
00668 QString("Channel(%1)::Tune(): Error %2 "
00669 "while setting frequency (v2): %3")
00670 .arg(device).arg(ioctlval).arg(strerror(errno)));
00671 return false;
00672 }
00673 ioctlval = ioctl(videofd, VIDIOC_G_FREQUENCY, &vf);
00674
00675 if (ioctlval >= 0)
00676 {
00677 VERBOSE(VB_CHANNEL, QString(
00678 "Channel(%1)::Tune(): Frequency is now %2")
00679 .arg(device).arg(vf.frequency * 62500));
00680 }
00681
00682 return true;
00683 }
00684
00685
00686 uint freq = frequency / 62500;
00687 ioctlval = ioctl(videofd, VIDIOCSFREQ, &freq);
00688 if (ioctlval < 0)
00689 {
00690 VERBOSE(VB_IMPORTANT,
00691 QString("Channel(%1)::Tune(): Error %2 "
00692 "while setting frequency (v1): %3")
00693 .arg(device).arg(ioctlval).arg(strerror(errno)));
00694 return false;
00695 }
00696
00697 SetSIStandard(si_std);
00698
00699 return true;
00700 }
00701
00707 bool Channel::Retune(void)
00708 {
00709 if (usingv4l2)
00710 {
00711 struct v4l2_frequency vf;
00712 bzero(&vf, sizeof(vf));
00713
00714 vf.tuner = 0;
00715 vf.type = V4L2_TUNER_ANALOG_TV;
00716
00717
00718 int ioctlval = ioctl(videofd, VIDIOC_G_FREQUENCY, &vf);
00719 if (ioctlval < 0)
00720 {
00721 VERBOSE(VB_IMPORTANT, LOC_ERR + "Retune failed (1)" + ENO);
00722 return false;
00723 }
00724
00725
00726 ioctlval = ioctl(videofd, VIDIOC_S_FREQUENCY, &vf);
00727 if (ioctlval < 0)
00728 {
00729 VERBOSE(VB_IMPORTANT, LOC_ERR + "Retune failed (2)" + ENO);
00730 return false;
00731 }
00732
00733 return true;
00734 }
00735
00736 return false;
00737 }
00738
00739
00740 bool Channel::TuneMultiplex(uint mplexid, QString inputname)
00741 {
00742 VERBOSE(VB_CHANNEL, LOC + QString("TuneMultiplex(%1)").arg(mplexid));
00743
00744 QString modulation;
00745 QString si_std;
00746 uint64_t frequency;
00747 uint transportid;
00748 uint dvb_networkid;
00749
00750 if (!ChannelUtil::GetTuningParams(
00751 mplexid, modulation, frequency,
00752 transportid, dvb_networkid, si_std))
00753 {
00754 VERBOSE(VB_IMPORTANT, LOC_ERR + "TuneMultiplex(): " +
00755 QString("Could not find tuning parameters for multiplex %1.")
00756 .arg(mplexid));
00757
00758 return false;
00759 }
00760
00761 if (!Tune(frequency, inputname, modulation, si_std))
00762 return false;
00763
00764 return true;
00765 }
00766
00767 QString Channel::GetFormatForChannel(QString channum, QString inputname)
00768 {
00769 MSqlQuery query(MSqlQuery::InitCon());
00770 query.prepare(
00771 "SELECT tvformat "
00772 "FROM channel, cardinput "
00773 "WHERE channum = :CHANNUM AND "
00774 " inputname = :INPUTNAME AND "
00775 " cardinput.cardid = :CARDID AND "
00776 " cardinput.sourceid = channel.sourceid");
00777 query.bindValue(":CHANNUM", channum);
00778 query.bindValue(":INPUTNAME", inputname);
00779 query.bindValue(":CARDID", GetCardID());
00780
00781 QString fmt = QString::null;
00782 if (!query.exec() || !query.isActive())
00783 MythContext::DBError("SwitchToInput:find format", query);
00784 else if (query.next())
00785 fmt = query.value(0).toString();
00786 return fmt;
00787 }
00788
00789 bool Channel::SetInputAndFormat(int inputNum, QString newFmt)
00790 {
00791 InputMap::const_iterator it = inputs.find(inputNum);
00792 if (it == inputs.end() || (*it)->inputNumV4L < 0)
00793 return false;
00794
00795 int inputNumV4L = (*it)->inputNumV4L;
00796 bool usingv4l1 = !usingv4l2;
00797 bool ok = true;
00798
00799 QString msg =
00800 QString("SetInputAndFormat(%1, %2) ").arg(inputNum).arg(newFmt);
00801
00802 if (usingv4l2)
00803 {
00804 VERBOSE(VB_CHANNEL, LOC + msg + "(v4l v2)");
00805
00806 int ioctlval = ioctl(videofd, VIDIOC_S_INPUT, &inputNumV4L);
00807
00808
00809
00810 bool streamingDisabled = false;
00811 int streamType = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00812 if ((ioctlval < 0) && (errno == EBUSY))
00813 {
00814 ioctlval = ioctl(videofd, VIDIOC_STREAMOFF, &streamType);
00815 if (ioctlval < 0)
00816 {
00817 VERBOSE(VB_IMPORTANT, LOC_ERR + msg +
00818 "\n\t\t\twhile disabling streaming (v4l v2)" + ENO);
00819
00820 ok = false;
00821 ioctlval = 0;
00822 }
00823 else
00824 {
00825 streamingDisabled = true;
00826
00827
00828 ioctlval = ioctl(videofd, VIDIOC_S_INPUT, &inputNumV4L);
00829 }
00830 }
00831
00832 if (ioctlval < 0)
00833 {
00834 VERBOSE(VB_IMPORTANT, LOC_ERR + msg +
00835 "\n\t\t\twhile setting input (v4l v2)" + ENO);
00836
00837 ok = false;
00838 }
00839
00840 v4l2_std_id vid_mode = format_to_mode(newFmt, 2);
00841 ioctlval = ioctl(videofd, VIDIOC_S_STD, &vid_mode);
00842 if (ioctlval < 0)
00843 {
00844 VERBOSE(VB_IMPORTANT, LOC_ERR + msg +
00845 "\n\t\t\twhile setting format (v4l v2)" + ENO);
00846
00847 ok = false;
00848 }
00849
00850
00851
00852 if (streamingDisabled)
00853 {
00854 ioctlval = ioctl(videofd, VIDIOC_STREAMON, &streamType);
00855 if (ioctlval < 0)
00856 {
00857 VERBOSE(VB_IMPORTANT, LOC_ERR + msg +
00858 "\n\t\t\twhile reenabling streaming (v4l v2)" + ENO);
00859
00860 ok = false;
00861 }
00862 }
00863 }
00864
00865 if (usingv4l1)
00866 {
00867 VERBOSE(VB_CHANNEL, LOC + msg + "(v4l v1)");
00868
00869
00870 struct video_channel set;
00871 bzero(&set, sizeof(set));
00872 ioctl(videofd, VIDIOCGCHAN, &set);
00873
00874
00875 set.channel = inputNumV4L;
00876 set.norm = format_to_mode(newFmt, 1);
00877 int ioctlval = ioctl(videofd, VIDIOCSCHAN, &set);
00878
00879 ok = (ioctlval >= 0);
00880 if (!ok)
00881 {
00882 VERBOSE(VB_IMPORTANT, LOC_ERR + msg +
00883 "\n\t\t\twhile setting format (v4l v1)" + ENO);
00884 }
00885 else if (usingv4l2)
00886 {
00887 VERBOSE(VB_IMPORTANT, LOC + msg +
00888 "\n\t\t\tSetting video mode with v4l version 1 worked");
00889 }
00890 }
00891 return ok;
00892 }
00893
00894 bool Channel::SwitchToInput(int inputnum, bool setstarting)
00895 {
00896 InputMap::const_iterator it = inputs.find(inputnum);
00897 if (it == inputs.end())
00898 return false;
00899
00900 QString tuneFreqId = (*it)->tuneToChannel;
00901 QString channum = (*it)->startChanNum;
00902 QString inputname = (*it)->name;
00903
00904 VERBOSE(VB_CHANNEL, QString("Channel(%1)::SwitchToInput(in %2, '%3')")
00905 .arg(device).arg(inputnum)
00906 .arg(setstarting ? channum : QString("")));
00907
00908 uint mplexid_restriction;
00909 if (!IsInputAvailable(inputnum, mplexid_restriction))
00910 return false;
00911
00912 QString newFmt = mode_to_format((*it)->videoModeV4L2, 2);
00913
00914
00915 bool chanValid = (channum != "Undefined") && !channum.isEmpty();
00916 if (setstarting && chanValid)
00917 {
00918 QString tmp = GetFormatForChannel(channum, inputname);
00919 if (tmp != "Default" && !tmp.isEmpty())
00920 newFmt = tmp;
00921 }
00922
00923 bool ok = SetInputAndFormat(inputnum, newFmt);
00924
00925
00926 if (!ok && newFmt == "NTSC")
00927 ok = SetInputAndFormat(inputnum, "ATSC");
00928
00929 if (!ok)
00930 {
00931 VERBOSE(VB_IMPORTANT, LOC + "SetInputAndFormat() failed");
00932 return false;
00933 }
00934
00935 currentFormat = newFmt;
00936 is_dtv = newFmt == "ATSC";
00937 currentInputID = inputnum;
00938 curchannelname = "";
00939
00940 if (!tuneFreqId.isEmpty() && tuneFreqId != "Undefined")
00941 ok = TuneTo(tuneFreqId, 0);
00942
00943 if (!ok)
00944 return false;
00945
00946 if (setstarting && chanValid)
00947 ok = SetChannelByString(channum);
00948 else if (setstarting && !chanValid)
00949 {
00950 VERBOSE(VB_IMPORTANT, LOC +
00951 QString("SwitchToInput(in %2, set ch): ").arg(inputnum) +
00952 QString("\n\t\t\tDefault channel '%1' is not valid.")
00953 .arg(channum));
00954 ok = false;
00955 }
00956
00957 return ok;
00958 }
00959
00960 static unsigned short *get_v4l1_field(
00961 int v4l2_attrib, struct video_picture &vid_pic)
00962 {
00963 switch (v4l2_attrib)
00964 {
00965 case V4L2_CID_CONTRAST:
00966 return &vid_pic.contrast;
00967 case V4L2_CID_BRIGHTNESS:
00968 return &vid_pic.brightness;
00969 case V4L2_CID_SATURATION:
00970 return &vid_pic.colour;
00971 case V4L2_CID_HUE:
00972 return &vid_pic.hue;
00973 default:
00974 VERBOSE(VB_IMPORTANT, "get_v4l1_field: "
00975 "invalid attribute argument "<<v4l2_attrib);
00976 }
00977 return NULL;
00978 }
00979
00980 static int get_v4l2_attribute(const QString &db_col_name)
00981 {
00982 if ("brightness" == db_col_name)
00983 return V4L2_CID_BRIGHTNESS;
00984 else if ("contrast" == db_col_name)
00985 return V4L2_CID_CONTRAST;
00986 else if ("colour" == db_col_name)
00987 return V4L2_CID_SATURATION;
00988 else if ("hue" == db_col_name)
00989 return V4L2_CID_HUE;
00990 return -1;
00991 }
00992
00993 bool Channel::InitPictureAttribute(const QString db_col_name)
00994 {
00995 if (!pParent || is_dtv)
00996 return false;
00997
00998 int v4l2_attrib = get_v4l2_attribute(db_col_name);
00999 if (v4l2_attrib == -1)
01000 return false;
01001
01002 int cfield = ChannelUtil::GetChannelValueInt(
01003 db_col_name, GetCurrentSourceID(), curchannelname);
01004 int sfield = CardUtil::GetValueInt(
01005 db_col_name, GetCardID());
01006
01007 if ((cfield == -1) || (sfield == -1))
01008 return false;
01009
01010 int field = (cfield + sfield) & 0xFFFF;
01011
01012 QString loc = LOC +
01013 QString("InitPictureAttribute(%1): ").arg(db_col_name, 10);
01014 QString loc_err = LOC_ERR +
01015 QString("InitPictureAttribute(%1): ").arg(db_col_name, 10);
01016
01017 if (usingv4l2)
01018 {
01019 struct v4l2_control ctrl;
01020 struct v4l2_queryctrl qctrl;
01021 bzero(&ctrl, sizeof(ctrl));
01022 bzero(&qctrl, sizeof(qctrl));
01023
01024 ctrl.id = qctrl.id = v4l2_attrib;
01025 if (ioctl(videofd, VIDIOC_QUERYCTRL, &qctrl) < 0)
01026 {
01027 VERBOSE(VB_IMPORTANT, loc_err + "failed to query controls." + ENO);
01028 return false;
01029 }
01030
01031 float new_range = qctrl.maximum - qctrl.minimum;
01032 float old_range = 65535 - 0;
01033 float scl_range = new_range / old_range;
01034 float dfl = (qctrl.default_value - qctrl.minimum) / new_range;
01035 int norm_dfl = (0x10000 + (int)(dfl * old_range) - 32768) & 0xFFFF;
01036
01037 if (pict_attr_default.find(db_col_name) == pict_attr_default.end())
01038 {
01039 if (device_name == "pcHDTV HD3000 HDTV")
01040 {
01041 pict_attr_default["brightness"] = 9830;
01042 pict_attr_default["contrast"] = 39322;
01043 pict_attr_default["colour"] = 45875;
01044 pict_attr_default["hue"] = 0;
01045 }
01046 else
01047 {
01048 pict_attr_default[db_col_name] = norm_dfl;
01049 }
01050 }
01051
01052 int dfield = pict_attr_default[db_col_name];
01053 field = (cfield + sfield + dfield) & 0xFFFF;
01054 int value0 = (int) ((scl_range * field) + qctrl.minimum);
01055 int value1 = min(value0, (int)qctrl.maximum);
01056 ctrl.value = max(value1, (int)qctrl.minimum);
01057
01058 #if DEBUG_ATTRIB
01059 VERBOSE(VB_CHANNEL, loc + QString(" %1\n\t\t\t"
01060 "[%2,%3] dflt(%4, %5, %6)")
01061 .arg(value0).arg(qctrl.minimum, 5).arg(qctrl.maximum, 5)
01062 .arg(qctrl.default_value, 5).arg(dfl, 4, 'f', 2)
01063 .arg(norm_dfl));
01064 #endif
01065
01066 if (ioctl(videofd, VIDIOC_S_CTRL, &ctrl) < 0)
01067 {
01068 VERBOSE(VB_IMPORTANT, loc_err + "failed to set controls" + ENO);
01069 return false;
01070 }
01071
01072 return true;
01073 }
01074
01075
01076 unsigned short *setfield;
01077 struct video_picture vid_pic;
01078 bzero(&vid_pic, sizeof(vid_pic));
01079
01080 if (ioctl(videofd, VIDIOCGPICT, &vid_pic) < 0)
01081 {
01082 VERBOSE(VB_IMPORTANT, loc_err + "failed to query controls." + ENO);
01083 return false;
01084 }
01085 setfield = get_v4l1_field(v4l2_attrib, vid_pic);
01086
01087 if (!setfield)
01088 return false;
01089
01090 *setfield = field;
01091 if (ioctl(videofd, VIDIOCSPICT, &vid_pic) < 0)
01092 {
01093 VERBOSE(VB_IMPORTANT, loc_err + "failed to set controls." + ENO);
01094 return false;
01095 }
01096
01097 return true;
01098 }
01099
01100 bool Channel::InitPictureAttributes(void)
01101 {
01102 return (InitPictureAttribute("brightness") &&
01103 InitPictureAttribute("contrast") &&
01104 InitPictureAttribute("colour") &&
01105 InitPictureAttribute("hue"));
01106 }
01107
01108 int Channel::GetPictureAttribute(PictureAttribute attr) const
01109 {
01110 QString db_col_name = toDBString(attr);
01111 if (db_col_name.isEmpty())
01112 return -1;
01113
01114 int cfield = ChannelUtil::GetChannelValueInt(
01115 db_col_name, GetCurrentSourceID(), curchannelname);
01116 int sfield = CardUtil::GetValueInt(
01117 db_col_name, GetCardID());
01118 int dfield = 0;
01119
01120 if (pict_attr_default.find(db_col_name) != pict_attr_default.end())
01121 dfield = pict_attr_default[db_col_name];
01122
01123 int val = (cfield + sfield + dfield) & 0xFFFF;
01124
01125 #if DEBUG_ATTRIB
01126 VERBOSE(VB_CHANNEL, QString(
01127 "GetPictureAttribute(%1) -> cdb %2 rdb %3 d %4 -> %5")
01128 .arg(db_col_name).arg(cfield).arg(sfield)
01129 .arg(dfield).arg(val));
01130 #endif
01131
01132 return val;
01133 }
01134
01135 static int get_v4l2_attribute_value(int videofd, int v4l2_attrib)
01136 {
01137 struct v4l2_control ctrl;
01138 struct v4l2_queryctrl qctrl;
01139 bzero(&ctrl, sizeof(ctrl));
01140 bzero(&qctrl, sizeof(qctrl));
01141
01142 ctrl.id = qctrl.id = v4l2_attrib;
01143 if (ioctl(videofd, VIDIOC_QUERYCTRL, &qctrl) < 0)
01144 {
01145 VERBOSE(VB_IMPORTANT, "get_v4l2_attribute_value: "
01146 "failed to query controls (1)" + ENO);
01147 return -1;
01148 }
01149
01150 if (ioctl(videofd, VIDIOC_G_CTRL, &ctrl) < 0)
01151 {
01152 VERBOSE(VB_IMPORTANT, "get_v4l2_attribute_value: "
01153 "failed to get controls (2)" + ENO);
01154 return -1;
01155 }
01156
01157 float mult = 65535.0 / (qctrl.maximum - qctrl.minimum);
01158 return min(max((int)(mult * (ctrl.value - qctrl.minimum)), 0), 65525);
01159 }
01160
01161 static int get_v4l1_attribute_value(int videofd, int v4l2_attrib)
01162 {
01163 struct video_picture vid_pic;
01164 bzero(&vid_pic, sizeof(vid_pic));
01165
01166 if (ioctl(videofd, VIDIOCGPICT, &vid_pic) < 0)
01167 {
01168 VERBOSE(VB_IMPORTANT, "get_v4l1_attribute_value: "
01169 "failed to get picture control (1)" + ENO);
01170 return -1;
01171 }
01172
01173 unsigned short *setfield = get_v4l1_field(v4l2_attrib, vid_pic);
01174 if (setfield)
01175 return *setfield;
01176
01177 return -1;
01178 }
01179
01180 static int get_attribute_value(bool usingv4l2, int videofd, int v4l2_attrib)
01181 {
01182 if (usingv4l2)
01183 return get_v4l2_attribute_value(videofd, v4l2_attrib);
01184 return get_v4l1_attribute_value(videofd, v4l2_attrib);
01185 }
01186
01187 static int set_v4l2_attribute_value(int videofd, int v4l2_attrib, int newvalue)
01188 {
01189 struct v4l2_control ctrl;
01190 struct v4l2_queryctrl qctrl;
01191 bzero(&ctrl, sizeof(ctrl));
01192 bzero(&qctrl, sizeof(qctrl));
01193
01194 ctrl.id = qctrl.id = v4l2_attrib;
01195 if (ioctl(videofd, VIDIOC_QUERYCTRL, &qctrl) < 0)
01196 {
01197 VERBOSE(VB_IMPORTANT, "set_v4l2_attribute_value: "
01198 "failed to query control" + ENO);
01199 return -1;
01200 }
01201
01202 float mult = (qctrl.maximum - qctrl.minimum) / 65535.0;
01203 ctrl.value = (int)(mult * newvalue + qctrl.minimum);
01204 ctrl.value = min(ctrl.value, qctrl.maximum);
01205 ctrl.value = max(ctrl.value, qctrl.minimum);
01206
01207 if (ioctl(videofd, VIDIOC_S_CTRL, &ctrl) < 0)
01208 {
01209 VERBOSE(VB_IMPORTANT, "set_v4l2_attribute_value: "
01210 "failed to set control" + ENO);
01211 return -1;
01212 }
01213
01214 return 0;
01215 }
01216
01217 static int set_v4l1_attribute_value(int videofd, int v4l2_attrib, int newvalue)
01218 {
01219 unsigned short *setfield;
01220 struct video_picture vid_pic;
01221 bzero(&vid_pic, sizeof(vid_pic));
01222
01223 if (ioctl(videofd, VIDIOCGPICT, &vid_pic) < 0)
01224 {
01225 VERBOSE(VB_IMPORTANT, "set_v4l1_attribute_value: "
01226 "failed to get picture control." + ENO);
01227 return -1;
01228 }
01229 setfield = get_v4l1_field(v4l2_attrib, vid_pic);
01230 if (newvalue != -1 && setfield)
01231 {
01232 *setfield = newvalue;
01233 if (ioctl(videofd, VIDIOCSPICT, &vid_pic) < 0)
01234 {
01235 VERBOSE(VB_IMPORTANT, "set_v4l1_attribute_value: "
01236 "failed to set picture control." + ENO);
01237 return -1;
01238 }
01239 }
01240 else
01241 {
01242
01243 return -1;
01244 }
01245
01246 return 0;
01247 }
01248
01249 static int set_attribute_value(bool usingv4l2, int videofd,
01250 int v4l2_attrib, int newvalue)
01251 {
01252 if (usingv4l2)
01253 return set_v4l2_attribute_value(videofd, v4l2_attrib, newvalue);
01254 return set_v4l1_attribute_value(videofd, v4l2_attrib, newvalue);
01255 }
01256
01257 int Channel::ChangePictureAttribute(
01258 PictureAdjustType type, PictureAttribute attr, bool up)
01259 {
01260 if (!pParent || is_dtv)
01261 return -1;
01262
01263 QString db_col_name = toDBString(attr);
01264 if (db_col_name.isEmpty())
01265 return -1;
01266
01267 int v4l2_attrib = get_v4l2_attribute(db_col_name);
01268 if (v4l2_attrib == -1)
01269 return -1;
01270
01271
01272
01273 if (get_attribute_value(usingv4l2, videofd, v4l2_attrib) < 0)
01274 return -1;
01275
01276 int old_value = GetPictureAttribute(attr);
01277 int new_value = old_value + ((up) ? 655 : -655);
01278
01279
01280 if (V4L2_CID_HUE == v4l2_attrib)
01281 new_value &= 0xffff;
01282 new_value = min(max(new_value, 0), 65535);
01283
01284 #if DEBUG_ATTRIB
01285 VERBOSE(VB_CHANNEL, QString(
01286 "ChangePictureAttribute(%1,%2,%3) cur %4 -> new %5")
01287 .arg(type).arg(db_col_name).arg(up)
01288 .arg(old_value).arg(new_value));
01289 #endif
01290
01291
01292 if (set_attribute_value(usingv4l2, videofd, v4l2_attrib, new_value) < 0)
01293 return -1;
01294
01295
01296 if (kAdjustingPicture_Channel == type)
01297 {
01298 int adj_value = ChannelUtil::GetChannelValueInt(
01299 db_col_name, GetCurrentSourceID(), curchannelname);
01300
01301 int tmp = new_value - old_value + adj_value;
01302 tmp = (tmp < 0) ? tmp + 0x10000 : tmp;
01303 tmp = (tmp > 0xffff) ? tmp - 0x10000 : tmp;
01304 ChannelUtil::SetChannelValue(db_col_name, QString::number(tmp),
01305 GetCurrentSourceID(), curchannelname);
01306 }
01307 else if (kAdjustingPicture_Recording == type)
01308 {
01309 int adj_value = CardUtil::GetValueInt(
01310 db_col_name, GetCardID());
01311
01312 int tmp = new_value - old_value + adj_value;
01313 tmp = (tmp < 0) ? tmp + 0x10000 : tmp;
01314 tmp = (tmp > 0xffff) ? tmp - 0x10000 : tmp;
01315 CardUtil::SetValue(db_col_name, GetCardID(),
01316 GetCurrentSourceID(), tmp);
01317 }
01318
01319 return new_value;
01320 }