1
0
mirror of https://github.com/rofafor/vdr-plugin-iptv.git synced 2023-10-10 13:37:03 +02:00

Fixed bugs found in the CURL implementation (Thanks to Jeremy Hall).

This commit is contained in:
Rolf Ahrenberg 2013-02-25 21:08:08 +02:00
parent ed09963253
commit e4657c1820
8 changed files with 86 additions and 68 deletions

View File

@ -193,3 +193,8 @@ VDR Plugin 'iptv' Revision History
- Updated for vdr-1.7.38. - Updated for vdr-1.7.38.
- Added a new CURL protocol for HTTP/HTTPS. - Added a new CURL protocol for HTTP/HTTPS.
2013-xx-xx: Version 1.2.1
- Fixed bugs found in the CURL implementation (Thanks
to Jeremy Hall).

10
README
View File

@ -89,11 +89,11 @@ Configuration:
- channels.conf - channels.conf
TV4;IPTV:40:S=1|P=0|F=EXT|U=iptvstream.sh|A=0:I:0:0:680:0:0:4:0:0:0 TV4;IPTV:60:S=1|P=0|F=EXT|U=iptvstream.sh|A=0:I:0:0:680:0:0:4:0:0:0
TV3;IPTV:30:S=0|P=1|F=FILE|U=/video/stream.ts|A=5:I:0:514:670:2321:0:3:0:0:0 TV3;IPTV:50:S=0|P=1|F=FILE|U=/video/stream.ts|A=5:I:0:514:670:2321:0:3:0:0:0
TV2;IPTV:20:S=0|P=1|F=HTTP|U=127.0.0.1/TS/2|A=3000:I:0:513:660:2321:0:2:0:0:0 TV2;IPTV:40:S=0|P=1|F=HTTP|U=127.0.0.1/TS/2|A=3000:I:0:513:660:2321:0:2:0:0:0
TV1;IPTV:10:S=1|P=0|F=CURL|U=http%3A//foo%3Abar@127.0.0.1%3A3000/TS/2|A=0:I:0:512:650:2321:0:1:0:0:0 TV1;IPTV:30:S=1|P=0|F=CURL|U=http%3A//foo%3Abar@127.0.0.1%3A3000/TS/2|A=0:I:0:512:650:2321:0:1:0:0:0
TV1;IPTV:10:S=1|P=0|F=UDP|U=127.0.0.1@127.0.0.1|A=1234:I:0:512:650:2321:0:1:0:0:0 TV1;IPTV:20:S=1|P=0|F=UDP|U=127.0.0.1@127.0.0.1|A=1234:I:0:512:650:2321:0:1:0:0:0
TV1;IPTV:10:S=1|P=0|F=UDP|U=127.0.0.1|A=1234:I:0:512:650:2321:0:1:0:0:0 TV1;IPTV:10:S=1|P=0|F=UDP|U=127.0.0.1|A=1234:I:0:512:650:2321:0:1:0:0:0
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
| | | | | | Source type ("I") | | | | | | Source type ("I")

View File

