Ticket #6138: 133-hdhr.multirec.3.patch
File 133-hdhr.multirec.3.patch, 82.4 KB (added by , 15 years ago) |
---|
-
mythtv/libs/libmythtv/cardutil.cpp
diff -r -u -N -X diff.exclude -x release.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/cardutil.cpp release.19740.0119b/mythtv/libs/libmythtv/cardutil.cpp
38 38 .arg(cardidA).arg(cardidB)); 39 39 40 40 MSqlQuery query(MSqlQuery::InitCon()); 41 query.prepare("SELECT videodevice, hostname, cardtype "41 query.prepare("SELECT videodevice, hostname, cardtype, dbox2_port " 42 42 "FROM capturecard " 43 43 "WHERE ( (cardid = :CARDID_A) OR " 44 44 " (cardid = :CARDID_B) )"); … … 57 57 const QString vdevice = query.value(0).toString(); 58 58 const QString hostname = query.value(1).toString(); 59 59 const QString cardtype = query.value(2).toString(); 60 const QString hdhrTuner = query.value(3).toString(); 60 61 61 62 if (!IsTunerSharingCapable(cardtype.upper())) 62 63 return false; … … 67 68 bool ret = ((vdevice == query.value(0).toString()) && 68 69 (hostname == query.value(1).toString()) && 69 70 (cardtype == query.value(2).toString())); 71 if (cardtype.upper() == "HDHOMERUN") 72 ret = ret && (hdhrTuner == query.value(3).toString()); 70 73 71 74 VERBOSE(VB_RECORD, QString("IsTunerShared(%1,%2) -> %3") 72 75 .arg(cardidA).arg(cardidB).arg(ret)); … … 417 420 return list; 418 421 } 419 422 423 /** \fn CardUtil::GetCardIDs(const QString&, uint hdhrTuner, QString) 424 * \brief Returns all cardids of cards that uses the specified 425 * videodevice, and optionally rawtype and a non-local 426 * hostname. The result is ordered from smallest to largest. 427 * \param videodevice Video device we want card ids for 428 * \param hdhrTuner tuner for this card 429 * \param hostname Host on which device resides, only 430 * required if said host is not the localhost 431 */ 432 vector<uint> CardUtil::GetCardIDs(const QString &videodevice, 433 uint hdhrTuner, 434 QString hostname) 435 { 436 vector<uint> list; 437 438 if (hostname.isEmpty()) 439 hostname = gContext->GetHostName(); 440 441 MSqlQuery query(MSqlQuery::InitCon()); 442 QString qstr = 443 "SELECT cardid " 444 "FROM capturecard " 445 "WHERE videodevice = :DEVICE AND " 446 " dbox2_port = :HDHRTUNER AND " 447 " hostname = :HOSTNAME"; 448 449 qstr += " ORDER BY cardid"; 450 451 query.prepare(qstr); 452 453 query.bindValue(":DEVICE", videodevice); 454 query.bindValue(":HDHRTUNER", hdhrTuner); 455 query.bindValue(":HOSTNAME", hostname); 456 457 if (!query.exec()) 458 MythContext::DBError("CardUtil::GetCardIDs(videodevice...)", query); 459 else 460 { 461 while (query.next()) 462 list.push_back(query.value(0).toUInt()); 463 } 464 465 return list; 466 } 467 420 468 static uint clone_capturecard(uint src_cardid, uint orig_dst_cardid) 421 469 { 422 470 uint dst_cardid = orig_dst_cardid; … … 468 516 "SELECT videodevice, cardtype, defaultinput, " 469 517 " hostname, signal_timeout, channel_timeout, " 470 518 " dvb_wait_for_seqstart, dvb_on_demand, dvb_tuning_delay, " 471 " dvb_diseqc_type, diseqcid, dvb_eitscan " 519 " dvb_diseqc_type, diseqcid, dvb_eitscan, " 520 " dbox2_port " 472 521 "FROM capturecard " 473 522 "WHERE cardid = :CARDID"); 474 523 query.bindValue(":CARDID", src_cardid); … … 498 547 " dvb_tuning_delay = :V8, " 499 548 " dvb_diseqc_type = :V9, " 500 549 " diseqcid = :V10," 501 " dvb_eitscan = :V11 " 550 " dvb_eitscan = :V11," 551 " dbox2_port = :V12 " 502 552 "WHERE cardid = :CARDID"); 503 553 for (uint i = 0; i < 12; i++) 504 554 query2.bindValue(QString(":V%1").arg(i), query.value(i).toString()); 555 query2.bindValue(":V12", query.value(12).toUInt()); 505 556 query2.bindValue(":CARDID", dst_cardid); 506 557 507 558 if (!query2.exec()) … … 1023 1074 uint id = 0; 1024 1075 for (uint i = 0; !id && (i < 100); i++) 1025 1076 { 1026 name = QString("DVB%1").arg(dev.toUInt()); 1077 bool ok; 1078 name = QString("DVB%1").arg(dev.toUInt(&ok)); 1079 if (! ok) 1080 { 1081 uint hdhrTuner = CardUtil::GetHDHRTuner(cardid); 1082 name = QString("HDHR%1").arg(hdhrTuner); 1083 } 1027 1084 name += (i) ? QString(":%1").arg(i) : QString(""); 1028 1085 id = CardUtil::CreateInputGroup(name); 1029 1086 } -
mythtv/libs/libmythtv/cardutil.h
diff -r -u -N -X diff.exclude -x release.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/cardutil.h release.19740.0119b/mythtv/libs/libmythtv/cardutil.h
106 106 107 107 static bool IsTunerSharingCapable(const QString &rawtype) 108 108 { 109 return (rawtype == "DVB") ;109 return (rawtype == "DVB") || (rawtype == "HDHOMERUN"); 110 110 } 111 111 112 112 static bool IsTunerShared(uint cardidA, uint cardidB); … … 135 135 QString rawtype = QString::null, 136 136 QString hostname = QString::null); 137 137 138 static vector<uint> GetCardIDs(const QString &videodevice, 139 uint hdhrTuner, 140 QString hostname = QString::null); 141 138 142 static bool IsCardTypePresent(const QString &rawtype, 139 143 QString hostname = QString::null); 140 144 static QStringVec GetVideoDevices(const QString &rawtype, -
mythtv/libs/libmythtv/hdhomerun_includes.h
diff -r -u -N -X diff.exclude -x release.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/hdhomerun_includes.h release.19740.0119b/mythtv/libs/libmythtv/hdhomerun_includes.h
1 #ifndef __HDHOMERUN_INCLUDES__ 2 #define __HDHOMERUN_INCLUDES__ 3 4 #include "hdhomerun/hdhomerun.h" 5 6 #endif /* __HDHOMERUN_INCLUDES__ */ 7 -
mythtv/libs/libmythtv/hdhrchannel.cpp
diff -r -u -N -X diff.exclude -x release.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/hdhrchannel.cpp release.19740.0119b/mythtv/libs/libmythtv/hdhrchannel.cpp
26 26 #include "channelutil.h" 27 27 #include "frequencytables.h" 28 28 29 #include "hdhrstreamhandler.h" 30 29 31 #define DEBUG_PID_FILTERS 30 32 31 33 #define LOC QString("HDHRChan(%1): ").arg(GetDevice()) 32 34 #define LOC_ERR QString("HDHRChan(%1), Error: ").arg(GetDevice()) 33 35 34 36 HDHRChannel::HDHRChannel(TVRec *parent, const QString &device, uint tuner) 35 : DTVChannel(parent), _ control_socket(NULL),37 : DTVChannel(parent), _stream_handler(NULL), 36 38 _device_id(0), _device_ip(0), 37 _tuner(tuner), _lock(true) 39 _tuner(tuner), _lock(true), 40 tune_lock(true), hw_lock(true) 38 41 { 39 42 bool valid; 40 43 _device_id = device.toUInt(&valid, 16); … … 65 68 66 69 bool HDHRChannel::Open(void) 67 70 { 71 VERBOSE(VB_CHANNEL, LOC + "Opening HDHR channel"); 72 73 QMutexLocker locker(&hw_lock); 74 68 75 if (IsOpen()) 69 76 return true; 70 77 71 if (!FindDevice()) 72 return false; 78 _stream_handler = HDHRStreamHandler::Get(_device_id, _tuner, GetDevice()); 73 79 74 80 if (!InitializeInputs()) 75 return false;76 77 return (_device_ip != 0) && Connect();78 }79 80 void HDHRChannel::Close(void)81 {82 if (_control_socket)83 {84 hdhomerun_control_destroy(_control_socket);85 _control_socket = NULL;86 }87 }88 89 bool HDHRChannel::EnterPowerSavingMode(void)90 {91 return QString::null != TunerSet("channel", "none", false);92 }93 94 bool HDHRChannel::FindDevice(void)95 {96 if (!_device_id)97 return _device_ip;98 99 _device_ip = 0;100 101 /* Discover. */102 struct hdhomerun_discover_device_t result;103 int ret = hdhomerun_discover_find_devices_custom(0, HDHOMERUN_DEVICE_TYPE_WILDCARD, _device_id, &result, 1);104 if (ret < 0)105 81 { 106 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to send discovery request" + ENO);82 Close(); 107 83 return false; 108 84 } 109 if (ret == 0)110 {111 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("device not found"));112 return false;113 }114 115 /* Found. */116 _device_ip = result.ip_addr;117 85 118 VERBOSE(VB_IMPORTANT, LOC + 119 QString("device found at address %1.%2.%3.%4") 120 .arg((_device_ip>>24) & 0xFF).arg((_device_ip>>16) & 0xFF) 121 .arg((_device_ip>> 8) & 0xFF).arg((_device_ip>> 0) & 0xFF)); 86 // nextInputID = currentInputID; 122 87 123 return true; 124 } 125 126 bool HDHRChannel::Connect(void) 127 { 128 _control_socket = hdhomerun_control_create(_device_id, _device_ip); 129 if (!_control_socket) 130 { 131 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to create control socket"); 132 return false; 133 } 134 135 if (hdhomerun_control_get_local_addr(_control_socket) == 0) 136 { 137 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to connect to device"); 138 return false; 139 } 88 return _stream_handler->Connected(); 140 89 141 VERBOSE(VB_CHANNEL, LOC + "Successfully connected to device");142 return true;143 90 } 144 91 145 QString HDHRChannel::DeviceGet(const QString &name, bool report_error_return)92 void HDHRChannel::Close() 146 93 { 147 QMutexLocker locker(&_lock); 148 149 if (!_control_socket) 150 { 151 VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed (not connected)"); 152 return QString::null; 153 } 94 VERBOSE(VB_CHANNEL, LOC + "Closing HDHR channel"); 154 95 155 char *value = NULL; 156 char *error = NULL; 157 if (hdhomerun_control_get(_control_socket, name, &value, &error) < 0) 158 { 159 VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed" + ENO); 160 return QString::null; 161 } 162 163 if (report_error_return && error) 164 { 165 VERBOSE(VB_IMPORTANT, LOC_ERR + 166 QString("DeviceGet(%1): %2").arg(name).arg(error)); 96 if (! IsOpen()) 97 return; // this caller didn't have it open in the first place.. 167 98 168 return QString::null; 169 } 170 171 return QString(value); 99 HDHRStreamHandler::Return(_stream_handler); 172 100 } 173 101 174 QString HDHRChannel::DeviceSet(const QString &name, const QString &val, 175 bool report_error_return) 102 bool HDHRChannel::EnterPowerSavingMode(void) 176 103 { 177 QMutexLocker locker(&_lock); 178 179 if (!_control_socket) 180 { 181 VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed (not connected)"); 182 return QString::null; 183 } 184 185 char *value = NULL; 186 char *error = NULL; 187 if (hdhomerun_control_set(_control_socket, name, val, &value, &error) < 0) 188 { 189 VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed" + ENO); 190 191 return QString::null; 192 } 193 194 if (report_error_return && error) 195 { 196 VERBOSE(VB_IMPORTANT, LOC_ERR + 197 QString("DeviceSet(%1 %2): %3").arg(name).arg(val).arg(error)); 198 199 return QString::null; 200 } 201 202 return QString(value); 104 if ( IsOpen()) 105 return _stream_handler->EnterPowerSavingMode(); 106 else 107 return true; 203 108 } 204 109 205 QString HDHRChannel::TunerGet(const QString &name, bool report_error_return)206 {207 return DeviceGet(QString("/tuner%1/%2").arg(_tuner).arg(name),208 report_error_return);209 }210 110 211 QString HDHRChannel::TunerSet(const QString &name, const QString &value, 212 bool report_error_return) 111 bool HDHRChannel::IsOpen(void) const 213 112 { 214 return DeviceSet(QString("/tuner%1/%2").arg(_tuner).arg(name), value, 215 report_error_return); 113 return (_stream_handler != NULL); 216 114 } 217 115 218 bool HDHRChannel:: DeviceSetTarget(unsigned short localPort)116 bool HDHRChannel::Init(QString &inputname, QString &startchannel, bool setchan) 219 117 { 220 if (localPort == 0) 221 { 222 return false; 223 } 224 225 unsigned long localIP = hdhomerun_control_get_local_addr(_control_socket); 226 if (localIP == 0) 227 { 228 return false; 229 } 230 231 QString configValue = QString("%1.%2.%3.%4:%5") 232 .arg((localIP >> 24) & 0xFF).arg((localIP >> 16) & 0xFF) 233 .arg((localIP >> 8) & 0xFF).arg((localIP >> 0) & 0xFF) 234 .arg(localPort); 118 if (setchan && !IsOpen()) 119 Open(); 235 120 236 if (!TunerSet("target", configValue)) 237 { 238 return false; 239 } 240 241 return true; 242 } 243 244 bool HDHRChannel::DeviceClearTarget() 245 { 246 return TunerSet("target", "0.0.0.0:0"); 121 return ChannelBase::Init(inputname, startchannel, setchan); 247 122 } 248 123 249 124 bool HDHRChannel::SetChannelByString(const QString &channum) … … 277 152 return SwitchToInput(inputName, channum); 278 153 279 154 ClearDTVInfo(); 280 _ignore_filters = false;281 155 282 156 InputMap::const_iterator it = inputs.find(currentInputID); 283 157 if (it == inputs.end()) … … 349 223 if (mpeg_prog_num && (GetTuningMode() == "mpeg")) 350 224 { 351 225 QString pnum = QString::number(mpeg_prog_num); 352 _ignore_filters = QString::null != TunerSet("program", pnum, false); 226 //_ignore_filters = _stream_handler->TuneProgram(pnum); 227 _stream_handler->TuneProgram(pnum); 353 228 } 354 229 355 230 return true; … … 398 273 QString("TuneTo(%1,%2)").arg(frequency).arg(modulation)); 399 274 400 275 if (modulation == "8vsb") 401 ok = TunerSet("channel",QString("8vsb:%1").arg(frequency));276 ok = _stream_handler->TuneChannel(QString("8vsb:%1").arg(frequency)); 402 277 else if (modulation == "qam_64") 403 ok = TunerSet("channel",QString("qam64:%1").arg(frequency));278 ok = _stream_handler->TuneChannel(QString("qam64:%1").arg(frequency)); 404 279 else if (modulation == "qam_256") 405 ok = TunerSet("channel",QString("qam256:%1").arg(frequency));280 ok = _stream_handler->TuneChannel(QString("qam256:%1").arg(frequency)); 406 281 407 282 if (ok) 408 283 SetSIStandard(si_std); 409 284 410 285 return ok; 411 286 } 412 413 bool HDHRChannel::AddPID(uint pid, bool do_update)414 {415 QMutexLocker locker(&_lock);416 417 vector<uint>::iterator it;418 it = lower_bound(_pids.begin(), _pids.end(), pid);419 if (it != _pids.end() && *it == pid)420 {421 #ifdef DEBUG_PID_FILTERS422 VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<") NOOP");423 #endif // DEBUG_PID_FILTERS424 return true;425 }426 427 _pids.insert(it, pid);428 429 #ifdef DEBUG_PID_FILTERS430 VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<")");431 #endif // DEBUG_PID_FILTERS432 433 if (do_update)434 return UpdateFilters();435 return true;436 }437 438 bool HDHRChannel::DelPID(uint pid, bool do_update)439 {440 QMutexLocker locker(&_lock);441 442 vector<uint>::iterator it;443 it = lower_bound(_pids.begin(), _pids.end(), pid);444 if (it == _pids.end())445 {446 #ifdef DEBUG_PID_FILTERS447 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") NOOP");448 #endif // DEBUG_PID_FILTERS449 450 return true;451 }452 453 if (*it == pid)454 {455 #ifdef DEBUG_PID_FILTERS456 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") -- found");457 #endif // DEBUG_PID_FILTERS458 _pids.erase(it);459 }460 else461 {462 #ifdef DEBUG_PID_FILTERS463 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") -- failed");464 #endif // DEBUG_PID_FILTERS465 }466 467 if (do_update)468 return UpdateFilters();469 return true;470 }471 472 bool HDHRChannel::DelAllPIDs(void)473 {474 QMutexLocker locker(&_lock);475 476 #ifdef DEBUG_PID_FILTERS477 VERBOSE(VB_CHANNEL, "DelAllPID()");478 #endif // DEBUG_PID_FILTERS479 480 _pids.clear();481 482 return UpdateFilters();483 }484 485 QString filt_str(uint pid)486 {487 uint pid0 = (pid / (16*16*16)) % 16;488 uint pid1 = (pid / (16*16)) % 16;489 uint pid2 = (pid / (16)) % 16;490 uint pid3 = pid % 16;491 return QString("0x%1%2%3%4")492 .arg(pid0,0,16).arg(pid1,0,16)493 .arg(pid2,0,16).arg(pid3,0,16);494 }495 496 bool HDHRChannel::UpdateFilters(void)497 {498 QMutexLocker locker(&_lock);499 500 QString filter = "";501 502 vector<uint> range_min;503 vector<uint> range_max;504 505 if (_ignore_filters)506 return true;507 508 for (uint i = 0; i < _pids.size(); i++)509 {510 uint pid_min = _pids[i];511 uint pid_max = pid_min;512 for (uint j = i + 1; j < _pids.size(); j++)513 {514 if (pid_max + 1 != _pids[j])515 break;516 pid_max++;517 i++;518 }519 range_min.push_back(pid_min);520 range_max.push_back(pid_max);521 }522 523 if (range_min.size() > 16)524 {525 range_min.resize(16);526 uint pid_max = range_max.back();527 range_max.resize(15);528 range_max.push_back(pid_max);529 }530 531 for (uint i = 0; i < range_min.size(); i++)532 {533 filter += filt_str(range_min[i]);534 if (range_min[i] != range_max[i])535 filter += QString("-%1").arg(filt_str(range_max[i]));536 filter += " ";537 }538 539 filter = filter.stripWhiteSpace();540 541 QString new_filter = TunerSet("filter", filter);542 543 #ifdef DEBUG_PID_FILTERS544 QString msg = QString("Filter: '%1'").arg(filter);545 if (filter != new_filter)546 msg += QString("\n\t\t\t\t'%2'").arg(new_filter);547 548 VERBOSE(VB_CHANNEL, msg);549 #endif // DEBUG_PID_FILTERS550 551 return filter == new_filter;552 } -
mythtv/libs/libmythtv/hdhrchannel.h
diff -r -u -N -X diff.exclude -x release.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/hdhrchannel.h release.19740.0119b/mythtv/libs/libmythtv/hdhrchannel.h
15 15 16 16 // HDHomeRun headers 17 17 #ifdef USING_HDHOMERUN 18 #include "hdhomerun /hdhomerun.h"18 #include "hdhomerun_includes.h" 19 19 #else 20 20 struct hdhomerun_control_sock_t { int dummy; }; 21 21 #endif 22 22 23 23 typedef struct hdhomerun_control_sock_t hdhr_socket_t; 24 24 25 class HDHRChannel; 26 class HDHRStreamHandler; 27 class ProgramMapTable; 28 25 29 class HDHRChannel : public DTVChannel 26 30 { 27 31 friend class HDHRSignalMonitor; … … 35 39 void Close(void); 36 40 bool EnterPowerSavingMode(void); 37 41 42 bool Init(QString &inputname, QString &startchannel, bool setchan); 43 38 44 // Sets 45 void SetPMT(const ProgramMapTable*) {}; 39 46 bool SetChannelByString(const QString &chan); 40 47 41 48 // Gets 42 bool IsOpen(void) const { return (_control_socket != NULL); }49 bool IsOpen(void) const; 43 50 QString GetDevice(void) const 44 51 { return QString("%1/%2").arg(_device_id, 8, 16).arg(_tuner); } 52 uint GetDeviceId(void) const { return _device_id; } 53 uint GetTuner(void) const { return _tuner; } 45 54 vector<uint> GetPIDs(void) const 46 55 { QMutexLocker locker(&_lock); return _pids; } 47 56 QString GetSIStandard(void) const { return "atsc"; } 48 57 49 // Commands50 bool AddPID(uint pid, bool do_update = true);51 bool DelPID(uint pid, bool do_update = true);52 bool DelAllPIDs(void);53 bool UpdateFilters(void);54 55 58 // ATSC scanning stuff 56 59 bool TuneMultiplex(uint mplexid, QString inputname); 57 60 bool Tune(const DTVMultiplex &tuning, QString inputname); 58 61 59 62 private: 60 bool FindDevice(void);61 bool Connect(void);62 63 bool Tune(uint frequency, QString inputname, 63 64 QString modulation, QString si_std); 64 65 65 bool DeviceSetTarget(unsigned short localPort);66 bool DeviceClearTarget(void);67 68 QString DeviceGet(const QString &name, bool report_error_return = true);69 QString DeviceSet(const QString &name, const QString &value,70 bool report_error_return = true);71 72 QString TunerGet(const QString &name, bool report_error_return = true);73 QString TunerSet(const QString &name, const QString &value,74 bool report_error_return = true);75 76 66 private: 77 hdhr_socket_t *_control_socket; 67 HDHRStreamHandler *_stream_handler; 68 78 69 uint _device_id; 79 70 uint _device_ip; 80 71 uint _tuner; 81 bool _ignore_filters;82 72 vector<uint> _pids; 83 73 mutable QMutex _lock; 74 mutable QMutex tune_lock; 75 mutable QMutex hw_lock; 84 76 }; 85 77 86 78 #endif -
mythtv/libs/libmythtv/hdhrrecorder.cpp
diff -r -u -N -X diff.exclude -x release.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/hdhrrecorder.cpp release.19740.0119b/mythtv/libs/libmythtv/hdhrrecorder.cpp
23 23 24 24 // MythTV includes 25 25 #include "RingBuffer.h" 26 #include "hdhrchannel.h"27 #include "hdhrrecorder.h"28 26 #include "atsctables.h" 29 27 #include "atscstreamdata.h" 30 28 #include "eithelper.h" 31 29 #include "tv_rec.h" 32 30 31 // MythTV HDHR includes 32 #include "hdhrchannel.h" 33 #include "hdhrrecorder.h" 34 #include "hdhrstreamhandler.h" 35 33 36 #define LOC QString("HDHRRec(%1): ").arg(tvrec->GetCaptureCardNum()) 37 #define LOC_WARN QString("HDHRRec(%1), Warning: ") \ 38 .arg(tvrec->GetCaptureCardNum()) 34 39 #define LOC_ERR QString("HDHRRec(%1), Error: ") \ 35 40 .arg(tvrec->GetCaptureCardNum()) 36 41 37 42 HDHRRecorder::HDHRRecorder(TVRec *rec, HDHRChannel *channel) 38 43 : DTVRecorder(rec), 39 _channel(channel), _video_socket(NULL), 44 _channel(channel), 45 _stream_handler(NULL), 40 46 _stream_data(NULL), 41 _input_pat(NULL), _input_pmt(NULL), 42 _reset_pid_filters(false),_pid_lock(true) 47 _pid_lock(true), 48 _input_pat(NULL), 49 _input_pmt(NULL), 50 _has_no_av(false) 43 51 { 44 52 } 45 53 … … 90 98 // HACK -- end 91 99 } 92 100 101 bool HDHRRecorder::IsOpen(void) { 102 return (_stream_handler != NULL); 103 } 104 93 105 bool HDHRRecorder::Open(void) 94 106 { 95 107 VERBOSE(VB_RECORD, LOC + "Open()"); 96 if ( _video_socket)108 if (IsOpen()) 97 109 { 98 110 VERBOSE(VB_RECORD, LOC + "Card already open (recorder)"); 99 111 return true; 100 112 } 101 113 102 /* Calculate buffer size */ 103 uint buffersize = gContext->GetNumSetting( 104 "HDRingbufferSize", 50 * TSPacket::SIZE) * 1024; 105 buffersize /= VIDEO_DATA_PACKET_SIZE; 106 buffersize *= VIDEO_DATA_PACKET_SIZE; 114 bzero(_stream_id, sizeof(_stream_id)); 115 bzero(_pid_status, sizeof(_pid_status)); 116 memset(_continuity_counter, 0xff, sizeof(_continuity_counter)); 107 117 108 // Buffer should be at least about 1MB.. 109 buffersize = max(49 * TSPacket::SIZE * 128, buffersize); 118 _stream_handler = HDHRStreamHandler::Get(_channel->GetDeviceId(), _channel->GetTuner(), _channel->GetDevice()); 110 119 111 /* Create TS socket. */ 112 _video_socket = hdhomerun_video_create(0, buffersize); 113 if (!_video_socket) 114 { 115 VERBOSE(VB_IMPORTANT, LOC + "Open() failed to open socket"); 116 return false; 117 } 120 VERBOSE(VB_RECORD, LOC + "HDHR opened successfully"); 118 121 119 /* Success. */120 122 return true; 121 123 } 122 124 123 /** \fn HDHRRecorder::StartData(void)124 * \brief Configure device to send video.125 */126 bool HDHRRecorder::StartData(void)127 {128 VERBOSE(VB_RECORD, LOC + "StartData()");129 uint localPort = hdhomerun_video_get_local_port(_video_socket);130 return _channel->DeviceSetTarget(localPort);131 }132 133 125 void HDHRRecorder::Close(void) 134 126 { 135 VERBOSE(VB_RECORD, LOC + "Close()"); 136 if (_video_socket) 137 { 138 hdhomerun_video_destroy(_video_socket); 139 _video_socket = NULL; 140 } 141 } 142 143 void HDHRRecorder::ProcessTSData(const uint8_t *buffer, int len) 144 { 145 QMutexLocker locker(&_pid_lock); 146 const uint8_t *data = buffer; 147 const uint8_t *end = buffer + len; 127 VERBOSE(VB_RECORD, LOC + "Close() - Begin"); 148 128 149 while (data + 188 <= end)129 if (IsOpen()) 150 130 { 151 if (data[0] != 0x47) 152 { 153 return; 154 } 155 156 const TSPacket *tspacket = reinterpret_cast<const TSPacket*>(data); 157 ProcessTSPacket(*tspacket); 158 159 data += 188; 131 HDHRStreamHandler::Return(_stream_handler); 160 132 } 133 134 VERBOSE(VB_RECORD, LOC + "Close() - End"); 161 135 } 162 136 163 137 void HDHRRecorder::SetStreamData(MPEGStreamData *data) … … 216 190 ProgramAssociationTable *oldpat = _input_pat; 217 191 _input_pat = new ProgramAssociationTable(*_pat); 218 192 delete oldpat; 219 220 _reset_pid_filters = true;221 193 } 222 194 223 195 void HDHRRecorder::HandlePMT(uint progNum, const ProgramMapTable *_pmt) … … 229 201 VERBOSE(VB_RECORD, LOC + "SetPMT("<<progNum<<")"); 230 202 ProgramMapTable *oldpmt = _input_pmt; 231 203 _input_pmt = new ProgramMapTable(*_pmt); 232 delete oldpmt;233 204 234 _reset_pid_filters = true; 205 QString sistandard = _channel->GetSIStandard(); 206 207 bool has_no_av = true; 208 for (uint i = 0; i < _input_pmt->StreamCount() && has_no_av; i++) 209 { 210 has_no_av &= !_input_pmt->IsVideo(i, sistandard); 211 has_no_av &= !_input_pmt->IsAudio(i, sistandard); 212 } 213 _has_no_av = has_no_av; 214 215 _channel->SetPMT(_input_pmt); 216 delete oldpmt; 235 217 } 236 218 } 237 219 … … 242 224 243 225 int next = (pat->tsheader()->ContinuityCounter()+1)&0xf; 244 226 pat->tsheader()->SetContinuityCounter(next); 245 BufferedWrite(*(reinterpret_cast<TSPacket*>(pat->tsheader())));227 DTVRecorder::BufferedWrite(*(reinterpret_cast<TSPacket*>(pat->tsheader()))); 246 228 } 247 229 248 230 void HDHRRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt) 249 231 { 250 232 if (!pmt) 233 { 234 VERBOSE(VB_RECORD, LOC + "HandleSingleProgramPMT(NULL)"); 235 return; 236 } 237 238 // collect stream types for H.264 (MPEG-4 AVC) keyframe detection 239 for (uint i = 0; i < pmt->StreamCount(); i++) 240 _stream_id[pmt->StreamPID(i)] = pmt->StreamType(i); 241 242 if (!ringBuffer) 251 243 return; 252 244 253 245 unsigned char buf[8 * 1024]; … … 255 247 pmt->tsheader()->SetContinuityCounter(next_cc); 256 248 uint size = pmt->WriteAsTSPackets(buf, next_cc); 257 249 250 uint posA[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() }; 251 258 252 for (uint i = 0; i < size ; i += TSPacket::SIZE) 259 253 DTVRecorder::BufferedWrite(*(reinterpret_cast<TSPacket*>(&buf[i]))); 254 255 uint posB[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() }; 256 257 if (posB[0] + posB[1] * TSPacket::SIZE > 258 posA[0] + posA[1] * TSPacket::SIZE) 259 { 260 VERBOSE(VB_RECORD, LOC + "Wrote PMT @" 261 << posA[0] << " + " << (posA[1] * TSPacket::SIZE)); 262 } 263 else 264 { 265 VERBOSE(VB_RECORD, LOC + "Saw PMT but did not write to disk yet"); 266 } 260 267 } 261 268 262 269 /** \fn HDHRRecorder::HandleMGT(const MasterGuideTable*) … … 276 283 } 277 284 */ 278 285 286 bool HDHRRecorder::ProcessVideoTSPacket(const TSPacket &tspacket) 287 { 288 uint streamType = _stream_id[tspacket.PID()]; 289 290 // Check for keyframes and count frames 291 if (streamType == StreamID::H264Video) 292 { 293 _buffer_packets = !FindH264Keyframes(&tspacket); 294 if (!_seen_sps) 295 return true; 296 } 297 else 298 { 299 _buffer_packets = !FindMPEG2Keyframes(&tspacket); 300 } 301 302 return ProcessAVTSPacket(tspacket); 303 } 304 305 bool HDHRRecorder::ProcessAudioTSPacket(const TSPacket &tspacket) 306 { 307 _buffer_packets = !FindAudioKeyframes(&tspacket); 308 return ProcessAVTSPacket(tspacket); 309 } 310 311 /// Common code for processing either audio or video packets 312 bool HDHRRecorder::ProcessAVTSPacket(const TSPacket &tspacket) 313 { 314 const uint pid = tspacket.PID(); 315 // Sync recording start to first keyframe 316 if (_wait_for_keyframe_option && _first_keyframe < 0) 317 return true; 318 319 // Sync streams to the first Payload Unit Start Indicator 320 // _after_ first keyframe iff _wait_for_keyframe_option is true 321 if (!(_pid_status[pid] & kPayloadStartSeen) && tspacket.HasPayload()) 322 { 323 if (!tspacket.PayloadStart()) 324 return true; // not payload start - drop packet 325 326 VERBOSE(VB_RECORD, 327 QString("PID 0x%1 Found Payload Start").arg(pid,0,16)); 328 329 _pid_status[pid] |= kPayloadStartSeen; 330 } 331 332 BufferedWrite(tspacket); 333 334 return true; 335 } 336 279 337 bool HDHRRecorder::ProcessTSPacket(const TSPacket& tspacket) 280 338 { 281 bool ok = !tspacket.TransportError();282 if ( ok && !tspacket.ScramplingControl())339 // Only create fake keyframe[s] if there are no audio/video streams 340 if (_input_pmt && _has_no_av) 283 341 { 284 if (tspacket.HasAdaptationField()) 285 GetStreamData()->HandleAdaptationFieldControl(&tspacket); 286 if (tspacket.HasPayload()) 287 { 288 const unsigned int lpid = tspacket.PID(); 342 _buffer_packets = !FindOtherKeyframes(&tspacket); 343 } 344 else 345 { 346 // There are audio/video streams. Only write the packet 347 // if audio/video key-frames have been found 348 if (_wait_for_keyframe_option && _first_keyframe < 0) 349 return true; 289 350 290 if ((GetStreamData()->VideoPIDSingleProgram() > 0x1fff) && 291 _wait_for_keyframe_option) 292 { 293 _wait_for_keyframe_option = false; 294 } 295 296 // Pass or reject frames based on PID, and parse info from them 297 if (lpid == GetStreamData()->VideoPIDSingleProgram()) 298 { 299 //cerr<<"v"; 300 _buffer_packets = !FindMPEG2Keyframes(&tspacket); 301 BufferedWrite(tspacket); 302 } 303 else if (GetStreamData()->IsAudioPID(lpid)) 304 { 305 //cerr<<"a"; 306 _buffer_packets = !FindAudioKeyframes(&tspacket); 307 BufferedWrite(tspacket); 308 } 309 else if (GetStreamData()->IsListeningPID(lpid)) 310 { 311 //cerr<<"t"; 312 GetStreamData()->HandleTSTables(&tspacket); 313 } 314 else if (GetStreamData()->IsWritingPID(lpid)) 315 BufferedWrite(tspacket); 316 } 351 _buffer_packets = true; 317 352 } 318 return ok; 353 354 BufferedWrite(tspacket); 319 355 } 320 356 321 357 void HDHRRecorder::StartRecording(void) … … 333 369 _request_recording = true; 334 370 _recording = true; 335 371 336 if (!StartData())337 {338 VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting recording "339 "(set target failed). Aborting.");340 Close();341 _error = true;342 VERBOSE(VB_RECORD, LOC + "StartRecording -- end 2"); 343 return;344 }345 346 hdhomerun_video_flush(_video_socket);372 // Make sure the first things in the file are a PAT & PMT 373 bool tmp = _wait_for_keyframe_option; 374 _wait_for_keyframe_option = false; 375 HandleSingleProgramPAT(_stream_data->PATSingleProgram()); 376 HandleSingleProgramPMT(_stream_data->PMTSingleProgram()); 377 _wait_for_keyframe_option = tmp; 378 379 _stream_data->AddAVListener(this); 380 _stream_data->AddWritingListener(this); 381 _stream_handler->AddListener(_stream_data); 382 347 383 while (_request_recording && !_error) 348 384 { 385 usleep(50000); 386 349 387 if (PauseAndWait()) 350 388 continue; 351 389 352 if ( _stream_data)390 if (!_input_pmt) 353 391 { 354 QMutexLocker read_lock(&_pid_lock); 355 _reset_pid_filters |= _stream_data->HasEITPIDChanges(_eit_pids); 392 VERBOSE(VB_GENERAL, LOC_WARN + 393 "Recording will not commence until a PMT is set."); 394 usleep(5000); 395 continue; 356 396 } 357 397 358 if ( _reset_pid_filters)398 if (!_stream_handler->IsRunning()) 359 399 { 360 _reset_pid_filters = false; 361 VERBOSE(VB_RECORD, LOC + "Resetting Demux Filters"); 362 AdjustFilters(); 363 } 400 _error = true; 364 401 365 size_t read_size = 64 * 1024; // read about 64KB 366 read_size /= VIDEO_DATA_PACKET_SIZE; 367 read_size *= VIDEO_DATA_PACKET_SIZE; 368 369 size_t data_length; 370 unsigned char *data_buffer = 371 hdhomerun_video_recv(_video_socket, read_size, &data_length); 372 if (!data_buffer) 373 { 374 usleep(5000); 375 continue; 376 } 377 378 ProcessTSData(data_buffer, data_length); 402 VERBOSE(VB_IMPORTANT, LOC_ERR + 403 "Stream handler died unexpectedly."); 404 } 379 405 } 380 406 381 407 VERBOSE(VB_RECORD, LOC + "StartRecording -- ending..."); 382 408 383 _channel->DeviceClearTarget(); 409 _stream_handler->RemoveListener(_stream_data); 410 _stream_data->RemoveWritingListener(this); 411 _stream_data->RemoveAVListener(this); 412 384 413 Close(); 385 414 386 415 FinishRecording(); … … 389 418 VERBOSE(VB_RECORD, LOC + "StartRecording -- end"); 390 419 } 391 420 392 bool HDHRRecorder::AdjustFilters(void)421 void HDHRRecorder::ResetForNewFile(void) 393 422 { 394 QMutexLocker change_lock(&_pid_lock);423 DTVRecorder::ResetForNewFile(); 395 424 396 if (!_channel) 397 { 398 VERBOSE(VB_IMPORTANT, LOC_ERR + "AdjustFilters() no channel"); 399 return false; 400 } 425 bzero(_stream_id, sizeof(_stream_id)); 426 bzero(_pid_status, sizeof(_pid_status)); 427 memset(_continuity_counter, 0xff, sizeof(_continuity_counter)); 401 428 402 if (!_input_pat || !_input_pmt) 403 { 404 VERBOSE(VB_IMPORTANT, LOC + "AdjustFilters() no pmt or no pat"); 405 return false; 406 } 407 408 uint_vec_t add_pid; 429 // FIXME 430 // Close and re-open ??? 431 //Close(); 432 //Open(); 433 } 409 434 410 add_pid.push_back(MPEG_PAT_PID); 411 _stream_data->AddListeningPID(MPEG_PAT_PID); 435 void HDHRRecorder::StopRecording(void) 436 { 437 _request_recording = false; 438 while (_recording) 439 usleep(2000); 440 } 412 441 413 for (uint i = 0; i < _input_pat->ProgramCount(); i++) 442 bool HDHRRecorder::PauseAndWait(int timeout) 443 { 444 if (request_pause) 414 445 { 415 add_pid.push_back(_input_pat->ProgramPID(i)); 416 _stream_data->AddListeningPID(_input_pat->ProgramPID(i)); 417 } 446 if (!paused) 447 { 448 assert(_stream_handler); 449 assert(_stream_data); 418 450 419 // Record the streams in the PMT... 420 bool need_pcr_pid = true; 421 for (uint i = 0; i < _input_pmt->StreamCount(); i++) 422 { 423 add_pid.push_back(_input_pmt->StreamPID(i)); 424 need_pcr_pid &= (_input_pmt->StreamPID(i) != _input_pmt->PCRPID()); 425 _stream_data->AddWritingPID(_input_pmt->StreamPID(i)); 426 } 451 _stream_handler->RemoveListener(_stream_data); 427 452 428 if (need_pcr_pid && (_input_pmt->PCRPID())) 429 { 430 add_pid.push_back(_input_pmt->PCRPID()); 431 _stream_data->AddWritingPID(_input_pmt->PCRPID()); 453 paused = true; 454 pauseWait.wakeAll(); 455 if (tvrec) 456 tvrec->RecorderPaused(); 457 } 458 unpauseWait.wait(timeout); 432 459 } 433 460 434 // Adjust for EIT 435 AdjustEITPIDs(); 436 for (uint i = 0; i < _eit_pids.size(); i++) 461 if (!request_pause && paused) 437 462 { 438 add_pid.push_back(_eit_pids[i]); 439 _stream_data->AddListeningPID(_eit_pids[i]); 440 } 463 paused = false; 441 464 442 // Delete filters for pids we no longer wish to monitor 443 vector<uint>::const_iterator it; 444 vector<uint> pids = _channel->GetPIDs(); 445 for (it = pids.begin(); it != pids.end(); ++it) 446 { 447 if (find(add_pid.begin(), add_pid.end(), *it) == add_pid.end()) 448 { 449 _stream_data->RemoveListeningPID(*it); 450 _stream_data->RemoveWritingPID(*it); 451 _channel->DelPID(*it, false); 452 } 453 } 465 assert(_stream_handler); 466 assert(_stream_data); 454 467 455 for (it = add_pid.begin(); it != add_pid.end(); ++it) 456 _channel->AddPID(*it, false); 457 458 _channel->UpdateFilters(); 468 _stream_handler->AddListener(_stream_data); 469 } 459 470 460 return add_pid.size();471 return paused; 461 472 } 462 473 463 /** \fn HDHRRecorder::AdjustEITPIDs(void) 464 * \brief Adjusts EIT PID monitoring to monitor the right number of EIT PIDs. 465 */ 466 bool HDHRRecorder::AdjustEITPIDs(void) 474 void HDHRRecorder::BufferedWrite(const TSPacket &tspacket) 467 475 { 468 bool changes = false; 469 uint_vec_t add, del; 470 471 QMutexLocker change_lock(&_pid_lock); 472 473 if (GetStreamData()->HasEITPIDChanges(_eit_pids)) 474 changes = GetStreamData()->GetEITPIDChanges(_eit_pids, add, del); 476 // Care must be taken to make sure that the packet actually gets written 477 // as the decision to actually write it has already been made 475 478 476 if (!changes) 477 return false; 478 479 for (uint i = 0; i < del.size(); i++) 479 // Do we have to buffer the packet for exact keyframe detection? 480 if (_buffer_packets) 480 481 { 481 uint_vec_t::iterator it;482 it = find(_eit_pids.begin(), _eit_pids.end(), del[i]);483 if (it != _eit_pids.end())484 _eit_pids.erase(it);482 int idx = _payload_buffer.size(); 483 _payload_buffer.resize(idx + TSPacket::SIZE); 484 memcpy(&_payload_buffer[idx], tspacket.data(), TSPacket::SIZE); 485 return; 485 486 } 486 487 487 for (uint i = 0; i < add.size(); i++) 488 _eit_pids.push_back(add[i]); 489 490 return true; 488 // We are free to write the packet, but if we have buffered packet[s] 489 // we have to write them first... 490 if (!_payload_buffer.empty()) 491 { 492 if (ringBuffer) 493 ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size()); 494 _payload_buffer.clear(); 495 } 496 if (ringBuffer) 497 ringBuffer->Write(tspacket.data(), TSPacket::SIZE); 491 498 } 492 499 -
mythtv/libs/libmythtv/hdhrrecorder.h
diff -r -u -N -X diff.exclude -x release.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/hdhrrecorder.h release.19740.0119b/mythtv/libs/libmythtv/hdhrrecorder.h
14 14 15 15 class HDHRChannel; 16 16 class ProgramMapTable; 17 class MPEGStreamData; 18 class HDHRStreamHandler; 19 17 20 18 21 typedef vector<uint> uint_vec_t; 19 22 20 23 class HDHRRecorder : public DTVRecorder, 21 24 public MPEGStreamListener, 22 public MPEGSingleProgramStreamListener 25 public MPEGSingleProgramStreamListener, 26 public TSPacketListener, 27 public TSPacketListenerAV 23 28 { 24 29 friend class ATSCStreamData; 25 30 … … 33 38 const QString &vbidev); 34 39 35 40 bool Open(void); 36 bool StartData(void);41 bool IsOpen(void); 37 42 void Close(void); 38 43 39 44 void StartRecording(void); 45 void ResetForNewFile(void); 46 void StopRecording(void); 40 47 41 48 void SetStreamData(MPEGStreamData*); 42 49 MPEGStreamData *GetStreamData(void) { return _stream_data; } … … 59 66 void HandleVCT(uint, const VirtualChannelTable*) {} 60 67 */ 61 68 62 private: 63 bool AdjustFilters(void); 64 bool AdjustEITPIDs(void); 69 // TSPacketListenerAV 70 bool ProcessVideoTSPacket(const TSPacket& tspacket); 71 bool ProcessAudioTSPacket(const TSPacket& tspacket); 72 73 // Common audio/visual processing 74 bool ProcessAVTSPacket(const TSPacket &tspacket); 65 75 66 void ProcessTSData(const unsigned char *buffer, int len);67 76 bool ProcessTSPacket(const TSPacket& tspacket); 77 78 void BufferedWrite(const TSPacket &tspacket); 79 private: 68 80 void TeardownAll(void); 81 82 void ReaderPaused(int fd); 83 bool PauseAndWait(int timeout = 100); 69 84 70 85 private: 71 86 HDHRChannel *_channel; 72 struct hdhomerun_video_sock_t *_video_socket;87 HDHRStreamHandler *_stream_handler; 73 88 MPEGStreamData *_stream_data; 74 89 90 mutable QMutex _pid_lock; 75 91 ProgramAssociationTable *_input_pat; 76 92 ProgramMapTable *_input_pmt; 77 bool _reset_pid_filters; 78 uint_vec_t _eit_pids; 79 mutable QMutex _pid_lock; 93 bool _has_no_av; 94 95 unsigned char _stream_id[0x1fff]; 96 unsigned char _pid_status[0x1fff]; 97 unsigned char _continuity_counter[0x1fff]; 98 99 // Constants 100 static const int TSPACKETS_BETWEEN_PSIP_SYNC; 101 static const int POLL_INTERVAL; 102 static const int POLL_WARNING_TIMEOUT; 103 104 static const unsigned char kPayloadStartSeen = 0x2; 80 105 }; 81 106 82 107 #endif -
mythtv/libs/libmythtv/hdhrsignalmonitor.cpp
diff -r -u -N -X diff.exclude -x release.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/hdhrsignalmonitor.cpp release.19740.0119b/mythtv/libs/libmythtv/hdhrsignalmonitor.cpp
18 18 19 19 #include "hdhrchannel.h" 20 20 #include "hdhrrecorder.h" 21 #include "hdhrstreamhandler.h" 21 22 22 23 #define LOC QString("HDHRSM(%1): ").arg(channel->GetDevice()) 23 24 #define LOC_ERR QString("HDHRSM(%1), Error: ").arg(channel->GetDevice()) … … 41 42 HDHRChannel* _channel, 42 43 uint64_t _flags, const char *_name) 43 44 : DTVSignalMonitor(db_cardnum, _channel, _flags, _name), 44 dtvMonitorRunning(false) 45 streamHandlerStarted(false), 46 streamHandler(NULL) 47 45 48 { 46 49 VERBOSE(VB_CHANNEL, LOC + "ctor"); 47 50 48 _channel->DelAllPIDs();49 50 51 signalStrength.SetThreshold(45); 51 52 52 53 AddFlags(kDTVSigMon_WaitForSig); 54 55 streamHandler = HDHRStreamHandler::Get(_channel->GetDeviceId(), _channel->GetTuner(), _channel->GetDevice()); 53 56 } 54 57 55 58 /** \fn HDHRSignalMonitor::~HDHRSignalMonitor() … … 59 62 { 60 63 VERBOSE(VB_CHANNEL, LOC + "dtor"); 61 64 Stop(); 65 HDHRStreamHandler::Return(streamHandler); 62 66 } 63 67 64 68 void HDHRSignalMonitor::deleteLater(void) … … 75 79 { 76 80 VERBOSE(VB_CHANNEL, LOC + "Stop() -- begin"); 77 81 SignalMonitor::Stop(); 78 if (dtvMonitorRunning) 79 { 80 dtvMonitorRunning = false; 81 pthread_join(table_monitor_thread, NULL); 82 } 83 VERBOSE(VB_CHANNEL, LOC + "Stop() -- end"); 84 } 82 if (GetStreamData()) 83 streamHandler->RemoveListener(GetStreamData()); 84 streamHandlerStarted = false; 85 streamHandler->SetRetuneAllowed(false, NULL, NULL); 85 86 86 void *HDHRSignalMonitor::TableMonitorThread(void *param) 87 { 88 HDHRSignalMonitor *mon = (HDHRSignalMonitor*) param; 89 mon->RunTableMonitor(); 90 return NULL; 91 } 92 93 bool HDHRSignalMonitor::UpdateFiltersFromStreamData(void) 94 { 95 vector<int> add_pids; 96 vector<int> del_pids; 97 98 if (!GetStreamData()) 99 return false; 100 101 UpdateListeningForEIT(); 102 103 const pid_map_t &listening = GetStreamData()->ListeningPIDs(); 104 105 // PIDs that need to be added.. 106 pid_map_t::const_iterator lit = listening.constBegin(); 107 for (; lit != listening.constEnd(); ++lit) 108 if (lit.data() && (filters.find(lit.key()) == filters.end())) 109 add_pids.push_back(lit.key()); 110 111 // PIDs that need to be removed.. 112 FilterMap::const_iterator fit = filters.constBegin(); 113 for (; fit != filters.constEnd(); ++fit) 114 if (listening.find(fit.key()) == listening.end()) 115 del_pids.push_back(fit.key()); 116 117 HDHRChannel *hdhr = dynamic_cast<HDHRChannel*>(channel); 118 // Remove PIDs 119 bool ok = true; 120 vector<int>::iterator dit = del_pids.begin(); 121 for (; dit != del_pids.end(); ++dit) 122 { 123 ok &= hdhr->DelPID(*dit); 124 filters.erase(filters.find(*dit)); 125 } 126 127 // Add PIDs 128 vector<int>::iterator ait = add_pids.begin(); 129 for (; ait != add_pids.end(); ++ait) 130 { 131 ok &= hdhr->AddPID(*ait); 132 filters[*ait] = 1; 133 } 134 135 return ok; 87 VERBOSE(VB_CHANNEL, LOC + "Stop() -- end"); 136 88 } 137 89 138 void HDHRSignalMonitor::RunTableMonitor(void)90 HDHRChannel *HDHRSignalMonitor::GetHDHRChannel(void) 139 91 { 140 dtvMonitorRunning = true; 141 142 struct hdhomerun_video_sock_t *_video_socket; 143 _video_socket = hdhomerun_video_create(0, VIDEO_DATA_BUFFER_SIZE_1S); 144 if (!_video_socket) 145 { 146 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to get video socket"); 147 return; 148 } 149 150 HDHRChannel *hdrc = dynamic_cast<HDHRChannel*>(channel); 151 uint localPort = hdhomerun_video_get_local_port(_video_socket); 152 if (!hdrc->DeviceSetTarget(localPort)) 153 { 154 hdhomerun_video_destroy(_video_socket); 155 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to set target"); 156 return; 157 } 158 159 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): " + 160 QString("begin (# of pids %1)") 161 .arg(GetStreamData()->ListeningPIDs().size())); 162 163 while (dtvMonitorRunning && GetStreamData()) 164 { 165 UpdateFiltersFromStreamData(); 166 167 size_t data_length; 168 unsigned char *data_buffer = 169 hdhomerun_video_recv(_video_socket, 170 VIDEO_DATA_BUFFER_SIZE_1S / 5, 171 &data_length); 172 173 if (data_buffer) 174 { 175 GetStreamData()->ProcessData(data_buffer, data_length); 176 continue; 177 } 178 179 usleep(2500); 180 } 181 182 hdrc->DeviceClearTarget(); 183 hdhomerun_video_destroy(_video_socket); 184 185 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- shutdown"); 186 187 // TODO teardown PID filters here 188 189 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- end"); 92 return dynamic_cast<HDHRChannel*>(channel); 190 93 } 191 94 192 95 /** \fn HDHRSignalMonitor::UpdateValues() … … 204 107 if (!running || exit) 205 108 return; 206 109 207 if ( dtvMonitorRunning)110 if (streamHandlerStarted) 208 111 { 209 112 EmitHDHRSignals(); 210 113 if (IsAllGood()) … … 215 118 return; 216 119 } 217 120 218 QString msg = ((HDHRChannel*)channel)->TunerGet("status");121 QString msg = streamHandler->GetTunerStatus(); 219 122 //ss = signal strength, [0,100] 220 123 //snq = signal to noise quality [0,100] 221 124 //seq = signal error quality [0,100] … … 253 156 kDTVSigMon_WaitForMGT | kDTVSigMon_WaitForVCT | 254 157 kDTVSigMon_WaitForNIT | kDTVSigMon_WaitForSDT)) 255 158 { 256 pthread_create(&table_monitor_thread, NULL, 257 TableMonitorThread, this); 258 259 VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- " 260 "Waiting for table monitor to start"); 261 262 while (!dtvMonitorRunning) 263 usleep(50); 264 265 VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- " 266 "Table monitor started"); 159 streamHandler->AddListener(GetStreamData()); 160 streamHandlerStarted = true; 267 161 } 268 162 269 163 update_done = true; -
mythtv/libs/libmythtv/hdhrsignalmonitor.h
diff -r -u -N -X diff.exclude -x release.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/hdhrsignalmonitor.h release.19740.0119b/mythtv/libs/libmythtv/hdhrsignalmonitor.h
7 7 #include "qstringlist.h" 8 8 9 9 class HDHRChannel; 10 class HDHRStreamHandler; 10 11 11 12 typedef QMap<uint,int> FilterMap; 12 13 … … 21 22 22 23 void Stop(void); 23 24 24 bool UpdateFiltersFromStreamData(void);25 26 25 public slots: 27 26 void deleteLater(void); 28 27 … … 33 32 virtual void UpdateValues(void); 34 33 void EmitHDHRSignals(void); 35 34 36 static void *TableMonitorThread(void *param);37 void RunTableMonitor(void);38 39 35 bool SupportsTSMonitoring(void); 40 36 37 HDHRChannel *GetHDHRChannel(void); 38 41 39 protected: 42 bool dtvMonitorRunning;43 pthread_t table_monitor_thread;44 40 45 FilterMap filters; ///< PID filters for table monitoring 41 bool streamHandlerStarted; 42 HDHRStreamHandler *streamHandler; 43 46 44 }; 47 45 48 46 #endif // HDHRSIGNALMONITOR_H -
mythtv/libs/libmythtv/hdhrstreamhandler.cpp
diff -r -u -N -X diff.exclude -x release.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/hdhrstreamhandler.cpp release.19740.0119b/mythtv/libs/libmythtv/hdhrstreamhandler.cpp
1 // -*- Mode: c++ -*- 2 3 #include <cassert> // remove when everything is filled in... 4 5 // POSIX headers 6 #include <pthread.h> 7 #include <fcntl.h> 8 #include <unistd.h> 9 #include <sys/select.h> 10 #include <sys/ioctl.h> 11 12 // Qt headers 13 #include <qstring.h> 14 #include <qdeepcopy.h> 15 16 // MythTV headers 17 #include "hdhrstreamhandler.h" 18 #include "hdhrchannel.h" 19 #include "dtvsignalmonitor.h" 20 #include "streamlisteners.h" 21 #include "mpegstreamdata.h" 22 #include "cardutil.h" 23 24 #define LOC QString("HDHRSH( %1 ): ").arg(_devicename) 25 #define LOC_WARN QString("HDHRSH( %1 ) Warning: ").arg(_devicename) 26 #define LOC_ERR QString("HDHRSH( %1 ) Error: ").arg(_devicename) 27 28 QMap<uint,bool> HDHRStreamHandler::_rec_supports_ts_monitoring; 29 QMutex HDHRStreamHandler::_rec_supports_ts_monitoring_lock; 30 31 QMap<QString,HDHRStreamHandler*> HDHRStreamHandler::_handlers; 32 QMap<QString,uint> HDHRStreamHandler::_handlers_refcnt; 33 QMutex HDHRStreamHandler::_handlers_lock; 34 35 36 #define DEBUG_PID_FILTERS 37 38 HDHRStreamHandler *HDHRStreamHandler::Get(uint device_id, uint tuner, QString devicename) 39 { 40 QMutexLocker locker(&_handlers_lock); 41 42 QMap<QString,HDHRStreamHandler*>::iterator it = 43 _handlers.find(devicename); 44 45 if (it == _handlers.end()) 46 { 47 HDHRStreamHandler *newhandler = new HDHRStreamHandler(device_id, tuner, devicename); 48 newhandler->Open(); 49 _handlers[devicename] = newhandler; 50 _handlers_refcnt[devicename] = 1; 51 VERBOSE(VB_RECORD, QString("HDHRSH: Creating new stream handler for %1") 52 .arg(devicename)); 53 } 54 else 55 { 56 _handlers_refcnt[devicename]++; 57 uint rcount=_handlers_refcnt[devicename]; 58 VERBOSE(VB_RECORD, QString("HDHRSH: Using existing stream handler for %1 (%2 in use)") 59 .arg(devicename).arg(rcount)); 60 } 61 62 return _handlers[devicename]; 63 } 64 65 void HDHRStreamHandler::Return(HDHRStreamHandler * & ref) 66 { 67 QMutexLocker locker(&_handlers_lock); 68 69 QMap<QString,uint>::iterator rit = _handlers_refcnt.find(ref->_devicename); 70 if (rit == _handlers_refcnt.end()) 71 return; 72 73 uint rcount = *rit; 74 VERBOSE(VB_RECORD, QString("HDHRSH: %1 streams left for %2") 75 .arg(rcount-1).arg(ref->_devicename)); 76 77 if (*rit > 1) 78 { 79 (*rit)--; 80 ref=NULL; 81 return; 82 } 83 84 QMap<QString, HDHRStreamHandler*>::iterator it = _handlers.find(ref->_devicename); 85 if ((it != _handlers.end()) && (*it == ref)) 86 { 87 VERBOSE(VB_RECORD, QString("HDHRSH: Closing handler for %1").arg(ref->_devicename)); 88 ref->Close(); 89 delete *it; 90 _handlers.erase(it); 91 } else { 92 VERBOSE(VB_IMPORTANT, QString("HDHRSH: Couldn't find handler for %1").arg(ref->_devicename)); 93 } 94 95 _handlers_refcnt.erase(rit); 96 ref=NULL; 97 } 98 99 HDHRStreamHandler::HDHRStreamHandler(uint device_id, uint tuner, QString devicename) : 100 _control_socket(NULL), 101 _video_socket(NULL), 102 _device_id(device_id), 103 _tuner(tuner), 104 _devicename(devicename), 105 _allow_retune(false), 106 107 _start_stop_lock(true), 108 _running(false), 109 110 111 _sigmon(NULL), 112 _channel(NULL), 113 114 _pid_lock(true), 115 _listener_lock(true), 116 _hdhr_lock(true) 117 { 118 } 119 120 HDHRStreamHandler::~HDHRStreamHandler() 121 { 122 assert(_stream_data_list.empty()); 123 } 124 125 bool HDHRStreamHandler::Open() 126 { 127 if (!FindDevice()) 128 return false; 129 130 return Connect(); 131 } 132 133 void HDHRStreamHandler::Close() 134 { 135 if (_control_socket) 136 { 137 TuneChannel("none"); 138 hdhomerun_control_destroy(_control_socket); 139 _control_socket=NULL; 140 } 141 } 142 143 bool HDHRStreamHandler::Connect() 144 { 145 _control_socket = hdhomerun_control_create(_device_id, _device_ip); 146 147 if (!_control_socket) 148 { 149 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to create control socket"); 150 return false; 151 } 152 153 if (hdhomerun_control_get_local_addr(_control_socket) == 0) 154 { 155 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to connect to device"); 156 return false; 157 } 158 159 VERBOSE(VB_CHANNEL, LOC + "Successfully connected to device"); 160 return true; 161 } 162 163 bool HDHRStreamHandler::FindDevice(void) 164 { 165 if (!_device_id) 166 return _device_ip; 167 168 _device_ip = 0; 169 170 /* Discover. */ 171 struct hdhomerun_discover_device_t result; 172 int ret = hdhomerun_discover_find_devices_custom(0, HDHOMERUN_DEVICE_TYPE_WILDCARD, _device_id, &result, 1); 173 if (ret < 0) 174 { 175 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to send discovery request" + ENO); 176 return false; 177 } 178 if (ret == 0) 179 { 180 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("device not found")); 181 return false; 182 } 183 184 /* Found. */ 185 _device_ip = result.ip_addr; 186 187 VERBOSE(VB_IMPORTANT, LOC + 188 QString("device found at address %1.%2.%3.%4") 189 .arg((_device_ip>>24) & 0xFF).arg((_device_ip>>16) & 0xFF) 190 .arg((_device_ip>> 8) & 0xFF).arg((_device_ip>> 0) & 0xFF)); 191 192 return true; 193 } 194 195 196 bool HDHRStreamHandler::EnterPowerSavingMode(void) 197 { 198 if (_video_socket) 199 { 200 VERBOSE(VB_CHANNEL, LOC + "Ignoring request - video streaming active"); 201 return false; 202 } 203 else 204 { 205 return TuneChannel("none"); 206 /* QString::null != TunerSet("channel", "none", false); */ 207 } 208 } 209 210 QString HDHRStreamHandler::DeviceGet(const QString &name, bool report_error_return) 211 { 212 QMutexLocker locker(&_hdhr_lock); 213 214 if (!_control_socket) 215 { 216 VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed (not connected)"); 217 return QString::null; 218 } 219 220 char *value = NULL; 221 char *error = NULL; 222 if (hdhomerun_control_get(_control_socket, name, &value, &error) < 0) 223 { 224 VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed" + ENO); 225 return QString::null; 226 } 227 228 if (report_error_return && error) 229 { 230 VERBOSE(VB_IMPORTANT, LOC_ERR + 231 QString("DeviceGet(%1): %2").arg(name).arg(error)); 232 233 return QString::null; 234 } 235 236 return QString(value); 237 } 238 239 240 QString HDHRStreamHandler::DeviceSet(const QString &name, const QString &val, 241 bool report_error_return) 242 { 243 QMutexLocker locker(&_hdhr_lock); 244 245 if (!_control_socket) 246 { 247 VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed (not connected)"); 248 return QString::null; 249 } 250 251 char *value = NULL; 252 char *error = NULL; 253 if (hdhomerun_control_set(_control_socket, name, val, &value, &error) < 0) 254 { 255 VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed" + ENO); 256 257 return QString::null; 258 } 259 260 if (report_error_return && error) 261 { 262 VERBOSE(VB_IMPORTANT, LOC_ERR + 263 QString("DeviceSet(%1 %2): %3").arg(name).arg(val).arg(error)); 264 265 return QString::null; 266 } 267 268 return QString(value); 269 } 270 271 QString HDHRStreamHandler::TunerGet(const QString &name, bool report_error_return) 272 { 273 return DeviceGet(QString("/tuner%1/%2").arg(_tuner).arg(name), 274 report_error_return); 275 } 276 277 QString HDHRStreamHandler::TunerSet(const QString &name, const QString &value, 278 bool report_error_return) 279 { 280 return DeviceSet(QString("/tuner%1/%2").arg(_tuner).arg(name), value, 281 report_error_return); 282 } 283 284 bool HDHRStreamHandler::DeviceSetTarget(unsigned short localPort) 285 { 286 if (localPort == 0) 287 { 288 return false; 289 } 290 291 unsigned long localIP = hdhomerun_control_get_local_addr(_control_socket); 292 if (localIP == 0) 293 { 294 return false; 295 } 296 297 QString configValue = QString("%1.%2.%3.%4:%5") 298 .arg((localIP >> 24) & 0xFF).arg((localIP >> 16) & 0xFF) 299 .arg((localIP >> 8) & 0xFF).arg((localIP >> 0) & 0xFF) 300 .arg(localPort); 301 302 if (!TunerSet("target", configValue)) 303 { 304 return false; 305 } 306 307 return true; 308 } 309 310 bool HDHRStreamHandler::DeviceClearTarget() 311 { 312 return (QString::null != TunerSet("target", "0.0.0.0:0")); 313 } 314 315 QString HDHRStreamHandler::GetTunerStatus() { 316 return TunerGet("status"); 317 } 318 319 bool HDHRStreamHandler::Connected() { 320 // FIXME 321 return (_control_socket != NULL); 322 } 323 324 bool HDHRStreamHandler::TuneChannel(QString chn) { 325 QString current = TunerGet("channel"); 326 if (current == chn) 327 { 328 VERBOSE(VB_RECORD, QString(LOC + "Not Re-Tuning channel %1").arg(chn)); 329 return true; 330 } 331 VERBOSE(VB_RECORD, QString(LOC + "Tuning channel %1 (was %2)").arg(chn).arg(current)); 332 return (QString::null != TunerSet("channel", chn)); 333 } 334 335 bool HDHRStreamHandler::TuneProgram(QString pnum) { 336 VERBOSE(VB_RECORD, QString(LOC + "Tuning program %1").arg(pnum)); 337 return (QString::null != TunerSet("program", pnum, false)); 338 } 339 340 void HDHRStreamHandler::AddListener(MPEGStreamData *data) 341 { 342 VERBOSE(VB_RECORD, LOC + "AddListener("<<data<<") -- begin"); 343 assert(data); 344 345 _listener_lock.lock(); 346 347 VERBOSE(VB_RECORD, LOC + "AddListener("<<data<<") -- locked"); 348 349 _stream_data_list.push_back(data); 350 351 _listener_lock.unlock(); 352 353 Start(); 354 355 VERBOSE(VB_RECORD, LOC + "AddListener("<<data<<") -- end"); 356 } 357 358 void HDHRStreamHandler::RemoveListener(MPEGStreamData *data) 359 { 360 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<data<<") -- begin"); 361 assert(data); 362 363 _listener_lock.lock(); 364 365 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<data<<") -- locked"); 366 367 vector<MPEGStreamData*>::iterator it = 368 find(_stream_data_list.begin(), _stream_data_list.end(), data); 369 370 if (it != _stream_data_list.end()) 371 _stream_data_list.erase(it); 372 373 if (_stream_data_list.empty()) 374 { 375 _listener_lock.unlock(); 376 Stop(); 377 } 378 else 379 { 380 _listener_lock.unlock(); 381 } 382 383 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<data<<") -- end"); 384 } 385 386 void *run_hdhr_stream_handler_thunk(void *param) 387 { 388 HDHRStreamHandler *mon = (HDHRStreamHandler*) param; 389 mon->Run(); 390 return NULL; 391 } 392 393 void HDHRStreamHandler::Start(void) 394 { 395 QMutexLocker locker(&_start_stop_lock); 396 397 _eit_pids.clear(); 398 399 if (!IsRunning()) 400 { 401 pthread_create(&_reader_thread, NULL, 402 run_hdhr_stream_handler_thunk, this); 403 404 while (!IsRunning()) 405 _running_state_changed.wait(100); 406 } 407 } 408 409 void HDHRStreamHandler::Stop(void) 410 { 411 QMutexLocker locker(&_start_stop_lock); 412 413 if (IsRunning()) 414 { 415 SetRunning(false); 416 pthread_join(_reader_thread, NULL); 417 } 418 } 419 420 void HDHRStreamHandler::Run(void) 421 { 422 SetRunning(true); 423 RunTS(); 424 } 425 426 /** \fn HDHRStreamHandler::RunTS(void) 427 * \brief Uses TS filtering devices to read a DVB device for tables & data 428 * 429 * This supports all types of MPEG based stream data, but is extreemely 430 * slow with DVB over USB 1.0 devices which for efficiency reasons buffer 431 * a stream until a full block transfer buffer full of the requested 432 * tables is available. This takes a very long time when you are just 433 * waiting for a PAT or PMT table, and the buffer is hundreds of packets 434 * in size. 435 */ 436 void HDHRStreamHandler::RunTS(void) 437 { 438 int remainder = 0; 439 VERBOSE(VB_RECORD, LOC + "RunTS()"); 440 441 /* Calculate buffer size */ 442 uint buffersize = gContext->GetNumSetting( 443 "HDRingbufferSize", 50 * TSPacket::SIZE) * 1024; 444 buffersize /= VIDEO_DATA_PACKET_SIZE; 445 buffersize *= VIDEO_DATA_PACKET_SIZE; 446 447 // Buffer should be at least about 1MB.. 448 buffersize = max(49 * TSPacket::SIZE * 128, buffersize); 449 450 VERBOSE(VB_GENERAL, QString(LOC + "HD Ringbuffer size = %1 KB").arg(buffersize / 1024)); 451 452 /* Create TS socket. */ 453 _video_socket = hdhomerun_video_create(0, buffersize); 454 if (!_video_socket) 455 { 456 VERBOSE(VB_IMPORTANT, LOC + "Open() failed to open socket"); 457 return; 458 } 459 460 uint localPort = hdhomerun_video_get_local_port(_video_socket); 461 if (!DeviceSetTarget(localPort)) 462 { 463 VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting recording (set target failed). Aborting."); 464 return; 465 } 466 hdhomerun_video_flush(_video_socket); 467 468 bool _error = false; 469 470 VERBOSE(VB_RECORD, LOC + "RunTS(): begin"); 471 472 int loopcount=0; 473 size_t data_count=0; 474 while (IsRunning() && !_error) 475 { 476 loopcount++; 477 if (0 == (loopcount % 1000)) { 478 QMutexLocker locker(&_listener_lock); 479 VERBOSE(VB_RECORD, LOC + QString("RunTS(): loopcount = %1, datacount = %2, listen") 480 .arg(loopcount).arg(data_count)); 481 data_count=0; 482 } 483 UpdateFiltersFromStreamData(); 484 485 size_t read_size = 64 * 1024; // read about 64KB 486 read_size /= VIDEO_DATA_PACKET_SIZE; 487 read_size *= VIDEO_DATA_PACKET_SIZE; 488 489 size_t data_length; 490 unsigned char *data_buffer = 491 hdhomerun_video_recv(_video_socket, read_size, &data_length); 492 493 if (! data_buffer) 494 { 495 usleep(5000); 496 continue; 497 } 498 499 data_count+=data_length; 500 // Assume data_length is a multiple of 188 (packet size) 501 ASSERT(0 == ( data_length % 188) ); 502 503 _listener_lock.lock(); 504 505 if (_stream_data_list.empty()) 506 { 507 _listener_lock.unlock(); 508 continue; 509 } 510 511 for (uint i = 0; i < _stream_data_list.size(); i++) 512 { 513 remainder = _stream_data_list[i]->ProcessData(data_buffer, data_length); 514 } 515 516 _listener_lock.unlock(); 517 if (remainder != 0) 518 VERBOSE(VB_GENERAL, QString(LOC + "RunTS(): data_length = %1 remainder = %2") 519 .arg(data_length).arg(remainder)); 520 } 521 VERBOSE(VB_RECORD, LOC + "RunTS(): " + "shutdown"); 522 523 DelAllPIDs(); 524 525 DeviceClearTarget(); 526 VERBOSE(VB_RECORD, LOC + "RunTS(): " + "end"); 527 528 hdhomerun_video_sock_t* tmp_video_socket; 529 { 530 QMutexLocker locker(&_hdhr_lock); 531 tmp_video_socket = _video_socket; 532 _video_socket=NULL; 533 } 534 535 hdhomerun_video_destroy(tmp_video_socket); 536 537 SetRunning(false); 538 } 539 540 bool HDHRStreamHandler::AddPID(uint pid, bool do_update) 541 { 542 QMutexLocker locker(&_pid_lock); 543 544 vector<uint>::iterator it; 545 it = lower_bound(_pid_info.begin(), _pid_info.end(), pid); 546 if (it != _pid_info.end() && *it == pid) 547 { 548 #ifdef DEBUG_PID_FILTERS 549 VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<", " << do_update << ") NOOP"); 550 #endif // DEBUG_PID_FILTERS 551 return true; 552 } 553 554 _pid_info.insert(it, pid); 555 556 #ifdef DEBUG_PID_FILTERS 557 VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<")", " << do_update << "); 558 #endif // DEBUG_PID_FILTERS 559 560 if (do_update) 561 return UpdateFilters(); 562 return true; 563 } 564 565 bool HDHRStreamHandler::DelPID(uint pid, bool do_update) 566 { 567 QMutexLocker locker(&_pid_lock); 568 569 vector<uint>::iterator it; 570 it = lower_bound(_pid_info.begin(), _pid_info.end(), pid); 571 if (it == _pid_info.end()) 572 { 573 #ifdef DEBUG_PID_FILTERS 574 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<", " << do_update << ") NOOP"); 575 #endif // DEBUG_PID_FILTERS 576 577 return true; 578 } 579 580 if (*it == pid) 581 { 582 #ifdef DEBUG_PID_FILTERS 583 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<", " << do_update << ") -- found"); 584 #endif // DEBUG_PID_FILTERS 585 _pid_info.erase(it); 586 } 587 else 588 { 589 #ifdef DEBUG_PID_FILTERS 590 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<", " << do_update << ") -- failed"); 591 #endif // DEBUG_PID_FILTERS 592 } 593 594 if (do_update) 595 return UpdateFilters(); 596 return true; 597 } 598 599 bool HDHRStreamHandler::DelAllPIDs(void) 600 { 601 QMutexLocker locker(&_pid_lock); 602 603 #ifdef DEBUG_PID_FILTERS 604 VERBOSE(VB_CHANNEL, "DelAllPID()"); 605 #endif // DEBUG_PID_FILTERS 606 607 _pid_info.clear(); 608 609 return UpdateFilters(); 610 } 611 612 QString filt_str(uint pid) 613 { 614 uint pid0 = (pid / (16*16*16)) % 16; 615 uint pid1 = (pid / (16*16)) % 16; 616 uint pid2 = (pid / (16)) % 16; 617 uint pid3 = pid % 16; 618 return QString("0x%1%2%3%4") 619 .arg(pid0,0,16).arg(pid1,0,16) 620 .arg(pid2,0,16).arg(pid3,0,16); 621 } 622 623 bool HDHRStreamHandler::UpdateFilters(void) 624 { 625 #ifdef DEBUG_PID_FILTERS 626 VERBOSE(VB_CHANNEL, LOC + "UpdateFilters()"); 627 #endif // DEBUG_PID_FILTERS 628 QMutexLocker locker(&_pid_lock); 629 630 QString filter = ""; 631 632 vector<uint> range_min; 633 vector<uint> range_max; 634 635 // FIXME 636 // if (_ignore_filters) 637 // return true; 638 639 for (uint i = 0; i < _pid_info.size(); i++) 640 { 641 uint pid_min = _pid_info[i]; 642 uint pid_max = pid_min; 643 for (uint j = i + 1; j < _pid_info.size(); j++) 644 { 645 if (pid_max + 1 != _pid_info[j]) 646 break; 647 pid_max++; 648 i++; 649 } 650 range_min.push_back(pid_min); 651 range_max.push_back(pid_max); 652 } 653 if (range_min.size() > 16) 654 { 655 range_min.resize(16); 656 uint pid_max = range_max.back(); 657 range_max.resize(15); 658 range_max.push_back(pid_max); 659 } 660 661 for (uint i = 0; i < range_min.size(); i++) 662 { 663 filter += filt_str(range_min[i]); 664 if (range_min[i] != range_max[i]) 665 filter += QString("-%1").arg(filt_str(range_max[i])); 666 filter += " "; 667 } 668 669 filter = filter.stripWhiteSpace(); 670 671 QString new_filter = TunerSet("filter", filter); 672 673 #ifdef DEBUG_PID_FILTERS 674 QString msg = QString("Filter: '%1'").arg(filter); 675 if (filter != new_filter) 676 msg += QString("\n\t\t\t\t'%2'").arg(new_filter); 677 678 VERBOSE(VB_CHANNEL, LOC + msg); 679 #endif // DEBUG_PID_FILTERS 680 681 return filter == new_filter; 682 } 683 684 void HDHRStreamHandler::UpdateListeningForEIT(void) 685 { 686 vector<uint> add_eit, del_eit; 687 688 QMutexLocker read_locker(&_listener_lock); 689 690 for (uint i = 0; i < _stream_data_list.size(); i++) 691 { 692 MPEGStreamData *sd = _stream_data_list[i]; 693 if (sd->HasEITPIDChanges(_eit_pids) && 694 sd->GetEITPIDChanges(_eit_pids, add_eit, del_eit)) 695 { 696 for (uint i = 0; i < del_eit.size(); i++) 697 { 698 uint_vec_t::iterator it; 699 it = find(_eit_pids.begin(), _eit_pids.end(), del_eit[i]); 700 if (it != _eit_pids.end()) 701 _eit_pids.erase(it); 702 sd->RemoveListeningPID(del_eit[i]); 703 } 704 705 for (uint i = 0; i < add_eit.size(); i++) 706 { 707 _eit_pids.push_back(add_eit[i]); 708 sd->AddListeningPID(add_eit[i]); 709 } 710 } 711 } 712 } 713 714 bool HDHRStreamHandler::UpdateFiltersFromStreamData(void) 715 { 716 717 UpdateListeningForEIT(); 718 719 pid_map_t pids; 720 721 { 722 QMutexLocker read_locker(&_listener_lock); 723 724 for (uint i = 0; i < _stream_data_list.size(); i++) 725 _stream_data_list[i]->GetPIDs(pids); 726 } 727 728 uint_vec_t add_pids; 729 vector<uint> del_pids; 730 731 { 732 QMutexLocker read_locker(&_pid_lock); 733 734 // PIDs that need to be added.. 735 pid_map_t::const_iterator lit = pids.constBegin(); 736 for (; lit != pids.constEnd(); ++lit) 737 { 738 vector<uint>::iterator it; 739 it = lower_bound(_pid_info.begin(), _pid_info.end(), lit.key()); 740 if (! (it != _pid_info.end() && *it == lit.key())) { 741 add_pids.push_back(lit.key()); 742 } 743 } 744 745 // PIDs that need to be removed.. 746 vector<uint>::iterator fit = _pid_info.begin(); 747 for (; fit != _pid_info.end(); ++fit) 748 { 749 pid_map_t::const_iterator it = pids.find(*fit); 750 if(it == pids.end()) 751 del_pids.push_back(*fit); 752 } 753 } 754 755 bool need_update = false; 756 757 // Remove PIDs 758 bool ok = true; 759 vector<uint>::iterator dit = del_pids.begin(); 760 for (; dit != del_pids.end(); ++dit) 761 { 762 need_update = true; 763 ok &= DelPID(*dit, false); 764 } 765 766 // Add PIDs 767 vector<uint>::iterator ait = add_pids.begin(); 768 for (; ait != add_pids.end(); ++ait) 769 { 770 need_update = true; 771 ok &= AddPID(*ait, false); 772 } 773 774 if (need_update) 775 return UpdateFilters(); 776 777 return ok; 778 } 779 780 void HDHRStreamHandler::SetRetuneAllowed( 781 bool allow, 782 DTVSignalMonitor *sigmon, 783 HDHRChannel *hdhrchan) 784 { 785 if (allow && sigmon && hdhrchan) 786 { 787 _allow_retune = true; 788 _sigmon = sigmon; 789 _channel = hdhrchan; 790 } 791 else 792 { 793 _allow_retune = false; 794 _sigmon = NULL; 795 _channel = NULL; 796 } 797 } 798 799 /** \fn HDHRStreamHandler::SupportsTSMonitoring(void) 800 * \brief Returns true if TS monitoring is supported. 801 * 802 * NOTE: If you are using a DEC2000-t device you need to 803 * apply the patches provided by Peter Beutner for it, see 804 * http://www.gossamer-threads.com/lists/mythtv/dev/166172 805 * These patches should make it in to Linux 2.6.15 or 2.6.16. 806 */ 807 bool HDHRStreamHandler::SupportsTSMonitoring(void) 808 { 809 return false; 810 811 // FIXME 812 #if 0 813 const uint pat_pid = 0x0; 814 815 { 816 QMutexLocker locker(&_rec_supports_ts_monitoring_lock); 817 QMap<uint,bool>::const_iterator it; 818 it = _rec_supports_ts_monitoring.find(_dvb_dev_num); 819 if (it != _rec_supports_ts_monitoring.end()) 820 return *it; 821 } 822 823 int dvr_fd = open(_dvr_dev_path.ascii(), O_RDONLY | O_NONBLOCK); 824 if (dvr_fd < 0) 825 { 826 QMutexLocker locker(&_rec_supports_ts_monitoring_lock); 827 _rec_supports_ts_monitoring[_dvb_dev_num] = false; 828 return false; 829 } 830 831 bool supports_ts = false; 832 if (AddPIDFilter(new PIDInfoHDHR(pat_pid))) 833 { 834 supports_ts = true; 835 RemovePIDFilter(pat_pid); 836 } 837 838 close(dvr_fd); 839 840 QMutexLocker locker(&_rec_supports_ts_monitoring_lock); 841 _rec_supports_ts_monitoring[_dvb_dev_num] = supports_ts; 842 843 return supports_ts; 844 #endif 845 } 846 847 void HDHRStreamHandler::SetRunning(bool is_running) 848 { 849 _running = is_running; 850 _running_state_changed.wakeAll(); 851 } 852 853 PIDPriority HDHRStreamHandler::GetPIDPriority(uint pid) const 854 { 855 QMutexLocker reading_locker(&_listener_lock); 856 857 PIDPriority tmp = kPIDPriorityNone; 858 859 for (uint i = 0; i < _stream_data_list.size(); i++) 860 tmp = max(tmp, _stream_data_list[i]->GetPIDPriority(pid)); 861 862 return tmp; 863 } -
mythtv/libs/libmythtv/hdhrstreamhandler.h
diff -r -u -N -X diff.exclude -x release.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/hdhrstreamhandler.h release.19740.0119b/mythtv/libs/libmythtv/hdhrstreamhandler.h
1 // -*- Mode: c++ -*- 2 3 #ifndef _HDHRSTREAMHANDLER_H_ 4 #define _HDHRSTREAMHANDLER_H_ 5 6 #include <vector> 7 using namespace std; 8 9 #include <qmap.h> 10 #include <qmutex.h> 11 12 #include "util.h" 13 #include "DeviceReadBuffer.h" 14 #include "mpegstreamdata.h" 15 16 class QString; 17 class HDHRStreamHandler; 18 class DTVSignalMonitor; 19 class HDHRChannel; 20 class DeviceReadBuffer; 21 22 // HDHomeRun headers 23 #ifdef USING_HDHOMERUN 24 #include "hdhomerun_includes.h" 25 #else 26 struct hdhomerun_control_sock_t { int dummy; }; 27 #endif 28 29 typedef QMap<uint,int> FilterMap; 30 31 //#define RETUNE_TIMEOUT 5000 32 33 class HDHRStreamHandler : public ReaderPausedCB 34 { 35 friend void *run_hdhr_stream_handler_thunk(void *param); 36 37 public: 38 static HDHRStreamHandler *Get(uint device_id, uint tuner, QString devicename); 39 static void Return(HDHRStreamHandler * & ref); 40 41 void AddListener(MPEGStreamData *data); 42 void RemoveListener(MPEGStreamData *data); 43 44 void RetuneMonitor(void); 45 46 bool IsRunning(void) const { return _running; } 47 bool IsRetuneAllowed(void) const { return _allow_retune; } 48 49 void SetRetuneAllowed(bool allow, 50 DTVSignalMonitor *sigmon, 51 HDHRChannel *dvbchan); 52 53 // ReaderPausedCB 54 virtual void ReaderPaused(int fd) { (void) fd; } 55 56 QString GetTunerStatus(void); 57 58 bool Connected(); 59 bool TuneChannel(QString ); 60 bool TuneProgram(QString ); 61 62 bool EnterPowerSavingMode(); 63 64 private: 65 66 bool FindDevice(); 67 bool Connect(void); 68 69 QString DeviceGet(const QString &name, bool report_error_return = true); 70 QString DeviceSet(const QString &name, const QString &value, 71 bool report_error_return = true); 72 73 QString TunerGet(const QString &name, bool report_error_return = true); 74 QString TunerSet(const QString &name, const QString &value, 75 bool report_error_return = true); 76 77 bool DeviceSetTarget(short unsigned int); 78 bool DeviceClearTarget(); 79 80 HDHRStreamHandler(uint, uint, QString); 81 ~HDHRStreamHandler(); 82 83 bool Open(void); 84 void Close(); 85 86 void Start(void); 87 void Stop(void); 88 89 void Run(void); 90 void RunTS(void); 91 92 void UpdateListeningForEIT(void); 93 bool UpdateFiltersFromStreamData(void); 94 95 // Commands 96 bool AddPID(uint pid, bool do_update = true); 97 bool DelPID(uint pid, bool do_update = true); 98 bool DelAllPIDs(void); 99 bool UpdateFilters(void); 100 101 void SetRunning(bool); 102 103 PIDPriority GetPIDPriority(uint pid) const; 104 bool SupportsTSMonitoring(void); 105 106 private: 107 hdhomerun_control_sock_t *_control_socket; 108 hdhomerun_video_sock_t *_video_socket; 109 uint _device_id; 110 uint _device_ip; 111 uint _tuner; 112 QString _devicename; 113 114 bool _allow_retune; 115 116 mutable QMutex _start_stop_lock; 117 bool _running; 118 QWaitCondition _running_state_changed; 119 pthread_t _reader_thread; 120 DTVSignalMonitor *_sigmon; 121 HDHRChannel *_channel; 122 123 mutable QMutex _pid_lock; 124 vector<uint> _eit_pids; 125 vector<uint> _pid_info; 126 uint _open_pid_filters; 127 MythTimer _cycle_timer; 128 129 mutable QMutex _listener_lock; 130 vector<MPEGStreamData*> _stream_data_list; 131 132 mutable QMutex _hdhr_lock; 133 134 // for caching TS monitoring supported value. 135 static QMutex _rec_supports_ts_monitoring_lock; 136 static QMap<uint,bool> _rec_supports_ts_monitoring; 137 138 // for implementing Get & Return 139 static QMutex _handlers_lock; 140 static QMap<QString, HDHRStreamHandler*> _handlers; 141 static QMap<QString, uint> _handlers_refcnt; 142 }; 143 144 #endif // _HDHRSTREAMHANDLER_H_ -
mythtv/libs/libmythtv/libmythtv.pro
diff -r -u -N -X diff.exclude -x release.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/libmythtv.pro release.19740.0119b/mythtv/libs/libmythtv/libmythtv.pro
451 451 using_hdhomerun { 452 452 # MythTV HDHomeRun glue 453 453 HEADERS += hdhrsignalmonitor.h hdhrchannel.h 454 HEADERS += hdhrrecorder.h 454 HEADERS += hdhrrecorder.h hdhrstreamhandler.h 455 455 456 456 SOURCES += hdhrsignalmonitor.cpp hdhrchannel.cpp 457 SOURCES += hdhrrecorder.cpp 457 SOURCES += hdhrrecorder.cpp hdhrstreamhandler.cpp 458 458 459 459 DEFINES += USING_HDHOMERUN 460 460 -
mythtv/libs/libmythtv/tv_rec.cpp
diff -r -u -N -X diff.exclude -x release.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/tv_rec.cpp release.19740.0119b/mythtv/libs/libmythtv/tv_rec.cpp
4080 4080 } 4081 4081 recorder->Reset(); 4082 4082 4083 #ifdef USING_HDHOMERUN4084 if (GetHDHRRecorder())4085 {4086 pauseNotify = false;4087 GetHDHRRecorder()->Close();4088 pauseNotify = true;4089 GetHDHRRecorder()->Open();4090 GetHDHRRecorder()->StartData();4091 }4092 #endif // USING_HDHOMERUN4093 4094 4083 // Set file descriptor of channel from recorder for V4L 4095 4084 channel->SetFd(recorder->GetVideoFd()); 4096 4085 -
mythtv/libs/libmythtv/videosource.cpp
diff -r -u -N -X diff.exclude -x release.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/videosource.cpp release.19740.0119b/mythtv/libs/libmythtv/videosource.cpp
131 131 class RecorderOptions : public ConfigurationWizard 132 132 { 133 133 public: 134 RecorderOptions(CaptureCard& parent );134 RecorderOptions(CaptureCard& parent, QString type); 135 135 uint GetInstanceCount(void) const { return (uint) count->intValue(); } 136 136 137 137 private: … … 1355 1355 addChild(new SignalTimeout(parent, 1000, 250)); 1356 1356 addChild(new ChannelTimeout(parent, 3000, 1750)); 1357 1357 addChild(new SingleCardInput(parent)); 1358 //addChild(new InstanceCount(parent)); 1359 1360 TransButtonSetting *buttonRecOpt = new TransButtonSetting(); 1361 buttonRecOpt->setLabel(tr("Recording Options")); 1362 addChild(buttonRecOpt); 1363 1364 connect(buttonRecOpt, SIGNAL(pressed()), 1365 &parent, SLOT( recorderOptionsPanelHDHomerun())); 1366 1367 1358 1368 }; 1359 1369 1360 1370 private: … … 1504 1514 { 1505 1515 MSqlQuery query(MSqlQuery::InitCon()); 1506 1516 QString qstr = 1507 "SELECT cardid, videodevice, cardtype "1517 "SELECT cardid, videodevice, cardtype, dbox2_port " 1508 1518 "FROM capturecard " 1509 1519 "WHERE hostname = :HOSTNAME " 1510 1520 "ORDER BY cardid"; … … 1524 1534 uint cardid = query.value(0).toUInt(); 1525 1535 QString videodevice = query.value(1).toString(); 1526 1536 QString cardtype = query.value(2).toString(); 1537 QString hdhrTuner = query.value(3).toString(); 1527 1538 1528 1539 if ((cardtype.lower() == "dvb") && (1 != ++device_refs[videodevice])) 1529 1540 continue; 1530 1541 1542 if (cardtype.lower() == "hdhomerun") 1543 { 1544 QString altvideodevice = videodevice + ":" + hdhrTuner; 1545 if (1 != ++device_refs[altvideodevice]) 1546 continue; 1547 } 1548 1531 1549 QString label = CardUtil::GetDeviceLabel( 1532 1550 cardid, cardtype, videodevice); 1533 1551 … … 1548 1566 if (CardUtil::IsTunerSharingCapable(type)) 1549 1567 { 1550 1568 QString dev = CardUtil::GetVideoDevice(cardid); 1551 vector<uint> cardids = CardUtil::GetCardIDs(dev, type); 1552 new_cnt = cardids.size(); 1569 if (type == "HDHOMERUN") 1570 { 1571 uint hdhrTuner = CardUtil::GetHDHRTuner(cardid); 1572 vector<uint> cardids = CardUtil::GetCardIDs(dev, hdhrTuner); 1573 new_cnt = cardids.size(); 1574 } 1575 else 1576 { 1577 vector<uint> cardids = CardUtil::GetCardIDs(dev, type); 1578 new_cnt = cardids.size(); 1579 } 1553 1580 } 1554 1581 } 1555 1582 instance_count = new_cnt; … … 1576 1603 1577 1604 if (!init_cardid) 1578 1605 { 1606 uint cid_size = 0; 1579 1607 QString dev = CardUtil::GetVideoDevice(cardid); 1580 vector<uint> cardids = CardUtil::GetCardIDs(dev, type); 1581 if (cardids.size() > 1) 1608 if (type == "HDHOMERUN") 1609 { 1610 uint hdhrTuner = CardUtil::GetHDHRTuner(cardid); 1611 vector<uint> cardids = CardUtil::GetCardIDs(dev, hdhrTuner); 1612 cid_size = cardids.size(); 1613 } 1614 else 1615 { 1616 vector<uint> cardids = CardUtil::GetCardIDs(dev, type); 1617 cid_size = cardids.size(); 1618 } 1619 if (cid_size > 1) 1582 1620 { 1583 1621 VERBOSE(VB_IMPORTANT, 1584 1622 "A card using this video device already exists!"); … … 1587 1625 return; 1588 1626 } 1589 1627 1590 vector<uint> cardids = CardUtil::GetCardIDs(init_dev, type); 1628 vector<uint> cardids; 1629 if (type == "HDHOMERUN") 1630 { 1631 uint hdhrTuner = CardUtil::GetHDHRTuner(cardid); 1632 cardids = CardUtil::GetCardIDs(init_dev, hdhrTuner); 1633 } 1634 else 1635 { 1636 cardids = CardUtil::GetCardIDs(init_dev, type); 1637 } 1591 1638 1592 1639 if (!instance_count) 1593 1640 instance_count = max((size_t)0, cardids.size()) + 1; … … 2644 2691 2645 2692 MSqlQuery query(MSqlQuery::InitCon()); 2646 2693 query.prepare( 2647 "SELECT cardid, videodevice, cardtype "2694 "SELECT cardid, videodevice, cardtype, dbox2_port " 2648 2695 "FROM capturecard " 2649 2696 "WHERE hostname = :HOSTNAME " 2650 2697 "ORDER BY cardid"); … … 2663 2710 uint cardid = query.value(0).toUInt(); 2664 2711 QString videodevice = query.value(1).toString(); 2665 2712 QString cardtype = query.value(2).toString(); 2713 QString hdhrTuner = query.value(3).toString(); 2666 2714 2667 2715 if ((cardtype.lower() == "dvb") && (1 != ++device_refs[videodevice])) 2668 2716 continue; 2669 2717 2718 if (cardtype.lower() == "hdhomerun") 2719 { 2720 QString altvideodevice = videodevice + ":" + hdhrTuner; 2721 if (1 != ++device_refs[altvideodevice]) 2722 continue; 2723 } 2724 2725 2670 2726 QStringList inputLabels; 2671 2727 vector<CardInput*> cardInputs; 2672 2728 … … 2908 2964 connect(buttonDiSEqC, SIGNAL(pressed()), 2909 2965 this, SLOT( DiSEqCPanel())); 2910 2966 connect(buttonRecOpt, SIGNAL(pressed()), 2911 &parent, SLOT( recorderOptionsPanel ()));2967 &parent, SLOT( recorderOptionsPanelDVB())); 2912 2968 } 2913 2969 2914 2970 DVBConfigurationGroup::~DVBConfigurationGroup() … … 2953 3009 } 2954 3010 } 2955 3011 2956 void CaptureCard::recorderOptionsPanel() 3012 void CaptureCard::recorderOptionsPanelHDHomerun() 3013 { 3014 reload(); 3015 3016 RecorderOptions acw(*this, "HDHOMERUN"); 3017 acw.exec(); 3018 instance_count = acw.GetInstanceCount(); 3019 } 3020 3021 void CaptureCard::recorderOptionsPanelDVB() 2957 3022 { 2958 3023 reload(); 2959 3024 2960 RecorderOptions acw(*this );3025 RecorderOptions acw(*this, "DVB"); 2961 3026 acw.exec(); 2962 3027 instance_count = acw.GetInstanceCount(); 2963 3028 } 2964 3029 2965 RecorderOptions::RecorderOptions(CaptureCard &parent )3030 RecorderOptions::RecorderOptions(CaptureCard &parent, QString type) 2966 3031 : count(new InstanceCount(parent)) 2967 3032 { 2968 3033 VerticalConfigurationGroup* rec = new VerticalConfigurationGroup(false); … … 2970 3035 rec->setUseLabel(false); 2971 3036 2972 3037 rec->addChild(count); 2973 rec->addChild(new DVBNoSeqStart(parent)); 2974 rec->addChild(new DVBOnDemand(parent)); 2975 rec->addChild(new DVBEITScan(parent)); 2976 rec->addChild(new DVBTuningDelay(parent)); 3038 if (type == "DVB") 3039 { 3040 rec->addChild(new DVBNoSeqStart(parent)); 3041 rec->addChild(new DVBOnDemand(parent)); 3042 rec->addChild(new DVBEITScan(parent)); 3043 rec->addChild(new DVBTuningDelay(parent)); 3044 } 2977 3045 2978 3046 addChild(rec); 2979 3047 } 3048 -
mythtv/libs/libmythtv/videosource.h
diff -r -u -N -X diff.exclude -x release.19740.0119a -x release.19740.0119b release.19740.0119a/mythtv/libs/libmythtv/videosource.h release.19740.0119b/mythtv/libs/libmythtv/videosource.h
477 477 uint GetInstanceCount(void) const { return instance_count; } 478 478 479 479 public slots: 480 void recorderOptionsPanel(); 480 void recorderOptionsPanelDVB(); 481 void recorderOptionsPanelHDHomerun(); 481 482 482 483 private: 483 484