Ticket #6138: 133-hdhr.multirec.9.trunk.patch
File 133-hdhr.multirec.9.trunk.patch, 83.4 KB (added by , 15 years ago) |
---|
-
mythtv/libs/libmythtv/cardutil.cpp
diff -r -u -N -X diff.exclude.noxml -x myth.20064 -x myth.20018 myth.20064/mythtv/libs/libmythtv/cardutil.cpp myth.20018/mythtv/libs/libmythtv/cardutil.cpp
29 29 #include "videodev_myth.h" 30 30 #endif 31 31 32 #include "hdhomerun_includes.h" 33 32 34 #define LOC QString("CardUtil: ") 33 35 #define LOC_WARN QString("CardUtil, Warning: ") 34 36 #define LOC_ERR QString("CardUtil, Error: ") … … 210 212 devs.push_back(subit->filePath()); 211 213 } 212 214 } 215 else if (rawtype.toUpper() == "HDHOMERUN") 216 { 217 218 uint32_t target_ip = 0; 219 uint32_t device_type = HDHOMERUN_DEVICE_TYPE_TUNER; 220 uint32_t device_id = HDHOMERUN_DEVICE_ID_WILDCARD; 221 const int max_count = 50; 222 hdhomerun_discover_device_t result_list[max_count]; 223 224 int result = hdhomerun_discover_find_devices_custom( 225 target_ip, 226 device_type, 227 device_id, 228 result_list, 229 max_count); 230 231 if (result == -1) 232 { 233 VERBOSE(VB_IMPORTANT, "CardUtil::ProbeVideoDevices: Error finding HDHomerun devices"); 234 return devs; 235 } 236 237 if (result == 20) 238 VERBOSE(VB_IMPORTANT, "CardUtil::ProbeVideoDevices: Warning: may be > 20 HDHomerun devices"); 239 240 // Fixme -- figure out some way to return ip address as well 241 for (int i = 0; i < result; i++) 242 { 243 QString did = QString("%1").arg(result_list[i].device_id,0, 16); 244 did=did.toUpper(); 245 246 devs.push_back(did + "-0"); 247 devs.push_back(did + "-1"); 248 } 249 } 213 250 else 214 251 { 215 252 VERBOSE(VB_IMPORTANT, QString("CardUtil::ProbeVideoDevices: ") + … … 1146 1183 uint id = 0; 1147 1184 for (uint i = 0; !id && (i < 100); i++) 1148 1185 { 1149 name = QString("DVB%1").arg(dev.toUInt()); 1186 bool ok; 1187 name = QString("DVB%1").arg(dev.toUInt(&ok)); 1188 if (! ok) 1189 { 1190 name = QString("HDHR_%1").arg(dev); 1191 } 1150 1192 name += (i) ? QString(":%1").arg(i) : QString(""); 1151 1193 id = CardUtil::CreateInputGroup(name); 1152 1194 } … … 1749 1791 } 1750 1792 else if (cardtype == "HDHOMERUN") 1751 1793 { 1752 MSqlQuery query(MSqlQuery::InitCon()); 1753 query.prepare( 1754 "SELECT dbox2_port " 1755 "FROM capturecard " 1756 "WHERE cardid = :CARDID"); 1757 query.bindValue(":CARDID", cardid); 1758 1759 if (!query.exec() || !query.isActive() || !query.next()) 1760 label = "[ DB ERROR ]"; 1761 else 1762 label = QString("[ HDHomeRun : ID %1 Port %2 ]") 1763 .arg(videodevice).arg(query.value(0).toString()); 1794 label = QString("[ HDHomeRun : %1 ]").arg(videodevice); 1764 1795 } 1765 1796 else 1766 1797 { -
mythtv/libs/libmythtv/cardutil.h
diff -r -u -N -X diff.exclude.noxml -x myth.20064 -x myth.20018 myth.20064/mythtv/libs/libmythtv/cardutil.h myth.20018/mythtv/libs/libmythtv/cardutil.h
115 115 116 116 static bool IsTunerSharingCapable(const QString &rawtype) 117 117 { 118 return (rawtype == "DVB") ;118 return (rawtype == "DVB") || (rawtype == "HDHOMERUN"); 119 119 } 120 120 121 121 static bool IsTunerShared(uint cardidA, uint cardidB); -
mythtv/libs/libmythtv/hdhomerun_includes.h
diff -r -u -N -X diff.exclude.noxml -x myth.20064 -x myth.20018 myth.20064/mythtv/libs/libmythtv/hdhomerun_includes.h myth.20018/mythtv/libs/libmythtv/hdhomerun_includes.h
1 #ifndef __HDHOMERUN_INCLUDES__ 2 #define __HDHOMERUN_INCLUDES__ 3 4 #include "hdhomerun.h" 5 6 #endif /* __HDHOMERUN_INCLUDES__ */ 7 -
mythtv/libs/libmythtv/hdhrchannel.cpp
diff -r -u -N -X diff.exclude.noxml -x myth.20064 -x myth.20018 myth.20064/mythtv/libs/libmythtv/hdhrchannel.cpp myth.20018/mythtv/libs/libmythtv/hdhrchannel.cpp
26 26 #include "videosource.h" 27 27 #include "channelutil.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 HDHRChannel::HDHRChannel(TVRec *parent, const QString &device, uint tuner) 35 : DTVChannel(parent), _control_socket(NULL), 36 _device_id(0), _device_ip(0), 37 _tuner(tuner), _lock(QMutex::Recursive) 38 { 39 bool valid; 40 _device_id = device.toUInt(&valid, 16); 41 42 if (valid && hdhomerun_discover_validate_device_id(_device_id)) 43 return; 44 45 /* Otherwise, is it a valid IP address? */ 46 struct in_addr address; 47 if (inet_aton(device.toLatin1().constData(), &address)) 48 { 49 _device_ip = ntohl(address.s_addr); 50 return; 51 } 52 53 /* Invalid, use wildcard device ID. */ 54 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Invalid DeviceID '%1'") 55 .arg(device)); 56 57 _device_id = HDHOMERUN_DEVICE_ID_WILDCARD; 36 HDHRChannel::HDHRChannel(TVRec *parent, const QString &device) 37 : DTVChannel(parent), _stream_handler(NULL), 38 _device_id(device), _lock(QMutex::Recursive), 39 tune_lock(QMutex::Recursive), 40 hw_lock(QMutex::Recursive) 41 { 58 42 } 59 43 60 44 HDHRChannel::~HDHRChannel(void) … … 64 48 65 49 bool HDHRChannel::Open(void) 66 50 { 51 VERBOSE(VB_CHANNEL, LOC + "Opening HDHR channel"); 52 53 QMutexLocker locker(&hw_lock); 54 67 55 if (IsOpen()) 68 56 return true; 69 57 70 if (!FindDevice()) 71 return false; 58 _stream_handler = HDHRStreamHandler::Get(_device_id); 72 59 73 60 if (!InitializeInputs()) 74 return false;75 76 return (_device_ip != 0) && Connect();77 }78 79 void HDHRChannel::Close(void)80 {81 if (_control_socket)82 61 { 83 hdhomerun_control_destroy(_control_socket); 84 _control_socket = NULL; 85 } 86 } 87 88 bool HDHRChannel::EnterPowerSavingMode(void) 89 { 90 return QString::null != TunerSet("channel", "none", false); 91 } 92 93 bool HDHRChannel::FindDevice(void) 94 { 95 if (!_device_id) 96 return _device_ip; 97 98 _device_ip = 0; 99 100 /* Discover. */ 101 struct hdhomerun_discover_device_t result; 102 int ret = hdhomerun_discover_find_devices_custom( 103 0, HDHOMERUN_DEVICE_TYPE_WILDCARD, _device_id, &result, 1); 104 if (ret < 0) 105 { 106 VERBOSE(VB_IMPORTANT, 107 LOC_ERR + "Unable to send discovery request" + ENO); 108 return false; 109 } 110 if (ret == 0) 111 { 112 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("device not found")); 62 Close(); 113 63 return false; 114 64 } 115 65 116 /* Found. */ 117 _device_ip = result.ip_addr; 118 119 VERBOSE(VB_IMPORTANT, LOC + 120 QString("device found at address %1.%2.%3.%4") 121 .arg((_device_ip>>24) & 0xFF).arg((_device_ip>>16) & 0xFF) 122 .arg((_device_ip>> 8) & 0xFF).arg((_device_ip>> 0) & 0xFF)); 123 124 return true; 66 return _stream_handler->Connected(); 125 67 } 126 68 127 bool HDHRChannel::Connect(void)69 void HDHRChannel::Close(void) 128 70 { 129 _control_socket = hdhomerun_control_create(_device_id, _device_ip); 130 if (!_control_socket) 131 { 132 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to create control socket"); 133 return false; 134 } 71 VERBOSE(VB_CHANNEL, LOC + "Closing HDHR channel"); 135 72 136 if (hdhomerun_control_get_local_addr(_control_socket) == 0) 137 { 138 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to connect to device"); 139 return false; 140 } 73 if (! IsOpen()) 74 return; // this caller didn't have it open in the first place.. 141 75 142 VERBOSE(VB_CHANNEL, LOC + "Successfully connected to device"); 143 return true; 76 HDHRStreamHandler::Return(_stream_handler); 144 77 } 145 78 146 QString HDHRChannel::DeviceGet(const QString &name, bool report_error_return)79 bool HDHRChannel::EnterPowerSavingMode(void) 147 80 { 148 QMutexLocker locker(&_lock); 149 150 if (!_control_socket) 151 { 152 VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed (not connected)"); 153 return QString::null; 154 } 155 156 char *value = NULL; 157 char *error = NULL; 158 if (hdhomerun_control_get(_control_socket, name.toLatin1().constData(), 159 &value, &error) < 0) 160 { 161 VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed" + ENO); 162 return QString::null; 163 } 164 165 if (report_error_return && error) 166 { 167 VERBOSE(VB_IMPORTANT, LOC_ERR + 168 QString("DeviceGet(%1): %2").arg(name).arg(error)); 169 170 return QString::null; 171 } 172 173 return QString(value); 81 if ( IsOpen()) 82 return _stream_handler->EnterPowerSavingMode(); 83 else 84 return true; 174 85 } 175 86 176 QString HDHRChannel::DeviceSet(const QString &name, const QString &val, 177 bool report_error_return) 87 bool HDHRChannel::IsOpen(void) const 178 88 { 179 QMutexLocker locker(&_lock); 180 181 if (!_control_socket) 182 { 183 VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed (not connected)"); 184 return QString::null; 185 } 186 187 char *value = NULL; 188 char *error = NULL; 189 if (hdhomerun_control_set(_control_socket, name.toLatin1().constData(), 190 val.toAscii().constData(), &value, &error) < 0) 191 { 192 VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed" + ENO); 193 194 return QString::null; 195 } 196 197 if (report_error_return && error) 198 { 199 VERBOSE(VB_IMPORTANT, LOC_ERR + 200 QString("DeviceSet(%1 %2): %3").arg(name).arg(val).arg(error)); 201 202 return QString::null; 203 } 204 205 return QString(value); 89 return (_stream_handler != NULL); 206 90 } 207 91 208 QString HDHRChannel::TunerGet(const QString &name, bool report_error_return)92 bool HDHRChannel::Init(QString &inputname, QString &startchannel, bool setchan) 209 93 { 210 return DeviceGet(QString("/tuner%1/%2").arg(_tuner).arg(name), 211 report_error_return); 212 } 94 if (setchan && !IsOpen()) 95 Open(); 213 96 214 QString HDHRChannel::TunerSet(const QString &name, const QString &value, 215 bool report_error_return) 216 { 217 return DeviceSet(QString("/tuner%1/%2").arg(_tuner).arg(name), value, 218 report_error_return); 219 } 220 221 bool HDHRChannel::DeviceSetTarget(unsigned short localPort) 222 { 223 if (localPort == 0) 224 { 225 return false; 226 } 227 228 unsigned long localIP = hdhomerun_control_get_local_addr(_control_socket); 229 if (localIP == 0) 230 { 231 return false; 232 } 233 234 QString configValue = QString("%1.%2.%3.%4:%5") 235 .arg((localIP >> 24) & 0xFF).arg((localIP >> 16) & 0xFF) 236 .arg((localIP >> 8) & 0xFF).arg((localIP >> 0) & 0xFF) 237 .arg(localPort); 238 239 if (TunerSet("target", configValue).isEmpty()) 240 { 241 return false; 242 } 243 244 return true; 245 } 246 247 bool HDHRChannel::DeviceClearTarget() 248 { 249 return !TunerSet("target", "0.0.0.0:0").isEmpty(); 97 return ChannelBase::Init(inputname, startchannel, setchan); 250 98 } 251 99 252 100 bool HDHRChannel::SetChannelByString(const QString &channum) … … 280 128 return SwitchToInput(inputName, channum); 281 129 282 130 ClearDTVInfo(); 283 _ignore_filters = false;284 131 285 132 InputMap::const_iterator it = inputs.find(currentInputID); 286 133 if (it == inputs.end()) … … 354 201 if (mpeg_prog_num && (GetTuningMode() == "mpeg")) 355 202 { 356 203 QString pnum = QString::number(mpeg_prog_num); 357 _ignore_filters = QString::null != TunerSet("program", pnum, false); 204 //_ignore_filters = _stream_handler->TuneProgram(pnum); 205 _stream_handler->TuneProgram(pnum); 358 206 } 359 207 360 208 return true; … … 408 256 409 257 VERBOSE(VB_CHANNEL, LOC + "Tune()ing to " + chan); 410 258 411 if ( TunerSet("channel", chan).length())259 if (_stream_handler->TuneChannel(chan)) 412 260 { 413 261 SetSIStandard(si_std); 414 262 return true; … … 416 264 417 265 return false; 418 266 } 419 420 bool HDHRChannel::AddPID(uint pid, bool do_update)421 {422 QMutexLocker locker(&_lock);423 424 vector<uint>::iterator it;425 it = lower_bound(_pids.begin(), _pids.end(), pid);426 if (it != _pids.end() && *it == pid)427 {428 #ifdef DEBUG_PID_FILTERS429 VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<") NOOP");430 #endif // DEBUG_PID_FILTERS431 return true;432 }433 434 _pids.insert(it, pid);435 436 #ifdef DEBUG_PID_FILTERS437 VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<")");438 #endif // DEBUG_PID_FILTERS439 440 if (do_update)441 return UpdateFilters();442 return true;443 }444 445 bool HDHRChannel::DelPID(uint pid, bool do_update)446 {447 QMutexLocker locker(&_lock);448 449 vector<uint>::iterator it;450 it = lower_bound(_pids.begin(), _pids.end(), pid);451 if (it == _pids.end())452 {453 #ifdef DEBUG_PID_FILTERS454 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") NOOP");455 #endif // DEBUG_PID_FILTERS456 457 return true;458 }459 460 if (*it == pid)461 {462 #ifdef DEBUG_PID_FILTERS463 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") -- found");464 #endif // DEBUG_PID_FILTERS465 _pids.erase(it);466 }467 else468 {469 #ifdef DEBUG_PID_FILTERS470 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") -- failed");471 #endif // DEBUG_PID_FILTERS472 }473 474 if (do_update)475 return UpdateFilters();476 return true;477 }478 479 bool HDHRChannel::DelAllPIDs(void)480 {481 QMutexLocker locker(&_lock);482 483 #ifdef DEBUG_PID_FILTERS484 VERBOSE(VB_CHANNEL, "DelAllPID()");485 #endif // DEBUG_PID_FILTERS486 487 _pids.clear();488 489 return UpdateFilters();490 }491 492 QString filt_str(uint pid)493 {494 uint pid0 = (pid / (16*16*16)) % 16;495 uint pid1 = (pid / (16*16)) % 16;496 uint pid2 = (pid / (16)) % 16;497 uint pid3 = pid % 16;498 return QString("0x%1%2%3%4")499 .arg(pid0,0,16).arg(pid1,0,16)500 .arg(pid2,0,16).arg(pid3,0,16);501 }502 503 bool HDHRChannel::UpdateFilters(void)504 {505 QMutexLocker locker(&_lock);506 507 QString filter = "";508 509 vector<uint> range_min;510 vector<uint> range_max;511 512 if (_ignore_filters)513 return true;514 515 for (uint i = 0; i < _pids.size(); i++)516 {517 uint pid_min = _pids[i];518 uint pid_max = pid_min;519 for (uint j = i + 1; j < _pids.size(); j++)520 {521 if (pid_max + 1 != _pids[j])522 break;523 pid_max++;524 i++;525 }526 range_min.push_back(pid_min);527 range_max.push_back(pid_max);528 }529 530 if (range_min.size() > 16)531 {532 range_min.resize(16);533 uint pid_max = range_max.back();534 range_max.resize(15);535 range_max.push_back(pid_max);536 }537 538 for (uint i = 0; i < range_min.size(); i++)539 {540 filter += filt_str(range_min[i]);541 if (range_min[i] != range_max[i])542 filter += QString("-%1").arg(filt_str(range_max[i]));543 filter += " ";544 }545 546 filter = filter.trimmed();547 548 QString new_filter = TunerSet("filter", filter);549 550 #ifdef DEBUG_PID_FILTERS551 QString msg = QString("Filter: '%1'").arg(filter);552 if (filter != new_filter)553 msg += QString("\n\t\t\t\t'%2'").arg(new_filter);554 555 VERBOSE(VB_CHANNEL, msg);556 #endif // DEBUG_PID_FILTERS557 558 return filter == new_filter;559 } -
mythtv/libs/libmythtv/hdhrchannel.h
diff -r -u -N -X diff.exclude.noxml -x myth.20064 -x myth.20018 myth.20064/mythtv/libs/libmythtv/hdhrchannel.h myth.20018/mythtv/libs/libmythtv/hdhrchannel.h
15 15 16 16 // HDHomeRun headers 17 17 #ifdef USING_HDHOMERUN 18 #include "hdhomerun.h" 19 #else 20 struct hdhomerun_control_sock_t { int dummy; }; 18 #include "hdhomerun_includes.h" 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 { … … 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 (_control_socket != 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 FindDevice(void);61 bool Connect(void);62 56 bool Tune(uint frequency, QString inputname, 63 57 QString modulation, QString si_std); 64 58 65 bool DeviceSetTarget(unsigned short localPort);66 bool DeviceClearTarget(void);59 private: 60 HDHRStreamHandler *_stream_handler; 67 61 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); 62 QString _device_id; 75 63 76 private:77 hdhr_socket_t *_control_socket;78 uint _device_id;79 uint _device_ip;80 uint _tuner;81 bool _ignore_filters;82 64 vector<uint> _pids; 83 65 mutable QMutex _lock; 66 mutable QMutex tune_lock; 67 mutable QMutex hw_lock; 84 68 }; 85 69 86 70 #endif -
mythtv/libs/libmythtv/hdhrrecorder.cpp
diff -r -u -N -X diff.exclude.noxml -x myth.20064 -x myth.20018 myth.20064/mythtv/libs/libmythtv/hdhrrecorder.cpp myth.20018/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 "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(QMutex::Recursive) 48 _pid_lock(QMutex::Recursive), 49 _input_pat(NULL), 50 _input_pmt(NULL), 51 _has_no_av(false) 44 52 { 45 53 } 46 54 … … 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); 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) … … 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) … … 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 … … 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]; … … 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*) … … 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 _buffer_packets = !FindMPEG2Keyframes(&tspacket); 305 BufferedWrite(tspacket); 306 } 307 else if (GetStreamData()->IsAudioPID(lpid)) 308 { 309 //cerr<<"a"; 310 _buffer_packets = !FindAudioKeyframes(&tspacket); 311 BufferedWrite(tspacket); 312 } 313 else if (GetStreamData()->IsListeningPID(lpid)) 314 { 315 //cerr<<"t"; 316 GetStreamData()->HandleTSTables(&tspacket); 317 } 318 else if (GetStreamData()->IsWritingPID(lpid)) 319 BufferedWrite(tspacket); 320 } 355 _buffer_packets = true; 321 356 } 322 return ok; 357 358 BufferedWrite(tspacket); 323 359 } 324 360 325 361 void HDHRRecorder::StartRecording(void) … … 337 373 _request_recording = true; 338 374 _recording = true; 339 375 340 if (!StartData())341 {342 VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting recording "343 "(set target failed). Aborting.");344 Close();345 _error = true;346 VERBOSE(VB_RECORD, LOC + "StartRecording -- end 2"); 347 return;348 }349 350 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 351 387 while (_request_recording && !_error) 352 388 { 389 usleep(50000); 390 353 391 if (PauseAndWait()) 354 392 continue; 355 393 356 if ( _stream_data)394 if (!_input_pmt) 357 395 { 358 QMutexLocker read_lock(&_pid_lock); 359 _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; 360 400 } 361 401 362 if ( _reset_pid_filters)402 if (!_stream_handler->IsRunning()) 363 403 { 364 _reset_pid_filters = false; 365 VERBOSE(VB_RECORD, LOC + "Resetting Demux Filters"); 366 AdjustFilters(); 367 } 404 _error = true; 368 405 369 size_t read_size = 64 * 1024; // read about 64KB 370 read_size /= VIDEO_DATA_PACKET_SIZE; 371 read_size *= VIDEO_DATA_PACKET_SIZE; 372 373 size_t data_length; 374 unsigned char *data_buffer = 375 hdhomerun_video_recv(_video_socket, read_size, &data_length); 376 if (!data_buffer) 377 { 378 usleep(5000); 379 continue; 380 } 381 382 ProcessTSData(data_buffer, data_length); 406 VERBOSE(VB_IMPORTANT, LOC_ERR + 407 "Stream handler died unexpectedly."); 408 } 383 409 } 384 410 385 411 VERBOSE(VB_RECORD, LOC + "StartRecording -- ending..."); 386 412 387 _channel->DeviceClearTarget(); 413 _stream_handler->RemoveListener(_stream_data); 414 _stream_data->RemoveWritingListener(this); 415 _stream_data->RemoveAVListener(this); 416 388 417 Close(); 389 418 390 419 FinishRecording(); … … 393 422 VERBOSE(VB_RECORD, LOC + "StartRecording -- end"); 394 423 } 395 424 396 bool HDHRRecorder::AdjustFilters(void)425 void HDHRRecorder::ResetForNewFile(void) 397 426 { 398 QMutexLocker change_lock(&_pid_lock);427 DTVRecorder::ResetForNewFile(); 399 428 400 if (!_channel) 401 { 402 VERBOSE(VB_IMPORTANT, LOC_ERR + "AdjustFilters() no channel"); 403 return false; 404 } 429 bzero(_stream_id, sizeof(_stream_id)); 430 bzero(_pid_status, sizeof(_pid_status)); 431 memset(_continuity_counter, 0xff, sizeof(_continuity_counter)); 405 432 406 if (!_input_pat || !_input_pmt) 407 { 408 VERBOSE(VB_IMPORTANT, LOC + "AdjustFilters() no pmt or no pat"); 409 return false; 410 } 411 412 uint_vec_t add_pid; 433 // FIXME 434 // Close and re-open ??? 435 //Close(); 436 //Open(); 437 } 413 438 414 add_pid.push_back(MPEG_PAT_PID); 415 _stream_data->AddListeningPID(MPEG_PAT_PID); 439 void HDHRRecorder::StopRecording(void) 440 { 441 _request_recording = false; 442 while (_recording) 443 usleep(2000); 444 } 416 445 417 for (uint i = 0; i < _input_pat->ProgramCount(); i++) 446 bool HDHRRecorder::PauseAndWait(int timeout) 447 { 448 if (request_pause) 418 449 { 419 add_pid.push_back(_input_pat->ProgramPID(i)); 420 _stream_data->AddListeningPID(_input_pat->ProgramPID(i)); 421 } 450 QMutex waitlock; 451 if (!paused) 452 { 453 assert(_stream_handler); 454 assert(_stream_data); 422 455 423 // Record the streams in the PMT... 424 bool need_pcr_pid = true; 425 for (uint i = 0; i < _input_pmt->StreamCount(); i++) 426 { 427 add_pid.push_back(_input_pmt->StreamPID(i)); 428 need_pcr_pid &= (_input_pmt->StreamPID(i) != _input_pmt->PCRPID()); 429 _stream_data->AddWritingPID(_input_pmt->StreamPID(i)); 430 } 456 _stream_handler->RemoveListener(_stream_data); 431 457 432 if (need_pcr_pid && (_input_pmt->PCRPID())) 433 { 434 add_pid.push_back(_input_pmt->PCRPID()); 435 _stream_data->AddWritingPID(_input_pmt->PCRPID()); 458 paused = true; 459 pauseWait.wakeAll(); 460 if (tvrec) 461 tvrec->RecorderPaused(); 462 } 463 waitlock.lock(); 464 unpauseWait.wait(&waitlock, timeout); 436 465 } 437 466 438 // Adjust for EIT 439 AdjustEITPIDs(); 440 for (uint i = 0; i < _eit_pids.size(); i++) 467 if (!request_pause && paused) 441 468 { 442 add_pid.push_back(_eit_pids[i]); 443 _stream_data->AddListeningPID(_eit_pids[i]); 444 } 469 paused = false; 445 470 446 // Delete filters for pids we no longer wish to monitor 447 vector<uint>::const_iterator it; 448 vector<uint> pids = _channel->GetPIDs(); 449 for (it = pids.begin(); it != pids.end(); ++it) 450 { 451 if (find(add_pid.begin(), add_pid.end(), *it) == add_pid.end()) 452 { 453 _stream_data->RemoveListeningPID(*it); 454 _stream_data->RemoveWritingPID(*it); 455 _channel->DelPID(*it, false); 456 } 457 } 471 assert(_stream_handler); 472 assert(_stream_data); 458 473 459 for (it = add_pid.begin(); it != add_pid.end(); ++it) 460 _channel->AddPID(*it, false); 461 462 _channel->UpdateFilters(); 474 _stream_handler->AddListener(_stream_data); 475 } 463 476 464 return add_pid.size();477 return paused; 465 478 } 466 479 467 /** \fn HDHRRecorder::AdjustEITPIDs(void) 468 * \brief Adjusts EIT PID monitoring to monitor the right number of EIT PIDs. 469 */ 470 bool HDHRRecorder::AdjustEITPIDs(void) 480 void HDHRRecorder::BufferedWrite(const TSPacket &tspacket) 471 481 { 472 bool changes = false; 473 uint_vec_t add, del; 474 475 QMutexLocker change_lock(&_pid_lock); 476 477 if (GetStreamData()->HasEITPIDChanges(_eit_pids)) 478 changes = GetStreamData()->GetEITPIDChanges(_eit_pids, add, del); 482 // Care must be taken to make sure that the packet actually gets written 483 // as the decision to actually write it has already been made 479 484 480 if (!changes) 481 return false; 482 483 for (uint i = 0; i < del.size(); i++) 485 // Do we have to buffer the packet for exact keyframe detection? 486 if (_buffer_packets) 484 487 { 485 uint_vec_t::iterator it;486 it = find(_eit_pids.begin(), _eit_pids.end(), del[i]);487 if (it != _eit_pids.end())488 _eit_pids.erase(it);488 int idx = _payload_buffer.size(); 489 _payload_buffer.resize(idx + TSPacket::SIZE); 490 memcpy(&_payload_buffer[idx], tspacket.data(), TSPacket::SIZE); 491 return; 489 492 } 490 493 491 for (uint i = 0; i < add.size(); i++) 492 _eit_pids.push_back(add[i]); 493 494 return true; 494 // We are free to write the packet, but if we have buffered packet[s] 495 // we have to write them first... 496 if (!_payload_buffer.empty()) 497 { 498 if (ringBuffer) 499 ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size()); 500 _payload_buffer.clear(); 501 } 502 if (ringBuffer) 503 ringBuffer->Write(tspacket.data(), TSPacket::SIZE); 495 504 } 496 505 -
mythtv/libs/libmythtv/hdhrrecorder.h
diff -r -u -N -X diff.exclude.noxml -x myth.20064 -x myth.20018 myth.20064/mythtv/libs/libmythtv/hdhrrecorder.h myth.20018/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 … … 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); … … 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; } … … 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 -r -u -N -X diff.exclude.noxml -x myth.20064 -x myth.20018 myth.20064/mythtv/libs/libmythtv/hdhrsignalmonitor.cpp myth.20018/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()) … … 39 40 HDHRSignalMonitor::HDHRSignalMonitor( 40 41 int db_cardnum, HDHRChannel* _channel, uint64_t _flags) : 41 42 DTVSignalMonitor(db_cardnum, _channel, _flags), 42 dtvMonitorRunning(false) 43 streamHandlerStarted(false), 44 streamHandler(NULL) 45 43 46 { 44 47 VERBOSE(VB_CHANNEL, LOC + "ctor"); 45 48 46 _channel->DelAllPIDs();47 48 49 signalStrength.SetThreshold(45); 49 50 50 51 AddFlags(kSigMon_WaitForSig); 52 53 streamHandler = HDHRStreamHandler::Get(_channel->GetDevice()); 51 54 } 52 55 53 56 /** \fn HDHRSignalMonitor::~HDHRSignalMonitor() … … 57 60 { 58 61 VERBOSE(VB_CHANNEL, LOC + "dtor"); 59 62 Stop(); 63 HDHRStreamHandler::Return(streamHandler); 60 64 } 61 65 62 66 /** \fn HDHRSignalMonitor::Stop(void) … … 66 70 { 67 71 VERBOSE(VB_CHANNEL, LOC + "Stop() -- begin"); 68 72 SignalMonitor::Stop(); 69 if (dtvMonitorRunning) 70 { 71 dtvMonitorRunning = false; 72 pthread_join(table_monitor_thread, NULL); 73 } 74 VERBOSE(VB_CHANNEL, LOC + "Stop() -- end"); 75 } 76 77 void *HDHRSignalMonitor::TableMonitorThread(void *param) 78 { 79 HDHRSignalMonitor *mon = (HDHRSignalMonitor*) param; 80 mon->RunTableMonitor(); 81 return NULL; 82 } 83 84 bool HDHRSignalMonitor::UpdateFiltersFromStreamData(void) 85 { 86 vector<int> add_pids; 87 vector<int> del_pids; 88 89 if (!GetStreamData()) 90 return false; 91 92 UpdateListeningForEIT(); 93 94 const pid_map_t &listening = GetStreamData()->ListeningPIDs(); 95 96 // PIDs that need to be added.. 97 pid_map_t::const_iterator lit = listening.constBegin(); 98 for (; lit != listening.constEnd(); ++lit) 99 if (*lit && (filters.find(lit.key()) == filters.end())) 100 add_pids.push_back(lit.key()); 101 102 // PIDs that need to be removed.. 103 FilterMap::const_iterator fit = filters.constBegin(); 104 for (; fit != filters.constEnd(); ++fit) 105 if (listening.find(fit.key()) == listening.end()) 106 del_pids.push_back(fit.key()); 107 108 HDHRChannel *hdhr = dynamic_cast<HDHRChannel*>(channel); 109 if (!hdhr) 110 return false; 111 112 // Remove PIDs 113 bool ok = true; 114 vector<int>::iterator dit = del_pids.begin(); 115 for (; dit != del_pids.end(); ++dit) 116 { 117 ok &= hdhr->DelPID(*dit); 118 filters.erase(filters.find(*dit)); 119 } 73 if (GetStreamData()) 74 streamHandler->RemoveListener(GetStreamData()); 75 streamHandlerStarted = false; 76 streamHandler->SetRetuneAllowed(false, NULL, NULL); 120 77 121 // Add PIDs 122 vector<int>::iterator ait = add_pids.begin(); 123 for (; ait != add_pids.end(); ++ait) 124 { 125 ok &= hdhr->AddPID(*ait); 126 filters[*ait] = 1; 127 } 128 129 return ok; 78 VERBOSE(VB_CHANNEL, LOC + "Stop() -- end"); 130 79 } 131 80 132 void HDHRSignalMonitor::RunTableMonitor(void)81 HDHRChannel *HDHRSignalMonitor::GetHDHRChannel(void) 133 82 { 134 dtvMonitorRunning = true; 135 136 struct hdhomerun_video_sock_t *_video_socket; 137 _video_socket = hdhomerun_video_create(0, VIDEO_DATA_BUFFER_SIZE_1S); 138 if (!_video_socket) 139 { 140 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to get video socket"); 141 return; 142 } 143 144 HDHRChannel *hdrc = dynamic_cast<HDHRChannel*>(channel); 145 if (!hdrc) 146 return; 147 148 uint localPort = hdhomerun_video_get_local_port(_video_socket); 149 if (!hdrc->DeviceSetTarget(localPort)) 150 { 151 hdhomerun_video_destroy(_video_socket); 152 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to set target"); 153 return; 154 } 155 156 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): " + 157 QString("begin (# of pids %1)") 158 .arg(GetStreamData()->ListeningPIDs().size())); 159 160 while (dtvMonitorRunning && GetStreamData()) 161 { 162 UpdateFiltersFromStreamData(); 163 164 size_t data_length; 165 unsigned char *data_buffer = 166 hdhomerun_video_recv(_video_socket, 167 VIDEO_DATA_BUFFER_SIZE_1S / 5, 168 &data_length); 169 170 if (data_buffer) 171 { 172 GetStreamData()->ProcessData(data_buffer, data_length); 173 continue; 174 } 175 176 usleep(2500); 177 } 178 179 hdrc->DeviceClearTarget(); 180 hdhomerun_video_destroy(_video_socket); 181 182 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- shutdown"); 183 184 // TODO teardown PID filters here 185 186 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- end"); 83 return dynamic_cast<HDHRChannel*>(channel); 187 84 } 188 85 189 86 /** \fn HDHRSignalMonitor::UpdateValues() … … 201 98 if (!running || exit) 202 99 return; 203 100 204 if ( dtvMonitorRunning)101 if (streamHandlerStarted) 205 102 { 206 103 EmitStatus(); 207 104 if (IsAllGood()) … … 212 109 return; 213 110 } 214 111 215 QString msg = ((HDHRChannel*)channel)->TunerGet("status");112 QString msg = streamHandler->GetTunerStatus(); 216 113 //ss = signal strength, [0,100] 217 114 //snq = signal to noise quality [0,100] 218 115 //seq = signal error quality [0,100] … … 250 147 kDTVSigMon_WaitForMGT | kDTVSigMon_WaitForVCT | 251 148 kDTVSigMon_WaitForNIT | kDTVSigMon_WaitForSDT)) 252 149 { 253 pthread_create(&table_monitor_thread, NULL, 254 TableMonitorThread, this); 255 256 VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- " 257 "Waiting for table monitor to start"); 258 259 while (!dtvMonitorRunning) 260 usleep(50); 261 262 VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- " 263 "Table monitor started"); 150 streamHandler->AddListener(GetStreamData()); 151 streamHandlerStarted = true; 264 152 } 265 153 266 154 update_done = true; -
mythtv/libs/libmythtv/hdhrsignalmonitor.h
diff -r -u -N -X diff.exclude.noxml -x myth.20064 -x myth.20018 myth.20064/mythtv/libs/libmythtv/hdhrsignalmonitor.h myth.20018/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 … … 19 20 20 21 void Stop(void); 21 22 22 bool UpdateFiltersFromStreamData(void);23 24 23 protected: 25 24 HDHRSignalMonitor(void); 26 25 HDHRSignalMonitor(const HDHRSignalMonitor&); 27 26 28 27 virtual void UpdateValues(void); 29 28 30 static void *TableMonitorThread(void *param);31 void RunTableMonitor(void);32 33 29 bool SupportsTSMonitoring(void); 34 30 31 HDHRChannel *GetHDHRChannel(void); 32 35 33 protected: 36 bool dtvMonitorRunning;37 pthread_t table_monitor_thread;38 34 39 FilterMap filters; ///< PID filters for table monitoring 35 bool streamHandlerStarted; 36 HDHRStreamHandler *streamHandler; 37 40 38 }; 41 39 42 40 #endif // HDHRSIGNALMONITOR_H -
mythtv/libs/libmythtv/hdhrstreamhandler.cpp
diff -r -u -N -X diff.exclude.noxml -x myth.20064 -x myth.20018 myth.20064/mythtv/libs/libmythtv/hdhrstreamhandler.cpp myth.20018/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(QMutex::Recursive), 106 _running(false), 107 108 _sigmon(NULL), 109 _channel(NULL), 110 111 _pid_lock(QMutex::Recursive), 112 _listener_lock(QMutex::Recursive), 113 _hdhr_lock(QMutex::Recursive) 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); 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.toLocal8Bit().constData()); 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.toLocal8Bit().constData(), &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.toLocal8Bit().constData(), val.toLocal8Bit().constData(), &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 return (QString::null != TunerSet("target", configValue)); 290 } 291 292 bool HDHRStreamHandler::DeviceClearTarget() 293 { 294 return (QString::null != TunerSet("target", "0.0.0.0:0")); 295 } 296 297 QString HDHRStreamHandler::GetTunerStatus() { 298 return TunerGet("status"); 299 } 300 301 bool HDHRStreamHandler::Connected() { 302 // FIXME 303 return (_control_socket != NULL); 304 } 305 306 bool HDHRStreamHandler::TuneChannel(QString chn) { 307 QString current = TunerGet("channel"); 308 if (current == chn) 309 { 310 VERBOSE(VB_RECORD, QString(LOC + "Not Re-Tuning channel %1").arg(chn)); 311 return true; 312 } 313 VERBOSE(VB_RECORD, QString(LOC + "Tuning channel %1 (was %2)").arg(chn).arg(current)); 314 return (QString::null != TunerSet("channel", chn)); 315 } 316 317 bool HDHRStreamHandler::TuneProgram(QString pnum) { 318 VERBOSE(VB_RECORD, QString(LOC + "Tuning program %1").arg(pnum)); 319 return (QString::null != TunerSet("program", pnum, false)); 320 } 321 322 void HDHRStreamHandler::AddListener(MPEGStreamData *data) 323 { 324 VERBOSE(VB_RECORD, LOC + "AddListener("<<data<<") -- begin"); 325 assert(data); 326 327 _listener_lock.lock(); 328 329 VERBOSE(VB_RECORD, LOC + "AddListener("<<data<<") -- locked"); 330 331 _stream_data_list.push_back(data); 332 333 _listener_lock.unlock(); 334 335 Start(); 336 337 VERBOSE(VB_RECORD, LOC + "AddListener("<<data<<") -- end"); 338 } 339 340 void HDHRStreamHandler::RemoveListener(MPEGStreamData *data) 341 { 342 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<data<<") -- begin"); 343 assert(data); 344 345 _listener_lock.lock(); 346 347 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<data<<") -- locked"); 348 349 vector<MPEGStreamData*>::iterator it = 350 find(_stream_data_list.begin(), _stream_data_list.end(), data); 351 352 if (it != _stream_data_list.end()) 353 _stream_data_list.erase(it); 354 355 if (_stream_data_list.empty()) 356 { 357 _listener_lock.unlock(); 358 Stop(); 359 } 360 else 361 { 362 _listener_lock.unlock(); 363 } 364 365 VERBOSE(VB_RECORD, LOC + "RemoveListener("<<data<<") -- end"); 366 } 367 368 void *run_hdhr_stream_handler_thunk(void *param) 369 { 370 HDHRStreamHandler *mon = (HDHRStreamHandler*) param; 371 mon->Run(); 372 return NULL; 373 } 374 375 void HDHRStreamHandler::Start(void) 376 { 377 QMutexLocker locker(&_start_stop_lock); 378 379 _eit_pids.clear(); 380 381 if (!IsRunning()) 382 { 383 QMutex is_running_lock; 384 int rval = pthread_create(&_reader_thread, NULL, 385 run_hdhr_stream_handler_thunk, this); 386 387 if (0 != rval) 388 { 389 VERBOSE(VB_IMPORTANT, LOC_ERR + 390 "Start: Failed to create thread." + ENO); 391 return; 392 } 393 394 while (!IsRunning()) 395 { 396 is_running_lock.lock(); 397 _running_state_changed.wait(&is_running_lock, 100); 398 } 399 } 400 } 401 402 void HDHRStreamHandler::Stop(void) 403 { 404 QMutexLocker locker(&_start_stop_lock); 405 406 if (IsRunning()) 407 { 408 SetRunning(false); 409 pthread_join(_reader_thread, NULL); 410 } 411 } 412 413 void HDHRStreamHandler::Run(void) 414 { 415 SetRunning(true); 416 RunTS(); 417 } 418 419 /** \fn HDHRStreamHandler::RunTS(void) 420 * \brief Uses TS filtering devices to read a DVB device for tables & data 421 * 422 * This supports all types of MPEG based stream data, but is extreemely 423 * slow with DVB over USB 1.0 devices which for efficiency reasons buffer 424 * a stream until a full block transfer buffer full of the requested 425 * tables is available. This takes a very long time when you are just 426 * waiting for a PAT or PMT table, and the buffer is hundreds of packets 427 * in size. 428 */ 429 void HDHRStreamHandler::RunTS(void) 430 { 431 int remainder = 0; 432 VERBOSE(VB_RECORD, LOC + "RunTS()"); 433 434 /* Calculate buffer size */ 435 uint buffersize = gContext->GetNumSetting( 436 "HDRingbufferSize", 50 * TSPacket::SIZE) * 1024; 437 buffersize /= VIDEO_DATA_PACKET_SIZE; 438 buffersize *= VIDEO_DATA_PACKET_SIZE; 439 440 // Buffer should be at least about 1MB.. 441 buffersize = max(49 * TSPacket::SIZE * 128, buffersize); 442 443 VERBOSE(VB_GENERAL, QString(LOC + "HD Ringbuffer size = %1 KB").arg(buffersize / 1024)); 444 445 /* Create TS socket. */ 446 _video_socket = hdhomerun_video_create(0, buffersize); 447 if (!_video_socket) 448 { 449 VERBOSE(VB_IMPORTANT, LOC + "Open() failed to open socket"); 450 return; 451 } 452 453 uint localPort = hdhomerun_video_get_local_port(_video_socket); 454 if (!DeviceSetTarget(localPort)) 455 { 456 VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting recording (set target failed). Aborting."); 457 return; 458 } 459 hdhomerun_video_flush(_video_socket); 460 461 bool _error = false; 462 463 VERBOSE(VB_RECORD, LOC + "RunTS(): begin"); 464 465 while (IsRunning() && !_error) 466 { 467 UpdateFiltersFromStreamData(); 468 469 size_t read_size = 64 * 1024; // read about 64KB 470 read_size /= VIDEO_DATA_PACKET_SIZE; 471 read_size *= VIDEO_DATA_PACKET_SIZE; 472 473 size_t data_length; 474 unsigned char *data_buffer = 475 hdhomerun_video_recv(_video_socket, read_size, &data_length); 476 477 if (! data_buffer) 478 { 479 usleep(5000); 480 continue; 481 } 482 483 // Assume data_length is a multiple of 188 (packet size) 484 // ASSERT(0 == ( data_length % 188) ); 485 486 _listener_lock.lock(); 487 488 if (_stream_data_list.empty()) 489 { 490 _listener_lock.unlock(); 491 continue; 492 } 493 494 for (uint i = 0; i < _stream_data_list.size(); i++) 495 { 496 remainder = _stream_data_list[i]->ProcessData(data_buffer, data_length); 497 } 498 499 _listener_lock.unlock(); 500 if (remainder != 0) 501 VERBOSE(VB_GENERAL, QString(LOC + "RunTS(): data_length = %1 remainder = %2") 502 .arg(data_length).arg(remainder)); 503 } 504 VERBOSE(VB_RECORD, LOC + "RunTS(): " + "shutdown"); 505 506 DelAllPIDs(); 507 508 DeviceClearTarget(); 509 VERBOSE(VB_RECORD, LOC + "RunTS(): " + "end"); 510 511 hdhomerun_video_sock_t* tmp_video_socket; 512 { 513 QMutexLocker locker(&_hdhr_lock); 514 tmp_video_socket = _video_socket; 515 _video_socket=NULL; 516 } 517 518 hdhomerun_video_destroy(tmp_video_socket); 519 520 SetRunning(false); 521 } 522 523 bool HDHRStreamHandler::AddPID(uint pid, bool do_update) 524 { 525 QMutexLocker locker(&_pid_lock); 526 527 vector<uint>::iterator it; 528 it = lower_bound(_pid_info.begin(), _pid_info.end(), pid); 529 if (it != _pid_info.end() && *it == pid) 530 { 531 #ifdef DEBUG_PID_FILTERS 532 VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<", " << do_update << ") NOOP"); 533 #endif // DEBUG_PID_FILTERS 534 return true; 535 } 536 537 _pid_info.insert(it, pid); 538 539 #ifdef DEBUG_PID_FILTERS 540 VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<")", " << do_update << "); 541 #endif // DEBUG_PID_FILTERS 542 543 if (do_update) 544 return UpdateFilters(); 545 return true; 546 } 547 548 bool HDHRStreamHandler::DelPID(uint pid, bool do_update) 549 { 550 QMutexLocker locker(&_pid_lock); 551 552 vector<uint>::iterator it; 553 it = lower_bound(_pid_info.begin(), _pid_info.end(), pid); 554 if (it == _pid_info.end()) 555 { 556 #ifdef DEBUG_PID_FILTERS 557 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<", " << do_update << ") NOOP"); 558 #endif // DEBUG_PID_FILTERS 559 560 return true; 561 } 562 563 if (*it == pid) 564 { 565 #ifdef DEBUG_PID_FILTERS 566 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<", " << do_update << ") -- found"); 567 #endif // DEBUG_PID_FILTERS 568 _pid_info.erase(it); 569 } 570 else 571 { 572 #ifdef DEBUG_PID_FILTERS 573 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<", " << do_update << ") -- failed"); 574 #endif // DEBUG_PID_FILTERS 575 } 576 577 if (do_update) 578 return UpdateFilters(); 579 return true; 580 } 581 582 bool HDHRStreamHandler::DelAllPIDs(void) 583 { 584 QMutexLocker locker(&_pid_lock); 585 586 #ifdef DEBUG_PID_FILTERS 587 VERBOSE(VB_CHANNEL, "DelAllPID()"); 588 #endif // DEBUG_PID_FILTERS 589 590 _pid_info.clear(); 591 592 return UpdateFilters(); 593 } 594 595 QString filt_str(uint pid) 596 { 597 uint pid0 = (pid / (16*16*16)) % 16; 598 uint pid1 = (pid / (16*16)) % 16; 599 uint pid2 = (pid / (16)) % 16; 600 uint pid3 = pid % 16; 601 return QString("0x%1%2%3%4") 602 .arg(pid0,0,16).arg(pid1,0,16) 603 .arg(pid2,0,16).arg(pid3,0,16); 604 } 605 606 bool HDHRStreamHandler::UpdateFilters(void) 607 { 608 #ifdef DEBUG_PID_FILTERS 609 VERBOSE(VB_CHANNEL, LOC + "UpdateFilters()"); 610 #endif // DEBUG_PID_FILTERS 611 QMutexLocker locker(&_pid_lock); 612 613 QString filter = ""; 614 615 vector<uint> range_min; 616 vector<uint> range_max; 617 618 // FIXME 619 // if (_ignore_filters) 620 // return true; 621 622 for (uint i = 0; i < _pid_info.size(); i++) 623 { 624 uint pid_min = _pid_info[i]; 625 uint pid_max = pid_min; 626 for (uint j = i + 1; j < _pid_info.size(); j++) 627 { 628 if (pid_max + 1 != _pid_info[j]) 629 break; 630 pid_max++; 631 i++; 632 } 633 range_min.push_back(pid_min); 634 range_max.push_back(pid_max); 635 } 636 if (range_min.size() > 16) 637 { 638 range_min.resize(16); 639 uint pid_max = range_max.back(); 640 range_max.resize(15); 641 range_max.push_back(pid_max); 642 } 643 644 for (uint i = 0; i < range_min.size(); i++) 645 { 646 filter += filt_str(range_min[i]); 647 if (range_min[i] != range_max[i]) 648 filter += QString("-%1").arg(filt_str(range_max[i])); 649 filter += " "; 650 } 651 652 filter = filter.trimmed(); 653 654 QString new_filter = TunerSet("filter", filter); 655 656 #ifdef DEBUG_PID_FILTERS 657 QString msg = QString("Filter: '%1'").arg(filter); 658 if (filter != new_filter) 659 msg += QString("\n\t\t\t\t'%2'").arg(new_filter); 660 661 VERBOSE(VB_CHANNEL, LOC + msg); 662 #endif // DEBUG_PID_FILTERS 663 664 return filter == new_filter; 665 } 666 667 void HDHRStreamHandler::UpdateListeningForEIT(void) 668 { 669 vector<uint> add_eit, del_eit; 670 671 QMutexLocker read_locker(&_listener_lock); 672 673 for (uint i = 0; i < _stream_data_list.size(); i++) 674 { 675 MPEGStreamData *sd = _stream_data_list[i]; 676 if (sd->HasEITPIDChanges(_eit_pids) && 677 sd->GetEITPIDChanges(_eit_pids, add_eit, del_eit)) 678 { 679 for (uint i = 0; i < del_eit.size(); i++) 680 { 681 uint_vec_t::iterator it; 682 it = find(_eit_pids.begin(), _eit_pids.end(), del_eit[i]); 683 if (it != _eit_pids.end()) 684 _eit_pids.erase(it); 685 sd->RemoveListeningPID(del_eit[i]); 686 } 687 688 for (uint i = 0; i < add_eit.size(); i++) 689 { 690 _eit_pids.push_back(add_eit[i]); 691 sd->AddListeningPID(add_eit[i]); 692 } 693 } 694 } 695 } 696 697 bool HDHRStreamHandler::UpdateFiltersFromStreamData(void) 698 { 699 700 UpdateListeningForEIT(); 701 702 pid_map_t pids; 703 704 { 705 QMutexLocker read_locker(&_listener_lock); 706 707 for (uint i = 0; i < _stream_data_list.size(); i++) 708 _stream_data_list[i]->GetPIDs(pids); 709 } 710 711 uint_vec_t add_pids; 712 vector<uint> del_pids; 713 714 { 715 QMutexLocker read_locker(&_pid_lock); 716 717 // PIDs that need to be added.. 718 pid_map_t::const_iterator lit = pids.constBegin(); 719 for (; lit != pids.constEnd(); ++lit) 720 { 721 vector<uint>::iterator it; 722 it = lower_bound(_pid_info.begin(), _pid_info.end(), lit.key()); 723 if (! (it != _pid_info.end() && *it == lit.key())) { 724 add_pids.push_back(lit.key()); 725 } 726 } 727 728 // PIDs that need to be removed.. 729 vector<uint>::iterator fit = _pid_info.begin(); 730 for (; fit != _pid_info.end(); ++fit) 731 { 732 pid_map_t::const_iterator it = pids.find(*fit); 733 if(it == pids.end()) 734 del_pids.push_back(*fit); 735 } 736 } 737 738 bool need_update = false; 739 740 // Remove PIDs 741 bool ok = true; 742 vector<uint>::iterator dit = del_pids.begin(); 743 for (; dit != del_pids.end(); ++dit) 744 { 745 need_update = true; 746 ok &= DelPID(*dit, false); 747 } 748 749 // Add PIDs 750 vector<uint>::iterator ait = add_pids.begin(); 751 for (; ait != add_pids.end(); ++ait) 752 { 753 need_update = true; 754 ok &= AddPID(*ait, false); 755 } 756 757 if (need_update) 758 return UpdateFilters(); 759 760 return ok; 761 } 762 763 void HDHRStreamHandler::SetRetuneAllowed( 764 bool allow, 765 DTVSignalMonitor *sigmon, 766 HDHRChannel *hdhrchan) 767 { 768 if (allow && sigmon && hdhrchan) 769 { 770 _allow_retune = true; 771 _sigmon = sigmon; 772 _channel = hdhrchan; 773 } 774 else 775 { 776 _allow_retune = false; 777 _sigmon = NULL; 778 _channel = NULL; 779 } 780 } 781 782 /** \fn HDHRStreamHandler::SupportsTSMonitoring(void) 783 * \brief Returns true if TS monitoring is supported. 784 * 785 * NOTE: If you are using a DEC2000-t device you need to 786 * apply the patches provided by Peter Beutner for it, see 787 * http://www.gossamer-threads.com/lists/mythtv/dev/166172 788 * These patches should make it in to Linux 2.6.15 or 2.6.16. 789 */ 790 bool HDHRStreamHandler::SupportsTSMonitoring(void) 791 { 792 return false; 793 794 // FIXME 795 #if 0 796 const uint pat_pid = 0x0; 797 798 { 799 QMutexLocker locker(&_rec_supports_ts_monitoring_lock); 800 QMap<uint,bool>::const_iterator it; 801 it = _rec_supports_ts_monitoring.find(_dvb_dev_num); 802 if (it != _rec_supports_ts_monitoring.end()) 803 return *it; 804 } 805 806 int dvr_fd = open(_dvr_dev_path.ascii(), O_RDONLY | O_NONBLOCK); 807 if (dvr_fd < 0) 808 { 809 QMutexLocker locker(&_rec_supports_ts_monitoring_lock); 810 _rec_supports_ts_monitoring[_dvb_dev_num] = false; 811 return false; 812 } 813 814 bool supports_ts = false; 815 if (AddPIDFilter(new PIDInfoHDHR(pat_pid))) 816 { 817 supports_ts = true; 818 RemovePIDFilter(pat_pid); 819 } 820 821 close(dvr_fd); 822 823 QMutexLocker locker(&_rec_supports_ts_monitoring_lock); 824 _rec_supports_ts_monitoring[_dvb_dev_num] = supports_ts; 825 826 return supports_ts; 827 #endif 828 } 829 830 void HDHRStreamHandler::SetRunning(bool is_running) 831 { 832 _running = is_running; 833 _running_state_changed.wakeAll(); 834 } 835 836 PIDPriority HDHRStreamHandler::GetPIDPriority(uint pid) const 837 { 838 QMutexLocker reading_locker(&_listener_lock); 839 840 PIDPriority tmp = kPIDPriorityNone; 841 842 for (uint i = 0; i < _stream_data_list.size(); i++) 843 tmp = max(tmp, _stream_data_list[i]->GetPIDPriority(pid)); 844 845 return tmp; 846 } -
mythtv/libs/libmythtv/hdhrstreamhandler.h
diff -r -u -N -X diff.exclude.noxml -x myth.20064 -x myth.20018 myth.20064/mythtv/libs/libmythtv/hdhrstreamhandler.h myth.20018/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(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 -r -u -N -X diff.exclude.noxml -x myth.20064 -x myth.20018 myth.20064/mythtv/libs/libmythtv/libmythtv.pro myth.20018/mythtv/libs/libmythtv/libmythtv.pro
494 494 using_hdhomerun { 495 495 # MythTV HDHomeRun glue 496 496 HEADERS += hdhrsignalmonitor.h hdhrchannel.h 497 HEADERS += hdhrrecorder.h 497 HEADERS += hdhrrecorder.h hdhrstreamhandler.h 498 498 499 499 SOURCES += hdhrsignalmonitor.cpp hdhrchannel.cpp 500 SOURCES += hdhrrecorder.cpp 500 SOURCES += hdhrrecorder.cpp hdhrstreamhandler.cpp 501 501 502 502 DEFINES += USING_HDHOMERUN 503 503 } -
mythtv/libs/libmythtv/scanwizardscanner.cpp
diff -r -u -N -X diff.exclude.noxml -x myth.20064 -x myth.20018 myth.20064/mythtv/libs/libmythtv/scanwizardscanner.cpp myth.20018/mythtv/libs/libmythtv/scanwizardscanner.cpp
523 523 #ifdef USING_HDHOMERUN 524 524 if ("HDHOMERUN" == card_type) 525 525 { 526 uint tuner = CardUtil::GetHDHRTuner(cardid); 527 channel = new HDHRChannel(NULL, device, tuner); 526 channel = new HDHRChannel(NULL, device); 528 527 } 529 528 #endif // USING_HDHOMERUN 530 529 -
mythtv/libs/libmythtv/tv_rec.cpp
diff -r -u -N -X diff.exclude.noxml -x myth.20064 -x myth.20018 myth.20064/mythtv/libs/libmythtv/tv_rec.cpp myth.20018/mythtv/libs/libmythtv/tv_rec.cpp
177 177 else if (genOpt.cardtype == "HDHOMERUN") 178 178 { 179 179 #ifdef USING_HDHOMERUN 180 channel = new HDHRChannel(this, genOpt.videodev , dboxOpt.port);180 channel = new HDHRChannel(this, genOpt.videodev); 181 181 if (!channel->Open()) 182 182 return false; 183 183 InitChannel(genOpt.defaultinput, startchannel); … … 3502 3502 return; 3503 3503 3504 3504 ClearFlags(kFlagWaitingForRecPause); 3505 #ifdef USING_HDHOMERUN3506 if (GetHDHRRecorder())3507 {3508 // We currently need to close the file descriptor for3509 // HDHomeRun signal monitoring to work.3510 GetHDHRRecorder()->Close();3511 GetHDHRRecorder()->SetRingBuffer(NULL);3512 }3513 #endif // USING_HDHOMERUN3514 3505 VERBOSE(VB_RECORD, LOC + "Recorder paused, calling TuningFrequency"); 3515 3506 TuningFrequency(lastTuningRequest); 3516 3507 } … … 4149 4140 } 4150 4141 recorder->Reset(); 4151 4142 4152 #ifdef USING_HDHOMERUN4153 if (GetHDHRRecorder())4154 {4155 pauseNotify = false;4156 GetHDHRRecorder()->Close();4157 pauseNotify = true;4158 GetHDHRRecorder()->Open();4159 GetHDHRRecorder()->StartData();4160 }4161 #endif // USING_HDHOMERUN4162 4163 4143 // Set file descriptor of channel from recorder for V4L 4164 4144 channel->SetFd(recorder->GetVideoFd()); 4165 4145 -
mythtv/libs/libmythtv/videosource.cpp
diff -r -u -N -X diff.exclude.noxml -x myth.20064 -x myth.20018 myth.20064/mythtv/libs/libmythtv/videosource.cpp myth.20018/mythtv/libs/libmythtv/videosource.cpp
50 50 51 51 QMutex XMLTVFindGrabbers::list_lock; 52 52 53 #include "hdhomerun_includes.h" 54 53 55 VideoSourceSelector::VideoSourceSelector(uint _initial_sourceid, 54 56 const QString &_card_types, 55 57 bool _must_have_mplexid) : … … 1406 1408 CaptureCard &parent; 1407 1409 }; 1408 1410 1409 class HDHomeRunDeviceID : public LineEditSetting, public CaptureCardDBStorage 1411 class HDHomeRunIP : public TransLabelSetting 1412 { 1413 public: 1414 HDHomeRunIP() 1415 { 1416 setLabel(QObject::tr("IP Address")); 1417 }; 1418 }; 1419 1420 class HDHomeRunTuner : public TransLabelSetting 1421 { 1422 public: 1423 HDHomeRunTuner() 1424 { 1425 setLabel(QObject::tr("Tuner")); 1426 }; 1427 }; 1428 1429 class HDHomeRunDeviceID : public ComboBoxSetting, public CaptureCardDBStorage 1410 1430 { 1411 1431 public: 1412 1432 HDHomeRunDeviceID(const CaptureCard &parent) : 1413 LineEditSetting(this),1433 ComboBoxSetting(this), 1414 1434 CaptureCardDBStorage(this, parent, "videodevice") 1415 1435 { 1416 setValue("FFFFFFFF");1417 1436 setLabel(QObject::tr("Device ID")); 1418 setHelpText(QObject::tr("IP address or Device ID from the bottom of " 1419 "the HDHomeRun. You may use " 1420 "'FFFFFFFF' if there is only one unit " 1421 "on your your network.")); 1437 setHelpText( 1438 QObject::tr("DevicedID and Tuner Number of available HDHomeRun " 1439 "devices. ")); 1440 fillSelections(""); 1441 }; 1442 1443 /// \brief Adds all available device-tuner combinations to list 1444 /// If current is >= 0 it will be considered available even 1445 /// if no device exists for it on the network 1446 void fillSelections(QString current) 1447 { 1448 clearSelections(); 1449 1450 // Get devices from filesystem 1451 vector<QString> devs = CardUtil::ProbeVideoDevices("HDHOMERUN"); 1452 1453 // Add current if needed 1454 if ((current != "") && 1455 (find(devs.begin(), devs.end(), current) == devs.end())) 1456 { 1457 devs.push_back(current); 1458 stable_sort(devs.begin(), devs.end()); 1459 } 1460 1461 vector<QString> db = CardUtil::GetVideoDevices("HDHOMERUN"); 1462 1463 QMap<QString, bool> in_use; 1464 QString sel = current; 1465 for (uint i = 0; i < devs.size(); i++) 1466 { 1467 const QString dev = devs[i]; 1468 in_use[devs[i]] = find(db.begin(), db.end(), dev) != db.end(); 1469 if (sel == "" && !in_use[devs[i]]) 1470 sel = dev; 1471 } 1472 1473 if (sel == "" && devs.size()) 1474 sel = devs[0]; 1475 1476 QString usestr = QString(" -- "); 1477 usestr += QObject::tr("Warning: already in use"); 1478 1479 for (uint i = 0; i < devs.size(); i++) 1480 { 1481 const QString dev = devs[i]; 1482 QString desc = dev + (in_use[devs[i]] ? usestr : ""); 1483 desc = (current == devs[i]) ? dev : desc; 1484 addSelection(desc, dev, dev == sel); 1485 } 1486 } 1487 1488 virtual void Load(void) 1489 { 1490 clearSelections(); 1491 addSelection(""); 1492 1493 CaptureCardDBStorage::Load(); 1494 1495 fillSelections(getValue()); 1422 1496 } 1423 1497 }; 1424 1498 … … 1452 1526 CaptureCard &parent; 1453 1527 }; 1454 1528 1455 class HDHomeRun TunerIndex : public ComboBoxSetting, public CaptureCardDBStorage1529 class HDHomeRunExtra : public ConfigurationWizard 1456 1530 { 1457 1531 public: 1458 HDHomeRunTunerIndex(const CaptureCard &parent) : 1459 ComboBoxSetting(this), 1460 CaptureCardDBStorage(this, parent, "dbox2_port") 1532 HDHomeRunExtra(HDHomeRunConfigurationGroup &parent); 1533 uint GetInstanceCount(void) const 1461 1534 { 1462 setLabel(QObject::tr("Tuner")); 1463 addSelection("0"); 1464 addSelection("1"); 1535 return (uint) count->intValue(); 1465 1536 } 1537 1538 private: 1539 InstanceCount *count; 1466 1540 }; 1467 1541 1468 class HDHomeRunConfigurationGroup : public VerticalConfigurationGroup 1542 HDHomeRunExtra::HDHomeRunExtra(HDHomeRunConfigurationGroup &parent) 1543 : count(new InstanceCount(parent.parent)) 1469 1544 { 1470 public: 1471 HDHomeRunConfigurationGroup(CaptureCard& a_parent) : 1472 VerticalConfigurationGroup(false, true, false, false), 1473 parent(a_parent) 1474 { 1475 setUseLabel(false); 1476 addChild(new HDHomeRunDeviceID(parent)); 1477 addChild(new HDHomeRunTunerIndex(parent)); 1478 addChild(new SignalTimeout(parent, 1000, 250)); 1479 addChild(new ChannelTimeout(parent, 3000, 1750)); 1480 addChild(new SingleCardInput(parent)); 1481 }; 1545 VerticalConfigurationGroup* rec = new VerticalConfigurationGroup(false); 1546 rec->setLabel(QObject::tr("Recorder Options")); 1547 rec->setUseLabel(false); 1548 1549 rec->addChild(count); 1550 1551 addChild(rec); 1552 } 1553 1554 HDHomeRunConfigurationGroup::HDHomeRunConfigurationGroup(CaptureCard& a_parent) : 1555 VerticalConfigurationGroup(false, true, false, false), 1556 parent(a_parent) 1557 { 1558 setUseLabel(false); 1559 deviceid = new HDHomeRunDeviceID(parent); 1560 addChild(deviceid); 1561 cardip = new HDHomeRunIP(); 1562 cardtuner = new HDHomeRunTuner(); 1563 1564 addChild(cardip); 1565 addChild(cardtuner); 1566 1567 addChild(new SignalTimeout(parent, 1000, 250)); 1568 addChild(new ChannelTimeout(parent, 3000, 1750)); 1569 addChild(new SingleCardInput(parent)); 1570 1571 TransButtonSetting *buttonRecOpt = new TransButtonSetting(); 1572 buttonRecOpt->setLabel(tr("Recording Options")); 1573 addChild(buttonRecOpt); 1574 1575 connect(deviceid, SIGNAL(valueChanged(const QString&)), 1576 this, SLOT( probeCard (const QString&))); 1577 connect(buttonRecOpt, SIGNAL(pressed()), 1578 this, SLOT( HDHomeRunExtraPanel())); 1579 1482 1580 1483 private:1484 CaptureCard &parent;1485 1581 }; 1486 1582 1583 void HDHomeRunConfigurationGroup::probeCard(const QString& deviceid) 1584 { 1585 hdhomerun_device_t* thisdevice = hdhomerun_device_create_from_str(deviceid.toLocal8Bit().constData()); 1586 1587 if (thisdevice) 1588 { 1589 uint device_ip = hdhomerun_device_get_device_ip(thisdevice); 1590 uint tuner = hdhomerun_device_get_tuner(thisdevice); 1591 hdhomerun_device_destroy(thisdevice); 1592 1593 QString ip = QString("%1.%2.%3.%4") 1594 .arg((device_ip>>24) & 0xFF).arg((device_ip>>16) & 0xFF) 1595 .arg((device_ip>> 8) & 0xFF).arg((device_ip>> 0) & 0xFF); 1596 1597 cardip->setValue(ip); 1598 cardtuner->setValue(QString("%1").arg(tuner)); 1599 } 1600 else 1601 { 1602 cardip->setValue("Unknown"); 1603 cardtuner->setValue("Unknown"); 1604 } 1605 } 1606 1607 void HDHomeRunConfigurationGroup::HDHomeRunExtraPanel(void) 1608 { 1609 parent.reload(); // ensure card id is valid 1610 1611 HDHomeRunExtra acw(*this); 1612 acw.exec(); 1613 parent.SetInstanceCount(acw.GetInstanceCount()); 1614 } 1615 1616 1487 1617 V4LConfigurationGroup::V4LConfigurationGroup(CaptureCard& a_parent) : 1488 1618 VerticalConfigurationGroup(false, true, false, false), 1489 1619 parent(a_parent), … … 1697 1827 if ((cardtype.toLower() == "dvb") && (1 != ++device_refs[videodevice])) 1698 1828 continue; 1699 1829 1830 if ((cardtype.toLower() == "hdhomerun") && (1 != ++device_refs[videodevice])) 1831 continue; 1832 1700 1833 QString label = CardUtil::GetDeviceLabel( 1701 1834 cardid, cardtype, videodevice); 1702 1835 … … 2839 2972 if ((cardtype.toLower() == "dvb") && (1 != ++device_refs[videodevice])) 2840 2973 continue; 2841 2974 2975 if ((cardtype.toLower() == "hdhomerun") && (1 != ++device_refs[videodevice])) 2976 continue; 2977 2842 2978 QStringList inputLabels; 2843 2979 vector<CardInput*> cardInputs; 2844 2980 -
mythtv/libs/libmythtv/videosource.h
diff -r -u -N -X diff.exclude.noxml -x myth.20064 -x myth.20018 myth.20064/mythtv/libs/libmythtv/videosource.h myth.20018/mythtv/libs/libmythtv/videosource.h
530 530 DiSEqCDevTree *diseqc_tree; 531 531 }; 532 532 533 class HDHomeRunDeviceID; 534 class HDHomeRunIP; 535 class HDHomeRunTuner; 536 class HDHomeRunConfigurationGroup : public VerticalConfigurationGroup 537 { 538 friend class HDHomeRunExtra; 539 540 Q_OBJECT 541 public: 542 HDHomeRunConfigurationGroup(CaptureCard& a_parent); 543 544 public slots: 545 void probeCard(const QString& deviceid); 546 void HDHomeRunExtraPanel(void); 547 548 private: 549 HDHomeRunDeviceID *deviceid; 550 HDHomeRunIP *cardip; 551 HDHomeRunTuner *cardtuner; 552 553 CaptureCard &parent; 554 }; 555 556 533 557 class FirewireGUID; 534 558 class FirewireModel : public ComboBoxSetting, public CaptureCardDBStorage 535 559 {