|
MythTV
0.26-pre
|
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 }
1.7.6.1