Ticket #6138: 133-hdhr.multirec.fixes.11.patch
File 133-hdhr.multirec.fixes.11.patch, 86.8 KB (added by , 16 years ago) |
---|
-
mythtv/libs/libmythtv/cardutil.cpp
diff -p -r -u -N -X /tmp/diff.exclude -x release.21404.0821a -x release.21404.0821b release.21404.0821a/mythtv/libs/libmythtv/cardutil.cpp release.21404.0821b/mythtv/libs/libmythtv/cardutil.cpp
28 28 #include "videodev_myth.h" 29 29 #endif 30 30 31 #include "hdhomerun/hdhomerun.h" 32 31 33 #define LOC QString("CardUtil: ") 32 34 #define LOC_WARN QString("CardUtil, Warning: ") 33 35 #define LOC_ERR QString("CardUtil, Error: ") … … QStringVec CardUtil::ProbeVideoDevices(c 197 199 for (uint i = 0; i < list.size(); i++) 198 200 devs.push_back(QString::number(list[i])); 199 201 } 202 else if (rawtype.upper() == "HDHOMERUN") 203 { 204 205 uint32_t target_ip = 0; 206 uint32_t device_type = HDHOMERUN_DEVICE_TYPE_TUNER; 207 uint32_t device_id = HDHOMERUN_DEVICE_ID_WILDCARD; 208 const int max_count = 50; 209 hdhomerun_discover_device_t result_list[max_count]; 210 211 int result = hdhomerun_discover_find_devices_custom( 212 target_ip, 213 device_type, 214 device_id, 215 result_list, 216 max_count); 217 218 if (result == -1) 219 { 220 VERBOSE(VB_IMPORTANT, "CardUtil::ProbeVideoDevices: Error finding HDHomerun devices"); 221 return devs; 222 } 223 224 if (result == 20) 225 VERBOSE(VB_IMPORTANT, "CardUtil::ProbeVideoDevices: Warning: may be > 20 HDHomerun devices"); 226 227 // Fixme -- figure out some way to return ip address as well 228 for (int i = 0; i < result; i++) 229 { 230 QString did = QString("%1").arg(result_list[i].device_id,0, 16); 231 did=did.upper(); 232 233 devs.push_back(did + "-0"); 234 devs.push_back(did + "-1"); 235 } 236 } 200 237 else 201 238 { 202 239 VERBOSE(VB_IMPORTANT, QString("CardUtil::ProbeVideoDevices: ") + … … bool CardUtil::CreateInputGroupIfNeeded( 1023 1060 uint id = 0; 1024 1061 for (uint i = 0; !id && (i < 100); i++) 1025 1062 { 1026 name = QString("DVB%1").arg(dev.toUInt()); 1063 bool ok; 1064 name = QString("DVB%1").arg(dev.toUInt(&ok)); 1065 if (! ok) 1066 { 1067 name = QString("HDHR_%1").arg(dev); 1068 } 1027 1069 name += (i) ? QString(":%1").arg(i) : QString(""); 1028 1070 id = CardUtil::CreateInputGroup(name); 1029 1071 } … … QString CardUtil::GetDeviceLabel(uint ca 1548 1590 } 1549 1591 else if (cardtype == "HDHOMERUN") 1550 1592 { 1551 MSqlQuery query(MSqlQuery::InitCon()); 1552 query.prepare( 1553 "SELECT dbox2_port " 1554 "FROM capturecard " 1555 "WHERE cardid = :CARDID"); 1556 query.bindValue(":CARDID", cardid); 1557 1558 if (!query.exec() || !query.isActive() || !query.next()) 1559 label = "[ DB ERROR ]"; 1560 else 1561 label = QString("[ HDHomeRun : ID %1 Port %2 ]") 1562 .arg(videodevice).arg(query.value(0).toString()); 1593 label = QString("[ HDHomeRun : %1 ]").arg(videodevice); 1563 1594 } 1564 1595 else 1565 1596 { -
mythtv/libs/libmythtv/cardutil.h
diff -p -r -u -N -X /tmp/diff.exclude -x release.21404.0821a -x release.21404.0821b release.21404.0821a/mythtv/libs/libmythtv/cardutil.h release.21404.0821b/mythtv/libs/libmythtv/cardutil.h
class MPUBLIC CardUtil 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); -
mythtv/libs/libmythtv/hdhrchannel.cpp
diff -p -r -u -N -X /tmp/diff.exclude -x release.21404.0821a -x release.21404.0821b release.21404.0821a/mythtv/libs/libmythtv/hdhrchannel.cpp release.21404.0821b/mythtv/libs/libmythtv/hdhrchannel.cpp
using namespace std; 25 25 #include "videosource.h" 26 26 #include "channelutil.h" 27 27 28 #include "hdhrstreamhandler.h" 29 28 30 #define DEBUG_PID_FILTERS 29 31 30 32 #define LOC QString("HDHRChan(%1): ").arg(GetDevice()) 31 33 #define LOC_ERR QString("HDHRChan(%1), Error: ").arg(GetDevice()) 32 34 33 HDHRChannel::HDHRChannel(TVRec *parent, const QString &device, uint tuner) 34 : DTVChannel(parent), _hdhomerun_device(NULL), 35 _device_id(0), _device_ip(0), 36 _tuner(tuner), _lock(true) 37 { 38 bool valid; 39 _device_id = device.toUInt(&valid, 16); 40 41 if (valid && hdhomerun_discover_validate_device_id(_device_id)) 42 return; 43 44 _device_id = HDHOMERUN_DEVICE_ID_WILDCARD; 45 46 /* Otherwise, is it a valid IP address? */ 47 struct in_addr address; 48 if (inet_aton(device, &address)) 49 { 50 _device_ip = ntohl(address.s_addr); 51 return; 52 } 53 54 /* Invalid, use wildcard device ID. */ 55 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Invalid DeviceID '%1'") 56 .arg(device)); 57 35 HDHRChannel::HDHRChannel(TVRec *parent, const QString &device) 36 : DTVChannel(parent), _stream_handler(NULL), 37 _device_id(device), _lock(true), 38 tune_lock(true), hw_lock(true) 39 { 58 40 } 59 41 60 42 HDHRChannel::~HDHRChannel(void) … … HDHRChannel::~HDHRChannel(void) 64 46 65 47 bool HDHRChannel::Open(void) 66 48 { 67 if (IsOpen()) 68 return true; 49 VERBOSE(VB_CHANNEL, LOC + "Opening HDHR channel"); 69 50 70 if (!InitializeInputs()) 71 return false; 72 73 return Connect(); 74 } 75 76 void HDHRChannel::Close(void) 77 { 78 if (_hdhomerun_device) 79 { 80 hdhomerun_device_destroy(_hdhomerun_device); 81 _hdhomerun_device = NULL; 82 } 83 } 51 QMutexLocker locker(&hw_lock); 84 52 85 bool HDHRChannel::EnterPowerSavingMode(void) 86 { 87 return hdhomerun_device_set_tuner_channel(_hdhomerun_device, "none") > 0; 88 } 53 if (IsOpen()) 54 return true; 89 55 90 bool HDHRChannel::Connect(void) 91 { 92 _hdhomerun_device = hdhomerun_device_create( 93 _device_id, _device_ip, _tuner, NULL); 56 _stream_handler = HDHRStreamHandler::Get(_device_id); 94 57 95 if (! _hdhomerun_device)58 if (!InitializeInputs()) 96 59 { 97 VERBOSE(VB_IMPORTANT, 98 LOC_ERR + "Unable to create hdhomerun device object"); 60 Close(); 99 61 return false; 100 62 } 101 63 102 return true; 103 } 104 105 QString HDHRChannel::DeviceGet(const QString &name, bool report_error_return) 106 { 107 QMutexLocker locker(&_lock); 108 109 if (!_hdhomerun_device) 110 { 111 VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed (not connected)"); 112 return QString::null; 113 } 114 115 char *value = NULL; 116 char *error = NULL; 117 if (hdhomerun_device_get_var(_hdhomerun_device, name, &value, &error) < 0) 118 { 119 VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed" + ENO); 120 return QString::null; 121 } 122 123 if (report_error_return && error) 124 { 125 VERBOSE(VB_IMPORTANT, LOC_ERR + 126 QString("DeviceGet(%1): %2").arg(name).arg(error)); 64 // nextInputID = currentInputID; 127 65 128 return QString::null; 129 } 66 return _stream_handler->Connected(); 130 67 131 return QString(value);132 68 } 133 69 134 QString HDHRChannel::DeviceSet(const QString &name, const QString &val, 135 bool report_error_return) 70 void HDHRChannel::Close() 136 71 { 137 QMutexLocker locker(&_lock); 138 139 if (!_hdhomerun_device) 140 { 141 VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed (not connected)"); 142 return QString::null; 143 } 72 VERBOSE(VB_CHANNEL, LOC + "Closing HDHR channel"); 144 73 145 char *value = NULL; 146 char *error = NULL; 147 if (hdhomerun_device_set_var( 148 _hdhomerun_device, name, val, &value, &error) < 0) 149 { 150 VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed" + ENO); 151 152 return QString::null; 153 } 154 155 if (report_error_return && error) 156 { 157 VERBOSE(VB_IMPORTANT, LOC_ERR + 158 QString("DeviceSet(%1 %2): %3").arg(name).arg(val).arg(error)); 159 160 return QString::null; 161 } 74 if (! IsOpen()) 75 return; // this caller didn't have it open in the first place.. 162 76 163 return QString(value);77 HDHRStreamHandler::Return(_stream_handler); 164 78 } 165 79 166 struct hdhomerun_device_t *HDHRChannel::GetHDHRDevice(void)80 bool HDHRChannel::EnterPowerSavingMode(void) 167 81 { 168 return _hdhomerun_device; 82 if ( IsOpen()) 83 return _stream_handler->EnterPowerSavingMode(); 84 else 85 return true; 169 86 } 170 87 171 QString HDHRChannel::TunerGet(const QString &name, bool report_error_return)172 {173 return DeviceGet(QString("/tuner%1/%2").arg(_tuner).arg(name),174 report_error_return);175 }176 88 177 QString HDHRChannel::TunerSet(const QString &name, const QString &value, 178 bool report_error_return) 89 bool HDHRChannel::IsOpen(void) const 179 90 { 180 return DeviceSet(QString("/tuner%1/%2").arg(_tuner).arg(name), value, 181 report_error_return); 91 return (_stream_handler != NULL); 182 92 } 183 93 184 bool HDHRChannel:: DeviceSetTarget(unsigned short localPort)94 bool HDHRChannel::Init(QString &inputname, QString &startchannel, bool setchan) 185 95 { 186 if (localPort == 0) 187 { 188 return false; 189 } 190 191 unsigned long localIP = hdhomerun_device_get_local_machine_addr( 192 _hdhomerun_device); 193 if (localIP == 0) 194 { 195 return false; 196 } 197 198 QString configValue = QString("%1.%2.%3.%4:%5") 199 .arg((localIP >> 24) & 0xFF).arg((localIP >> 16) & 0xFF) 200 .arg((localIP >> 8) & 0xFF).arg((localIP >> 0) & 0xFF) 201 .arg(localPort); 202 203 if (hdhomerun_device_set_tuner_target(_hdhomerun_device, configValue) <= 0) 204 { 205 return false; 206 } 96 if (setchan && !IsOpen()) 97 Open(); 207 98 208 return true; 209 } 210 211 bool HDHRChannel::DeviceClearTarget(void) 212 { 213 return hdhomerun_device_set_tuner_target(_hdhomerun_device, "none") > 0; 99 return ChannelBase::Init(inputname, startchannel, setchan); 214 100 } 215 101 216 102 bool HDHRChannel::SetChannelByString(const QString &channum) … … bool HDHRChannel::SetChannelByString(con 244 130 return SwitchToInput(inputName, channum); 245 131 246 132 ClearDTVInfo(); 247 _ignore_filters = false;248 133 249 134 InputMap::const_iterator it = inputs.find(currentInputID); 250 135 if (it == inputs.end()) … … bool HDHRChannel::SetChannelByString(con 316 201 if (mpeg_prog_num && (GetTuningMode() == "mpeg")) 317 202 { 318 203 QString pnum = QString::number(mpeg_prog_num); 319 _ignore_filters = (hdhomerun_device_set_tuner_program(320 _hdhomerun_device, pnum) > 0);204 //_ignore_filters = _stream_handler->TuneProgram(pnum); 205 _stream_handler->TuneProgram(pnum); 321 206 } 322 207 323 208 return true; … … bool HDHRChannel::Tune(uint frequency, Q 364 249 365 250 VERBOSE(VB_CHANNEL, LOC + "Tune()ing to " + chan); 366 251 367 if ( hdhomerun_device_set_tuner_channel(_hdhomerun_device, chan) > 0)252 if (_stream_handler->TuneChannel(chan)) 368 253 { 369 254 SetSIStandard(si_std); 370 255 return true; 371 256 } 372 373 374 // dtv_multiplex.modulation is from the DB. Could contain almost anything.375 // As a fallback, use the HDHR device's automatic scanning:376 chan = "auto:" + QString::number(frequency);377 378 VERBOSE(VB_CHANNEL, LOC + "Failed. Now trying " + chan);379 380 if (hdhomerun_device_set_tuner_channel(_hdhomerun_device, chan) > 0)381 {382 SetSIStandard(si_std);383 return true;384 }385 386 387 257 return false; 388 258 } 389 390 bool HDHRChannel::AddPID(uint pid, bool do_update)391 {392 QMutexLocker locker(&_lock);393 394 vector<uint>::iterator it;395 it = lower_bound(_pids.begin(), _pids.end(), pid);396 if (it != _pids.end() && *it == pid)397 {398 #ifdef DEBUG_PID_FILTERS399 VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<") NOOP");400 #endif // DEBUG_PID_FILTERS401 return true;402 }403 404 _pids.insert(it, pid);405 406 #ifdef DEBUG_PID_FILTERS407 VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<")");408 #endif // DEBUG_PID_FILTERS409 410 if (do_update)411 return UpdateFilters();412 return true;413 }414 415 bool HDHRChannel::DelPID(uint pid, bool do_update)416 {417 QMutexLocker locker(&_lock);418 419 vector<uint>::iterator it;420 it = lower_bound(_pids.begin(), _pids.end(), pid);421 if (it == _pids.end())422 {423 #ifdef DEBUG_PID_FILTERS424 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") NOOP");425 #endif // DEBUG_PID_FILTERS426 427 return true;428 }429 430 if (*it == pid)431 {432 #ifdef DEBUG_PID_FILTERS433 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") -- found");434 #endif // DEBUG_PID_FILTERS435 _pids.erase(it);436 }437 else438 {439 #ifdef DEBUG_PID_FILTERS440 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") -- failed");441 #endif // DEBUG_PID_FILTERS442 }443 444 if (do_update)445 return UpdateFilters();446 return true;447 }448 449 bool HDHRChannel::DelAllPIDs(void)450 {451 QMutexLocker locker(&_lock);452 453 #ifdef DEBUG_PID_FILTERS454 VERBOSE(VB_CHANNEL, "DelAllPID()");455 #endif // DEBUG_PID_FILTERS456 457 _pids.clear();458 459 return UpdateFilters();460 }461 462 QString filt_str(uint pid)463 {464 uint pid0 = (pid / (16*16*16)) % 16;465 uint pid1 = (pid / (16*16)) % 16;466 uint pid2 = (pid / (16)) % 16;467 uint pid3 = pid % 16;468 return QString("0x%1%2%3%4")469 .arg(pid0,0,16).arg(pid1,0,16)470 .arg(pid2,0,16).arg(pid3,0,16);471 }472 473 bool HDHRChannel::UpdateFilters(void)474 {475 QMutexLocker locker(&_lock);476 477 QString filter = "";478 479 vector<uint> range_min;480 vector<uint> range_max;481 482 if (_ignore_filters)483 return true;484 485 for (uint i = 0; i < _pids.size(); i++)486 {487 uint pid_min = _pids[i];488 uint pid_max = pid_min;489 for (uint j = i + 1; j < _pids.size(); j++)490 {491 if (pid_max + 1 != _pids[j])492 break;493 pid_max++;494 i++;495 }496 range_min.push_back(pid_min);497 range_max.push_back(pid_max);498 }499 500 if (range_min.size() > 16)501 {502 range_min.resize(16);503 uint pid_max = range_max.back();504 range_max.resize(15);505 range_max.push_back(pid_max);506 }507 508 for (uint i = 0; i < range_min.size(); i++)509 {510 filter += filt_str(range_min[i]);511 if (range_min[i] != range_max[i])512 filter += QString("-%1").arg(filt_str(range_max[i]));513 filter += " ";514 }515 516 filter = filter.stripWhiteSpace();517 518 QString new_filter = TunerSet("filter", filter);519 520 #ifdef DEBUG_PID_FILTERS521 QString msg = QString("Filter: '%1'").arg(filter);522 if (filter != new_filter)523 msg += QString("\n\t\t\t\t'%2'").arg(new_filter);524 525 VERBOSE(VB_CHANNEL, msg);526 #endif // DEBUG_PID_FILTERS527 528 return filter == new_filter;529 } -
mythtv/libs/libmythtv/hdhrchannel.h
diff -p -r -u -N -X /tmp/diff.exclude -x release.21404.0821a -x release.21404.0821b release.21404.0821a/mythtv/libs/libmythtv/hdhrchannel.h release.21404.0821b/mythtv/libs/libmythtv/hdhrchannel.h
16 16 // HDHomeRun headers 17 17 #ifdef USING_HDHOMERUN 18 18 #include "hdhomerun/hdhomerun.h" 19 #else20 struct hdhomerun_control_sock_t { int dummy; };21 19 #endif 22 20 23 typedef struct hdhomerun_control_sock_t hdhr_socket_t; 21 class HDHRChannel; 22 class HDHRStreamHandler; 23 class ProgramMapTable; 24 24 25 25 class HDHRChannel : public DTVChannel 26 26 { … … class HDHRChannel : public DTVChannel 28 28 friend class HDHRRecorder; 29 29 30 30 public: 31 HDHRChannel(TVRec *parent, const QString &device , uint tuner);31 HDHRChannel(TVRec *parent, const QString &device); 32 32 ~HDHRChannel(void); 33 33 34 34 bool Open(void); 35 35 void Close(void); 36 36 bool EnterPowerSavingMode(void); 37 37 38 bool Init(QString &inputname, QString &startchannel, bool setchan); 39 38 40 // Sets 41 void SetPMT(const ProgramMapTable*) {}; 39 42 bool SetChannelByString(const QString &chan); 40 43 41 44 // Gets 42 bool IsOpen(void) const { return (_hdhomerun_device != NULL); } 43 QString GetDevice(void) const 44 { return QString("%1/%2").arg(_device_id, 8, 16).arg(_tuner); } 45 bool IsOpen(void) const; 46 QString GetDevice(void) const { return _device_id; } 45 47 vector<uint> GetPIDs(void) const 46 48 { QMutexLocker locker(&_lock); return _pids; } 47 49 QString GetSIStandard(void) const { return "atsc"; } 48 50 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 51 // ATSC scanning stuff 56 52 bool TuneMultiplex(uint mplexid, QString inputname); 57 53 bool Tune(const DTVMultiplex &tuning, QString inputname); 58 54 59 55 private: 60 bool Connect(void);61 56 bool Tune(uint frequency, QString inputname, 62 57 QString modulation, QString si_std); 63 58 59 private: 60 HDHRStreamHandler *_stream_handler; 64 61 65 struct hdhomerun_device_t *GetHDHRDevice(void); 66 67 bool DeviceSetTarget(unsigned short localPort); 68 bool DeviceClearTarget(void); 69 70 QString DeviceGet(const QString &name, bool report_error_return = true); 71 QString DeviceSet(const QString &name, const QString &value, 72 bool report_error_return = true); 73 74 QString TunerGet(const QString &name, bool report_error_return = true); 75 QString TunerSet(const QString &name, const QString &value, 76 bool report_error_return = true); 62 QString _device_id; 77 63 78 private:79 struct hdhomerun_device_t *_hdhomerun_device;80 uint _device_id;81 uint _device_ip;82 uint _tuner;83 bool _ignore_filters;84 64 vector<uint> _pids; 85 65 mutable QMutex _lock; 66 mutable QMutex tune_lock; 67 mutable QMutex hw_lock; 86 68 }; 87 69 88 70 #endif -
mythtv/libs/libmythtv/hdhrrecorder.cpp
diff -p -r -u -N -X /tmp/diff.exclude -x release.21404.0821a -x release.21404.0821b release.21404.0821a/mythtv/libs/libmythtv/hdhrrecorder.cpp release.21404.0821b/mythtv/libs/libmythtv/hdhrrecorder.cpp
using namespace std; 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 "dvbstreamdata.h" 31 29 #include "eithelper.h" 32 30 #include "tv_rec.h" 33 31 32 // MythTV HDHR includes 33 #include "hdhrchannel.h" 34 #include "hdhrrecorder.h" 35 #include "hdhrstreamhandler.h" 36 34 37 #define LOC QString("HDHRRec(%1): ").arg(tvrec->GetCaptureCardNum()) 38 #define LOC_WARN QString("HDHRRec(%1), Warning: ") \ 39 .arg(tvrec->GetCaptureCardNum()) 35 40 #define LOC_ERR QString("HDHRRec(%1), Error: ") \ 36 41 .arg(tvrec->GetCaptureCardNum()) 37 42 38 43 HDHRRecorder::HDHRRecorder(TVRec *rec, HDHRChannel *channel) 39 44 : DTVRecorder(rec), 40 _channel(channel), _video_socket(NULL), 45 _channel(channel), 46 _stream_handler(NULL), 41 47 _stream_data(NULL), 42 _input_pat(NULL), _input_pmt(NULL), 43 _reset_pid_filters(false),_pid_lock(true) 48 _pid_lock(true), 49 _input_pat(NULL), 50 _input_pmt(NULL), 51 _has_no_av(false) 44 52 { 45 53 } 46 54 … … void HDHRRecorder::SetOptionsFromProfile 91 99 // HACK -- end 92 100 } 93 101 102 bool HDHRRecorder::IsOpen(void) { 103 return (_stream_handler != NULL); 104 } 105 94 106 bool HDHRRecorder::Open(void) 95 107 { 96 108 VERBOSE(VB_RECORD, LOC + "Open()"); 97 if ( _video_socket)109 if (IsOpen()) 98 110 { 99 111 VERBOSE(VB_RECORD, LOC + "Card already open (recorder)"); 100 112 return true; 101 113 } 102 114 103 /* Calculate buffer size */ 104 uint buffersize = gContext->GetNumSetting( 105 "HDRingbufferSize", 50 * TSPacket::SIZE) * 1024; 106 buffersize /= VIDEO_DATA_PACKET_SIZE; 107 buffersize *= VIDEO_DATA_PACKET_SIZE; 115 bzero(_stream_id, sizeof(_stream_id)); 116 bzero(_pid_status, sizeof(_pid_status)); 117 memset(_continuity_counter, 0xff, sizeof(_continuity_counter)); 108 118 109 // Buffer should be at least about 1MB.. 110 buffersize = max(49 * TSPacket::SIZE * 128, buffersize); 119 _stream_handler = HDHRStreamHandler::Get(_channel->GetDevice()); 111 120 112 /* Create TS socket. */ 113 _video_socket = hdhomerun_video_create(0, buffersize, NULL); 114 if (!_video_socket) 115 { 116 VERBOSE(VB_IMPORTANT, LOC + "Open() failed to open socket"); 117 return false; 118 } 121 VERBOSE(VB_RECORD, LOC + "HDHR opened successfully"); 119 122 120 /* Success. */121 123 return true; 122 124 } 123 125 124 /** \fn HDHRRecorder::StartData(void)125 * \brief Configure device to send video.126 */127 bool HDHRRecorder::StartData(void)128 {129 VERBOSE(VB_RECORD, LOC + "StartData()");130 uint localPort = hdhomerun_video_get_local_port(_video_socket);131 return _channel->DeviceSetTarget(localPort);132 }133 134 126 void HDHRRecorder::Close(void) 135 127 { 136 VERBOSE(VB_RECORD, LOC + "Close()"); 137 if (_video_socket) 138 { 139 hdhomerun_video_destroy(_video_socket); 140 _video_socket = NULL; 141 } 142 } 143 144 void HDHRRecorder::ProcessTSData(const uint8_t *buffer, int len) 145 { 146 QMutexLocker locker(&_pid_lock); 147 const uint8_t *data = buffer; 148 const uint8_t *end = buffer + len; 128 VERBOSE(VB_RECORD, LOC + "Close() - Begin"); 149 129 150 while (data + 188 <= end)130 if (IsOpen()) 151 131 { 152 if (data[0] != 0x47) 153 { 154 return; 155 } 156 157 const TSPacket *tspacket = reinterpret_cast<const TSPacket*>(data); 158 ProcessTSPacket(*tspacket); 159 160 data += 188; 132 HDHRStreamHandler::Return(_stream_handler); 161 133 } 134 135 VERBOSE(VB_RECORD, LOC + "Close() - End"); 162 136 } 163 137 164 138 void HDHRRecorder::SetStreamData(MPEGStreamData *data) … … void HDHRRecorder::HandlePAT(const Progr 220 194 ProgramAssociationTable *oldpat = _input_pat; 221 195 _input_pat = new ProgramAssociationTable(*_pat); 222 196 delete oldpat; 223 224 _reset_pid_filters = true;225 197 } 226 198 227 199 void HDHRRecorder::HandlePMT(uint progNum, const ProgramMapTable *_pmt) … … void HDHRRecorder::HandlePMT(uint progNu 233 205 VERBOSE(VB_RECORD, LOC + "SetPMT("<<progNum<<")"); 234 206 ProgramMapTable *oldpmt = _input_pmt; 235 207 _input_pmt = new ProgramMapTable(*_pmt); 236 delete oldpmt;237 208 238 _reset_pid_filters = true; 209 QString sistandard = _channel->GetSIStandard(); 210 211 bool has_no_av = true; 212 for (uint i = 0; i < _input_pmt->StreamCount() && has_no_av; i++) 213 { 214 has_no_av &= !_input_pmt->IsVideo(i, sistandard); 215 has_no_av &= !_input_pmt->IsAudio(i, sistandard); 216 } 217 _has_no_av = has_no_av; 218 219 _channel->SetPMT(_input_pmt); 220 delete oldpmt; 239 221 } 240 222 } 241 223 … … void HDHRRecorder::HandleSingleProgramPA 246 228 247 229 int next = (pat->tsheader()->ContinuityCounter()+1)&0xf; 248 230 pat->tsheader()->SetContinuityCounter(next); 249 BufferedWrite(*(reinterpret_cast<TSPacket*>(pat->tsheader())));231 DTVRecorder::BufferedWrite(*(reinterpret_cast<TSPacket*>(pat->tsheader()))); 250 232 } 251 233 252 234 void HDHRRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt) 253 235 { 254 236 if (!pmt) 237 { 238 VERBOSE(VB_RECORD, LOC + "HandleSingleProgramPMT(NULL)"); 239 return; 240 } 241 242 // collect stream types for H.264 (MPEG-4 AVC) keyframe detection 243 for (uint i = 0; i < pmt->StreamCount(); i++) 244 _stream_id[pmt->StreamPID(i)] = pmt->StreamType(i); 245 246 if (!ringBuffer) 255 247 return; 256 248 257 249 unsigned char buf[8 * 1024]; … … void HDHRRecorder::HandleSingleProgramPM 259 251 pmt->tsheader()->SetContinuityCounter(next_cc); 260 252 uint size = pmt->WriteAsTSPackets(buf, next_cc); 261 253 254 uint posA[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() }; 255 262 256 for (uint i = 0; i < size ; i += TSPacket::SIZE) 263 257 DTVRecorder::BufferedWrite(*(reinterpret_cast<TSPacket*>(&buf[i]))); 258 259 uint posB[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() }; 260 261 if (posB[0] + posB[1] * TSPacket::SIZE > 262 posA[0] + posA[1] * TSPacket::SIZE) 263 { 264 VERBOSE(VB_RECORD, LOC + "Wrote PMT @" 265 << posA[0] << " + " << (posA[1] * TSPacket::SIZE)); 266 } 267 else 268 { 269 VERBOSE(VB_RECORD, LOC + "Saw PMT but did not write to disk yet"); 270 } 264 271 } 265 272 266 273 /** \fn HDHRRecorder::HandleMGT(const MasterGuideTable*) … … void HDHRRecorder::HandleMGT(const Maste 280 287 } 281 288 */ 282 289 290 bool HDHRRecorder::ProcessVideoTSPacket(const TSPacket &tspacket) 291 { 292 uint streamType = _stream_id[tspacket.PID()]; 293 294 // Check for keyframes and count frames 295 if (streamType == StreamID::H264Video) 296 { 297 _buffer_packets = !FindH264Keyframes(&tspacket); 298 if (!_seen_sps) 299 return true; 300 } 301 else 302 { 303 _buffer_packets = !FindMPEG2Keyframes(&tspacket); 304 } 305 306 return ProcessAVTSPacket(tspacket); 307 } 308 309 bool HDHRRecorder::ProcessAudioTSPacket(const TSPacket &tspacket) 310 { 311 _buffer_packets = !FindAudioKeyframes(&tspacket); 312 return ProcessAVTSPacket(tspacket); 313 } 314 315 /// Common code for processing either audio or video packets 316 bool HDHRRecorder::ProcessAVTSPacket(const TSPacket &tspacket) 317 { 318 const uint pid = tspacket.PID(); 319 // Sync recording start to first keyframe 320 if (_wait_for_keyframe_option && _first_keyframe < 0) 321 return true; 322 323 // Sync streams to the first Payload Unit Start Indicator 324 // _after_ first keyframe iff _wait_for_keyframe_option is true 325 if (!(_pid_status[pid] & kPayloadStartSeen) && tspacket.HasPayload()) 326 { 327 if (!tspacket.PayloadStart()) 328 return true; // not payload start - drop packet 329 330 VERBOSE(VB_RECORD, 331 QString("PID 0x%1 Found Payload Start").arg(pid,0,16)); 332 333 _pid_status[pid] |= kPayloadStartSeen; 334 } 335 336 BufferedWrite(tspacket); 337 338 return true; 339 } 340 283 341 bool HDHRRecorder::ProcessTSPacket(const TSPacket& tspacket) 284 342 { 285 bool ok = !tspacket.TransportError();286 if ( ok && !tspacket.ScramplingControl())343 // Only create fake keyframe[s] if there are no audio/video streams 344 if (_input_pmt && _has_no_av) 287 345 { 288 if (tspacket.HasAdaptationField()) 289 GetStreamData()->HandleAdaptationFieldControl(&tspacket); 290 if (tspacket.HasPayload()) 291 { 292 const unsigned int lpid = tspacket.PID(); 346 _buffer_packets = !FindOtherKeyframes(&tspacket); 347 } 348 else 349 { 350 // There are audio/video streams. Only write the packet 351 // if audio/video key-frames have been found 352 if (_wait_for_keyframe_option && _first_keyframe < 0) 353 return true; 293 354 294 if ((GetStreamData()->VideoPIDSingleProgram() > 0x1fff) && 295 _wait_for_keyframe_option) 296 { 297 _wait_for_keyframe_option = false; 298 } 299 300 // Pass or reject frames based on PID, and parse info from them 301 if (lpid == GetStreamData()->VideoPIDSingleProgram()) 302 { 303 //cerr<<"v"; 304 ProgramMapTable *pmt = _stream_data->PMTSingleProgram(); 305 uint video_stream_type = pmt->StreamType(pmt->FindPID(lpid)); 306 307 if (video_stream_type == StreamID::H264Video) 308 _buffer_packets = !FindH264Keyframes(&tspacket); 309 else if (StreamID::IsVideo(video_stream_type)) 310 _buffer_packets = !FindMPEG2Keyframes(&tspacket); 311 312 if ((video_stream_type != StreamID::H264Video) || _seen_sps) 313 BufferedWrite(tspacket); 314 } 315 else if (GetStreamData()->IsAudioPID(lpid)) 316 { 317 //cerr<<"a"; 318 _buffer_packets = !FindAudioKeyframes(&tspacket); 319 BufferedWrite(tspacket); 320 } 321 else if (GetStreamData()->IsListeningPID(lpid)) 322 { 323 //cerr<<"t"; 324 GetStreamData()->HandleTSTables(&tspacket); 325 } 326 else if (GetStreamData()->IsWritingPID(lpid)) 327 BufferedWrite(tspacket); 328 } 355 _buffer_packets = true; 329 356 } 330 return ok; 357 358 BufferedWrite(tspacket); 331 359 } 332 360 333 361 void HDHRRecorder::StartRecording(void) … … void HDHRRecorder::StartRecording(void) 345 373 _request_recording = true; 346 374 _recording = true; 347 375 348 if (!StartData())349 {350 VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting recording "351 "(set target failed). Aborting.");352 Close();353 _error = true;354 VERBOSE(VB_RECORD, LOC + "StartRecording -- end 2"); 355 return;356 }357 358 hdhomerun_video_flush(_video_socket);376 // Make sure the first things in the file are a PAT & PMT 377 bool tmp = _wait_for_keyframe_option; 378 _wait_for_keyframe_option = false; 379 HandleSingleProgramPAT(_stream_data->PATSingleProgram()); 380 HandleSingleProgramPMT(_stream_data->PMTSingleProgram()); 381 _wait_for_keyframe_option = tmp; 382 383 _stream_data->AddAVListener(this); 384 _stream_data->AddWritingListener(this); 385 _stream_handler->AddListener(_stream_data); 386 359 387 while (_request_recording && !_error) 360 388 { 389 usleep(50000); 390 361 391 if (PauseAndWait()) 362 392 continue; 363 393 364 if ( _stream_data)394 if (!_input_pmt) 365 395 { 366 QMutexLocker read_lock(&_pid_lock); 367 _reset_pid_filters |= _stream_data->HasEITPIDChanges(_eit_pids); 396 VERBOSE(VB_GENERAL, LOC_WARN + 397 "Recording will not commence until a PMT is set."); 398 usleep(5000); 399 continue; 368 400 } 369 401 370 if ( _reset_pid_filters)402 if (!_stream_handler->IsRunning()) 371 403 { 372 _reset_pid_filters = false; 373 VERBOSE(VB_RECORD, LOC + "Resetting Demux Filters"); 374 AdjustFilters(); 375 } 404 _error = true; 376 405 377 size_t read_size = 64 * 1024; // read about 64KB 378 read_size /= VIDEO_DATA_PACKET_SIZE; 379 read_size *= VIDEO_DATA_PACKET_SIZE; 380 381 size_t data_length; 382 unsigned char *data_buffer = 383 hdhomerun_video_recv(_video_socket, read_size, &data_length); 384 if (!data_buffer) 385 { 386 usleep(5000); 387 continue; 388 } 389 390 ProcessTSData(data_buffer, data_length); 406 VERBOSE(VB_IMPORTANT, LOC_ERR + 407 "Stream handler died unexpectedly."); 408 } 391 409 } 392 410 393 411 VERBOSE(VB_RECORD, LOC + "StartRecording -- ending..."); 394 412 395 _channel->DeviceClearTarget(); 413 _stream_handler->RemoveListener(_stream_data); 414 _stream_data->RemoveWritingListener(this); 415 _stream_data->RemoveAVListener(this); 416 396 417 Close(); 397 418 398 419 FinishRecording(); … … void HDHRRecorder::StartRecording(void) 401 422 VERBOSE(VB_RECORD, LOC + "StartRecording -- end"); 402 423 } 403 424 404 bool HDHRRecorder::AdjustFilters(void)425 void HDHRRecorder::ResetForNewFile(void) 405 426 { 406 QMutexLocker change_lock(&_pid_lock);427 DTVRecorder::ResetForNewFile(); 407 428 408 if (!_channel) 409 { 410 VERBOSE(VB_IMPORTANT, LOC_ERR + "AdjustFilters() no channel"); 411 return false; 412 } 429 bzero(_stream_id, sizeof(_stream_id)); 430 bzero(_pid_status, sizeof(_pid_status)); 431 memset(_continuity_counter, 0xff, sizeof(_continuity_counter)); 413 432 414 if (!_input_pat || !_input_pmt) 415 { 416 VERBOSE(VB_IMPORTANT, LOC + "AdjustFilters() no pmt or no pat"); 417 return false; 418 } 419 420 uint_vec_t add_pid; 433 // FIXME 434 // Close and re-open ??? 435 //Close(); 436 //Open(); 437 } 421 438 422 add_pid.push_back(MPEG_PAT_PID); 423 _stream_data->AddListeningPID(MPEG_PAT_PID); 439 void HDHRRecorder::StopRecording(void) 440 { 441 _request_recording = false; 442 while (_recording) 443 usleep(2000); 444 } 424 445 425 for (uint i = 0; i < _input_pat->ProgramCount(); i++) 446 bool HDHRRecorder::PauseAndWait(int timeout) 447 { 448 if (request_pause) 426 449 { 427 add_pid.push_back(_input_pat->ProgramPID(i)); 428 _stream_data->AddListeningPID(_input_pat->ProgramPID(i)); 429 } 450 if (!paused) 451 { 452 assert(_stream_handler); 453 assert(_stream_data); 430 454 431 // Record the streams in the PMT... 432 bool need_pcr_pid = true; 433 for (uint i = 0; i < _input_pmt->StreamCount(); i++) 434 { 435 add_pid.push_back(_input_pmt->StreamPID(i)); 436 need_pcr_pid &= (_input_pmt->StreamPID(i) != _input_pmt->PCRPID()); 437 _stream_data->AddWritingPID(_input_pmt->StreamPID(i)); 438 } 455 _stream_handler->RemoveListener(_stream_data); 439 456 440 if (need_pcr_pid && (_input_pmt->PCRPID())) 441 { 442 add_pid.push_back(_input_pmt->PCRPID()); 443 _stream_data->AddWritingPID(_input_pmt->PCRPID()); 457 paused = true; 458 pauseWait.wakeAll(); 459 if (tvrec) 460 tvrec->RecorderPaused(); 461 } 462 unpauseWait.wait(timeout); 444 463 } 445 464 446 // Adjust for EIT 447 AdjustEITPIDs(); 448 for (uint i = 0; i < _eit_pids.size(); i++) 465 if (!request_pause && paused) 449 466 { 450 add_pid.push_back(_eit_pids[i]); 451 _stream_data->AddListeningPID(_eit_pids[i]); 452 } 467 paused = false; 453 468 454 // Delete filters for pids we no longer wish to monitor 455 vector<uint>::const_iterator it; 456 vector<uint> pids = _channel->GetPIDs(); 457 for (it = pids.begin(); it != pids.end(); ++it) 458 { 459 if (find(add_pid.begin(), add_pid.end(), *it) == add_pid.end()) 460 { 461 _stream_data->RemoveListeningPID(*it); 462 _stream_data->RemoveWritingPID(*it); 463 _channel->DelPID(*it, false); 464 } 465 } 469 assert(_stream_handler); 470 assert(_stream_data); 466 471 467 for (it = add_pid.begin(); it != add_pid.end(); ++it) 468 _channel->AddPID(*it, false); 469 470 _channel->UpdateFilters(); 472 _stream_handler->AddListener(_stream_data); 473 } 471 474 472 return add_pid.size();475 return paused; 473 476 } 474 477 475 /** \fn HDHRRecorder::AdjustEITPIDs(void) 476 * \brief Adjusts EIT PID monitoring to monitor the right number of EIT PIDs. 477 */ 478 bool HDHRRecorder::AdjustEITPIDs(void) 478 void HDHRRecorder::BufferedWrite(const TSPacket &tspacket) 479 479 { 480 bool changes = false; 481 uint_vec_t add, del; 482 483 QMutexLocker change_lock(&_pid_lock); 484 485 if (GetStreamData()->HasEITPIDChanges(_eit_pids)) 486 changes = GetStreamData()->GetEITPIDChanges(_eit_pids, add, del); 480 // Care must be taken to make sure that the packet actually gets written 481 // as the decision to actually write it has already been made 487 482 488 if (!changes) 489 return false; 490 491 for (uint i = 0; i < del.size(); i++) 483 // Do we have to buffer the packet for exact keyframe detection? 484 if (_buffer_packets) 492 485 { 493 uint_vec_t::iterator it;494 it = find(_eit_pids.begin(), _eit_pids.end(), del[i]);495 if (it != _eit_pids.end())496 _eit_pids.erase(it);486 int idx = _payload_buffer.size(); 487 _payload_buffer.resize(idx + TSPacket::SIZE); 488 memcpy(&_payload_buffer[idx], tspacket.data(), TSPacket::SIZE); 489 return; 497 490 } 498 491 499 for (uint i = 0; i < add.size(); i++) 500 _eit_pids.push_back(add[i]); 501 502 return true; 492 // We are free to write the packet, but if we have buffered packet[s] 493 // we have to write them first... 494 if (!_payload_buffer.empty()) 495 { 496 if (ringBuffer) 497 ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size()); 498 _payload_buffer.clear(); 499 } 500 if (ringBuffer) 501 ringBuffer->Write(tspacket.data(), TSPacket::SIZE); 503 502 } 504 503 -
mythtv/libs/libmythtv/hdhrrecorder.h
diff -p -r -u -N -X /tmp/diff.exclude -x release.21404.0821a -x release.21404.0821b release.21404.0821a/mythtv/libs/libmythtv/hdhrrecorder.h release.21404.0821b/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 … … class HDHRRecorder : public DTVRecorder, 21 24 public DVBMainStreamListener, 22 25 public ATSCMainStreamListener, 23 26 public MPEGStreamListener, 24 public MPEGSingleProgramStreamListener 27 public MPEGSingleProgramStreamListener, 28 public TSPacketListener, 29 public TSPacketListenerAV 25 30 { 26 31 public: 27 32 HDHRRecorder(TVRec *rec, HDHRChannel *channel); … … class HDHRRecorder : public DTVRecorder, 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; } … … class HDHRRecorder : public DTVRecorder, 62 69 void HandleNIT(const NetworkInformationTable*) {} 63 70 void HandleSDT(uint /*tsid*/, const ServiceDescriptionTable*) {} 64 71 65 private: 66 bool AdjustFilters(void); 67 bool AdjustEITPIDs(void); 72 // TSPacketListenerAV 73 bool ProcessVideoTSPacket(const TSPacket& tspacket); 74 bool ProcessAudioTSPacket(const TSPacket& tspacket); 75 76 // Common audio/visual processing 77 bool ProcessAVTSPacket(const TSPacket &tspacket); 68 78 69 void ProcessTSData(const unsigned char *buffer, int len);70 79 bool ProcessTSPacket(const TSPacket& tspacket); 80 81 void BufferedWrite(const TSPacket &tspacket); 82 private: 71 83 void TeardownAll(void); 84 85 void ReaderPaused(int fd); 86 bool PauseAndWait(int timeout = 100); 72 87 73 88 private: 74 89 HDHRChannel *_channel; 75 struct hdhomerun_video_sock_t *_video_socket;90 HDHRStreamHandler *_stream_handler; 76 91 MPEGStreamData *_stream_data; 77 92 93 mutable QMutex _pid_lock; 78 94 ProgramAssociationTable *_input_pat; 79 95 ProgramMapTable *_input_pmt; 80 bool _reset_pid_filters; 81 uint_vec_t _eit_pids; 82 mutable QMutex _pid_lock; 96 bool _has_no_av; 97 98 unsigned char _stream_id[0x1fff]; 99 unsigned char _pid_status[0x1fff]; 100 unsigned char _continuity_counter[0x1fff]; 101 102 // Constants 103 static const int TSPACKETS_BETWEEN_PSIP_SYNC; 104 static const int POLL_INTERVAL; 105 static const int POLL_WARNING_TIMEOUT; 106 107 static const unsigned char kPayloadStartSeen = 0x2; 83 108 }; 84 109 85 110 #endif -
mythtv/libs/libmythtv/hdhrsignalmonitor.cpp
diff -p -r -u -N -X /tmp/diff.exclude -x release.21404.0821a -x release.21404.0821b release.21404.0821a/mythtv/libs/libmythtv/hdhrsignalmonitor.cpp release.21404.0821b/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()) … … HDHRSignalMonitor::HDHRSignalMonitor(int 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->GetDevice()); 53 56 } 54 57 55 58 /** \fn HDHRSignalMonitor::~HDHRSignalMonitor() … … 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) … … void HDHRSignalMonitor::Stop(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 } 85 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 } 82 if (GetStreamData()) 83 streamHandler->RemoveListener(GetStreamData()); 84 streamHandlerStarted = false; 85 streamHandler->SetRetuneAllowed(false, NULL, NULL); 126 86 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 HDHRChannel *hdrc = dynamic_cast<HDHRChannel*>(channel); 143 struct hdhomerun_device_t *_hdhomerun_device = hdrc->GetHDHRDevice(); 144 145 if (!_hdhomerun_device) 146 { 147 VERBOSE(VB_IMPORTANT, "Failed to get HDHomeRun device handle"); 148 return; 149 } 150 151 if (!hdhomerun_device_stream_start(_hdhomerun_device)) 152 { 153 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to set target"); 154 return; 155 } 156 157 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): " + 158 QString("begin (# of pids %1)") 159 .arg(GetStreamData()->ListeningPIDs().size())); 160 161 while (dtvMonitorRunning && GetStreamData()) 162 { 163 UpdateFiltersFromStreamData(); 164 165 size_t data_length; 166 unsigned char *data_buffer = 167 hdhomerun_device_stream_recv(_hdhomerun_device, 168 VIDEO_DATA_BUFFER_SIZE_1S / 5, 169 &data_length); 170 171 if (data_buffer) 172 { 173 GetStreamData()->ProcessData(data_buffer, data_length); 174 continue; 175 } 176 177 usleep(2500); 178 } 179 180 hdhomerun_device_stream_stop(_hdhomerun_device); 181 182 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- shutdown"); 183 184 // TODO teardown PID filters here 185 186 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- end"); 92 return dynamic_cast<HDHRChannel*>(channel); 187 93 } 188 94 189 95 /** \fn HDHRSignalMonitor::UpdateValues() … … void HDHRSignalMonitor::UpdateValues(voi 201 107 if (!running || exit) 202 108 return; 203 109 204 if ( dtvMonitorRunning)110 if (streamHandlerStarted) 205 111 { 206 112 EmitHDHRSignals(); 207 113 if (IsAllGood()) … … void HDHRSignalMonitor::UpdateValues(voi 212 118 return; 213 119 } 214 120 215 HDHRChannel *hdrc = dynamic_cast<HDHRChannel*>(channel); 216 struct hdhomerun_device_t *_hdhomerun_device = hdrc->GetHDHRDevice(); 217 struct hdhomerun_tuner_status_t status; 218 hdhomerun_device_get_tuner_status(_hdhomerun_device, NULL, &status); 219 220 uint sig = status.signal_strength; 221 uint snq = status.signal_to_noise_quality; 222 uint seq = status.symbol_error_quality; 223 121 QString msg = streamHandler->GetTunerStatus(); 122 //ss = signal strength, [0,100] 123 //snq = signal to noise quality [0,100] 124 //seq = signal error quality [0,100] 125 int loc_sig = msg.find("ss="), loc_snq = msg.find("snq="); 126 int loc_seq = msg.find("seq="), loc_end = msg.length(); 127 bool ok0, ok1, ok2; 128 uint sig = msg.mid(loc_sig + 3, loc_snq - loc_sig - 4).toUInt(&ok0); 129 uint snq = msg.mid(loc_snq + 4, loc_seq - loc_snq - 5).toUInt(&ok1); 130 uint seq = msg.mid(loc_seq + 4, loc_end - loc_seq - 4).toUInt(&ok2); 224 131 (void) snq; // TODO should convert to S/N 225 132 (void) seq; // TODO should report this... 226 133 … … void HDHRSignalMonitor::UpdateValues(voi 232 139 bool isLocked = false; 233 140 { 234 141 QMutexLocker locker(&statusLock); 235 signalStrength.SetValue(sig); 236 signalLock.SetValue(status.lock_supported); 142 if (loc_sig > 0 && loc_snq > 0 && ok0) 143 signalStrength.SetValue(sig); 144 signalLock.SetValue(signalStrength.IsGood() ? 1 : 0); 237 145 isLocked = signalLock.IsGood(); 238 146 } 239 147 … … void HDHRSignalMonitor::UpdateValues(voi 248 156 kDTVSigMon_WaitForMGT | kDTVSigMon_WaitForVCT | 249 157 kDTVSigMon_WaitForNIT | kDTVSigMon_WaitForSDT)) 250 158 { 251 pthread_create(&table_monitor_thread, NULL, 252 TableMonitorThread, this); 253 254 VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- " 255 "Waiting for table monitor to start"); 256 257 while (!dtvMonitorRunning) 258 usleep(50); 259 260 VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- " 261 "Table monitor started"); 159 streamHandler->AddListener(GetStreamData()); 160 streamHandlerStarted = true; 262 161 } 263 162 264 163 update_done = true; -
mythtv/libs/libmythtv/hdhrsignalmonitor.h
diff -p -r -u -N -X /tmp/diff.exclude -x release.21404.0821a -x release.21404.0821b release.21404.0821a/mythtv/libs/libmythtv/hdhrsignalmonitor.h release.21404.0821b/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 … … class HDHRSignalMonitor: public DTVSigna 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 … … class HDHRSignalMonitor: public DTVSigna 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 -p -r -u -N -X /tmp/diff.exclude -x release.21404.0821a -x release.21404.0821b release.21404.0821a/mythtv/libs/libmythtv/hdhrstreamhandler.cpp release.21404.0821b/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(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(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(QString devicename) : 100 _control_socket(NULL), 101 _video_socket(NULL), 102 _devicename(devicename), 103 _allow_retune(false), 104 105 _start_stop_lock(true), 106 _running(false), 107 108 _sigmon(NULL), 109 _channel(NULL), 110 111 _pid_lock(true), 112 _listener_lock(true), 113 _hdhr_lock(true) 114 { 115 } 116 117 HDHRStreamHandler::~HDHRStreamHandler() 118 { 119 assert(_stream_data_list.empty()); 120 } 121 122 bool HDHRStreamHandler::Open() 123 { 124 if (!FindDevice()) 125 return false; 126 127 return Connect(); 128 } 129 130 void HDHRStreamHandler::Close() 131 { 132 if (_control_socket) 133 { 134 TuneChannel("none"); 135 hdhomerun_control_destroy(_control_socket); 136 _control_socket=NULL; 137 } 138 } 139 140 bool HDHRStreamHandler::Connect() 141 { 142 _control_socket = hdhomerun_control_create(_device_id, _device_ip, NULL); 143 144 if (!_control_socket) 145 { 146 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to create control socket"); 147 return false; 148 } 149 150 if (hdhomerun_control_get_local_addr(_control_socket) == 0) 151 { 152 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to connect to device"); 153 return false; 154 } 155 156 VERBOSE(VB_CHANNEL, LOC + "Successfully connected to device"); 157 return true; 158 } 159 160 bool HDHRStreamHandler::FindDevice(void) 161 { 162 hdhomerun_device_t* thisdevice = hdhomerun_device_create_from_str(_devicename, NULL); 163 164 if (thisdevice) 165 { 166 _device_id = hdhomerun_device_get_device_id(thisdevice); 167 _device_ip = hdhomerun_device_get_device_ip(thisdevice); 168 _tuner = hdhomerun_device_get_tuner(thisdevice); 169 hdhomerun_device_destroy(thisdevice); 170 171 VERBOSE(VB_IMPORTANT, LOC + 172 QString("device %5 found at address %1.%2.%3.%4 tuner %6") 173 .arg((_device_ip>>24) & 0xFF).arg((_device_ip>>16) & 0xFF) 174 .arg((_device_ip>> 8) & 0xFF).arg((_device_ip>> 0) & 0xFF) 175 .arg(_devicename).arg(_tuner)); 176 177 return true; 178 } 179 return false; 180 } 181 182 183 bool HDHRStreamHandler::EnterPowerSavingMode(void) 184 { 185 if (_video_socket) 186 { 187 VERBOSE(VB_CHANNEL, LOC + "Ignoring request - video streaming active"); 188 return false; 189 } 190 else 191 { 192 return TuneChannel("none"); 193 /* QString::null != TunerSet("channel", "none", false); */ 194 } 195 } 196 197 QString HDHRStreamHandler::DeviceGet(const QString &name, bool report_error_return) 198 { 199 QMutexLocker locker(&_hdhr_lock); 200 201 if (!_control_socket) 202 { 203 VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed (not connected)"); 204 return QString::null; 205 } 206 207 char *value = NULL; 208 char *error = NULL; 209 if (hdhomerun_control_get(_control_socket, name, &value, &error) < 0) 210 { 211 VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed" + ENO); 212 return QString::null; 213 } 214 215 if (report_error_return && error) 216 { 217 VERBOSE(VB_IMPORTANT, LOC_ERR + 218 QString("DeviceGet(%1): %2").arg(name).arg(error)); 219 220 return QString::null; 221 } 222 223 return QString(value); 224 } 225 226 227 QString HDHRStreamHandler::DeviceSet(const QString &name, const QString &val, 228 bool report_error_return) 229 { 230 QMutexLocker locker(&_hdhr_lock); 231 232 if (!_control_socket) 233 { 234 VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed (not connected)"); 235 return QString::null; 236 } 237 238 char *value = NULL; 239 char *error = NULL; 240 if (hdhomerun_control_set(_control_socket, name, val, &value, &error) < 0) 241 { 242 VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed" + ENO); 243 244 return QString::null; 245 } 246 247 if (report_error_return && error) 248 { 249 VERBOSE(VB_IMPORTANT, LOC_ERR + 250 QString("DeviceSet(%1 %2): %3").arg(name).arg(val).arg(error)); 251 252 return QString::null; 253 } 254 255 return QString(value); 256 } 257 258 QString HDHRStreamHandler::TunerGet(const QString &name, bool report_error_return) 259 { 260 return DeviceGet(QString("/tuner%1/%2").arg(_tuner).arg(name), 261 report_error_return); 262 } 263 264 QString HDHRStreamHandler::TunerSet(const QString &name, const QString &value, 265 bool report_error_return) 266 { 267 return DeviceSet(QString("/tuner%1/%2").arg(_tuner).arg(name), value, 268 report_error_return); 269 } 270 271 bool HDHRStreamHandler::DeviceSetTarget(unsigned short localPort) 272 { 273 if (localPort == 0) 274 { 275 return false; 276 } 277 278 unsigned long localIP = hdhomerun_control_get_local_addr(_control_socket); 279 if (localIP == 0) 280 { 281 return false; 282 } 283 284 QString configValue = QString("rtp://%1.%2.%3.%4:%5") 285 .arg((localIP >> 24) & 0xFF).arg((localIP >> 16) & 0xFF) 286 .arg((localIP >> 8) & 0xFF).arg((localIP >> 0) & 0xFF) 287 .arg(localPort); 288 289 if (!TunerSet("target", configValue)) 290 { 291 return false; 292 } 293 294 return true; 295 } 296 297 bool HDHRStreamHandler::DeviceClearTarget() 298 { 299 return (QString::null != TunerSet("target", "0.0.0.0:0")); 300 } 301 302 QString HDHRStreamHandler::GetTunerStatus() { 303 return TunerGet("status"); 304 } 305 306 bool HDHRStreamHandler::Connected() { 307 // FIXME 308 return (_control_socket != NULL); 309 } 310 311 bool HDHRStreamHandler::TuneChannel(QString chn) { 312 QString current = TunerGet("channel"); 313 if (current == chn) 314 { 315 VERBOSE(VB_RECORD, QString(LOC + "Not Re-Tuning channel %1").arg(chn)); 316 return true; 317 } 318 VERBOSE(VB_RECORD, QString(LOC + "Tuning channel %1 (was %2)").arg(chn).arg(current)); 319 return (QString::null != TunerSet("channel", chn)); 320 } 321 322 bool HDHRStreamHandler::TuneProgram(QString pnum) { 323 VERBOSE(VB_RECORD, QString(LOC + "Tuning program %1").arg(pnum)); 324 return (QString::null != TunerSet("program", pnum, false)); 325 } 326 327 void HDHRStreamHandler::AddListener(MPEGStreamData *data) 328 { 329 VERBOSE(VB_RECORD, LOC + "AddListener("<<data<<") -- begin"); 330 assert(data); 331 332 _listener_lock.lock(); 333 334 VERBOSE(VB_RECORD, LOC + "AddListener("<<data<<") -- locked"); 335 336 _stream_data_list.push_back(data); 337 338 _listener_lock.unlock(); 339 340 Start(); 341 342 VERBOSE(VB_RECORD, LOC + "AddListener("<<data<<") -- end"); 343 } 344 345 void HDHRStreamHandler::RemoveListener(MPEGStreamData *data) 346 { 347 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<data<<") -- begin"); 348 assert(data); 349 350 _listener_lock.lock(); 351 352 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<data<<") -- locked"); 353 354 vector<MPEGStreamData*>::iterator it = 355 find(_stream_data_list.begin(), _stream_data_list.end(), data); 356 357 if (it != _stream_data_list.end()) 358 _stream_data_list.erase(it); 359 360 if (_stream_data_list.empty()) 361 { 362 _listener_lock.unlock(); 363 Stop(); 364 } 365 else 366 { 367 _listener_lock.unlock(); 368 } 369 370 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<data<<") -- end"); 371 } 372 373 void *run_hdhr_stream_handler_thunk(void *param) 374 { 375 HDHRStreamHandler *mon = (HDHRStreamHandler*) param; 376 mon->Run(); 377 return NULL; 378 } 379 380 void HDHRStreamHandler::Start(void) 381 { 382 QMutexLocker locker(&_start_stop_lock); 383 384 _eit_pids.clear(); 385 386 if (!IsRunning()) 387 { 388 pthread_create(&_reader_thread, NULL, 389 run_hdhr_stream_handler_thunk, this); 390 391 while (!IsRunning()) 392 _running_state_changed.wait(100); 393 } 394 } 395 396 void HDHRStreamHandler::Stop(void) 397 { 398 QMutexLocker locker(&_start_stop_lock); 399 400 if (IsRunning()) 401 { 402 SetRunning(false); 403 pthread_join(_reader_thread, NULL); 404 } 405 } 406 407 void HDHRStreamHandler::Run(void) 408 { 409 SetRunning(true); 410 RunTS(); 411 } 412 413 /** \fn HDHRStreamHandler::RunTS(void) 414 * \brief Uses TS filtering devices to read a DVB device for tables & data 415 * 416 * This supports all types of MPEG based stream data, but is extreemely 417 * slow with DVB over USB 1.0 devices which for efficiency reasons buffer 418 * a stream until a full block transfer buffer full of the requested 419 * tables is available. This takes a very long time when you are just 420 * waiting for a PAT or PMT table, and the buffer is hundreds of packets 421 * in size. 422 */ 423 void HDHRStreamHandler::RunTS(void) 424 { 425 int remainder = 0; 426 VERBOSE(VB_RECORD, LOC + "RunTS()"); 427 428 /* Calculate buffer size */ 429 uint buffersize = gContext->GetNumSetting( 430 "HDRingbufferSize", 50 * TSPacket::SIZE) * 1024; 431 buffersize /= VIDEO_DATA_PACKET_SIZE; 432 buffersize *= VIDEO_DATA_PACKET_SIZE; 433 434 // Buffer should be at least about 1MB.. 435 buffersize = max(49 * TSPacket::SIZE * 128, buffersize); 436 437 VERBOSE(VB_GENERAL, QString(LOC + "HD Ringbuffer size = %1 KB").arg(buffersize / 1024)); 438 439 /* Create TS socket. */ 440 _video_socket = hdhomerun_video_create(0, buffersize, NULL); 441 if (!_video_socket) 442 { 443 VERBOSE(VB_IMPORTANT, LOC + "Open() failed to open socket"); 444 return; 445 } 446 447 uint localPort = hdhomerun_video_get_local_port(_video_socket); 448 if (!DeviceSetTarget(localPort)) 449 { 450 VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting recording (set target failed). Aborting."); 451 return; 452 } 453 hdhomerun_video_flush(_video_socket); 454 455 bool _error = false; 456 457 VERBOSE(VB_RECORD, LOC + "RunTS(): begin"); 458 459 while (IsRunning() && !_error) 460 { 461 UpdateFiltersFromStreamData(); 462 463 size_t read_size = 64 * 1024; // read about 64KB 464 read_size /= VIDEO_DATA_PACKET_SIZE; 465 read_size *= VIDEO_DATA_PACKET_SIZE; 466 467 size_t data_length; 468 unsigned char *data_buffer = 469 hdhomerun_video_recv(_video_socket, read_size, &data_length); 470 471 if (! data_buffer) 472 { 473 usleep(5000); 474 continue; 475 } 476 477 // Assume data_length is a multiple of 188 (packet size) 478 ASSERT(0 == ( data_length % 188) ); 479 480 _listener_lock.lock(); 481 482 if (_stream_data_list.empty()) 483 { 484 _listener_lock.unlock(); 485 continue; 486 } 487 488 for (uint i = 0; i < _stream_data_list.size(); i++) 489 { 490 remainder = _stream_data_list[i]->ProcessData(data_buffer, data_length); 491 } 492 493 _listener_lock.unlock(); 494 if (remainder != 0) 495 VERBOSE(VB_GENERAL, QString(LOC + "RunTS(): data_length = %1 remainder = %2") 496 .arg(data_length).arg(remainder)); 497 } 498 VERBOSE(VB_RECORD, LOC + "RunTS(): " + "shutdown"); 499 500 DelAllPIDs(); 501 502 DeviceClearTarget(); 503 VERBOSE(VB_RECORD, LOC + "RunTS(): " + "end"); 504 505 hdhomerun_video_sock_t* tmp_video_socket; 506 { 507 QMutexLocker locker(&_hdhr_lock); 508 tmp_video_socket = _video_socket; 509 _video_socket=NULL; 510 } 511 512 hdhomerun_video_destroy(tmp_video_socket); 513 514 SetRunning(false); 515 } 516 517 bool HDHRStreamHandler::AddPID(uint pid, bool do_update) 518 { 519 QMutexLocker locker(&_pid_lock); 520 521 vector<uint>::iterator it; 522 it = lower_bound(_pid_info.begin(), _pid_info.end(), pid); 523 if (it != _pid_info.end() && *it == pid) 524 { 525 #ifdef DEBUG_PID_FILTERS 526 VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<", " << do_update << ") NOOP"); 527 #endif // DEBUG_PID_FILTERS 528 return true; 529 } 530 531 _pid_info.insert(it, pid); 532 533 #ifdef DEBUG_PID_FILTERS 534 VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<")", " << do_update << "); 535 #endif // DEBUG_PID_FILTERS 536 537 if (do_update) 538 return UpdateFilters(); 539 return true; 540 } 541 542 bool HDHRStreamHandler::DelPID(uint pid, bool do_update) 543 { 544 QMutexLocker locker(&_pid_lock); 545 546 vector<uint>::iterator it; 547 it = lower_bound(_pid_info.begin(), _pid_info.end(), pid); 548 if (it == _pid_info.end()) 549 { 550 #ifdef DEBUG_PID_FILTERS 551 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<", " << do_update << ") NOOP"); 552 #endif // DEBUG_PID_FILTERS 553 554 return true; 555 } 556 557 if (*it == pid) 558 { 559 #ifdef DEBUG_PID_FILTERS 560 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<", " << do_update << ") -- found"); 561 #endif // DEBUG_PID_FILTERS 562 _pid_info.erase(it); 563 } 564 else 565 { 566 #ifdef DEBUG_PID_FILTERS 567 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<", " << do_update << ") -- failed"); 568 #endif // DEBUG_PID_FILTERS 569 } 570 571 if (do_update) 572 return UpdateFilters(); 573 return true; 574 } 575 576 bool HDHRStreamHandler::DelAllPIDs(void) 577 { 578 QMutexLocker locker(&_pid_lock); 579 580 #ifdef DEBUG_PID_FILTERS 581 VERBOSE(VB_CHANNEL, "DelAllPID()"); 582 #endif // DEBUG_PID_FILTERS 583 584 _pid_info.clear(); 585 586 return UpdateFilters(); 587 } 588 589 QString filt_str(uint pid) 590 { 591 uint pid0 = (pid / (16*16*16)) % 16; 592 uint pid1 = (pid / (16*16)) % 16; 593 uint pid2 = (pid / (16)) % 16; 594 uint pid3 = pid % 16; 595 return QString("0x%1%2%3%4") 596 .arg(pid0,0,16).arg(pid1,0,16) 597 .arg(pid2,0,16).arg(pid3,0,16); 598 } 599 600 bool HDHRStreamHandler::UpdateFilters(void) 601 { 602 #ifdef DEBUG_PID_FILTERS 603 VERBOSE(VB_CHANNEL, LOC + "UpdateFilters()"); 604 #endif // DEBUG_PID_FILTERS 605 QMutexLocker locker(&_pid_lock); 606 607 QString filter = ""; 608 609 vector<uint> range_min; 610 vector<uint> range_max; 611 612 // FIXME 613 // if (_ignore_filters) 614 // return true; 615 616 for (uint i = 0; i < _pid_info.size(); i++) 617 { 618 uint pid_min = _pid_info[i]; 619 uint pid_max = pid_min; 620 for (uint j = i + 1; j < _pid_info.size(); j++) 621 { 622 if (pid_max + 1 != _pid_info[j]) 623 break; 624 pid_max++; 625 i++; 626 } 627 range_min.push_back(pid_min); 628 range_max.push_back(pid_max); 629 } 630 if (range_min.size() > 16) 631 { 632 range_min.resize(16); 633 uint pid_max = range_max.back(); 634 range_max.resize(15); 635 range_max.push_back(pid_max); 636 } 637 638 for (uint i = 0; i < range_min.size(); i++) 639 { 640 filter += filt_str(range_min[i]); 641 if (range_min[i] != range_max[i]) 642 filter += QString("-%1").arg(filt_str(range_max[i])); 643 filter += " "; 644 } 645 646 filter = filter.stripWhiteSpace(); 647 648 QString new_filter = TunerSet("filter", filter); 649 650 #ifdef DEBUG_PID_FILTERS 651 QString msg = QString("Filter: '%1'").arg(filter); 652 if (filter != new_filter) 653 msg += QString("\n\t\t\t\t'%2'").arg(new_filter); 654 655 VERBOSE(VB_CHANNEL, LOC + msg); 656 #endif // DEBUG_PID_FILTERS 657 658 return filter == new_filter; 659 } 660 661 void HDHRStreamHandler::UpdateListeningForEIT(void) 662 { 663 vector<uint> add_eit, del_eit; 664 665 QMutexLocker read_locker(&_listener_lock); 666 667 for (uint i = 0; i < _stream_data_list.size(); i++) 668 { 669 MPEGStreamData *sd = _stream_data_list[i]; 670 if (sd->HasEITPIDChanges(_eit_pids) && 671 sd->GetEITPIDChanges(_eit_pids, add_eit, del_eit)) 672 { 673 for (uint i = 0; i < del_eit.size(); i++) 674 { 675 uint_vec_t::iterator it; 676 it = find(_eit_pids.begin(), _eit_pids.end(), del_eit[i]); 677 if (it != _eit_pids.end()) 678 _eit_pids.erase(it); 679 sd->RemoveListeningPID(del_eit[i]); 680 } 681 682 for (uint i = 0; i < add_eit.size(); i++) 683 { 684 _eit_pids.push_back(add_eit[i]); 685 sd->AddListeningPID(add_eit[i]); 686 } 687 } 688 } 689 } 690 691 bool HDHRStreamHandler::UpdateFiltersFromStreamData(void) 692 { 693 694 UpdateListeningForEIT(); 695 696 pid_map_t pids; 697 698 { 699 QMutexLocker read_locker(&_listener_lock); 700 701 for (uint i = 0; i < _stream_data_list.size(); i++) 702 _stream_data_list[i]->GetPIDs(pids); 703 } 704 705 uint_vec_t add_pids; 706 vector<uint> del_pids; 707 708 { 709 QMutexLocker read_locker(&_pid_lock); 710 711 // PIDs that need to be added.. 712 pid_map_t::const_iterator lit = pids.constBegin(); 713 for (; lit != pids.constEnd(); ++lit) 714 { 715 vector<uint>::iterator it; 716 it = lower_bound(_pid_info.begin(), _pid_info.end(), lit.key()); 717 if (! (it != _pid_info.end() && *it == lit.key())) { 718 add_pids.push_back(lit.key()); 719 } 720 } 721 722 // PIDs that need to be removed.. 723 vector<uint>::iterator fit = _pid_info.begin(); 724 for (; fit != _pid_info.end(); ++fit) 725 { 726 pid_map_t::const_iterator it = pids.find(*fit); 727 if(it == pids.end()) 728 del_pids.push_back(*fit); 729 } 730 } 731 732 bool need_update = false; 733 734 // Remove PIDs 735 bool ok = true; 736 vector<uint>::iterator dit = del_pids.begin(); 737 for (; dit != del_pids.end(); ++dit) 738 { 739 need_update = true; 740 ok &= DelPID(*dit, false); 741 } 742 743 // Add PIDs 744 vector<uint>::iterator ait = add_pids.begin(); 745 for (; ait != add_pids.end(); ++ait) 746 { 747 need_update = true; 748 ok &= AddPID(*ait, false); 749 } 750 751 if (need_update) 752 return UpdateFilters(); 753 754 return ok; 755 } 756 757 void HDHRStreamHandler::SetRetuneAllowed( 758 bool allow, 759 DTVSignalMonitor *sigmon, 760 HDHRChannel *hdhrchan) 761 { 762 if (allow && sigmon && hdhrchan) 763 { 764 _allow_retune = true; 765 _sigmon = sigmon; 766 _channel = hdhrchan; 767 } 768 else 769 { 770 _allow_retune = false; 771 _sigmon = NULL; 772 _channel = NULL; 773 } 774 } 775 776 /** \fn HDHRStreamHandler::SupportsTSMonitoring(void) 777 * \brief Returns true if TS monitoring is supported. 778 * 779 * NOTE: If you are using a DEC2000-t device you need to 780 * apply the patches provided by Peter Beutner for it, see 781 * http://www.gossamer-threads.com/lists/mythtv/dev/166172 782 * These patches should make it in to Linux 2.6.15 or 2.6.16. 783 */ 784 bool HDHRStreamHandler::SupportsTSMonitoring(void) 785 { 786 return false; 787 788 // FIXME 789 #if 0 790 const uint pat_pid = 0x0; 791 792 { 793 QMutexLocker locker(&_rec_supports_ts_monitoring_lock); 794 QMap<uint,bool>::const_iterator it; 795 it = _rec_supports_ts_monitoring.find(_dvb_dev_num); 796 if (it != _rec_supports_ts_monitoring.end()) 797 return *it; 798 } 799 800 int dvr_fd = open(_dvr_dev_path.ascii(), O_RDONLY | O_NONBLOCK); 801 if (dvr_fd < 0) 802 { 803 QMutexLocker locker(&_rec_supports_ts_monitoring_lock); 804 _rec_supports_ts_monitoring[_dvb_dev_num] = false; 805 return false; 806 } 807 808 bool supports_ts = false; 809 if (AddPIDFilter(new PIDInfoHDHR(pat_pid))) 810 { 811 supports_ts = true; 812 RemovePIDFilter(pat_pid); 813 } 814 815 close(dvr_fd); 816 817 QMutexLocker locker(&_rec_supports_ts_monitoring_lock); 818 _rec_supports_ts_monitoring[_dvb_dev_num] = supports_ts; 819 820 return supports_ts; 821 #endif 822 } 823 824 void HDHRStreamHandler::SetRunning(bool is_running) 825 { 826 _running = is_running; 827 _running_state_changed.wakeAll(); 828 } 829 830 PIDPriority HDHRStreamHandler::GetPIDPriority(uint pid) const 831 { 832 QMutexLocker reading_locker(&_listener_lock); 833 834 PIDPriority tmp = kPIDPriorityNone; 835 836 for (uint i = 0; i < _stream_data_list.size(); i++) 837 tmp = max(tmp, _stream_data_list[i]->GetPIDPriority(pid)); 838 839 return tmp; 840 } -
mythtv/libs/libmythtv/hdhrstreamhandler.h
diff -p -r -u -N -X /tmp/diff.exclude -x release.21404.0821a -x release.21404.0821b release.21404.0821a/mythtv/libs/libmythtv/hdhrstreamhandler.h release.21404.0821b/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/hdhomerun.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(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(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 -p -r -u -N -X /tmp/diff.exclude -x release.21404.0821a -x release.21404.0821b release.21404.0821a/mythtv/libs/libmythtv/libmythtv.pro release.21404.0821b/mythtv/libs/libmythtv/libmythtv.pro
using_backend { 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/scanwizardscanner.cpp
diff -p -r -u -N -X /tmp/diff.exclude -x release.21404.0821a -x release.21404.0821b release.21404.0821a/mythtv/libs/libmythtv/scanwizardscanner.cpp release.21404.0821b/mythtv/libs/libmythtv/scanwizardscanner.cpp
void ScanWizardScanner::PreScanCommon(in 518 518 #ifdef USING_HDHOMERUN 519 519 if ("HDHOMERUN" == card_type) 520 520 { 521 uint tuner = CardUtil::GetHDHRTuner(cardid); 522 channel = new HDHRChannel(NULL, device, tuner); 521 channel = new HDHRChannel(NULL, device); 523 522 } 524 523 #endif // USING_HDHOMERUN 525 524 -
mythtv/libs/libmythtv/tv_rec.cpp
diff -p -r -u -N -X /tmp/diff.exclude -x release.21404.0821a -x release.21404.0821b release.21404.0821a/mythtv/libs/libmythtv/tv_rec.cpp release.21404.0821b/mythtv/libs/libmythtv/tv_rec.cpp
bool TVRec::CreateChannel(const QString 174 174 else if (genOpt.cardtype == "HDHOMERUN") 175 175 { 176 176 #ifdef USING_HDHOMERUN 177 channel = new HDHRChannel(this, genOpt.videodev , dboxOpt.port);177 channel = new HDHRChannel(this, genOpt.videodev); 178 178 if (!channel->Open()) 179 179 return false; 180 180 InitChannel(genOpt.defaultinput, startchannel); … … void TVRec::HandleTuning(void) 3430 3430 return; 3431 3431 3432 3432 ClearFlags(kFlagWaitingForRecPause); 3433 #ifdef USING_HDHOMERUN3434 if (GetHDHRRecorder())3435 {3436 // We currently need to close the file descriptor for3437 // HDHomeRun signal monitoring to work.3438 GetHDHRRecorder()->Close();3439 GetHDHRRecorder()->SetRingBuffer(NULL);3440 }3441 #endif // USING_HDHOMERUN3442 3433 VERBOSE(VB_RECORD, LOC + "Recorder paused, calling TuningFrequency"); 3443 3434 TuningFrequency(lastTuningRequest); 3444 3435 } … … void TVRec::TuningRestartRecorder(void) 4077 4068 } 4078 4069 recorder->Reset(); 4079 4070 4080 #ifdef USING_HDHOMERUN4081 if (GetHDHRRecorder())4082 {4083 pauseNotify = false;4084 GetHDHRRecorder()->Close();4085 pauseNotify = true;4086 GetHDHRRecorder()->Open();4087 GetHDHRRecorder()->StartData();4088 }4089 #endif // USING_HDHOMERUN4090 4091 4071 // Set file descriptor of channel from recorder for V4L 4092 4072 channel->SetFd(recorder->GetVideoFd()); 4093 4073 -
mythtv/libs/libmythtv/videosource.cpp
diff -p -r -u -N -X /tmp/diff.exclude -x release.21404.0821a -x release.21404.0821b release.21404.0821a/mythtv/libs/libmythtv/videosource.cpp release.21404.0821b/mythtv/libs/libmythtv/videosource.cpp
using namespace std; 47 47 #include "videodev_myth.h" 48 48 #endif 49 49 50 #include "hdhomerun/hdhomerun.h" 51 50 52 VideoSourceSelector::VideoSourceSelector(uint _initial_sourceid, 51 53 const QString &_card_types, 52 54 bool _must_have_mplexid) : … … class InstanceCount : public TransSpinBo 131 133 class RecorderOptions : public ConfigurationWizard 132 134 { 133 135 public: 134 RecorderOptions(CaptureCard& parent );136 RecorderOptions(CaptureCard& parent, QString type); 135 137 uint GetInstanceCount(void) const { return (uint) count->intValue(); } 136 138 137 139 private: … … class DBOX2ConfigurationGroup : public V 1283 1285 CaptureCard &parent; 1284 1286 }; 1285 1287 1286 class HDHomeRunDeviceID : public LineEditSetting, public CaptureCardDBStorage 1288 class HDHomeRunIP : public TransLabelSetting 1289 { 1290 public: 1291 HDHomeRunIP() 1292 { 1293 setLabel(QObject::tr("IP Address")); 1294 }; 1295 }; 1296 1297 class HDHomeRunTuner : public TransLabelSetting 1298 { 1299 public: 1300 HDHomeRunTuner() 1301 { 1302 setLabel(QObject::tr("Tuner")); 1303 }; 1304 }; 1305 1306 class HDHomeRunDeviceID : public ComboBoxSetting, public CaptureCardDBStorage 1287 1307 { 1288 1308 public: 1289 1309 HDHomeRunDeviceID(const CaptureCard &parent) : 1290 LineEditSetting(this),1310 ComboBoxSetting(this), 1291 1311 CaptureCardDBStorage(this, parent, "videodevice") 1292 1312 { 1293 setValue("FFFFFFFF");1294 1313 setLabel(QObject::tr("Device ID")); 1295 setHelpText(QObject::tr("IP address or Device ID from the bottom of " 1296 "the HDHomeRun. You may use " 1297 "'FFFFFFFF' if there is only one unit " 1298 "on your your network.")); 1314 setHelpText( 1315 QObject::tr("DevicedID and Tuner Number of available HDHomeRun " 1316 "devices. ")); 1317 fillSelections(""); 1318 }; 1319 1320 /// \brief Adds all available device-tuner combinations to list 1321 /// If current is >= 0 it will be considered available even 1322 /// if no device exists for it on the network 1323 void fillSelections(QString current) 1324 { 1325 clearSelections(); 1326 1327 // Get devices from filesystem 1328 vector<QString> devs = CardUtil::ProbeVideoDevices("HDHOMERUN"); 1329 1330 // Add current if needed 1331 if ((current != "") && 1332 (find(devs.begin(), devs.end(), current) == devs.end())) 1333 { 1334 devs.push_back(current); 1335 stable_sort(devs.begin(), devs.end()); 1336 } 1337 1338 vector<QString> db = CardUtil::GetVideoDevices("HDHOMERUN"); 1339 1340 QMap<QString, bool> in_use; 1341 QString sel = current; 1342 for (uint i = 0; i < devs.size(); i++) 1343 { 1344 const QString dev = devs[i]; 1345 in_use[devs[i]] = find(db.begin(), db.end(), dev) != db.end(); 1346 if (sel == "" && !in_use[devs[i]]) 1347 sel = dev; 1348 } 1349 1350 if (sel == "" && devs.size()) 1351 sel = devs[0]; 1352 1353 QString usestr = QString(" -- "); 1354 usestr += QObject::tr("Warning: already in use"); 1355 1356 for (uint i = 0; i < devs.size(); i++) 1357 { 1358 const QString dev = devs[i]; 1359 QString desc = dev + (in_use[devs[i]] ? usestr : ""); 1360 desc = (current == devs[i]) ? dev : desc; 1361 addSelection(desc, dev, dev == sel); 1362 } 1363 } 1364 1365 virtual void load(void) 1366 { 1367 clearSelections(); 1368 addSelection(""); 1369 1370 CaptureCardDBStorage::load(); 1371 1372 fillSelections(getValue()); 1299 1373 } 1300 1374 }; 1301 1375 … … class IPTVConfigurationGroup : public Ve 1329 1403 CaptureCard &parent; 1330 1404 }; 1331 1405 1332 class HDHomeRunTunerIndex : public ComboBoxSetting, public CaptureCardDBStorage 1406 HDHomeRunConfigurationGroup::HDHomeRunConfigurationGroup(CaptureCard& a_parent) : 1407 VerticalConfigurationGroup(false, true, false, false), 1408 parent(a_parent) 1333 1409 { 1334 public: 1335 HDHomeRunTunerIndex(const CaptureCard &parent) : 1336 ComboBoxSetting(this), 1337 CaptureCardDBStorage(this, parent, "dbox2_port") 1338 { 1339 setLabel(QObject::tr("Tuner")); 1340 addSelection("0"); 1341 addSelection("1"); 1342 } 1410 setUseLabel(false); 1411 deviceid = new HDHomeRunDeviceID(parent); 1412 addChild(deviceid); 1413 cardip = new HDHomeRunIP(); 1414 cardtuner = new HDHomeRunTuner(); 1415 1416 addChild(cardip); 1417 addChild(cardtuner); 1418 1419 addChild(new SignalTimeout(parent, 1000, 250)); 1420 addChild(new ChannelTimeout(parent, 3000, 1750)); 1421 addChild(new SingleCardInput(parent)); 1422 1423 TransButtonSetting *buttonRecOpt = new TransButtonSetting(); 1424 buttonRecOpt->setLabel(tr("Recording Options")); 1425 addChild(buttonRecOpt); 1426 1427 connect(buttonRecOpt, SIGNAL(pressed()), 1428 &parent, SLOT( recorderOptionsPanelHDHomerun())); 1429 connect(deviceid, SIGNAL(valueChanged(const QString&)), 1430 this, SLOT( probeCard (const QString&))); 1431 1432 1343 1433 }; 1344 1434 1345 class HDHomeRunConfigurationGroup : public VerticalConfigurationGroup 1435 void HDHomeRunConfigurationGroup::probeCard(const QString& deviceid) 1346 1436 { 1347 public: 1348 HDHomeRunConfigurationGroup(CaptureCard& a_parent) : 1349 VerticalConfigurationGroup(false, true, false, false), 1350 parent(a_parent) 1437 hdhomerun_device_t* thisdevice = hdhomerun_device_create_from_str(deviceid, NULL); 1438 1439 if (thisdevice) 1351 1440 { 1352 setUseLabel(false); 1353 addChild(new HDHomeRunDeviceID(parent)); 1354 addChild(new HDHomeRunTunerIndex(parent)); 1355 addChild(new SignalTimeout(parent, 1000, 250)); 1356 addChild(new ChannelTimeout(parent, 3000, 1750)); 1357 addChild(new SingleCardInput(parent)); 1358 }; 1441 uint device_ip = hdhomerun_device_get_device_ip(thisdevice); 1442 uint tuner = hdhomerun_device_get_tuner(thisdevice); 1443 hdhomerun_device_destroy(thisdevice); 1359 1444 1360 private: 1361 CaptureCard &parent; 1362 }; 1445 QString ip = QString("%1.%2.%3.%4") 1446 .arg((device_ip>>24) & 0xFF).arg((device_ip>>16) & 0xFF) 1447 .arg((device_ip>> 8) & 0xFF).arg((device_ip>> 0) & 0xFF); 1448 1449 cardip->setValue(ip); 1450 cardtuner->setValue(QString("%1").arg(tuner)); 1451 } 1452 else 1453 { 1454 cardip->setValue("Unknown"); 1455 cardtuner->setValue("Unknown"); 1456 } 1457 } 1363 1458 1364 1459 V4LConfigurationGroup::V4LConfigurationGroup(CaptureCard& a_parent) : 1365 1460 VerticalConfigurationGroup(false, true, false, false), … … void CaptureCard::fillSelections(SelectS 1528 1623 if ((cardtype.lower() == "dvb") && (1 != ++device_refs[videodevice])) 1529 1624 continue; 1530 1625 1626 if ((cardtype.lower() == "hdhomerun") && (1 != ++device_refs[videodevice])) 1627 continue; 1628 1531 1629 QString label = CardUtil::GetDeviceLabel( 1532 1630 cardid, cardtype, videodevice); 1533 1631 … … void CardInputEditor::load() 2667 2765 if ((cardtype.lower() == "dvb") && (1 != ++device_refs[videodevice])) 2668 2766 continue; 2669 2767 2768 if ((cardtype.lower() == "hdhomerun") && (1 != ++device_refs[videodevice])) 2769 continue; 2770 2670 2771 QStringList inputLabels; 2671 2772 vector<CardInput*> cardInputs; 2672 2773 … … DVBConfigurationGroup::DVBConfigurationG 2908 3009 connect(buttonDiSEqC, SIGNAL(pressed()), 2909 3010 this, SLOT( DiSEqCPanel())); 2910 3011 connect(buttonRecOpt, SIGNAL(pressed()), 2911 &parent, SLOT( recorderOptionsPanel ()));3012 &parent, SLOT( recorderOptionsPanelDVB())); 2912 3013 } 2913 3014 2914 3015 DVBConfigurationGroup::~DVBConfigurationGroup() … … void CaptureCard::reload(void) 2953 3054 } 2954 3055 } 2955 3056 2956 void CaptureCard::recorderOptionsPanel() 3057 void CaptureCard::recorderOptionsPanelHDHomerun() 3058 { 3059 reload(); 3060 3061 RecorderOptions acw(*this, "HDHOMERUN"); 3062 acw.exec(); 3063 instance_count = acw.GetInstanceCount(); 3064 } 3065 3066 void CaptureCard::recorderOptionsPanelDVB() 2957 3067 { 2958 3068 reload(); 2959 3069 2960 RecorderOptions acw(*this );3070 RecorderOptions acw(*this, "DVB"); 2961 3071 acw.exec(); 2962 3072 instance_count = acw.GetInstanceCount(); 2963 3073 } 2964 3074 2965 RecorderOptions::RecorderOptions(CaptureCard &parent )3075 RecorderOptions::RecorderOptions(CaptureCard &parent, QString type) 2966 3076 : count(new InstanceCount(parent)) 2967 3077 { 2968 3078 VerticalConfigurationGroup* rec = new VerticalConfigurationGroup(false); … … RecorderOptions::RecorderOptions(Capture 2970 3080 rec->setUseLabel(false); 2971 3081 2972 3082 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)); 3083 if (type == "DVB") 3084 { 3085 rec->addChild(new DVBNoSeqStart(parent)); 3086 rec->addChild(new DVBOnDemand(parent)); 3087 rec->addChild(new DVBEITScan(parent)); 3088 rec->addChild(new DVBTuningDelay(parent)); 3089 } 2977 3090 2978 3091 addChild(rec); 2979 3092 } 3093 -
mythtv/libs/libmythtv/videosource.h
diff -p -r -u -N -X /tmp/diff.exclude -x release.21404.0821a -x release.21404.0821b release.21404.0821a/mythtv/libs/libmythtv/videosource.h release.21404.0821b/mythtv/libs/libmythtv/videosource.h
private: 418 418 DiSEqCDevTree *diseqc_tree; 419 419 }; 420 420 421 class HDHomeRunDeviceID; 422 class HDHomeRunIP; 423 class HDHomeRunTuner; 424 class HDHomeRunConfigurationGroup : public VerticalConfigurationGroup 425 { 426 Q_OBJECT 427 public: 428 HDHomeRunConfigurationGroup(CaptureCard& a_parent); 429 430 public slots: 431 void probeCard(const QString& deviceid); 432 433 private: 434 HDHomeRunDeviceID *deviceid; 435 HDHomeRunIP *cardip; 436 HDHomeRunTuner *cardtuner; 437 438 CaptureCard &parent; 439 }; 440 441 421 442 class FirewireGUID; 422 443 class FirewireModel : public ComboBoxSetting, public CaptureCardDBStorage 423 444 { … … public: 477 498 uint GetInstanceCount(void) const { return instance_count; } 478 499 479 500 public slots: 480 void recorderOptionsPanel(); 501 void recorderOptionsPanelDVB(); 502 void recorderOptionsPanelHDHomerun(); 481 503 482 504 private: 483 505