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