@ -74,6 +74,7 @@ cIptvDevice::~cIptvDevice()
DELETE_POINTER(pSidScannerM); DELETE_POINTER(pSidScannerM);
} }
// Destroy all filters // Destroy all filters
cMutexLock MutexLock(&mutexM);
for (int i = 0; i < eMaxSecFilterCount; ++i) for (int i = 0; i < eMaxSecFilterCount; ++i)
DeleteFilter(i); DeleteFilter(i);
// Close dvr fifo // Close dvr fifo
@ -143,6 +144,7 @@ cString cIptvDevice::GetFiltersInformation(void)
unsigned int count = 0; unsigned int count = 0;
cString s("Active section filters:\n"); cString s("Active section filters:\n");
// loop through active section filters // loop through active section filters
cMutexLock MutexLock(&mutexM);
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) { for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
if (secFiltersM[i]) { if (secFiltersM[i]) {
s = cString::sprintf("%sFilter %d: %s Pid=0x%02X (%s)\n", *s, i, s = cString::sprintf("%sFilter %d: %s Pid=0x%02X (%s)\n", *s, i,
@ -321,7 +323,7 @@ bool cIptvDevice::IsBlackListed(u_short pidP, u_char tidP, u_char maskP) const
// loop through section filter table // loop through section filter table
for (int i = 0; i < SECTION_FILTER_TABLE_SIZE; ++i) { for (int i = 0; i < SECTION_FILTER_TABLE_SIZE; ++i) {
int index = IptvConfig.GetDisabledFilters(i); int index = IptvConfig.GetDisabledFilters(i);
// check if matches // Check if matches
if ((index >= 0) && (index < SECTION_FILTER_TABLE_SIZE) && if ((index >= 0) && (index < SECTION_FILTER_TABLE_SIZE) &&
(section_filter_table[index].pid == pidP) && (section_filter_table[index].tid == tidP) && (section_filter_table[index].pid == pidP) && (section_filter_table[index].tid == tidP) &&
(section_filter_table[index].mask == maskP)) { (section_filter_table[index].mask == maskP)) {
@ -418,7 +420,7 @@ bool cIptvDevice::HasInternalCam(void)
void cIptvDevice::ResetBuffering(void) void cIptvDevice::ResetBuffering(void)
{ {
debug("cIptvDevice::%s(%d)", __FUNCTION__, deviceIndexM); debug("cIptvDevice::%s(%d)", __FUNCTION__, deviceIndexM);
// pad prefill to multiple of TS_SIZE // Pad prefill to multiple of TS_SIZE
tsBufferPrefillM = (unsigned int)MEGABYTE(IptvConfig.GetTsBufferSize()) * tsBufferPrefillM = (unsigned int)MEGABYTE(IptvConfig.GetTsBufferSize()) *
IptvConfig.GetTsBufferPrefillRatio() / 100; IptvConfig.GetTsBufferPrefillRatio() / 100;
tsBufferPrefillM -= (tsBufferPrefillM % TS_SIZE); tsBufferPrefillM -= (tsBufferPrefillM % TS_SIZE);

2
iptv.c
View File

@ -21,7 +21,7 @@
#define GITVERSION "" #define GITVERSION ""
#endif #endif
const char VERSION[] = "1.2.0" GITVERSION; const char VERSION[] = "1.2.1" GITVERSION;
static const char DESCRIPTION[] = trNOOP("Experience the IPTV"); static const char DESCRIPTION[] = trNOOP("Experience the IPTV");
class cPluginIptv : public cPlugin { class cPluginIptv : public cPlugin {

View File

@ -10,10 +10,14 @@
#include "protocolcurl.h" #include "protocolcurl.h"
#define iptv_curl_easy_setopt(X, Y, Z) \ #define iptv_curl_easy_setopt(X, Y, Z) \
if ((res = curl_easy_setopt((X), (Y), (Z))) != CURLE_OK) { error("curl_easy_setopt(%s, %s, %s) failed: %d\n", #X, #Y, #Z, res); } if ((res = curl_easy_setopt((X), (Y), (Z))) != CURLE_OK) { \
error("curl_easy_setopt(%s, %s, %s) failed: %d\n", #X, #Y, #Z, res); \
}
#define iptv_curl_easy_perform(X) \ #define iptv_curl_easy_perform(X) \
if ((res = curl_easy_perform((X))) != CURLE_OK) { error("curl_easy_perform(%s) failed: %d\n", #X, res); } if ((res = curl_easy_perform((X))) != CURLE_OK) { \
error("curl_easy_perform(%s) failed: %d\n", #X, res); \
}
cIptvProtocolCurl::cIptvProtocolCurl() cIptvProtocolCurl::cIptvProtocolCurl()
: streamUrlM(""), : streamUrlM(""),
@ -22,7 +26,8 @@ cIptvProtocolCurl::cIptvProtocolCurl()
handleM(NULL), handleM(NULL),
multiM(NULL), multiM(NULL),
headerListM(NULL), headerListM(NULL),
ringBufferM(new cRingBufferLinear(MEGABYTE(IptvConfig.GetTsBufferSize()), 7 * TS_SIZE)), ringBufferM(new cRingBufferLinear(MEGABYTE(IptvConfig.GetTsBufferSize()), 7 * TS_SIZE,
false, *cString::sprintf("IPTV CURL"))),
rtspControlM(), rtspControlM(),
modeM(eModeUnknown), modeM(eModeUnknown),
connectedM(false), connectedM(false),
@ -61,29 +66,29 @@ size_t cIptvProtocolCurl::WriteRtspCallback(void *ptrP, size_t sizeP, size_t nme
unsigned char *p = (unsigned char *)ptrP; unsigned char *p = (unsigned char *)ptrP;
//debug("cIptvProtocolCurl::%s(%zu)", __FUNCTION__, len); //debug("cIptvProtocolCurl::%s(%zu)", __FUNCTION__, len);
// validate packet header ('$') and channel (0) // Validate packet header ('$') and channel (0)
if (obj && (p[0] == 0x24 ) && (p[1] == 0)) { if (obj && (p[0] == 0x24 ) && (p[1] == 0)) {
int length = (p[2] << 8) | p[3]; int length = (p[2] << 8) | p[3];
if (length > 3) { if (length > 3) {
// skip interleave header // Skip interleave header
p += 4; p += 4;
// http://tools.ietf.org/html/rfc3550 // http://tools.ietf.org/html/rfc3550
// http://tools.ietf.org/html/rfc2250 // http://tools.ietf.org/html/rfc2250
// version // Version
unsigned int v = (p[0] >> 6) & 0x03; unsigned int v = (p[0] >> 6) & 0x03;
// extension bit // Extension bit
unsigned int x = (p[0] >> 4) & 0x01; unsigned int x = (p[0] >> 4) & 0x01;
// cscr count // CSCR count
unsigned int cc = p[0] & 0x0F; unsigned int cc = p[0] & 0x0F;
// payload type: MPEG2 TS = 33 // Payload type: MPEG2 TS = 33
//unsigned int pt = p[1] & 0x7F; //unsigned int pt = p[1] & 0x7F;
// header lenght // Header lenght
unsigned int headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t); unsigned int headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t);
// check if extension // Check if extension
if (x) { if (x) {
// extension header length // Extension header length
unsigned int ehl = (((p[headerlen + 2] & 0xFF) << 8) |(p[headerlen + 3] & 0xFF)); unsigned int ehl = (((p[headerlen + 2] & 0xFF) << 8) |(p[headerlen + 3] & 0xFF));
// update header length // Update header length
headerlen += (ehl + 1) * (unsigned int)sizeof(uint32_t); headerlen += (ehl + 1) * (unsigned int)sizeof(uint32_t);
} }
// Check that rtp is version 2 and payload contains multiple of TS packet data // Check that rtp is version 2 and payload contains multiple of TS packet data
@ -155,9 +160,10 @@ bool cIptvProtocolCurl::PutData(unsigned char *dataP, int lenP)
if (pausedM) if (pausedM)
return false; return false;
if (ringBufferM && (lenP >= 0)) { if (ringBufferM && (lenP >= 0)) {
// should be pause the transfer? // Should we pause the transfer ?
if (ringBufferM->Free() < (2 * CURL_MAX_WRITE_SIZE)) { if (ringBufferM->Free() < (2 * CURL_MAX_WRITE_SIZE)) {
debug("cIptvProtocolCurl::%s(pause): free=%d available=%d len=%d", __FUNCTION__, ringBufferM->Free(), ringBufferM->Available(), lenP); debug("cIptvProtocolCurl::%s(pause): free=%d available=%d len=%d", __FUNCTION__,
ringBufferM->Free(), ringBufferM->Available(), lenP);
pausedM = true; pausedM = true;
return false; return false;
} }
@ -223,7 +229,7 @@ bool cIptvProtocolCurl::Connect()
if (connectedM) if (connectedM)
return true; return true;
// initialize the curl session // Initialize the curl session
if (!handleM) if (!handleM)
handleM = curl_easy_init(); handleM = curl_easy_init();
if (!multiM) if (!multiM)
@ -234,49 +240,49 @@ bool cIptvProtocolCurl::Connect()
cString netrc = cString::sprintf("%s/netrc", IptvConfig.GetConfigDirectory()); cString netrc = cString::sprintf("%s/netrc", IptvConfig.GetConfigDirectory());
#ifdef DEBUG #ifdef DEBUG
// verbose output // Verbose output
iptv_curl_easy_setopt(handleM, CURLOPT_VERBOSE, 1L); iptv_curl_easy_setopt(handleM, CURLOPT_VERBOSE, 1L);
#endif #endif
// set callbacks // Set callbacks
iptv_curl_easy_setopt(handleM, CURLOPT_WRITEFUNCTION, cIptvProtocolCurl::WriteCallback); iptv_curl_easy_setopt(handleM, CURLOPT_WRITEFUNCTION, cIptvProtocolCurl::WriteCallback);
iptv_curl_easy_setopt(handleM, CURLOPT_WRITEDATA, this); iptv_curl_easy_setopt(handleM, CURLOPT_WRITEDATA, this);
iptv_curl_easy_setopt(handleM, CURLOPT_HEADERFUNCTION, cIptvProtocolCurl::HeaderCallback); iptv_curl_easy_setopt(handleM, CURLOPT_HEADERFUNCTION, cIptvProtocolCurl::HeaderCallback);
iptv_curl_easy_setopt(handleM, CURLOPT_WRITEHEADER, this); iptv_curl_easy_setopt(handleM, CURLOPT_WRITEHEADER, this);
// no progress meter and no signaling // No progress meter and no signaling
iptv_curl_easy_setopt(handleM, CURLOPT_NOPROGRESS, 1L); iptv_curl_easy_setopt(handleM, CURLOPT_NOPROGRESS, 1L);
iptv_curl_easy_setopt(handleM, CURLOPT_NOSIGNAL, 1L); iptv_curl_easy_setopt(handleM, CURLOPT_NOSIGNAL, 1L);
// support netrc // Support netrc
iptv_curl_easy_setopt(handleM, CURLOPT_NETRC, (long)CURL_NETRC_OPTIONAL); iptv_curl_easy_setopt(handleM, CURLOPT_NETRC, (long)CURL_NETRC_OPTIONAL);
iptv_curl_easy_setopt(handleM, CURLOPT_NETRC_FILE, *netrc); iptv_curl_easy_setopt(handleM, CURLOPT_NETRC_FILE, *netrc);
// set timeout // Set timeout
iptv_curl_easy_setopt(handleM, CURLOPT_CONNECTTIMEOUT, (long)eConnectTimeoutS); iptv_curl_easy_setopt(handleM, CURLOPT_CONNECTTIMEOUT, (long)eConnectTimeoutS);
// set user-agent // Set user-agent
iptv_curl_easy_setopt(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s", PLUGIN_NAME_I18N, VERSION)); iptv_curl_easy_setopt(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s", PLUGIN_NAME_I18N, VERSION));
// set url // Set URL
//char *p = curl_easy_unescape(handleM, *streamUrlM, 0, NULL); //char *p = curl_easy_unescape(handleM, *streamUrlM, 0, NULL);
//streamUrlM = p; //streamUrlM = p;
//curl_free(p); //curl_free(p);
iptv_curl_easy_setopt(handleM, CURLOPT_URL, *streamUrlM); iptv_curl_easy_setopt(handleM, CURLOPT_URL, *streamUrlM);
// protocol specific initializations // Protocol specific initializations
switch (modeM) { switch (modeM) {
case eModeRtsp: case eModeRtsp:
{ {
cString uri, control, transport, range; cString uri, control, transport, range;
// request server options // Request server options
uri = cString::sprintf("%s", *streamUrlM); uri = cString::sprintf("%s", *streamUrlM);
iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_STREAM_URI, *uri); iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_OPTIONS); iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_OPTIONS);
iptv_curl_easy_perform(handleM); iptv_curl_easy_perform(handleM);
// request session description - SDP is delivered in message body and not in the header! // Request session description - SDP is delivered in message body and not in the header!
iptv_curl_easy_setopt(handleM, CURLOPT_WRITEFUNCTION, cIptvProtocolCurl::DescribeCallback); iptv_curl_easy_setopt(handleM, CURLOPT_WRITEFUNCTION, cIptvProtocolCurl::DescribeCallback);
iptv_curl_easy_setopt(handleM, CURLOPT_WRITEDATA, this); iptv_curl_easy_setopt(handleM, CURLOPT_WRITEDATA, this);
uri = cString::sprintf("%s", *streamUrlM); uri = cString::sprintf("%s", *streamUrlM);
@ -286,7 +292,7 @@ bool cIptvProtocolCurl::Connect()
iptv_curl_easy_setopt(handleM, CURLOPT_WRITEFUNCTION, NULL); iptv_curl_easy_setopt(handleM, CURLOPT_WRITEFUNCTION, NULL);
iptv_curl_easy_setopt(handleM, CURLOPT_WRITEDATA, NULL); iptv_curl_easy_setopt(handleM, CURLOPT_WRITEDATA, NULL);
// setup media stream // Setup media stream
uri = cString::sprintf("%s/%s", *streamUrlM, *rtspControlM); uri = cString::sprintf("%s/%s", *streamUrlM, *rtspControlM);
transport = "RTP/AVP/TCP;unicast;interleaved=0-1"; transport = "RTP/AVP/TCP;unicast;interleaved=0-1";
iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_STREAM_URI, *uri); iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
@ -294,7 +300,7 @@ bool cIptvProtocolCurl::Connect()
iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_SETUP); iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_SETUP);
iptv_curl_easy_perform(handleM); iptv_curl_easy_perform(handleM);
// start playing // Start playing
uri = cString::sprintf("%s/", *streamUrlM); uri = cString::sprintf("%s/", *streamUrlM);
range = "0.000-"; range = "0.000-";
iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_STREAM_URI, *uri); iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
@ -302,7 +308,7 @@ bool cIptvProtocolCurl::Connect()
iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_PLAY); iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_PLAY);
iptv_curl_easy_perform(handleM); iptv_curl_easy_perform(handleM);
// start receiving // Start receiving
iptv_curl_easy_setopt(handleM, CURLOPT_INTERLEAVEFUNCTION, cIptvProtocolCurl::WriteRtspCallback); iptv_curl_easy_setopt(handleM, CURLOPT_INTERLEAVEFUNCTION, cIptvProtocolCurl::WriteRtspCallback);
iptv_curl_easy_setopt(handleM, CURLOPT_INTERLEAVEDATA, this); iptv_curl_easy_setopt(handleM, CURLOPT_INTERLEAVEDATA, this);
iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_RECEIVE); iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_RECEIVE);
@ -313,16 +319,16 @@ bool cIptvProtocolCurl::Connect()
case eModeHttp: case eModeHttp:
case eModeHttps: case eModeHttps:
{ {
// limit download speed (bytes/s) // Limit download speed (bytes/s)
iptv_curl_easy_setopt(handleM, CURLOPT_MAX_RECV_SPEED_LARGE, eMaxDownloadSpeedMBits * 131072L); iptv_curl_easy_setopt(handleM, CURLOPT_MAX_RECV_SPEED_LARGE, eMaxDownloadSpeedMBits * 131072L);
// follow location // Follow location
iptv_curl_easy_setopt(handleM, CURLOPT_FOLLOWLOCATION, 1L); iptv_curl_easy_setopt(handleM, CURLOPT_FOLLOWLOCATION, 1L);
// fail if HTTP return code is >= 400 // Fail if HTTP return code is >= 400
iptv_curl_easy_setopt(handleM, CURLOPT_FAILONERROR, 1L); iptv_curl_easy_setopt(handleM, CURLOPT_FAILONERROR, 1L);
// set additional headers to prevent caching // Set additional headers to prevent caching
headerListM = curl_slist_append(headerListM, "Cache-Control: no-store, no-cache, must-revalidate"); headerListM = curl_slist_append(headerListM, "Cache-Control: no-store, no-cache, must-revalidate");
headerListM = curl_slist_append(headerListM, "Cache-Control: post-check=0, pre-check=0"); headerListM = curl_slist_append(headerListM, "Cache-Control: post-check=0, pre-check=0");
headerListM = curl_slist_append(headerListM, "Pragma: no-cache"); headerListM = curl_slist_append(headerListM, "Pragma: no-cache");
@ -337,7 +343,7 @@ bool cIptvProtocolCurl::Connect()
break; break;
} }
// add handle into multi set // Add handle into multi set
curl_multi_add_handle(multiM, handleM); curl_multi_add_handle(multiM, handleM);
connectedM = true; connectedM = true;
@ -351,13 +357,17 @@ bool cIptvProtocolCurl::Disconnect()
{ {
cMutexLock MutexLock(&mutexM); cMutexLock MutexLock(&mutexM);
debug("cIptvProtocolCurl::%s()", __FUNCTION__); debug("cIptvProtocolCurl::%s()", __FUNCTION__);
if (handleM) { if (!connectedM)
// mode specific tricks return true;
// Terminate curl session
if (handleM && multiM) {
// Mode specific tricks
switch (modeM) { switch (modeM) {
case eModeRtsp: case eModeRtsp:
{ {
CURLcode res = CURLE_OK; CURLcode res = CURLE_OK;
// teardown rtsp session // Teardown rtsp session
cString uri = cString::sprintf("%s/", *streamUrlM); cString uri = cString::sprintf("%s/", *streamUrlM);
iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_STREAM_URI, *uri); iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_TEARDOWN); iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_TEARDOWN);
@ -374,16 +384,16 @@ bool cIptvProtocolCurl::Disconnect()
break; break;
} }
// cleanup curl stuff // Cleanup curl stuff
if (headerListM) { if (headerListM) {
curl_slist_free_all(headerListM); curl_slist_free_all(headerListM);
headerListM = NULL; headerListM = NULL;
} }
curl_multi_remove_handle(multiM, handleM); curl_multi_remove_handle(multiM, handleM);
curl_multi_cleanup(multiM);
multiM = NULL;
curl_easy_cleanup(handleM); curl_easy_cleanup(handleM);
handleM = NULL; handleM = NULL;
curl_multi_cleanup(multiM);
multiM = NULL;
} }
ClearData(); ClearData();
@ -409,21 +419,19 @@ int cIptvProtocolCurl::Read(unsigned char* bufferAddrP, unsigned int bufferLenP)
//debug("cIptvProtocolCurl::%s()", __FUNCTION__); //debug("cIptvProtocolCurl::%s()", __FUNCTION__);
int len = 0; int len = 0;
if (ringBufferM) { if (ringBufferM) {
// fill up the buffer // Fill up the buffer
if (handleM && multiM) { if (handleM && multiM) {
switch (modeM) { switch (modeM) {
case eModeRtsp: case eModeRtsp:
{ {
//CURLcode res = CURLE_OK; CURLcode res = CURLE_OK;
//iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_RECEIVE); iptv_curl_easy_setopt(handleM, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_RECEIVE);
//iptv_curl_easy_perform(handleM); iptv_curl_easy_perform(handleM);
// @todo - how to detect eof? // @todo - How to detect eof?
} }
break; break;
case eModeFile: case eModeFile:
break;
case eModeHttp: case eModeHttp:
case eModeHttps: case eModeHttps:
{ {
@ -434,21 +442,23 @@ int cIptvProtocolCurl::Read(unsigned char* bufferAddrP, unsigned int bufferLenP)
res = curl_multi_perform(multiM, &running_handles); res = curl_multi_perform(multiM, &running_handles);
} while (res == CURLM_CALL_MULTI_PERFORM); } while (res == CURLM_CALL_MULTI_PERFORM);
// shall be continue filling up the buffer? // Shall we continue filling up the buffer?
mutexM.Lock(); mutexM.Lock();
if (pausedM && (ringBufferM->Free() > ringBufferM->Available())) { if (pausedM && (ringBufferM->Free() > ringBufferM->Available())) {
debug("cIptvProtocolCurl::%s(continue): free=%d available=%d", __FUNCTION__, ringBufferM->Free(), ringBufferM->Available()); debug("cIptvProtocolCurl::%s(continue): free=%d available=%d", __FUNCTION__,
ringBufferM->Free(), ringBufferM->Available());
pausedM = false; pausedM = false;
curl_easy_pause(handleM, CURLPAUSE_CONT); curl_easy_pause(handleM, CURLPAUSE_CONT);
} }
mutexM.Unlock(); mutexM.Unlock();
// check end of file // Check if end of file
if (running_handles == 0) { if (running_handles == 0) {
int msgcount; int msgcount;
CURLMsg *msg = curl_multi_info_read(multiM, &msgcount); CURLMsg *msg = curl_multi_info_read(multiM, &msgcount);
if (msg && (msg->msg == CURLMSG_DONE)) { if (msg && (msg->msg == CURLMSG_DONE)) {
debug("cIptvProtocolCurl::%s(done): %s (%d)", __FUNCTION__, curl_easy_strerror(msg->data.result), msg->data.result); debug("cIptvProtocolCurl::%s(done): %s (%d)", __FUNCTION__,
curl_easy_strerror(msg->data.result), msg->data.result);
Disconnect(); Disconnect();
Connect(); Connect();
} }
@ -456,6 +466,7 @@ int cIptvProtocolCurl::Read(unsigned char* bufferAddrP, unsigned int bufferLenP)
} }
break; break;
case eModeUnknown:
default: default:
break; break;
} }

View File

@ -29,7 +29,6 @@ private:
}; };
enum { enum {
eConnectTimeoutS = 5, // in seconds eConnectTimeoutS = 5, // in seconds
eSelectTimeoutMs = 10, // in milliseconds
eMaxDownloadSpeedMBits = 20 // in megabits per second eMaxDownloadSpeedMBits = 20 // in megabits per second
}; };

View File

@ -264,22 +264,22 @@ int cIptvUdpSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP)
else if (len > 3) { else if (len > 3) {
// http://tools.ietf.org/html/rfc3550 // http://tools.ietf.org/html/rfc3550
// http://tools.ietf.org/html/rfc2250 // http://tools.ietf.org/html/rfc2250
// version // Version
unsigned int v = (bufferAddrP[0] >> 6) & 0x03; unsigned int v = (bufferAddrP[0] >> 6) & 0x03;
// extension bit // Extension bit
unsigned int x = (bufferAddrP[0] >> 4) & 0x01; unsigned int x = (bufferAddrP[0] >> 4) & 0x01;
// cscr count // CSCR count
unsigned int cc = bufferAddrP[0] & 0x0F; unsigned int cc = bufferAddrP[0] & 0x0F;
// payload type: MPEG2 TS = 33 // Payload type: MPEG2 TS = 33
//unsigned int pt = bufferAddrP[1] & 0x7F; //unsigned int pt = bufferAddrP[1] & 0x7F;
// header lenght // Header lenght
unsigned int headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t); unsigned int headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t);
// check if extension // Check if extension
if (x) { if (x) {
// extension header length // Extension header length
unsigned int ehl = (((bufferAddrP[headerlen + 2] & 0xFF) << 8) | unsigned int ehl = (((bufferAddrP[headerlen + 2] & 0xFF) << 8) |
(bufferAddrP[headerlen + 3] & 0xFF)); (bufferAddrP[headerlen + 3] & 0xFF));
// update header length // Update header length
headerlen += (ehl + 1) * (unsigned int)sizeof(uint32_t); headerlen += (ehl + 1) * (unsigned int)sizeof(uint32_t);
} }
// Check that rtp is version 2 and payload contains multiple of TS packet data // Check that rtp is version 2 and payload contains multiple of TS packet data

View File

@ -14,6 +14,7 @@
cIptvStreamer::cIptvStreamer(cRingBufferLinear* ringBufferP, unsigned int packetLenP) cIptvStreamer::cIptvStreamer(cRingBufferLinear* ringBufferP, unsigned int packetLenP)
: cThread("IPTV streamer"), : cThread("IPTV streamer"),
ringBufferM(ringBufferP), ringBufferM(ringBufferP),
sleepM(),
packetBufferLenM(packetLenP), packetBufferLenM(packetLenP),
protocolM(NULL) protocolM(NULL)
{ {