MythTV  0.26-pre
v4lchannel.cpp
Go to the documentation of this file.
00001 // Std C headers
00002 #include <cstdio>
00003 #include <cstdlib>
00004 #include <cerrno>
00005 
00006 // POSIX headers
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 // C++ headers
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 // MythTV headers
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; // driver workaround, see #9825 & #10519
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         // generics...
00169         else if (fmt.left(4) == "NTSC")
00170             return V4L2_STD_NTSC;
00171         else if (fmt.left(4) == "ATSC")
00172             return V4L2_STD_NTSC; // We've dropped V4L ATSC support...
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         // generics...
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; // We've dropped V4L ATSC support...
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; // assume V4L version 2
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         // generic..
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             // We've dropped V4L ATSC support, but this still needs to be
00268             // returned here so we will change the mode if the device is
00269             // in ATSC mode already.
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     // Get Inputs from DB
00313     if (!ChannelBase::InitializeInputs())
00314         return false;
00315 
00316     // Get global TVFormat setting
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     // Insert info from hardware
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     // print em
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, // to visual carrier
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     // Video4Linux version 2 tuning
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; // use first tuner
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     // Video4Linux version 1 tuning
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; // use first tuner
00588         vf.type = V4L2_TUNER_ANALOG_TV;
00589 
00590         // Get the last tuned frequency
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         // Set the last tuned frequency again...
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         // ConvertX (wis-go7007) requires streaming to be disabled
00664         // before an input switch, do this if CAP_STREAMING is set.
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             // Send the input switch ioctl.
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         // read in old settings
00727         struct video_channel set;
00728         memset(&set, 0, sizeof(set));
00729         ioctl(videofd, VIDIOCGCHAN, &set);
00730 
00731         // set new settings
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     // If we are setting a channel, get its video mode...
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    = ""; // this will be set by SetChannelByString
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     // V4L1
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     // get the old attribute value from the hardware, this is
01137     // just a sanity check on whether this attribute exists
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     // make sure we are within bounds (wrap around for hue)
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     // actually set the new attribute value on the hardware
01157     if (set_attribute_value(usingv4l2, videofd, v4l2_attrib, new_value) < 0)
01158         return -1;
01159 
01160     // tell the DB about the new attribute value
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends