Ticket #6138: 133-hdhr.multirec.6.patch
File 133-hdhr.multirec.6.patch, 84.5 KB (added by , 17 years ago) |
---|
-
mythtv/libs/libmythtv/cardutil.cpp
diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/cardutil.cpp release.19757.0120a/mythtv/libs/libmythtv/cardutil.cpp
28 28 #include "videodev_myth.h" 29 29 #endif 30 30 31 #include "hdhomerun_includes.h" 32 31 33 #define LOC QString("CardUtil: ") 32 34 #define LOC_WARN QString("CardUtil, Warning: ") 33 35 #define LOC_ERR QString("CardUtil, Error: ") … … 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: ") + … … 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 } … … 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 -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/cardutil.h release.19757.0120a/mythtv/libs/libmythtv/cardutil.h
106 106 107 107 static bool IsTunerSharingCapable(const QString &rawtype) 108 108 { 109 return (rawtype == "DVB") ;109 return (rawtype == "DVB") || (rawtype == "HDHOMERUN"); 110 110 } 111 111 112 112 static bool IsTunerShared(uint cardidA, uint cardidB); -
mythtv/libs/libmythtv/hdhomerun_includes.h
diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/hdhomerun_includes.h release.19757.0120a/mythtv/libs/libmythtv/hdhomerun_includes.h
1 #ifndef __HDHOMERUN_INCLUDES__ 2 #define __HDHOMERUN_INCLUDES__ 3 4 #include "hdhomerun/hdhomerun.h" 5 6 #endif /* __HDHOMERUN_INCLUDES__ */ 7 -
mythtv/libs/libmythtv/hdhrchannel.cpp
diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/hdhrchannel.cpp release.19757.0120a/mythtv/libs/libmythtv/hdhrchannel.cpp
26 26 #include "channelutil.h" 27 27 #include "frequencytables.h" 28 28 29 #include "hdhrstreamhandler.h" 30 29 31 #define DEBUG_PID_FILTERS 30 32 31 33 #define LOC QString("HDHRChan(%1): ").arg(GetDevice()) 32 34 #define LOC_ERR QString("HDHRChan(%1), Error: ").arg(GetDevice()) 33 35 34 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(true) 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 _device_id = HDHOMERUN_DEVICE_ID_WILDCARD; 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 58 _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(true), 39 tune_lock(true), hw_lock(true) 40 { 59 41 } 60 42 61 43 HDHRChannel::~HDHRChannel(void) … … 65 47 66 48 bool HDHRChannel::Open(void) 67 49 { 50 VERBOSE(VB_CHANNEL, LOC + "Opening HDHR channel"); 51 52 QMutexLocker locker(&hw_lock); 53 68 54 if (IsOpen()) 69 55 return true; 70 56 71 if (!FindDevice()) 72 return false; 57 _stream_handler = HDHRStreamHandler::Get(_device_id); 73 58 74 59 if (!InitializeInputs()) 75 return false;76 77 return (_device_ip != 0) && Connect();78 }79 80 void HDHRChannel::Close(void)81 {82 if (_control_socket)83 {84 hdhomerun_control_destroy(_control_socket);85 _control_socket = NULL;86 }87 }88 89 bool HDHRChannel::EnterPowerSavingMode(void)90 {91 return QString::null != TunerSet("channel", "none", false);92 }93 94 bool HDHRChannel::FindDevice(void)95 {96 if (!_device_id)97 return _device_ip;98 99 _device_ip = 0;100 101 /* Discover. */102 struct hdhomerun_discover_device_t result;103 int ret = hdhomerun_discover_find_devices_custom(0, HDHOMERUN_DEVICE_TYPE_WILDCARD, _device_id, &result, 1);104 if (ret < 0)105 {106 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to send discovery request" + ENO);107 return false;108 }109 if (ret == 0)110 60 { 111 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("device not found"));61 Close(); 112 62 return false; 113 63 } 114 64 115 /* Found. */ 116 _device_ip = result.ip_addr; 65 // nextInputID = currentInputID; 117 66 118 VERBOSE(VB_IMPORTANT, LOC + 119 QString("device found at address %1.%2.%3.%4") 120 .arg((_device_ip>>24) & 0xFF).arg((_device_ip>>16) & 0xFF) 121 .arg((_device_ip>> 8) & 0xFF).arg((_device_ip>> 0) & 0xFF)); 67 return _stream_handler->Connected(); 122 68 123 return true;124 69 } 125 70 126 bool HDHRChannel::Connect(void)71 void HDHRChannel::Close() 127 72 { 128 _control_socket = hdhomerun_control_create(_device_id, _device_ip); 129 if (!_control_socket) 130 { 131 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to create control socket"); 132 return false; 133 } 73 VERBOSE(VB_CHANNEL, LOC + "Closing HDHR channel"); 134 74 135 if (hdhomerun_control_get_local_addr(_control_socket) == 0) 136 { 137 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to connect to device"); 138 return false; 139 } 75 if (! IsOpen()) 76 return; // this caller didn't have it open in the first place.. 140 77 141 VERBOSE(VB_CHANNEL, LOC + "Successfully connected to device"); 142 return true; 78 HDHRStreamHandler::Return(_stream_handler); 143 79 } 144 80 145 QString HDHRChannel::DeviceGet(const QString &name, bool report_error_return) 146 { 147 QMutexLocker locker(&_lock); 148 149 if (!_control_socket) 150 { 151 VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed (not connected)"); 152 return QString::null; 153 } 154 155 char *value = NULL; 156 char *error = NULL; 157 if (hdhomerun_control_get(_control_socket, name, &value, &error) < 0) 158 { 159 VERBOSE(VB_IMPORTANT, LOC_ERR + "Get request failed" + ENO); 160 return QString::null; 161 } 162 163 if (report_error_return && error) 164 { 165 VERBOSE(VB_IMPORTANT, LOC_ERR + 166 QString("DeviceGet(%1): %2").arg(name).arg(error)); 167 168 return QString::null; 169 } 170 171 return QString(value); 172 } 173 174 QString HDHRChannel::DeviceSet(const QString &name, const QString &val, 175 bool report_error_return) 81 bool HDHRChannel::EnterPowerSavingMode(void) 176 82 { 177 QMutexLocker locker(&_lock); 178 179 if (!_control_socket) 180 { 181 VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed (not connected)"); 182 return QString::null; 183 } 184 185 char *value = NULL; 186 char *error = NULL; 187 if (hdhomerun_control_set(_control_socket, name, val, &value, &error) < 0) 188 { 189 VERBOSE(VB_IMPORTANT, LOC_ERR + "Set request failed" + ENO); 190 191 return QString::null; 192 } 193 194 if (report_error_return && error) 195 { 196 VERBOSE(VB_IMPORTANT, LOC_ERR + 197 QString("DeviceSet(%1 %2): %3").arg(name).arg(val).arg(error)); 198 199 return QString::null; 200 } 201 202 return QString(value); 83 if ( IsOpen()) 84 return _stream_handler->EnterPowerSavingMode(); 85 else 86 return true; 203 87 } 204 88 205 QString HDHRChannel::TunerGet(const QString &name, bool report_error_return)206 {207 return DeviceGet(QString("/tuner%1/%2").arg(_tuner).arg(name),208 report_error_return);209 }210 89 211 QString HDHRChannel::TunerSet(const QString &name, const QString &value, 212 bool report_error_return) 90 bool HDHRChannel::IsOpen(void) const 213 91 { 214 return DeviceSet(QString("/tuner%1/%2").arg(_tuner).arg(name), value, 215 report_error_return); 92 return (_stream_handler != NULL); 216 93 } 217 94 218 bool HDHRChannel:: DeviceSetTarget(unsigned short localPort)95 bool HDHRChannel::Init(QString &inputname, QString &startchannel, bool setchan) 219 96 { 220 if (localPort == 0) 221 { 222 return false; 223 } 97 if (setchan && !IsOpen()) 98 Open(); 224 99 225 unsigned long localIP = hdhomerun_control_get_local_addr(_control_socket); 226 if (localIP == 0) 227 { 228 return false; 229 } 230 231 QString configValue = QString("%1.%2.%3.%4:%5") 232 .arg((localIP >> 24) & 0xFF).arg((localIP >> 16) & 0xFF) 233 .arg((localIP >> 8) & 0xFF).arg((localIP >> 0) & 0xFF) 234 .arg(localPort); 235 236 if (!TunerSet("target", configValue)) 237 { 238 return false; 239 } 240 241 return true; 242 } 243 244 bool HDHRChannel::DeviceClearTarget() 245 { 246 return TunerSet("target", "0.0.0.0:0"); 100 return ChannelBase::Init(inputname, startchannel, setchan); 247 101 } 248 102 249 103 bool HDHRChannel::SetChannelByString(const QString &channum) … … 277 131 return SwitchToInput(inputName, channum); 278 132 279 133 ClearDTVInfo(); 280 _ignore_filters = false;281 134 282 135 InputMap::const_iterator it = inputs.find(currentInputID); 283 136 if (it == inputs.end()) … … 349 202 if (mpeg_prog_num && (GetTuningMode() == "mpeg")) 350 203 { 351 204 QString pnum = QString::number(mpeg_prog_num); 352 _ignore_filters = QString::null != TunerSet("program", pnum, false); 205 //_ignore_filters = _stream_handler->TuneProgram(pnum); 206 _stream_handler->TuneProgram(pnum); 353 207 } 354 208 355 209 return true; … … 398 252 QString("TuneTo(%1,%2)").arg(frequency).arg(modulation)); 399 253 400 254 if (modulation == "8vsb") 401 ok = TunerSet("channel",QString("8vsb:%1").arg(frequency));255 ok = _stream_handler->TuneChannel(QString("8vsb:%1").arg(frequency)); 402 256 else if (modulation == "qam_64") 403 ok = TunerSet("channel",QString("qam64:%1").arg(frequency));257 ok = _stream_handler->TuneChannel(QString("qam64:%1").arg(frequency)); 404 258 else if (modulation == "qam_256") 405 ok = TunerSet("channel",QString("qam256:%1").arg(frequency));259 ok = _stream_handler->TuneChannel(QString("qam256:%1").arg(frequency)); 406 260 407 261 if (ok) 408 262 SetSIStandard(si_std); 409 263 410 264 return ok; 411 265 } 412 413 bool HDHRChannel::AddPID(uint pid, bool do_update)414 {415 QMutexLocker locker(&_lock);416 417 vector<uint>::iterator it;418 it = lower_bound(_pids.begin(), _pids.end(), pid);419 if (it != _pids.end() && *it == pid)420 {421 #ifdef DEBUG_PID_FILTERS422 VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<") NOOP");423 #endif // DEBUG_PID_FILTERS424 return true;425 }426 427 _pids.insert(it, pid);428 429 #ifdef DEBUG_PID_FILTERS430 VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<")");431 #endif // DEBUG_PID_FILTERS432 433 if (do_update)434 return UpdateFilters();435 return true;436 }437 438 bool HDHRChannel::DelPID(uint pid, bool do_update)439 {440 QMutexLocker locker(&_lock);441 442 vector<uint>::iterator it;443 it = lower_bound(_pids.begin(), _pids.end(), pid);444 if (it == _pids.end())445 {446 #ifdef DEBUG_PID_FILTERS447 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") NOOP");448 #endif // DEBUG_PID_FILTERS449 450 return true;451 }452 453 if (*it == pid)454 {455 #ifdef DEBUG_PID_FILTERS456 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") -- found");457 #endif // DEBUG_PID_FILTERS458 _pids.erase(it);459 }460 else461 {462 #ifdef DEBUG_PID_FILTERS463 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<") -- failed");464 #endif // DEBUG_PID_FILTERS465 }466 467 if (do_update)468 return UpdateFilters();469 return true;470 }471 472 bool HDHRChannel::DelAllPIDs(void)473 {474 QMutexLocker locker(&_lock);475 476 #ifdef DEBUG_PID_FILTERS477 VERBOSE(VB_CHANNEL, "DelAllPID()");478 #endif // DEBUG_PID_FILTERS479 480 _pids.clear();481 482 return UpdateFilters();483 }484 485 QString filt_str(uint pid)486 {487 uint pid0 = (pid / (16*16*16)) % 16;488 uint pid1 = (pid / (16*16)) % 16;489 uint pid2 = (pid / (16)) % 16;490 uint pid3 = pid % 16;491 return QString("0x%1%2%3%4")492 .arg(pid0,0,16).arg(pid1,0,16)493 .arg(pid2,0,16).arg(pid3,0,16);494 }495 496 bool HDHRChannel::UpdateFilters(void)497 {498 QMutexLocker locker(&_lock);499 500 QString filter = "";501 502 vector<uint> range_min;503 vector<uint> range_max;504 505 if (_ignore_filters)506 return true;507 508 for (uint i = 0; i < _pids.size(); i++)509 {510 uint pid_min = _pids[i];511 uint pid_max = pid_min;512 for (uint j = i + 1; j < _pids.size(); j++)513 {514 if (pid_max + 1 != _pids[j])515 break;516 pid_max++;517 i++;518 }519 range_min.push_back(pid_min);520 range_max.push_back(pid_max);521 }522 523 if (range_min.size() > 16)524 {525 range_min.resize(16);526 uint pid_max = range_max.back();527 range_max.resize(15);528 range_max.push_back(pid_max);529 }530 531 for (uint i = 0; i < range_min.size(); i++)532 {533 filter += filt_str(range_min[i]);534 if (range_min[i] != range_max[i])535 filter += QString("-%1").arg(filt_str(range_max[i]));536 filter += " ";537 }538 539 filter = filter.stripWhiteSpace();540 541 QString new_filter = TunerSet("filter", filter);542 543 #ifdef DEBUG_PID_FILTERS544 QString msg = QString("Filter: '%1'").arg(filter);545 if (filter != new_filter)546 msg += QString("\n\t\t\t\t'%2'").arg(new_filter);547 548 VERBOSE(VB_CHANNEL, msg);549 #endif // DEBUG_PID_FILTERS550 551 return filter == new_filter;552 } -
mythtv/libs/libmythtv/hdhrchannel.h
diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/hdhrchannel.h release.19757.0120a/mythtv/libs/libmythtv/hdhrchannel.h
15 15 16 16 // HDHomeRun headers 17 17 #ifdef USING_HDHOMERUN 18 #include "hdhomerun/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 -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/hdhrrecorder.cpp release.19757.0120a/mythtv/libs/libmythtv/hdhrrecorder.cpp
23 23 24 24 // MythTV includes 25 25 #include "RingBuffer.h" 26 #include "hdhrchannel.h"27 #include "hdhrrecorder.h"28 26 #include "atsctables.h" 29 27 #include "atscstreamdata.h" 30 28 #include "eithelper.h" 31 29 #include "tv_rec.h" 32 30 31 // MythTV HDHR includes 32 #include "hdhrchannel.h" 33 #include "hdhrrecorder.h" 34 #include "hdhrstreamhandler.h" 35 33 36 #define LOC QString("HDHRRec(%1): ").arg(tvrec->GetCaptureCardNum()) 37 #define LOC_WARN QString("HDHRRec(%1), Warning: ") \ 38 .arg(tvrec->GetCaptureCardNum()) 34 39 #define LOC_ERR QString("HDHRRec(%1), Error: ") \ 35 40 .arg(tvrec->GetCaptureCardNum()) 36 41 37 42 HDHRRecorder::HDHRRecorder(TVRec *rec, HDHRChannel *channel) 38 43 : DTVRecorder(rec), 39 _channel(channel), _video_socket(NULL), 44 _channel(channel), 45 _stream_handler(NULL), 40 46 _stream_data(NULL), 41 _input_pat(NULL), _input_pmt(NULL), 42 _reset_pid_filters(false),_pid_lock(true) 47 _pid_lock(true), 48 _input_pat(NULL), 49 _input_pmt(NULL), 50 _has_no_av(false) 43 51 { 44 52 } 45 53 … … 90 98 // HACK -- end 91 99 } 92 100 101 bool HDHRRecorder::IsOpen(void) { 102 return (_stream_handler != NULL); 103 } 104 93 105 bool HDHRRecorder::Open(void) 94 106 { 95 107 VERBOSE(VB_RECORD, LOC + "Open()"); 96 if ( _video_socket)108 if (IsOpen()) 97 109 { 98 110 VERBOSE(VB_RECORD, LOC + "Card already open (recorder)"); 99 111 return true; 100 112 } 101 113 102 /* Calculate buffer size */ 103 uint buffersize = gContext->GetNumSetting( 104 "HDRingbufferSize", 50 * TSPacket::SIZE) * 1024; 105 buffersize /= VIDEO_DATA_PACKET_SIZE; 106 buffersize *= VIDEO_DATA_PACKET_SIZE; 114 bzero(_stream_id, sizeof(_stream_id)); 115 bzero(_pid_status, sizeof(_pid_status)); 116 memset(_continuity_counter, 0xff, sizeof(_continuity_counter)); 107 117 108 // Buffer should be at least about 1MB.. 109 buffersize = max(49 * TSPacket::SIZE * 128, buffersize); 118 _stream_handler = HDHRStreamHandler::Get(_channel->GetDevice()); 110 119 111 /* Create TS socket. */ 112 _video_socket = hdhomerun_video_create(0, buffersize); 113 if (!_video_socket) 114 { 115 VERBOSE(VB_IMPORTANT, LOC + "Open() failed to open socket"); 116 return false; 117 } 120 VERBOSE(VB_RECORD, LOC + "HDHR opened successfully"); 118 121 119 /* Success. */120 122 return true; 121 123 } 122 124 123 /** \fn HDHRRecorder::StartData(void)124 * \brief Configure device to send video.125 */126 bool HDHRRecorder::StartData(void)127 {128 VERBOSE(VB_RECORD, LOC + "StartData()");129 uint localPort = hdhomerun_video_get_local_port(_video_socket);130 return _channel->DeviceSetTarget(localPort);131 }132 133 125 void HDHRRecorder::Close(void) 134 126 { 135 VERBOSE(VB_RECORD, LOC + "Close()"); 136 if (_video_socket) 137 { 138 hdhomerun_video_destroy(_video_socket); 139 _video_socket = NULL; 140 } 141 } 142 143 void HDHRRecorder::ProcessTSData(const uint8_t *buffer, int len) 144 { 145 QMutexLocker locker(&_pid_lock); 146 const uint8_t *data = buffer; 147 const uint8_t *end = buffer + len; 127 VERBOSE(VB_RECORD, LOC + "Close() - Begin"); 148 128 149 while (data + 188 <= end)129 if (IsOpen()) 150 130 { 151 if (data[0] != 0x47) 152 { 153 return; 154 } 155 156 const TSPacket *tspacket = reinterpret_cast<const TSPacket*>(data); 157 ProcessTSPacket(*tspacket); 158 159 data += 188; 131 HDHRStreamHandler::Return(_stream_handler); 160 132 } 133 134 VERBOSE(VB_RECORD, LOC + "Close() - End"); 161 135 } 162 136 163 137 void HDHRRecorder::SetStreamData(MPEGStreamData *data) … … 216 190 ProgramAssociationTable *oldpat = _input_pat; 217 191 _input_pat = new ProgramAssociationTable(*_pat); 218 192 delete oldpat; 219 220 _reset_pid_filters = true;221 193 } 222 194 223 195 void HDHRRecorder::HandlePMT(uint progNum, const ProgramMapTable *_pmt) … … 229 201 VERBOSE(VB_RECORD, LOC + "SetPMT("<<progNum<<")"); 230 202 ProgramMapTable *oldpmt = _input_pmt; 231 203 _input_pmt = new ProgramMapTable(*_pmt); 232 delete oldpmt;233 204 234 _reset_pid_filters = true; 205 QString sistandard = _channel->GetSIStandard(); 206 207 bool has_no_av = true; 208 for (uint i = 0; i < _input_pmt->StreamCount() && has_no_av; i++) 209 { 210 has_no_av &= !_input_pmt->IsVideo(i, sistandard); 211 has_no_av &= !_input_pmt->IsAudio(i, sistandard); 212 } 213 _has_no_av = has_no_av; 214 215 _channel->SetPMT(_input_pmt); 216 delete oldpmt; 235 217 } 236 218 } 237 219 … … 242 224 243 225 int next = (pat->tsheader()->ContinuityCounter()+1)&0xf; 244 226 pat->tsheader()->SetContinuityCounter(next); 245 BufferedWrite(*(reinterpret_cast<TSPacket*>(pat->tsheader())));227 DTVRecorder::BufferedWrite(*(reinterpret_cast<TSPacket*>(pat->tsheader()))); 246 228 } 247 229 248 230 void HDHRRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt) 249 231 { 250 232 if (!pmt) 233 { 234 VERBOSE(VB_RECORD, LOC + "HandleSingleProgramPMT(NULL)"); 235 return; 236 } 237 238 // collect stream types for H.264 (MPEG-4 AVC) keyframe detection 239 for (uint i = 0; i < pmt->StreamCount(); i++) 240 _stream_id[pmt->StreamPID(i)] = pmt->StreamType(i); 241 242 if (!ringBuffer) 251 243 return; 252 244 253 245 unsigned char buf[8 * 1024]; … … 255 247 pmt->tsheader()->SetContinuityCounter(next_cc); 256 248 uint size = pmt->WriteAsTSPackets(buf, next_cc); 257 249 250 uint posA[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() }; 251 258 252 for (uint i = 0; i < size ; i += TSPacket::SIZE) 259 253 DTVRecorder::BufferedWrite(*(reinterpret_cast<TSPacket*>(&buf[i]))); 254 255 uint posB[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() }; 256 257 if (posB[0] + posB[1] * TSPacket::SIZE > 258 posA[0] + posA[1] * TSPacket::SIZE) 259 { 260 VERBOSE(VB_RECORD, LOC + "Wrote PMT @" 261 << posA[0] << " + " << (posA[1] * TSPacket::SIZE)); 262 } 263 else 264 { 265 VERBOSE(VB_RECORD, LOC + "Saw PMT but did not write to disk yet"); 266 } 260 267 } 261 268 262 269 /** \fn HDHRRecorder::HandleMGT(const MasterGuideTable*) … … 276 283 } 277 284 */ 278 285 286 bool HDHRRecorder::ProcessVideoTSPacket(const TSPacket &tspacket) 287 { 288 uint streamType = _stream_id[tspacket.PID()]; 289 290 // Check for keyframes and count frames 291 if (streamType == StreamID::H264Video) 292 { 293 _buffer_packets = !FindH264Keyframes(&tspacket); 294 if (!_seen_sps) 295 return true; 296 } 297 else 298 { 299 _buffer_packets = !FindMPEG2Keyframes(&tspacket); 300 } 301 302 return ProcessAVTSPacket(tspacket); 303 } 304 305 bool HDHRRecorder::ProcessAudioTSPacket(const TSPacket &tspacket) 306 { 307 _buffer_packets = !FindAudioKeyframes(&tspacket); 308 return ProcessAVTSPacket(tspacket); 309 } 310 311 /// Common code for processing either audio or video packets 312 bool HDHRRecorder::ProcessAVTSPacket(const TSPacket &tspacket) 313 { 314 const uint pid = tspacket.PID(); 315 // Sync recording start to first keyframe 316 if (_wait_for_keyframe_option && _first_keyframe < 0) 317 return true; 318 319 // Sync streams to the first Payload Unit Start Indicator 320 // _after_ first keyframe iff _wait_for_keyframe_option is true 321 if (!(_pid_status[pid] & kPayloadStartSeen) && tspacket.HasPayload()) 322 { 323 if (!tspacket.PayloadStart()) 324 return true; // not payload start - drop packet 325 326 VERBOSE(VB_RECORD, 327 QString("PID 0x%1 Found Payload Start").arg(pid,0,16)); 328 329 _pid_status[pid] |= kPayloadStartSeen; 330 } 331 332 BufferedWrite(tspacket); 333 334 return true; 335 } 336 279 337 bool HDHRRecorder::ProcessTSPacket(const TSPacket& tspacket) 280 338 { 281 bool ok = !tspacket.TransportError();282 if ( ok && !tspacket.ScramplingControl())339 // Only create fake keyframe[s] if there are no audio/video streams 340 if (_input_pmt && _has_no_av) 283 341 { 284 if (tspacket.HasAdaptationField()) 285 GetStreamData()->HandleAdaptationFieldControl(&tspacket); 286 if (tspacket.HasPayload()) 287 { 288 const unsigned int lpid = tspacket.PID(); 342 _buffer_packets = !FindOtherKeyframes(&tspacket); 343 } 344 else 345 { 346 // There are audio/video streams. Only write the packet 347 // if audio/video key-frames have been found 348 if (_wait_for_keyframe_option && _first_keyframe < 0) 349 return true; 289 350 290 if ((GetStreamData()->VideoPIDSingleProgram() > 0x1fff) && 291 _wait_for_keyframe_option) 292 { 293 _wait_for_keyframe_option = false; 294 } 295 296 // Pass or reject frames based on PID, and parse info from them 297 if (lpid == GetStreamData()->VideoPIDSingleProgram()) 298 { 299 //cerr<<"v"; 300 _buffer_packets = !FindMPEG2Keyframes(&tspacket); 301 BufferedWrite(tspacket); 302 } 303 else if (GetStreamData()->IsAudioPID(lpid)) 304 { 305 //cerr<<"a"; 306 _buffer_packets = !FindAudioKeyframes(&tspacket); 307 BufferedWrite(tspacket); 308 } 309 else if (GetStreamData()->IsListeningPID(lpid)) 310 { 311 //cerr<<"t"; 312 GetStreamData()->HandleTSTables(&tspacket); 313 } 314 else if (GetStreamData()->IsWritingPID(lpid)) 315 BufferedWrite(tspacket); 316 } 351 _buffer_packets = true; 317 352 } 318 return ok; 353 354 BufferedWrite(tspacket); 319 355 } 320 356 321 357 void HDHRRecorder::StartRecording(void) … … 333 369 _request_recording = true; 334 370 _recording = true; 335 371 336 if (!StartData())337 {338 VERBOSE(VB_IMPORTANT, LOC_ERR + "Starting recording "339 "(set target failed). Aborting.");340 Close();341 _error = true;342 VERBOSE(VB_RECORD, LOC + "StartRecording -- end 2"); 343 return;344 }345 346 hdhomerun_video_flush(_video_socket);372 // Make sure the first things in the file are a PAT & PMT 373 bool tmp = _wait_for_keyframe_option; 374 _wait_for_keyframe_option = false; 375 HandleSingleProgramPAT(_stream_data->PATSingleProgram()); 376 HandleSingleProgramPMT(_stream_data->PMTSingleProgram()); 377 _wait_for_keyframe_option = tmp; 378 379 _stream_data->AddAVListener(this); 380 _stream_data->AddWritingListener(this); 381 _stream_handler->AddListener(_stream_data); 382 347 383 while (_request_recording && !_error) 348 384 { 385 usleep(50000); 386 349 387 if (PauseAndWait()) 350 388 continue; 351 389 352 if ( _stream_data)390 if (!_input_pmt) 353 391 { 354 QMutexLocker read_lock(&_pid_lock); 355 _reset_pid_filters |= _stream_data->HasEITPIDChanges(_eit_pids); 392 VERBOSE(VB_GENERAL, LOC_WARN + 393 "Recording will not commence until a PMT is set."); 394 usleep(5000); 395 continue; 356 396 } 357 397 358 if ( _reset_pid_filters)398 if (!_stream_handler->IsRunning()) 359 399 { 360 _reset_pid_filters = false; 361 VERBOSE(VB_RECORD, LOC + "Resetting Demux Filters"); 362 AdjustFilters(); 363 } 400 _error = true; 364 401 365 size_t read_size = 64 * 1024; // read about 64KB 366 read_size /= VIDEO_DATA_PACKET_SIZE; 367 read_size *= VIDEO_DATA_PACKET_SIZE; 368 369 size_t data_length; 370 unsigned char *data_buffer = 371 hdhomerun_video_recv(_video_socket, read_size, &data_length); 372 if (!data_buffer) 373 { 374 usleep(5000); 375 continue; 376 } 377 378 ProcessTSData(data_buffer, data_length); 402 VERBOSE(VB_IMPORTANT, LOC_ERR + 403 "Stream handler died unexpectedly."); 404 } 379 405 } 380 406 381 407 VERBOSE(VB_RECORD, LOC + "StartRecording -- ending..."); 382 408 383 _channel->DeviceClearTarget(); 409 _stream_handler->RemoveListener(_stream_data); 410 _stream_data->RemoveWritingListener(this); 411 _stream_data->RemoveAVListener(this); 412 384 413 Close(); 385 414 386 415 FinishRecording(); … … 389 418 VERBOSE(VB_RECORD, LOC + "StartRecording -- end"); 390 419 } 391 420 392 bool HDHRRecorder::AdjustFilters(void)421 void HDHRRecorder::ResetForNewFile(void) 393 422 { 394 QMutexLocker change_lock(&_pid_lock);423 DTVRecorder::ResetForNewFile(); 395 424 396 if (!_channel) 397 { 398 VERBOSE(VB_IMPORTANT, LOC_ERR + "AdjustFilters() no channel"); 399 return false; 400 } 425 bzero(_stream_id, sizeof(_stream_id)); 426 bzero(_pid_status, sizeof(_pid_status)); 427 memset(_continuity_counter, 0xff, sizeof(_continuity_counter)); 401 428 402 if (!_input_pat || !_input_pmt) 403 { 404 VERBOSE(VB_IMPORTANT, LOC + "AdjustFilters() no pmt or no pat"); 405 return false; 406 } 407 408 uint_vec_t add_pid; 429 // FIXME 430 // Close and re-open ??? 431 //Close(); 432 //Open(); 433 } 409 434 410 add_pid.push_back(MPEG_PAT_PID); 411 _stream_data->AddListeningPID(MPEG_PAT_PID); 435 void HDHRRecorder::StopRecording(void) 436 { 437 _request_recording = false; 438 while (_recording) 439 usleep(2000); 440 } 412 441 413 for (uint i = 0; i < _input_pat->ProgramCount(); i++) 442 bool HDHRRecorder::PauseAndWait(int timeout) 443 { 444 if (request_pause) 414 445 { 415 add_pid.push_back(_input_pat->ProgramPID(i)); 416 _stream_data->AddListeningPID(_input_pat->ProgramPID(i)); 417 } 446 if (!paused) 447 { 448 assert(_stream_handler); 449 assert(_stream_data); 418 450 419 // Record the streams in the PMT... 420 bool need_pcr_pid = true; 421 for (uint i = 0; i < _input_pmt->StreamCount(); i++) 422 { 423 add_pid.push_back(_input_pmt->StreamPID(i)); 424 need_pcr_pid &= (_input_pmt->StreamPID(i) != _input_pmt->PCRPID()); 425 _stream_data->AddWritingPID(_input_pmt->StreamPID(i)); 426 } 451 _stream_handler->RemoveListener(_stream_data); 427 452 428 if (need_pcr_pid && (_input_pmt->PCRPID())) 429 { 430 add_pid.push_back(_input_pmt->PCRPID()); 431 _stream_data->AddWritingPID(_input_pmt->PCRPID()); 453 paused = true; 454 pauseWait.wakeAll(); 455 if (tvrec) 456 tvrec->RecorderPaused(); 457 } 458 unpauseWait.wait(timeout); 432 459 } 433 460 434 // Adjust for EIT 435 AdjustEITPIDs(); 436 for (uint i = 0; i < _eit_pids.size(); i++) 461 if (!request_pause && paused) 437 462 { 438 add_pid.push_back(_eit_pids[i]); 439 _stream_data->AddListeningPID(_eit_pids[i]); 440 } 463 paused = false; 441 464 442 // Delete filters for pids we no longer wish to monitor 443 vector<uint>::const_iterator it; 444 vector<uint> pids = _channel->GetPIDs(); 445 for (it = pids.begin(); it != pids.end(); ++it) 446 { 447 if (find(add_pid.begin(), add_pid.end(), *it) == add_pid.end()) 448 { 449 _stream_data->RemoveListeningPID(*it); 450 _stream_data->RemoveWritingPID(*it); 451 _channel->DelPID(*it, false); 452 } 453 } 465 assert(_stream_handler); 466 assert(_stream_data); 454 467 455 for (it = add_pid.begin(); it != add_pid.end(); ++it) 456 _channel->AddPID(*it, false); 457 458 _channel->UpdateFilters(); 468 _stream_handler->AddListener(_stream_data); 469 } 459 470 460 return add_pid.size();471 return paused; 461 472 } 462 473 463 /** \fn HDHRRecorder::AdjustEITPIDs(void) 464 * \brief Adjusts EIT PID monitoring to monitor the right number of EIT PIDs. 465 */ 466 bool HDHRRecorder::AdjustEITPIDs(void) 474 void HDHRRecorder::BufferedWrite(const TSPacket &tspacket) 467 475 { 468 bool changes = false; 469 uint_vec_t add, del; 470 471 QMutexLocker change_lock(&_pid_lock); 472 473 if (GetStreamData()->HasEITPIDChanges(_eit_pids)) 474 changes = GetStreamData()->GetEITPIDChanges(_eit_pids, add, del); 476 // Care must be taken to make sure that the packet actually gets written 477 // as the decision to actually write it has already been made 475 478 476 if (!changes) 477 return false; 478 479 for (uint i = 0; i < del.size(); i++) 479 // Do we have to buffer the packet for exact keyframe detection? 480 if (_buffer_packets) 480 481 { 481 uint_vec_t::iterator it;482 it = find(_eit_pids.begin(), _eit_pids.end(), del[i]);483 if (it != _eit_pids.end())484 _eit_pids.erase(it);482 int idx = _payload_buffer.size(); 483 _payload_buffer.resize(idx + TSPacket::SIZE); 484 memcpy(&_payload_buffer[idx], tspacket.data(), TSPacket::SIZE); 485 return; 485 486 } 486 487 487 for (uint i = 0; i < add.size(); i++) 488 _eit_pids.push_back(add[i]); 489 490 return true; 488 // We are free to write the packet, but if we have buffered packet[s] 489 // we have to write them first... 490 if (!_payload_buffer.empty()) 491 { 492 if (ringBuffer) 493 ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size()); 494 _payload_buffer.clear(); 495 } 496 if (ringBuffer) 497 ringBuffer->Write(tspacket.data(), TSPacket::SIZE); 491 498 } 492 499 -
mythtv/libs/libmythtv/hdhrrecorder.h
diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/hdhrrecorder.h release.19757.0120a/mythtv/libs/libmythtv/hdhrrecorder.h
14 14 15 15 class HDHRChannel; 16 16 class ProgramMapTable; 17 class MPEGStreamData; 18 class HDHRStreamHandler; 19 17 20 18 21 typedef vector<uint> uint_vec_t; 19 22 20 23 class HDHRRecorder : public DTVRecorder, 21 24 public MPEGStreamListener, 22 public MPEGSingleProgramStreamListener 25 public MPEGSingleProgramStreamListener, 26 public TSPacketListener, 27 public TSPacketListenerAV 23 28 { 24 29 friend class ATSCStreamData; 25 30 … … 33 38 const QString &vbidev); 34 39 35 40 bool Open(void); 36 bool StartData(void);41 bool IsOpen(void); 37 42 void Close(void); 38 43 39 44 void StartRecording(void); 45 void ResetForNewFile(void); 46 void StopRecording(void); 40 47 41 48 void SetStreamData(MPEGStreamData*); 42 49 MPEGStreamData *GetStreamData(void) { return _stream_data; } … … 59 66 void HandleVCT(uint, const VirtualChannelTable*) {} 60 67 */ 61 68 62 private: 63 bool AdjustFilters(void); 64 bool AdjustEITPIDs(void); 69 // TSPacketListenerAV 70 bool ProcessVideoTSPacket(const TSPacket& tspacket); 71 bool ProcessAudioTSPacket(const TSPacket& tspacket); 72 73 // Common audio/visual processing 74 bool ProcessAVTSPacket(const TSPacket &tspacket); 65 75 66 void ProcessTSData(const unsigned char *buffer, int len);67 76 bool ProcessTSPacket(const TSPacket& tspacket); 77 78 void BufferedWrite(const TSPacket &tspacket); 79 private: 68 80 void TeardownAll(void); 81 82 void ReaderPaused(int fd); 83 bool PauseAndWait(int timeout = 100); 69 84 70 85 private: 71 86 HDHRChannel *_channel; 72 struct hdhomerun_video_sock_t *_video_socket;87 HDHRStreamHandler *_stream_handler; 73 88 MPEGStreamData *_stream_data; 74 89 90 mutable QMutex _pid_lock; 75 91 ProgramAssociationTable *_input_pat; 76 92 ProgramMapTable *_input_pmt; 77 bool _reset_pid_filters; 78 uint_vec_t _eit_pids; 79 mutable QMutex _pid_lock; 93 bool _has_no_av; 94 95 unsigned char _stream_id[0x1fff]; 96 unsigned char _pid_status[0x1fff]; 97 unsigned char _continuity_counter[0x1fff]; 98 99 // Constants 100 static const int TSPACKETS_BETWEEN_PSIP_SYNC; 101 static const int POLL_INTERVAL; 102 static const int POLL_WARNING_TIMEOUT; 103 104 static const unsigned char kPayloadStartSeen = 0x2; 80 105 }; 81 106 82 107 #endif -
mythtv/libs/libmythtv/hdhrsignalmonitor.cpp
diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/hdhrsignalmonitor.cpp release.19757.0120a/mythtv/libs/libmythtv/hdhrsignalmonitor.cpp
18 18 19 19 #include "hdhrchannel.h" 20 20 #include "hdhrrecorder.h" 21 #include "hdhrstreamhandler.h" 21 22 22 23 #define LOC QString("HDHRSM(%1): ").arg(channel->GetDevice()) 23 24 #define LOC_ERR QString("HDHRSM(%1), Error: ").arg(channel->GetDevice()) … … 41 42 HDHRChannel* _channel, 42 43 uint64_t _flags, const char *_name) 43 44 : DTVSignalMonitor(db_cardnum, _channel, _flags, _name), 44 dtvMonitorRunning(false) 45 streamHandlerStarted(false), 46 streamHandler(NULL) 47 45 48 { 46 49 VERBOSE(VB_CHANNEL, LOC + "ctor"); 47 50 48 _channel->DelAllPIDs();49 50 51 signalStrength.SetThreshold(45); 51 52 52 53 AddFlags(kDTVSigMon_WaitForSig); 54 55 streamHandler = HDHRStreamHandler::Get(_channel->GetDevice()); 53 56 } 54 57 55 58 /** \fn HDHRSignalMonitor::~HDHRSignalMonitor() … … 59 62 { 60 63 VERBOSE(VB_CHANNEL, LOC + "dtor"); 61 64 Stop(); 65 HDHRStreamHandler::Return(streamHandler); 62 66 } 63 67 64 68 void HDHRSignalMonitor::deleteLater(void) … … 75 79 { 76 80 VERBOSE(VB_CHANNEL, LOC + "Stop() -- begin"); 77 81 SignalMonitor::Stop(); 78 if (dtvMonitorRunning) 79 { 80 dtvMonitorRunning = false; 81 pthread_join(table_monitor_thread, NULL); 82 } 83 VERBOSE(VB_CHANNEL, LOC + "Stop() -- end"); 84 } 82 if (GetStreamData()) 83 streamHandler->RemoveListener(GetStreamData()); 84 streamHandlerStarted = false; 85 streamHandler->SetRetuneAllowed(false, NULL, NULL); 85 86 86 void *HDHRSignalMonitor::TableMonitorThread(void *param) 87 { 88 HDHRSignalMonitor *mon = (HDHRSignalMonitor*) param; 89 mon->RunTableMonitor(); 90 return NULL; 91 } 92 93 bool HDHRSignalMonitor::UpdateFiltersFromStreamData(void) 94 { 95 vector<int> add_pids; 96 vector<int> del_pids; 97 98 if (!GetStreamData()) 99 return false; 100 101 UpdateListeningForEIT(); 102 103 const pid_map_t &listening = GetStreamData()->ListeningPIDs(); 104 105 // PIDs that need to be added.. 106 pid_map_t::const_iterator lit = listening.constBegin(); 107 for (; lit != listening.constEnd(); ++lit) 108 if (lit.data() && (filters.find(lit.key()) == filters.end())) 109 add_pids.push_back(lit.key()); 110 111 // PIDs that need to be removed.. 112 FilterMap::const_iterator fit = filters.constBegin(); 113 for (; fit != filters.constEnd(); ++fit) 114 if (listening.find(fit.key()) == listening.end()) 115 del_pids.push_back(fit.key()); 116 117 HDHRChannel *hdhr = dynamic_cast<HDHRChannel*>(channel); 118 // Remove PIDs 119 bool ok = true; 120 vector<int>::iterator dit = del_pids.begin(); 121 for (; dit != del_pids.end(); ++dit) 122 { 123 ok &= hdhr->DelPID(*dit); 124 filters.erase(filters.find(*dit)); 125 } 126 127 // Add PIDs 128 vector<int>::iterator ait = add_pids.begin(); 129 for (; ait != add_pids.end(); ++ait) 130 { 131 ok &= hdhr->AddPID(*ait); 132 filters[*ait] = 1; 133 } 134 135 return ok; 87 VERBOSE(VB_CHANNEL, LOC + "Stop() -- end"); 136 88 } 137 89 138 void HDHRSignalMonitor::RunTableMonitor(void)90 HDHRChannel *HDHRSignalMonitor::GetHDHRChannel(void) 139 91 { 140 dtvMonitorRunning = true; 141 142 struct hdhomerun_video_sock_t *_video_socket; 143 _video_socket = hdhomerun_video_create(0, VIDEO_DATA_BUFFER_SIZE_1S); 144 if (!_video_socket) 145 { 146 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to get video socket"); 147 return; 148 } 149 150 HDHRChannel *hdrc = dynamic_cast<HDHRChannel*>(channel); 151 uint localPort = hdhomerun_video_get_local_port(_video_socket); 152 if (!hdrc->DeviceSetTarget(localPort)) 153 { 154 hdhomerun_video_destroy(_video_socket); 155 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to set target"); 156 return; 157 } 158 159 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): " + 160 QString("begin (# of pids %1)") 161 .arg(GetStreamData()->ListeningPIDs().size())); 162 163 while (dtvMonitorRunning && GetStreamData()) 164 { 165 UpdateFiltersFromStreamData(); 166 167 size_t data_length; 168 unsigned char *data_buffer = 169 hdhomerun_video_recv(_video_socket, 170 VIDEO_DATA_BUFFER_SIZE_1S / 5, 171 &data_length); 172 173 if (data_buffer) 174 { 175 GetStreamData()->ProcessData(data_buffer, data_length); 176 continue; 177 } 178 179 usleep(2500); 180 } 181 182 hdrc->DeviceClearTarget(); 183 hdhomerun_video_destroy(_video_socket); 184 185 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- shutdown"); 186 187 // TODO teardown PID filters here 188 189 VERBOSE(VB_CHANNEL, LOC + "RunTableMonitor(): -- end"); 92 return dynamic_cast<HDHRChannel*>(channel); 190 93 } 191 94 192 95 /** \fn HDHRSignalMonitor::UpdateValues() … … 204 107 if (!running || exit) 205 108 return; 206 109 207 if ( dtvMonitorRunning)110 if (streamHandlerStarted) 208 111 { 209 112 EmitHDHRSignals(); 210 113 if (IsAllGood()) … … 215 118 return; 216 119 } 217 120 218 QString msg = ((HDHRChannel*)channel)->TunerGet("status");121 QString msg = streamHandler->GetTunerStatus(); 219 122 //ss = signal strength, [0,100] 220 123 //snq = signal to noise quality [0,100] 221 124 //seq = signal error quality [0,100] … … 253 156 kDTVSigMon_WaitForMGT | kDTVSigMon_WaitForVCT | 254 157 kDTVSigMon_WaitForNIT | kDTVSigMon_WaitForSDT)) 255 158 { 256 pthread_create(&table_monitor_thread, NULL, 257 TableMonitorThread, this); 258 259 VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- " 260 "Waiting for table monitor to start"); 261 262 while (!dtvMonitorRunning) 263 usleep(50); 264 265 VERBOSE(VB_CHANNEL, LOC + "UpdateValues() -- " 266 "Table monitor started"); 159 streamHandler->AddListener(GetStreamData()); 160 streamHandlerStarted = true; 267 161 } 268 162 269 163 update_done = true; -
mythtv/libs/libmythtv/hdhrsignalmonitor.h
diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/hdhrsignalmonitor.h release.19757.0120a/mythtv/libs/libmythtv/hdhrsignalmonitor.h
7 7 #include "qstringlist.h" 8 8 9 9 class HDHRChannel; 10 class HDHRStreamHandler; 10 11 11 12 typedef QMap<uint,int> FilterMap; 12 13 … … 21 22 22 23 void Stop(void); 23 24 24 bool UpdateFiltersFromStreamData(void);25 26 25 public slots: 27 26 void deleteLater(void); 28 27 … … 33 32 virtual void UpdateValues(void); 34 33 void EmitHDHRSignals(void); 35 34 36 static void *TableMonitorThread(void *param);37 void RunTableMonitor(void);38 39 35 bool SupportsTSMonitoring(void); 40 36 37 HDHRChannel *GetHDHRChannel(void); 38 41 39 protected: 42 bool dtvMonitorRunning;43 pthread_t table_monitor_thread;44 40 45 FilterMap filters; ///< PID filters for table monitoring 41 bool streamHandlerStarted; 42 HDHRStreamHandler *streamHandler; 43 46 44 }; 47 45 48 46 #endif // HDHRSIGNALMONITOR_H -
mythtv/libs/libmythtv/hdhrstreamhandler.cpp
diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/hdhrstreamhandler.cpp release.19757.0120a/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); 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); 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); 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 int loopcount=0; 460 size_t data_count=0; 461 while (IsRunning() && !_error) 462 { 463 loopcount++; 464 if (0 == (loopcount % 1000)) { 465 QMutexLocker locker(&_listener_lock); 466 VERBOSE(VB_RECORD, LOC + QString("RunTS(): loopcount = %1, datacount = %2, listen") 467 .arg(loopcount).arg(data_count)); 468 data_count=0; 469 } 470 UpdateFiltersFromStreamData(); 471 472 size_t read_size = 64 * 1024; // read about 64KB 473 read_size /= VIDEO_DATA_PACKET_SIZE; 474 read_size *= VIDEO_DATA_PACKET_SIZE; 475 476 size_t data_length; 477 unsigned char *data_buffer = 478 hdhomerun_video_recv(_video_socket, read_size, &data_length); 479 480 if (! data_buffer) 481 { 482 usleep(5000); 483 continue; 484 } 485 486 data_count+=data_length; 487 // Assume data_length is a multiple of 188 (packet size) 488 ASSERT(0 == ( data_length % 188) ); 489 490 _listener_lock.lock(); 491 492 if (_stream_data_list.empty()) 493 { 494 _listener_lock.unlock(); 495 continue; 496 } 497 498 for (uint i = 0; i < _stream_data_list.size(); i++) 499 { 500 remainder = _stream_data_list[i]->ProcessData(data_buffer, data_length); 501 } 502 503 _listener_lock.unlock(); 504 if (remainder != 0) 505 VERBOSE(VB_GENERAL, QString(LOC + "RunTS(): data_length = %1 remainder = %2") 506 .arg(data_length).arg(remainder)); 507 } 508 VERBOSE(VB_RECORD, LOC + "RunTS(): " + "shutdown"); 509 510 DelAllPIDs(); 511 512 DeviceClearTarget(); 513 VERBOSE(VB_RECORD, LOC + "RunTS(): " + "end"); 514 515 hdhomerun_video_sock_t* tmp_video_socket; 516 { 517 QMutexLocker locker(&_hdhr_lock); 518 tmp_video_socket = _video_socket; 519 _video_socket=NULL; 520 } 521 522 hdhomerun_video_destroy(tmp_video_socket); 523 524 SetRunning(false); 525 } 526 527 bool HDHRStreamHandler::AddPID(uint pid, bool do_update) 528 { 529 QMutexLocker locker(&_pid_lock); 530 531 vector<uint>::iterator it; 532 it = lower_bound(_pid_info.begin(), _pid_info.end(), pid); 533 if (it != _pid_info.end() && *it == pid) 534 { 535 #ifdef DEBUG_PID_FILTERS 536 VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<", " << do_update << ") NOOP"); 537 #endif // DEBUG_PID_FILTERS 538 return true; 539 } 540 541 _pid_info.insert(it, pid); 542 543 #ifdef DEBUG_PID_FILTERS 544 VERBOSE(VB_CHANNEL, "AddPID(0x"<<hex<<pid<<dec<<")", " << do_update << "); 545 #endif // DEBUG_PID_FILTERS 546 547 if (do_update) 548 return UpdateFilters(); 549 return true; 550 } 551 552 bool HDHRStreamHandler::DelPID(uint pid, bool do_update) 553 { 554 QMutexLocker locker(&_pid_lock); 555 556 vector<uint>::iterator it; 557 it = lower_bound(_pid_info.begin(), _pid_info.end(), pid); 558 if (it == _pid_info.end()) 559 { 560 #ifdef DEBUG_PID_FILTERS 561 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<", " << do_update << ") NOOP"); 562 #endif // DEBUG_PID_FILTERS 563 564 return true; 565 } 566 567 if (*it == pid) 568 { 569 #ifdef DEBUG_PID_FILTERS 570 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<", " << do_update << ") -- found"); 571 #endif // DEBUG_PID_FILTERS 572 _pid_info.erase(it); 573 } 574 else 575 { 576 #ifdef DEBUG_PID_FILTERS 577 VERBOSE(VB_CHANNEL, "DelPID(0x"<<hex<<pid<<dec<<", " << do_update << ") -- failed"); 578 #endif // DEBUG_PID_FILTERS 579 } 580 581 if (do_update) 582 return UpdateFilters(); 583 return true; 584 } 585 586 bool HDHRStreamHandler::DelAllPIDs(void) 587 { 588 QMutexLocker locker(&_pid_lock); 589 590 #ifdef DEBUG_PID_FILTERS 591 VERBOSE(VB_CHANNEL, "DelAllPID()"); 592 #endif // DEBUG_PID_FILTERS 593 594 _pid_info.clear(); 595 596 return UpdateFilters(); 597 } 598 599 QString filt_str(uint pid) 600 { 601 uint pid0 = (pid / (16*16*16)) % 16; 602 uint pid1 = (pid / (16*16)) % 16; 603 uint pid2 = (pid / (16)) % 16; 604 uint pid3 = pid % 16; 605 return QString("0x%1%2%3%4") 606 .arg(pid0,0,16).arg(pid1,0,16) 607 .arg(pid2,0,16).arg(pid3,0,16); 608 } 609 610 bool HDHRStreamHandler::UpdateFilters(void) 611 { 612 #ifdef DEBUG_PID_FILTERS 613 VERBOSE(VB_CHANNEL, LOC + "UpdateFilters()"); 614 #endif // DEBUG_PID_FILTERS 615 QMutexLocker locker(&_pid_lock); 616 617 QString filter = ""; 618 619 vector<uint> range_min; 620 vector<uint> range_max; 621 622 // FIXME 623 // if (_ignore_filters) 624 // return true; 625 626 for (uint i = 0; i < _pid_info.size(); i++) 627 { 628 uint pid_min = _pid_info[i]; 629 uint pid_max = pid_min; 630 for (uint j = i + 1; j < _pid_info.size(); j++) 631 { 632 if (pid_max + 1 != _pid_info[j]) 633 break; 634 pid_max++; 635 i++; 636 } 637 range_min.push_back(pid_min); 638 range_max.push_back(pid_max); 639 } 640 if (range_min.size() > 16) 641 { 642 range_min.resize(16); 643 uint pid_max = range_max.back(); 644 range_max.resize(15); 645 range_max.push_back(pid_max); 646 } 647 648 for (uint i = 0; i < range_min.size(); i++) 649 { 650 filter += filt_str(range_min[i]); 651 if (range_min[i] != range_max[i]) 652 filter += QString("-%1").arg(filt_str(range_max[i])); 653 filter += " "; 654 } 655 656 filter = filter.stripWhiteSpace(); 657 658 QString new_filter = TunerSet("filter", filter); 659 660 #ifdef DEBUG_PID_FILTERS 661 QString msg = QString("Filter: '%1'").arg(filter); 662 if (filter != new_filter) 663 msg += QString("\n\t\t\t\t'%2'").arg(new_filter); 664 665 VERBOSE(VB_CHANNEL, LOC + msg); 666 #endif // DEBUG_PID_FILTERS 667 668 return filter == new_filter; 669 } 670 671 void HDHRStreamHandler::UpdateListeningForEIT(void) 672 { 673 vector<uint> add_eit, del_eit; 674 675 QMutexLocker read_locker(&_listener_lock); 676 677 for (uint i = 0; i < _stream_data_list.size(); i++) 678 { 679 MPEGStreamData *sd = _stream_data_list[i]; 680 if (sd->HasEITPIDChanges(_eit_pids) && 681 sd->GetEITPIDChanges(_eit_pids, add_eit, del_eit)) 682 { 683 for (uint i = 0; i < del_eit.size(); i++) 684 { 685 uint_vec_t::iterator it; 686 it = find(_eit_pids.begin(), _eit_pids.end(), del_eit[i]); 687 if (it != _eit_pids.end()) 688 _eit_pids.erase(it); 689 sd->RemoveListeningPID(del_eit[i]); 690 } 691 692 for (uint i = 0; i < add_eit.size(); i++) 693 { 694 _eit_pids.push_back(add_eit[i]); 695 sd->AddListeningPID(add_eit[i]); 696 } 697 } 698 } 699 } 700 701 bool HDHRStreamHandler::UpdateFiltersFromStreamData(void) 702 { 703 704 UpdateListeningForEIT(); 705 706 pid_map_t pids; 707 708 { 709 QMutexLocker read_locker(&_listener_lock); 710 711 for (uint i = 0; i < _stream_data_list.size(); i++) 712 _stream_data_list[i]->GetPIDs(pids); 713 } 714 715 uint_vec_t add_pids; 716 vector<uint> del_pids; 717 718 { 719 QMutexLocker read_locker(&_pid_lock); 720 721 // PIDs that need to be added.. 722 pid_map_t::const_iterator lit = pids.constBegin(); 723 for (; lit != pids.constEnd(); ++lit) 724 { 725 vector<uint>::iterator it; 726 it = lower_bound(_pid_info.begin(), _pid_info.end(), lit.key()); 727 if (! (it != _pid_info.end() && *it == lit.key())) { 728 add_pids.push_back(lit.key()); 729 } 730 } 731 732 // PIDs that need to be removed.. 733 vector<uint>::iterator fit = _pid_info.begin(); 734 for (; fit != _pid_info.end(); ++fit) 735 { 736 pid_map_t::const_iterator it = pids.find(*fit); 737 if(it == pids.end()) 738 del_pids.push_back(*fit); 739 } 740 } 741 742 bool need_update = false; 743 744 // Remove PIDs 745 bool ok = true; 746 vector<uint>::iterator dit = del_pids.begin(); 747 for (; dit != del_pids.end(); ++dit) 748 { 749 need_update = true; 750 ok &= DelPID(*dit, false); 751 } 752 753 // Add PIDs 754 vector<uint>::iterator ait = add_pids.begin(); 755 for (; ait != add_pids.end(); ++ait) 756 { 757 need_update = true; 758 ok &= AddPID(*ait, false); 759 } 760 761 if (need_update) 762 return UpdateFilters(); 763 764 return ok; 765 } 766 767 void HDHRStreamHandler::SetRetuneAllowed( 768 bool allow, 769 DTVSignalMonitor *sigmon, 770 HDHRChannel *hdhrchan) 771 { 772 if (allow && sigmon && hdhrchan) 773 { 774 _allow_retune = true; 775 _sigmon = sigmon; 776 _channel = hdhrchan; 777 } 778 else 779 { 780 _allow_retune = false; 781 _sigmon = NULL; 782 _channel = NULL; 783 } 784 } 785 786 /** \fn HDHRStreamHandler::SupportsTSMonitoring(void) 787 * \brief Returns true if TS monitoring is supported. 788 * 789 * NOTE: If you are using a DEC2000-t device you need to 790 * apply the patches provided by Peter Beutner for it, see 791 * http://www.gossamer-threads.com/lists/mythtv/dev/166172 792 * These patches should make it in to Linux 2.6.15 or 2.6.16. 793 */ 794 bool HDHRStreamHandler::SupportsTSMonitoring(void) 795 { 796 return false; 797 798 // FIXME 799 #if 0 800 const uint pat_pid = 0x0; 801 802 { 803 QMutexLocker locker(&_rec_supports_ts_monitoring_lock); 804 QMap<uint,bool>::const_iterator it; 805 it = _rec_supports_ts_monitoring.find(_dvb_dev_num); 806 if (it != _rec_supports_ts_monitoring.end()) 807 return *it; 808 } 809 810 int dvr_fd = open(_dvr_dev_path.ascii(), O_RDONLY | O_NONBLOCK); 811 if (dvr_fd < 0) 812 { 813 QMutexLocker locker(&_rec_supports_ts_monitoring_lock); 814 _rec_supports_ts_monitoring[_dvb_dev_num] = false; 815 return false; 816 } 817 818 bool supports_ts = false; 819 if (AddPIDFilter(new PIDInfoHDHR(pat_pid))) 820 { 821 supports_ts = true; 822 RemovePIDFilter(pat_pid); 823 } 824 825 close(dvr_fd); 826 827 QMutexLocker locker(&_rec_supports_ts_monitoring_lock); 828 _rec_supports_ts_monitoring[_dvb_dev_num] = supports_ts; 829 830 return supports_ts; 831 #endif 832 } 833 834 void HDHRStreamHandler::SetRunning(bool is_running) 835 { 836 _running = is_running; 837 _running_state_changed.wakeAll(); 838 } 839 840 PIDPriority HDHRStreamHandler::GetPIDPriority(uint pid) const 841 { 842 QMutexLocker reading_locker(&_listener_lock); 843 844 PIDPriority tmp = kPIDPriorityNone; 845 846 for (uint i = 0; i < _stream_data_list.size(); i++) 847 tmp = max(tmp, _stream_data_list[i]->GetPIDPriority(pid)); 848 849 return tmp; 850 } -
mythtv/libs/libmythtv/hdhrstreamhandler.h
diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/hdhrstreamhandler.h release.19757.0120a/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 -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/libmythtv.pro release.19757.0120a/mythtv/libs/libmythtv/libmythtv.pro
451 451 using_hdhomerun { 452 452 # MythTV HDHomeRun glue 453 453 HEADERS += hdhrsignalmonitor.h hdhrchannel.h 454 HEADERS += hdhrrecorder.h 454 HEADERS += hdhrrecorder.h hdhrstreamhandler.h 455 455 456 456 SOURCES += hdhrsignalmonitor.cpp hdhrchannel.cpp 457 SOURCES += hdhrrecorder.cpp 457 SOURCES += hdhrrecorder.cpp hdhrstreamhandler.cpp 458 458 459 459 DEFINES += USING_HDHOMERUN 460 460 -
mythtv/libs/libmythtv/scanwizardscanner.cpp
diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/scanwizardscanner.cpp release.19757.0120a/mythtv/libs/libmythtv/scanwizardscanner.cpp
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 -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/tv_rec.cpp release.19757.0120a/mythtv/libs/libmythtv/tv_rec.cpp
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); … … 4080 4080 } 4081 4081 recorder->Reset(); 4082 4082 4083 #ifdef USING_HDHOMERUN4084 if (GetHDHRRecorder())4085 {4086 pauseNotify = false;4087 GetHDHRRecorder()->Close();4088 pauseNotify = true;4089 GetHDHRRecorder()->Open();4090 GetHDHRRecorder()->StartData();4091 }4092 #endif // USING_HDHOMERUN4093 4094 4083 // Set file descriptor of channel from recorder for V4L 4095 4084 channel->SetFd(recorder->GetVideoFd()); 4096 4085 -
mythtv/libs/libmythtv/videosource.cpp
diff -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/videosource.cpp release.19757.0120a/mythtv/libs/libmythtv/videosource.cpp
47 47 #include "videodev_myth.h" 48 48 #endif 49 49 50 #include "hdhomerun_includes.h" 51 50 52 VideoSourceSelector::VideoSourceSelector(uint _initial_sourceid, 51 53 const QString &_card_types, 52 54 bool _must_have_mplexid) : … … 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: … … 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 … … 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); 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), … … 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 … … 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 … … 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() … … 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); … … 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 -r -u -N -X diff.exclude -x release.19764.0120a -x release.19757.0120a release.19764.0120a/mythtv/libs/libmythtv/videosource.h release.19757.0120a/mythtv/libs/libmythtv/videosource.h
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 { … … 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