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:
parent
ed09963253
commit
e4657c1820
5
HISTORY
5
HISTORY
@ -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
10
README
@ -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")
|
||||||
|
6
device.c
6
device.c
@ -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
2
iptv.c
@ -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 {
|
||||||
|
113
protocolcurl.c
113
protocolcurl.c
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
16
socket.c
16
socket.c
@ -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
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user