Ticket #12168: iptv_extension_master_01.patch
File iptv_extension_master_01.patch, 30.2 KB (added by , 10 years ago) |
---|
-
mythtv/libs/libmythbase/mythsingledownload.cpp
From 39397069cfd31dd5fb1c87848d728e204007277a Mon Sep 17 00:00:00 2001 From: Lincoln Rogers <lincoln@performaplus.co.nz> Date: Fri, 16 May 2014 09:01:57 +1200 Subject: [PATCH] 1. Subclass IPTVStreamHandler to HTTPStreamHandler to add IPTV stream support for Http TS streams. 2. Extend iptvtuningdata to include a protocol type for udp, rtp, rtsp, http_hls, http_ts. 3. Add to ChannelUtil::GetIPTVTuningData to set the type based on URL and by testing if the URL is a HLS playlist 4. Extend MythSingleDownload to support a maximum file size limit. Without this, if the URL from (3) is actually a video stream then the download would not terminate until the 30 second timeout. 5. Extend tv_rec to include a new system event for Tuning Timeout. Allows user to run a script to reboot a STB. Conflicts (Resolved): mythtv/libs/libmythbase/mythsingledownload.h mythtv/libs/libmythtv/channelscan/iptvchannelfetcher.h mythtv/libs/libmythtv/recorders/HLS/HLSReader.h mythtv/libs/libmythtv/tv_rec.cpp diff --git a/mythtv/libs/libmythbase/mythsingledownload.cpp b/mythtv/libs/libmythbase/mythsingledownload.cpp index 95db42d..600d9eb 100644
a b 8 8 * ) works well. 9 9 */ 10 10 11 #define LOC QString("MythSingleDownload: ") 12 11 13 bool MythSingleDownload::DownloadURL(const QString &url, QByteArray *buffer, 12 uint timeout )14 uint timeout, qint64 maxsize) 13 15 { 14 16 QMutexLocker lock(&m_lock); 15 16 // create custom temporary event loop on stack17 17 QEventLoop event_loop; 18 m_buffer = buffer; 18 19 19 20 // the HTTP request 20 21 QNetworkRequest req(url); … … bool MythSingleDownload::DownloadURL(const QString &url, QByteArray *buffer, 26 27 QNetworkRequest::AlwaysNetwork); 27 28 28 29 // "quit()" the event-loop, when the network request "finished()" 29 connect(m_reply, SIGNAL(finished()), &event_loop, SLOT(quit()));30 30 connect(&m_timer, SIGNAL(timeout()), &event_loop, SLOT(quit())); 31 connect(m_reply, SIGNAL(finished()), &event_loop, SLOT(quit())); 32 connect(m_reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(Progress(qint64,qint64))); 31 33 32 // Configure timeout 34 // Configure timeout and size limit 35 m_maxsize = maxsize; 33 36 m_timer.setSingleShot(true); 34 37 m_timer.start(timeout); // 30 secs. by default 35 38 … … bool MythSingleDownload::DownloadURL(const QString &url, QByteArray *buffer, 37 40 38 41 disconnect(&m_timer, SIGNAL(timeout()), &event_loop, SLOT(quit())); 39 42 disconnect(m_reply, SIGNAL(finished()), &event_loop, SLOT(quit())); 43 disconnect(m_reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(Progress(qint64,qint64))); 40 44 41 45 if (ret != 0) 42 46 { 43 LOG(VB_GENERAL, LOG_ERR, QString("MythSingleDownload evenloop failed"));47 LOG(VB_GENERAL, LOG_ERR, LOC + "eventloop failed"); 44 48 } 45 49 46 50 QMutexLocker replylock(&m_replylock); 47 if (m_timer.isActive()) 51 if (!m_timer.isActive()) 52 { 53 m_errorstring = "timed-out"; 54 m_reply->abort(); 55 ret = false; 56 } 57 else 48 58 { 49 59 m_timer.stop(); 50 60 m_errorcode = m_reply->error(); 51 61 if (m_errorcode == QNetworkReply::NoError) 52 62 { 53 *buffer += m_reply->readAll(); 54 delete m_reply; 55 m_reply = NULL; 63 *m_buffer += m_reply->readAll(); 56 64 m_errorstring.clear(); 57 ret urntrue;65 ret = true; 58 66 } 59 67 else 60 68 { 61 69 m_errorstring = m_reply->errorString(); 62 delete m_reply; 63 m_reply = NULL; 64 return false; 70 ret = false; 65 71 } 66 72 } 67 else 68 { 69 m_errorstring = "timed-out"; 70 m_timer.stop(); 71 m_reply->abort(); 72 delete m_reply; 73 m_reply = NULL; 74 return false; 75 } 73 delete m_reply; 74 m_reply = NULL; 75 m_buffer = NULL; 76 return ret; 76 77 } 77 78 78 79 void MythSingleDownload::Cancel(void) … … void MythSingleDownload::Cancel(void) 80 81 QMutexLocker replylock(&m_replylock); 81 82 if (m_reply) 82 83 { 83 LOG(VB_GENERAL, LOG_INFO, "MythSingleDownload:Aborting download");84 LOG(VB_GENERAL, LOG_INFO, LOC + "Aborting download"); 84 85 m_reply->abort(); 85 86 } 86 87 } 88 89 void MythSingleDownload::Progress(qint64 bytesRead, qint64 totalBytes) 90 { 91 if(m_maxsize && bytesRead>=m_maxsize) 92 { 93 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Reached specified max file size (%1 bytes)").arg(m_maxsize)); 94 { 95 QMutexLocker replylock(&m_replylock); 96 *m_buffer += m_reply->read(m_maxsize); 97 } 98 m_maxsize=0; 99 Cancel(); 100 } 101 } -
mythtv/libs/libmythbase/mythsingledownload.h
diff --git a/mythtv/libs/libmythbase/mythsingledownload.h b/mythtv/libs/libmythbase/mythsingledownload.h index af7144d..cf3e1ef 100644
a b class MBASE_PUBLIC MythSingleDownload : public QObject 28 28 MythSingleDownload(void) : m_reply(NULL), m_errorcode(QNetworkReply::NoError) { ; } 29 29 ~MythSingleDownload(void) { ; } 30 30 31 bool DownloadURL(const QString &url, QByteArray *buffer, uint timeout = 30000 );31 bool DownloadURL(const QString &url, QByteArray *buffer, uint timeout = 30000, qint64 maxsize = 0); 32 32 void Cancel(void); 33 33 QString ErrorString(void) const { return m_errorstring; } 34 34 QNetworkReply::NetworkError ErrorCode(void) const { return m_errorcode; } 35 35 36 private slots: 37 void Progress(qint64 bytesRead, qint64 totalBytes); 38 36 39 private: 37 40 38 41 QNetworkAccessManager m_mgr; … … class MBASE_PUBLIC MythSingleDownload : public QObject 43 46 44 47 QString m_errorstring; 45 48 QNetworkReply::NetworkError m_errorcode; 49 QByteArray *m_buffer; 50 qint64 m_maxsize; 46 51 }; 47 52 48 53 #endif -
mythtv/libs/libmythtv/channelscan/iptvchannelfetcher.h
diff --git a/mythtv/libs/libmythtv/channelscan/iptvchannelfetcher.h b/mythtv/libs/libmythtv/channelscan/iptvchannelfetcher.h index fd855dc..4060216 100644
a b class IPTVChannelInfo 39 39 uint programnumber) : 40 40 m_name(name), m_xmltvid(xmltvid), m_programnumber(programnumber), 41 41 m_tuning(data_url, data_bitrate, 42 fec_type, fec_url0, fec_bitrate0, fec_url1, fec_bitrate1) 42 fec_type, fec_url0, fec_bitrate0, fec_url1, fec_bitrate1, 43 IPTVTuningData::inValid) 43 44 { 44 45 } 45 46 46 bool IsValid(void) const47 {48 return !m_name.isEmpty() && m_tuning.IsValid();49 }50 51 47 public: 52 48 QString m_name; 53 49 QString m_xmltvid; -
mythtv/libs/libmythtv/channelutil.cpp
diff --git a/mythtv/libs/libmythtv/channelutil.cpp b/mythtv/libs/libmythtv/channelutil.cpp index acf2da9..26028ae 100644
a b IPTVTuningData ChannelUtil::GetIPTVTuningData(uint chanid) 1968 1968 1969 1969 QString data_url, fec_url0, fec_url1; 1970 1970 IPTVTuningData::FECType fec_type = IPTVTuningData::kNone; 1971 IPTVTuningData::IPTVProtocol protocol = IPTVTuningData::inValid; 1971 1972 uint bitrate[3] = { 0, 0, 0, }; 1972 1973 while (query.next()) 1973 1974 { … … IPTVTuningData ChannelUtil::GetIPTVTuningData(uint chanid) 2010 2011 case IPTVTuningData::kSMPTE2022_2: 2011 2012 break; // will be handled by type of first FEC stream 2012 2013 } 2014 2015 if (data_url.toLower().startsWith("udp")) 2016 protocol = IPTVTuningData::udp; 2017 2018 else if (data_url.toLower().startsWith("rtp")) 2019 protocol = IPTVTuningData::rtp; 2020 2021 else if (data_url.toLower().startsWith("rtsp")) 2022 protocol = IPTVTuningData::rtsp; 2023 2024 else if (data_url.toLower().startsWith("http") && ChannelUtil::IsHLSPlaylist(data_url)) 2025 protocol = IPTVTuningData::http_hls; 2026 2027 else if (data_url.toLower().startsWith("http")) 2028 protocol = IPTVTuningData::http_ts; 2013 2029 } 2014 2030 2015 2031 IPTVTuningData tuning(data_url, bitrate[0], fec_type, 2016 fec_url0, bitrate[1], fec_url1, bitrate[2]); 2032 fec_url0, bitrate[1], fec_url1, bitrate[2], 2033 protocol); 2017 2034 LOG(VB_GENERAL, LOG_INFO, QString("Loaded %1 for %2") 2018 2035 .arg(tuning.GetDeviceName()).arg(chanid)); 2019 2036 return tuning; 2020 2037 } 2021 2038 2039 2040 2041 2042 2043 2044 2045 #include "HLSReader.h" 2046 2047 bool ChannelUtil::IsHLSPlaylist(QString url) 2048 { 2049 QByteArray buffer; 2050 2051 MythSingleDownload downloader; 2052 downloader.DownloadURL(url, &buffer, 5000, 10000); 2053 if (!buffer.size()) 2054 { 2055 LOG(VB_GENERAL, LOG_ERR,QString("IsHLSPlaylist - Open Failed: %1") 2056 .arg(downloader.ErrorString())); 2057 return false; 2058 } 2059 2060 QTextStream text(&buffer); 2061 text.setCodec("UTF-8"); 2062 return (HLSReader::IsValidPlaylist(text)); 2063 } 2064 2065 2066 2067 2068 2069 2070 2022 2071 // TODO This should be modified to load a complete channelinfo object including 2023 2072 // all fields from the database 2024 2073 /** -
mythtv/libs/libmythtv/channelutil.h
diff --git a/mythtv/libs/libmythtv/channelutil.h b/mythtv/libs/libmythtv/channelutil.h index 93cb19b..a1ceb7d 100644
a b class MTV_PUBLIC ChannelUtil 185 185 static QString GetVideoFilters(uint sourceid, const QString &channum) 186 186 { return GetChannelValueStr("videofilters", sourceid, channum); } 187 187 static IPTVTuningData GetIPTVTuningData(uint chanid); 188 static bool IsHLSPlaylist(QString url); 188 189 189 190 // Are there any other possibly useful sort orders? 190 191 // e.g. Sorting by sourceid would probably be better done by two distinct -
mythtv/libs/libmythtv/iptvtuningdata.h
diff --git a/mythtv/libs/libmythtv/iptvtuningdata.h b/mythtv/libs/libmythtv/iptvtuningdata.h index 2e89ffd..92aab07 100644
a b 8 8 9 9 // MythTV headers 10 10 #include "mythtvexp.h" 11 #include "mythlogging.h" 11 12 12 13 class MTV_PUBLIC IPTVTuningData 13 14 { … … class MTV_PUBLIC IPTVTuningData 31 32 kSMPTE2022_2, 32 33 } IPTVType; 33 34 35 typedef enum IPTVProtocol 36 { 37 inValid = 0, 38 udp, 39 rtp, 40 rtsp, 41 http_ts, 42 http_hls 43 } IPTVProtocol; 44 34 45 IPTVTuningData() : m_fec_type(kNone) 35 46 { 36 47 memset(&m_bitrate, 0, sizeof(m_bitrate)); 37 48 } 38 49 39 50 IPTVTuningData(const QString &data_url, uint data_bitrate, 40 FECType fec_type,51 const FECType fec_type, 41 52 const QString &fec_url0, uint fec_bitrate0, 42 const QString &fec_url1, uint fec_bitrate1) : 53 const QString &fec_url1, uint fec_bitrate1, 54 const IPTVProtocol protocol) : 43 55 m_data_url(data_url), 44 m_fec_type(fec_type), m_fec_url0(fec_url0), m_fec_url1(fec_url1) 56 m_fec_type(fec_type), m_fec_url0(fec_url0), m_fec_url1(fec_url1), 57 m_protocol(protocol) 45 58 { 46 59 m_bitrate[0] = data_bitrate; 47 60 m_bitrate[1] = fec_bitrate0; … … class MTV_PUBLIC IPTVTuningData 51 64 IPTVTuningData(const QString &data_url, uint data_bitrate, 52 65 const QString &fec_type, 53 66 const QString &fec_url0, uint fec_bitrate0, 54 const QString &fec_url1, uint fec_bitrate1) : 67 const QString &fec_url1, uint fec_bitrate1, 68 const IPTVProtocol protocol) : 55 69 m_data_url(data_url), 56 m_fec_type(kNone), m_fec_url0(fec_url0), m_fec_url1(fec_url1) 70 m_fec_type(kNone), m_fec_url0(fec_url0), m_fec_url1(fec_url1), 71 m_protocol(protocol) 57 72 { 58 73 m_bitrate[0] = data_bitrate; 59 74 m_bitrate[1] = fec_bitrate0; … … class MTV_PUBLIC IPTVTuningData 134 149 135 150 uint GetURLCount(void) const { return 3; } 136 151 137 bool IsHLS(void) const138 {139 return m_data_url.scheme().startsWith("http") && m_data_url.isValid();140 }141 142 152 bool IsValid(void) const 143 153 { 144 return m_data_url.isValid() && 145 (IsHLS() || 146 ((m_data_url.scheme() == "rtp" || m_data_url.scheme() == "udp") && m_data_url.port() != -1) || 147 m_data_url.scheme() == "rtsp" 148 ); 154 bool ret = (m_data_url.isValid() && (IsUDP() || IsRTP() || IsRTSP() || IsHLS() || IsHTTPTS())); 155 156 LOG(VB_CHANNEL, LOG_DEBUG, QString("IPTVTuningdata (%1): IsValid = %2") 157 .arg(m_data_url.toString()) 158 .arg(ret ? "true" : "false")); 159 160 return ret; 161 } 162 163 bool IsUDP(void) const 164 { 165 return (m_protocol == udp); 166 } 167 168 bool IsRTP(void) const 169 { 170 return (m_protocol == rtp); 171 } 172 173 bool IsRTSP(void) const 174 { 175 return (m_protocol == rtsp); 176 } 177 178 bool IsHLS() const 179 { 180 return (m_protocol == http_hls); 181 } 182 183 bool IsHTTPTS() const 184 { 185 return (m_protocol == http_ts); 149 186 } 150 187 151 188 public: … … class MTV_PUBLIC IPTVTuningData 154 191 QUrl m_fec_url0; 155 192 QUrl m_fec_url1; 156 193 uint m_bitrate[3]; 194 IPTVProtocol m_protocol; 157 195 }; 158 196 159 197 #endif // _IPTV_TUNING_DATA_H_ -
mythtv/libs/libmythtv/libmythtv.pro
diff --git a/mythtv/libs/libmythtv/libmythtv.pro b/mythtv/libs/libmythtv/libmythtv.pro index e69cf8e..3d51281 100644
a b using_backend { 666 666 SOURCES += recorders/rtp/packetbuffer.cpp 667 667 SOURCES += recorders/rtp/rtppacketbuffer.cpp 668 668 669 # Support for HTTP TS streams 670 HEADERS += recorders/httptsstreamhandler.h 671 SOURCES += recorders/httptsstreamhandler.cpp 672 669 673 # Suppport for HLS recorder 670 674 HEADERS += recorders/hlsstreamhandler.h 671 675 SOURCES += recorders/hlsstreamhandler.cpp -
mythtv/libs/libmythtv/mythsystemevent.cpp
diff --git a/mythtv/libs/libmythtv/mythsystemevent.cpp b/mythtv/libs/libmythtv/mythsystemevent.cpp index 085cee5..30063a4 100644
a b MythSystemEventEditor::MythSystemEventEditor(MythScreenStack *parent, 403 403 tr("Playback unpaused"); 404 404 m_settings["EventCmdPlayChanged"] = // PLAY_CHANGED 405 405 tr("Playback program changed"); 406 m_settings["EventCmdTuningSignalTimeout"] = // TUNING_SIGNAL_TIMEOUT 407 tr("Tuning signal waiting"); 406 408 m_settings["EventCmdMasterStarted"] = // MASTER_STARTED 407 409 tr("Master backend started"); 408 410 m_settings["EventCmdMasterShutdown"] = // MASTER_SHUTDOWN -
mythtv/libs/libmythtv/recorders/HLS/HLSReader.cpp
diff --git a/mythtv/libs/libmythtv/recorders/HLS/HLSReader.cpp b/mythtv/libs/libmythtv/recorders/HLS/HLSReader.cpp index 60cfb15..822d608 100644
a b bool HLSReader::IsValidPlaylist(QTextStream & text) 274 274 line = text.readLine(); 275 275 if (line.isNull()) 276 276 break; 277 LOG(VB_RECORD, LOG_DEBUG, LOC +277 LOG(VB_RECORD, LOG_DEBUG, /* LOC + */ 278 278 QString("IsValidPlaylist: |'%1'").arg(line)); 279 279 if (line.startsWith(QLatin1String("#EXT-X-TARGETDURATION")) || 280 280 line.startsWith(QLatin1String("#EXT-X-MEDIA-SEQUENCE")) || -
mythtv/libs/libmythtv/recorders/HLS/HLSReader.h
diff --git a/mythtv/libs/libmythtv/recorders/HLS/HLSReader.h b/mythtv/libs/libmythtv/recorders/HLS/HLSReader.h index 620b84c..6a71cf4 100644
a b class HLSReader 65 65 static void CancelURL(const QString &url); 66 66 static void CancelURL(const QStringList &urls); 67 67 static QString RelativeURI(const QString& surl, const QString& spath); 68 69 static bool IsValidPlaylist(QTextStream & text); 68 70 69 71 protected: 70 72 void Cancel(bool quiet = false); … … class HLSReader 81 83 82 84 private: 83 85 static QString DecodedURI(const QString& uri); 84 85 bool IsValidPlaylist(QTextStream & text);86 87 86 static QString ParseAttributes(const QString& line, const char* attr); 88 87 static bool ParseDecimalValue(const QString& line, int& target); 89 88 static bool ParseDecimalValue(const QString& line, int64_t& target); -
mythtv/libs/libmythtv/recorders/cetonstreamhandler.cpp
diff --git a/mythtv/libs/libmythtv/recorders/cetonstreamhandler.cpp b/mythtv/libs/libmythtv/recorders/cetonstreamhandler.cpp index f45782a..8d298f4 100644
a b void CetonStreamHandler::Return(CetonStreamHandler * & ref) 107 107 108 108 CetonStreamHandler::CetonStreamHandler(const QString &device) : 109 109 IPTVStreamHandler(IPTVTuningData( 110 "", 0, IPTVTuningData::kNone, "", 0, "", 0 )),110 "", 0, IPTVTuningData::kNone, "", 0, "", 0, IPTVTuningData::inValid)), 111 111 _card(0), 112 112 _tuner(0), 113 113 _using_cablecard(false), … … CetonStreamHandler::CetonStreamHandler(const QString &device) : 150 150 int rtspPort = 8554; 151 151 QString url = QString("rtsp://%1:%2/cetonmpeg%3") 152 152 .arg(_ip_address).arg(rtspPort).arg(_tuner); 153 m_tuning = IPTVTuningData(url, 0, IPTVTuningData::kNone, "", 0, "", 0 );153 m_tuning = IPTVTuningData(url, 0, IPTVTuningData::kNone, "", 0, "", 0, IPTVTuningData::rtsp); 154 154 m_use_rtp_streaming = true; 155 155 156 156 _valid = true; -
new file mythtv/libs/libmythtv/recorders/httptsstreamhandler.cpp
diff --git a/mythtv/libs/libmythtv/recorders/httptsstreamhandler.cpp b/mythtv/libs/libmythtv/recorders/httptsstreamhandler.cpp new file mode 100644 index 0000000..6a03436
- + 1 // MythTV headers 2 #include "httptsstreamhandler.h" 3 #include "mythlogging.h" 4 5 // POSIX headers 6 #include <unistd.h> // for usleep 7 8 #define LOC QString("HTTPTSSH(%1): ").arg(_device) 9 10 // BUFFER_SIZE is a multiple of TS_SIZE 11 #define TS_SIZE 188 12 #define BUFFER_SIZE (512 * TS_SIZE) 13 14 QMap<QString,HTTPTSStreamHandler*> HTTPTSStreamHandler::s_handlers; 15 QMap<QString,uint> HTTPTSStreamHandler::s_handlers_refcnt; 16 QMutex HTTPTSStreamHandler::s_handlers_lock; 17 18 HTTPTSStreamHandler* HTTPTSStreamHandler::Get(const IPTVTuningData& tuning) 19 { 20 QMutexLocker locker(&s_handlers_lock); 21 22 QString devkey = tuning.GetDeviceKey(); 23 24 QMap<QString,HTTPTSStreamHandler*>::iterator it = s_handlers.find(devkey); 25 26 if (it == s_handlers.end()) 27 { 28 HTTPTSStreamHandler* newhandler = new HTTPTSStreamHandler(tuning); 29 newhandler->Start(); 30 s_handlers[devkey] = newhandler; 31 s_handlers_refcnt[devkey] = 1; 32 33 LOG(VB_RECORD, LOG_INFO, 34 QString("HTTPTSSH: Creating new stream handler %1 for %2") 35 .arg(devkey).arg(tuning.GetDeviceName())); 36 } 37 else 38 { 39 s_handlers_refcnt[devkey]++; 40 uint rcount = s_handlers_refcnt[devkey]; 41 LOG(VB_RECORD, LOG_INFO, 42 QString("HTTPTSSH: Using existing stream handler %1 for %2") 43 .arg(devkey).arg(tuning.GetDeviceName()) + 44 QString(" (%1 in use)").arg(rcount)); 45 } 46 47 return s_handlers[devkey]; 48 } 49 50 HTTPTSStreamHandler::HTTPTSStreamHandler(const IPTVTuningData& tuning) : 51 IPTVStreamHandler(tuning) 52 { 53 LOG(VB_GENERAL, LOG_INFO, LOC + "ctor"); 54 } 55 56 HTTPTSStreamHandler::~HTTPTSStreamHandler(void) 57 { 58 LOG(VB_GENERAL, LOG_INFO, LOC + "dtor"); 59 Stop(); 60 } 61 62 void HTTPTSStreamHandler::run(void) 63 { 64 RunProlog(); 65 int open_sleep = 250000; 66 LOG(VB_RECORD, LOG_INFO, LOC + "run() -- begin"); 67 SetRunning(true, false, false); 68 69 m_reader = new HTTPReader(this); 70 while (_running_desired) 71 { 72 if (!m_reader->DownloadStream(m_tuning.GetURL(0))) 73 { 74 LOG(VB_RECORD, LOG_INFO, LOC + "DownloadStream failed to recieve bytes from " + m_tuning.GetURL(0).toString()); 75 usleep(open_sleep); 76 if (open_sleep < 10000000) 77 open_sleep += 250000; 78 continue; 79 } 80 open_sleep = 250000; 81 } 82 83 delete m_reader; 84 SetRunning(false, false, false); 85 RunEpilog(); 86 LOG(VB_RECORD, LOG_INFO, LOC + "run() -- done"); 87 } 88 89 90 #undef LOC 91 #define LOC QString("HTTPReader(%1): ").arg(m_parent->_device) 92 93 bool HTTPReader::DownloadStream(const QUrl url) 94 { 95 LOG(VB_RECORD, LOG_INFO, LOC + "DownloadStream -- begin"); 96 97 QMutexLocker lock(&m_lock); 98 QEventLoop event_loop; 99 100 m_buffer = new uint8_t[BUFFER_SIZE]; 101 size = 0; 102 m_ok = false; 103 104 // the HTTP request 105 m_replylock.lock(); 106 m_reply = m_mgr.get(QNetworkRequest(url)); 107 m_replylock.unlock(); 108 109 connect(&m_timer, SIGNAL(timeout()), &event_loop, SLOT(quit())); 110 connect(m_reply, SIGNAL(finished()), &event_loop, SLOT(quit())); 111 connect(m_reply,SIGNAL(readyRead()), this, SLOT(HttpRead())); 112 113 // Configure timeout and size limit 114 m_timer.setSingleShot(true); 115 m_timer.start(10000); 116 117 event_loop.exec(); // blocks stack until quit() is called 118 119 disconnect(&m_timer, SIGNAL(timeout()), &event_loop, SLOT(quit())); 120 disconnect(m_reply, SIGNAL(finished()), &event_loop, SLOT(quit())); 121 disconnect(m_reply,SIGNAL(readyRead()), this, SLOT(HttpRead())); 122 123 if (m_timer.isActive()) 124 m_timer.stop(); 125 126 QMutexLocker replylock(&m_replylock); 127 if (!m_reply->error() == QNetworkReply::NoError) 128 { 129 LOG(VB_RECORD, LOG_ERR, LOC + "DownloadStream exited with " + m_reply->errorString()); 130 } 131 132 delete m_reply; 133 m_reply = NULL; 134 delete[] m_buffer; 135 m_buffer=NULL; 136 137 LOG(VB_RECORD, LOG_INFO, LOC + "DownloadStream -- end"); 138 return m_ok; 139 } 140 141 void HTTPReader::HttpRead() 142 { 143 m_timer.stop(); 144 m_ok = true; 145 ReadBytes(); 146 WriteBytes(); 147 } 148 149 void HTTPReader::ReadBytes() 150 { 151 QMutexLocker replylock(&m_replylock); 152 QMutexLocker bufferlock(&m_bufferlock); 153 154 if(m_reply == NULL || m_buffer == NULL || size > BUFFER_SIZE) 155 return; 156 157 qint64 bytesRead = m_reply->read( reinterpret_cast<char*>(m_buffer+size), BUFFER_SIZE-size); 158 size += (bytesRead > 0 ? bytesRead : 0); 159 LOG(VB_RECORD, LOG_DEBUG, LOC + QString("ReadBytes: %1 bytes recieved").arg(bytesRead)); 160 } 161 162 void HTTPReader::WriteBytes() 163 { 164 if (size < TS_SIZE) 165 return; 166 167 QMutexLocker replylock(&m_bufferlock); 168 int remainder = 0; 169 { 170 QMutexLocker locker(&m_parent->_listener_lock); 171 HTTPTSStreamHandler::StreamDataList::const_iterator sit; 172 sit = m_parent->_stream_data_list.begin(); 173 for (; sit != m_parent->_stream_data_list.end(); ++sit) 174 { 175 remainder = sit.key()->ProcessData(m_buffer, size); 176 } 177 } 178 LOG(VB_RECORD, LOG_DEBUG, LOC + QString("WriteBytes: %1/%2 bytes remain").arg(remainder).arg(size)); 179 memcpy(m_buffer, m_buffer+(size-remainder), remainder); 180 size = remainder; 181 } 182 183 void HTTPReader::Cancel(void) 184 { 185 QMutexLocker replylock(&m_replylock); 186 if (m_reply) 187 { 188 LOG(VB_RECORD, LOG_INFO, LOC + "Cancel: Aborting stream download"); 189 m_reply->abort(); 190 } 191 } -
new file mythtv/libs/libmythtv/recorders/httptsstreamhandler.h
diff --git a/mythtv/libs/libmythtv/recorders/httptsstreamhandler.h b/mythtv/libs/libmythtv/recorders/httptsstreamhandler.h new file mode 100644 index 0000000..c36952b
- + 1 #ifndef _HTTPTSSTREAMHANDLER_H_ 2 #define _HTTPTSSTREAMHANDLER_H_ 3 4 #include <vector> 5 using namespace std; 6 7 #include <QString> 8 #include <QMutex> 9 #include <QMap> 10 #include <QNetworkAccessManager> 11 #include <QNetworkRequest> 12 #include <QNetworkReply> 13 14 #include "channelutil.h" 15 #include "iptvstreamhandler.h" 16 17 class HTTPReader; 18 19 class HTTPTSStreamHandler : public IPTVStreamHandler 20 { 21 friend class HTTPReader; 22 public: 23 static HTTPTSStreamHandler* Get(const IPTVTuningData& tuning); 24 25 protected: 26 HTTPTSStreamHandler(const IPTVTuningData &tuning); 27 virtual ~HTTPTSStreamHandler(void); 28 virtual void run(void); 29 30 protected: 31 HTTPReader* m_reader; 32 // for implementing Get & Return 33 static QMutex s_handlers_lock; 34 static QMap<QString, HTTPTSStreamHandler*> s_handlers; 35 static QMap<QString, uint> s_handlers_refcnt; 36 }; 37 38 39 class MBASE_PUBLIC HTTPReader : public QObject 40 { 41 Q_OBJECT 42 43 public: 44 HTTPReader(HTTPTSStreamHandler* parent) : m_parent(parent){} 45 void Cancel(void); 46 bool DownloadStream(const QUrl url); 47 48 protected: 49 void ReadBytes(); 50 void WriteBytes(); 51 52 private slots: 53 void HttpRead(); 54 55 private: 56 HTTPTSStreamHandler *m_parent; 57 QTimer m_timer; 58 QNetworkAccessManager m_mgr; 59 QNetworkReply *m_reply; 60 QMutex m_lock; 61 QMutex m_replylock; 62 QMutex m_bufferlock; 63 uint8_t *m_buffer; 64 bool m_ok; 65 int size; 66 }; 67 68 #endif // _HTTPTSSTREAMHANDLER_H_ -
mythtv/libs/libmythtv/recorders/iptvchannel.cpp
diff --git a/mythtv/libs/libmythtv/recorders/iptvchannel.cpp b/mythtv/libs/libmythtv/recorders/iptvchannel.cpp index 4456976..0b7ae38 100644
a b 12 12 13 13 // MythTV headers 14 14 #include "iptvstreamhandler.h" 15 #include "httptsstreamhandler.h" 15 16 #include "hlsstreamhandler.h" 16 17 #include "iptvrecorder.h" 17 18 #include "iptvchannel.h" … … 20 21 21 22 #define LOC QString("IPTVChan[%1]: ").arg(GetCardID()) 22 23 23 IPTVChannel::IPTVChannel(TVRec *rec, const QString &) :24 DTVChannel(rec), m_ firsttune(true),24 IPTVChannel::IPTVChannel(TVRec *rec, const QString &videodev) : 25 DTVChannel(rec), m_videodev(videodev), m_firsttune(true), 25 26 m_stream_handler(NULL), m_stream_data(NULL) 26 27 { 27 28 LOG(VB_CHANNEL, LOG_INFO, LOC + "ctor"); … … void IPTVChannel::OpenStreamHandler(void) 100 101 { 101 102 m_stream_handler = HLSStreamHandler::Get(m_last_tuning); 102 103 } 104 else if (m_last_tuning.IsHTTPTS()) 105 { 106 m_stream_handler = HTTPTSStreamHandler::Get(m_last_tuning); 107 } 103 108 else 104 109 { 105 110 m_stream_handler = IPTVStreamHandler::Get(m_last_tuning); -
mythtv/libs/libmythtv/recorders/iptvchannel.h
diff --git a/mythtv/libs/libmythtv/recorders/iptvchannel.h b/mythtv/libs/libmythtv/recorders/iptvchannel.h index db757c0..781ef55 100644
a b class IPTVChannel : QObject, public DTVChannel 64 64 mutable QMutex m_stream_lock; 65 65 IPTVStreamHandler *m_stream_handler; 66 66 MPEGStreamData *m_stream_data; 67 QString m_videodev; 67 68 }; 68 69 69 70 #endif // _IPTV_CHANNEL_H_ -
mythtv/libs/libmythtv/recorders/iptvstreamhandler.cpp
diff --git a/mythtv/libs/libmythtv/recorders/iptvstreamhandler.cpp b/mythtv/libs/libmythtv/recorders/iptvstreamhandler.cpp index cab9be2..f2c93b5 100644
a b IPTVStreamHandler::IPTVStreamHandler(const IPTVTuningData &tuning) : 115 115 { 116 116 memset(m_sockets, 0, sizeof(m_sockets)); 117 117 memset(m_read_helpers, 0, sizeof(m_read_helpers)); 118 m_use_rtp_streaming = m_tuning. GetDataURL().scheme().toUpper() == "RTP";118 m_use_rtp_streaming = m_tuning.IsRTP(); 119 119 } 120 120 121 121 void IPTVStreamHandler::run(void) … … void IPTVStreamHandler::run(void) 131 131 // Setup 132 132 CetonRTSP *rtsp = NULL; 133 133 IPTVTuningData tuning = m_tuning; 134 if (m_tuning.GetURL(0).scheme().toLower() == "rtsp")134 if(m_tuning.IsRTSP()) 135 135 { 136 136 rtsp = new CetonRTSP(m_tuning.GetURL(0)); 137 137 … … void IPTVStreamHandler::run(void) 165 165 urltuned.setScheme("rtp"); 166 166 urltuned.setPort(0); 167 167 tuning = IPTVTuningData(urltuned.toString(), 0, IPTVTuningData::kNone, 168 urltuned.toString(), 0, "", 0 );168 urltuned.toString(), 0, "", 0, IPTVTuningData::rtp); 169 169 } 170 170 171 171 bool error = false; 172 172 173 int start_port = 0; 173 174 for (uint i = 0; i < IPTV_SOCKET_COUNT; i++) 174 175 { … … void IPTVStreamHandler::run(void) 279 280 280 281 if (!error) 281 282 { 282 if (m_ use_rtp_streaming)283 if (m_tuning.IsRTP() || m_tuning.IsRTSP()) 283 284 m_buffer = new RTPPacketBuffer(tuning.GetBitrate(0)); 284 285 else 285 286 m_buffer = new UDPPacketBuffer(tuning.GetBitrate(0)); -
mythtv/libs/libmythtv/recorders/iptvstreamhandler.h
diff --git a/mythtv/libs/libmythtv/recorders/iptvstreamhandler.h b/mythtv/libs/libmythtv/recorders/iptvstreamhandler.h index 27f1a05..6f590af 100644
a b using namespace std; 12 12 #include <QMutex> 13 13 #include <QMap> 14 14 15 #include <QNetworkAccessManager> 16 #include <QtNetwork> 17 15 18 #include "channelutil.h" 16 19 #include "streamhandler.h" 17 20 -
mythtv/libs/libmythtv/tv_rec.cpp
diff --git a/mythtv/libs/libmythtv/tv_rec.cpp b/mythtv/libs/libmythtv/tv_rec.cpp index 778f36d..4697923 100644
a b void TVRec::TuningFrequency(const TuningRequest &request) 3889 3889 expire.addMSecs(genOpt.channel_timeout * 2); 3890 3890 } 3891 3891 signalMonitorCheckCnt = 0; 3892 3893 //System Event TUNING_TIMEOUT deadline 3894 QDateTime expire = MythDate::current(); 3895 signalEventCmdTimeout = expire.addMSecs(genOpt.channel_timeout); 3896 signalEventCmdSent = false; 3892 3897 } 3893 3898 } 3894 3899 … … void TVRec::TuningFrequency(const TuningRequest &request) 3927 3932 MPEGStreamData *TVRec::TuningSignalCheck(void) 3928 3933 { 3929 3934 RecStatusType newRecStatus = rsRecording; 3935 if ((signalMonitor->IsErrored() || 3936 MythDate::current() > signalEventCmdTimeout) && 3937 !signalEventCmdSent) 3938 { 3939 gCoreContext->SendSystemEvent(QString("TUNING_SIGNAL_TIMEOUT CARDID %1").arg(cardid)); 3940 signalEventCmdSent=true; 3941 } 3930 3942 if (signalMonitor->IsAllGood()) 3931 3943 { 3932 3944 LOG(VB_RECORD, LOG_INFO, LOC + "TuningSignalCheck: Have a good signal"); -
mythtv/libs/libmythtv/tv_rec.h
diff --git a/mythtv/libs/libmythtv/tv_rec.h b/mythtv/libs/libmythtv/tv_rec.h index 91e5229..bad9f11 100644
a b class MTV_PUBLIC TVRec : public SignalMonitorListener, public QRunnable 329 329 SignalMonitor *signalMonitor; 330 330 EITScanner *scanner; 331 331 332 QDateTime signalEventCmdTimeout; 333 bool signalEventCmdSent; 334 332 335 QDateTime signalMonitorDeadline; 333 336 uint signalMonitorCheckCnt; 334 337