Optimized TS packet data flow.

This commit is contained in:
Rolf Ahrenberg 2009-02-26 16:04:12 +02:00
parent 73906ab698
commit 024ee7ba89
18 changed files with 105 additions and 149 deletions

View File

@ -84,3 +84,7 @@ VDR Plugin 'iptv' Revision History
- Fixed blacklisting of PAT section filter. - Fixed blacklisting of PAT section filter.
- Set max IPTV device count to VDR's max devices. - Set max IPTV device count to VDR's max devices.
- Fixed a possible crash in sid and pid scanners. - Fixed a possible crash in sid and pid scanners.
2009-xx-xx: Version 0.2.4
- Optimized TS packet data flow.

View File

@ -10,8 +10,7 @@
cIptvConfig IptvConfig; cIptvConfig IptvConfig;
cIptvConfig::cIptvConfig(void) cIptvConfig::cIptvConfig(void)
: readBufferTsCount(48), : tsBufferSize(2),
tsBufferSize(2),
tsBufferPrefillRatio(0), tsBufferPrefillRatio(0),
extProtocolBasePort(4321), extProtocolBasePort(4321),
useBytes(1), useBytes(1),

View File

@ -14,7 +14,6 @@
class cIptvConfig class cIptvConfig
{ {
private: private:
unsigned int readBufferTsCount;
unsigned int tsBufferSize; unsigned int tsBufferSize;
unsigned int tsBufferPrefillRatio; unsigned int tsBufferPrefillRatio;
unsigned int extProtocolBasePort; unsigned int extProtocolBasePort;
@ -25,7 +24,6 @@ private:
public: public:
cIptvConfig(); cIptvConfig();
unsigned int GetReadBufferTsCount(void) const { return readBufferTsCount; }
unsigned int GetTsBufferSize(void) const { return tsBufferSize; } unsigned int GetTsBufferSize(void) const { return tsBufferSize; }
unsigned int GetTsBufferPrefillRatio(void) const { return tsBufferPrefillRatio; } unsigned int GetTsBufferPrefillRatio(void) const { return tsBufferPrefillRatio; }
unsigned int GetExtProtocolBasePort(void) const { return extProtocolBasePort; } unsigned int GetExtProtocolBasePort(void) const { return extProtocolBasePort; }

View File

@ -20,21 +20,20 @@ cIptvDevice::cIptvDevice(unsigned int Index)
isPacketDelivered(false), isPacketDelivered(false),
isOpenDvr(false), isOpenDvr(false),
sidScanEnabled(false), sidScanEnabled(false),
pidScanEnabled(false), pidScanEnabled(false)
mutex()
{ {
//debug("cIptvDevice::cIptvDevice(%d)\n", deviceIndex); unsigned int bufsize = MEGABYTE(IptvConfig.GetTsBufferSize());
bufsize -= (bufsize % TS_SIZE);
isyslog("creating IPTV device %d (CardIndex=%d)", deviceIndex, CardIndex()); isyslog("creating IPTV device %d (CardIndex=%d)", deviceIndex, CardIndex());
tsBuffer = new cRingBufferLinear(MEGABYTE(IptvConfig.GetTsBufferSize()), tsBuffer = new cRingBufferLinear(bufsize + 1, TS_SIZE, false,
(TS_SIZE * IptvConfig.GetReadBufferTsCount()), *cString::sprintf("IPTV %d", deviceIndex));
false, "IPTV"); tsBuffer->SetTimeouts(10, 10);
tsBuffer->SetTimeouts(100, 100);
ResetBuffering(); ResetBuffering();
pUdpProtocol = new cIptvProtocolUdp(); pUdpProtocol = new cIptvProtocolUdp();
pHttpProtocol = new cIptvProtocolHttp(); pHttpProtocol = new cIptvProtocolHttp();
pFileProtocol = new cIptvProtocolFile(); pFileProtocol = new cIptvProtocolFile();
pExtProtocol = new cIptvProtocolExt(); pExtProtocol = new cIptvProtocolExt();
pIptvStreamer = new cIptvStreamer(tsBuffer, &mutex); pIptvStreamer = new cIptvStreamer(tsBuffer, (100 * TS_SIZE));
pPidScanner = new cPidScanner; pPidScanner = new cPidScanner;
// Initialize filter pointers // Initialize filter pointers
memset(secfilters, '\0', sizeof(secfilters)); memset(secfilters, '\0', sizeof(secfilters));
@ -356,12 +355,11 @@ void cIptvDevice::CloseFilter(int Handle)
bool cIptvDevice::OpenDvr(void) bool cIptvDevice::OpenDvr(void)
{ {
debug("cIptvDevice::OpenDvr(%d)\n", deviceIndex); debug("cIptvDevice::OpenDvr(%d)\n", deviceIndex);
mutex.Lock();
isPacketDelivered = false; isPacketDelivered = false;
tsBuffer->Clear(); tsBuffer->Clear();
mutex.Unlock();
ResetBuffering(); ResetBuffering();
pIptvStreamer->Open(); if (pIptvStreamer)
pIptvStreamer->Open();
if (sidScanEnabled && pSidScanner && IptvConfig.GetSectionFiltering()) if (sidScanEnabled && pSidScanner && IptvConfig.GetSectionFiltering())
pSidScanner->SetStatus(true); pSidScanner->SetStatus(true);
isOpenDvr = true; isOpenDvr = true;
@ -407,7 +405,7 @@ bool cIptvDevice::GetTSPacket(uchar *&Data)
{ {
int Count = 0; int Count = 0;
//debug("cIptvDevice::GetTSPacket(%d)\n", deviceIndex); //debug("cIptvDevice::GetTSPacket(%d)\n", deviceIndex);
if (!IsBuffering()) { if (tsBuffer && !IsBuffering()) {
if (isPacketDelivered) { if (isPacketDelivered) {
tsBuffer->Del(TS_SIZE); tsBuffer->Del(TS_SIZE);
isPacketDelivered = false; isPacketDelivered = false;
@ -432,8 +430,8 @@ bool cIptvDevice::GetTSPacket(uchar *&Data)
// Update pid statistics // Update pid statistics
AddPidStatistic(ts_pid(p), payload(p)); AddPidStatistic(ts_pid(p), payload(p));
// Send data also to dvr fifo // Send data also to dvr fifo
if ((dvrFd >= 0) && (write(dvrFd, p, TS_SIZE) != TS_SIZE)) if (dvrFd >= 0)
error("ERROR: write failed to FIFO\n"); Count = write(dvrFd, p, TS_SIZE);
// Analyze incomplete streams with built-in pid analyzer // Analyze incomplete streams with built-in pid analyzer
if (pidScanEnabled && pPidScanner) if (pidScanEnabled && pPidScanner)
pPidScanner->Process(p); pPidScanner->Process(p);
@ -446,7 +444,7 @@ bool cIptvDevice::GetTSPacket(uchar *&Data)
} }
} }
// Reduce cpu load by preventing busylooping // Reduce cpu load by preventing busylooping
cCondWait::SleepMs(100); cCondWait::SleepMs(10);
Data = NULL; Data = NULL;
return true; return true;
} }

2
iptv.c
View File

@ -20,7 +20,7 @@
#error "VDR-1.6.0 API version or greater is required!" #error "VDR-1.6.0 API version or greater is required!"
#endif #endif
static const char VERSION[] = "0.2.4"; static const char VERSION[] = "0.2.5";
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

@ -127,9 +127,9 @@ bool cIptvProtocolExt::Close(void)
return true; return true;
} }
int cIptvProtocolExt::Read(unsigned char* *BufferAddr) int cIptvProtocolExt::Read(unsigned char* BufferAddr, unsigned int BufferLen)
{ {
return cIptvUdpSocket::Read(BufferAddr); return cIptvUdpSocket::Read(BufferAddr, BufferLen);
} }
bool cIptvProtocolExt::Set(const char* Location, const int Parameter, const int Index) bool cIptvProtocolExt::Set(const char* Location, const int Parameter, const int Index)

View File

@ -25,7 +25,7 @@ private:
public: public:
cIptvProtocolExt(); cIptvProtocolExt();
virtual ~cIptvProtocolExt(); virtual ~cIptvProtocolExt();
int Read(unsigned char* *BufferAddr); int Read(unsigned char* BufferAddr, unsigned int BufferLen);
bool Set(const char* Location, const int Parameter, const int Index); bool Set(const char* Location, const int Parameter, const int Index);
bool Open(void); bool Open(void);
bool Close(void); bool Close(void);

View File

@ -16,15 +16,10 @@
cIptvProtocolFile::cIptvProtocolFile() cIptvProtocolFile::cIptvProtocolFile()
: fileDelay(0), : fileDelay(0),
readBufferLen(TS_SIZE * IptvConfig.GetReadBufferTsCount()),
isActive(false) isActive(false)
{ {
debug("cIptvProtocolFile::cIptvProtocolFile()\n"); debug("cIptvProtocolFile::cIptvProtocolFile()\n");
fileLocation = strdup(""); fileLocation = strdup("");
// Allocate receive buffer
readBuffer = MALLOC(unsigned char, readBufferLen);
if (!readBuffer)
error("ERROR: MALLOC() failed in ProtocolFile()");
} }
cIptvProtocolFile::~cIptvProtocolFile() cIptvProtocolFile::~cIptvProtocolFile()
@ -34,7 +29,6 @@ cIptvProtocolFile::~cIptvProtocolFile()
cIptvProtocolFile::Close(); cIptvProtocolFile::Close();
// Free allocated memory // Free allocated memory
free(fileLocation); free(fileLocation);
free(readBuffer);
} }
bool cIptvProtocolFile::OpenFile(void) bool cIptvProtocolFile::OpenFile(void)
@ -61,10 +55,9 @@ void cIptvProtocolFile::CloseFile(void)
} }
} }
int cIptvProtocolFile::Read(unsigned char* *BufferAddr) int cIptvProtocolFile::Read(unsigned char* BufferAddr, unsigned int BufferLen)
{ {
//debug("cIptvProtocolFile::Read()\n"); //debug("cIptvProtocolFile::Read()\n");
*BufferAddr = readBuffer;
// Check errors // Check errors
if (ferror(fileStream)) { if (ferror(fileStream)) {
debug("Read error\n"); debug("Read error\n");
@ -81,7 +74,7 @@ int cIptvProtocolFile::Read(unsigned char* *BufferAddr)
// during the sleep and buffers are disposed. Check here that the plugin is // during the sleep and buffers are disposed. Check here that the plugin is
// still active before accessing the buffers // still active before accessing the buffers
if (isActive) if (isActive)
return fread(readBuffer, sizeof(unsigned char), readBufferLen, fileStream); return fread(BufferAddr, sizeof(unsigned char), BufferLen, fileStream);
return -1; return -1;
} }

View File

@ -16,8 +16,6 @@ private:
char* fileLocation; char* fileLocation;
int fileDelay; int fileDelay;
FILE* fileStream; FILE* fileStream;
unsigned char* readBuffer;
unsigned int readBufferLen;
bool isActive; bool isActive;
private: private:
@ -27,7 +25,7 @@ private:
public: public:
cIptvProtocolFile(); cIptvProtocolFile();
virtual ~cIptvProtocolFile(); virtual ~cIptvProtocolFile();
int Read(unsigned char* *BufferAddr); int Read(unsigned char* BufferAddr, unsigned int BufferLen);
bool Set(const char* Location, const int Parameter, const int Index); bool Set(const char* Location, const int Parameter, const int Index);
bool Open(void); bool Open(void);
bool Close(void); bool Close(void);

View File

@ -45,7 +45,7 @@ bool cIptvProtocolHttp::Connect(void)
// First try only the IP address // First try only the IP address
sockAddr.sin_addr.s_addr = inet_addr(streamAddr); sockAddr.sin_addr.s_addr = inet_addr(streamAddr);
if (sockAddr.sin_addr.s_addr == INADDR_NONE) { if (sockAddr.sin_addr.s_addr == INADDR_NONE) {
debug("Cannot convert %s directly to internet address\n", streamAddr); debug("Cannot convert %s directly to internet address\n", streamAddr);
@ -214,9 +214,9 @@ bool cIptvProtocolHttp::Close(void)
return true; return true;
} }
int cIptvProtocolHttp::Read(unsigned char* *BufferAddr) int cIptvProtocolHttp::Read(unsigned char* BufferAddr, unsigned int BufferLen)
{ {
return cIptvTcpSocket::Read(BufferAddr); return cIptvTcpSocket::Read(BufferAddr, BufferLen);
} }
bool cIptvProtocolHttp::Set(const char* Location, const int Parameter, const int Index) bool cIptvProtocolHttp::Set(const char* Location, const int Parameter, const int Index)

View File

@ -27,7 +27,7 @@ private:
public: public:
cIptvProtocolHttp(); cIptvProtocolHttp();
virtual ~cIptvProtocolHttp(); virtual ~cIptvProtocolHttp();
int Read(unsigned char* *BufferAddr); int Read(unsigned char* BufferAddr, unsigned int BufferLen);
bool Set(const char* Location, const int Parameter, const int Index); bool Set(const char* Location, const int Parameter, const int Index);
bool Open(void); bool Open(void);
bool Close(void); bool Close(void);

View File

@ -12,7 +12,7 @@ class cIptvProtocolIf {
public: public:
cIptvProtocolIf() {} cIptvProtocolIf() {}
virtual ~cIptvProtocolIf() {} virtual ~cIptvProtocolIf() {}
virtual int Read(unsigned char* *BufferAddr) = 0; virtual int Read(unsigned char* BufferAddr, unsigned int BufferLen) = 0;
virtual bool Set(const char* Location, const int Parameter, const int Index) = 0; virtual bool Set(const char* Location, const int Parameter, const int Index) = 0;
virtual bool Open(void) = 0; virtual bool Open(void) = 0;
virtual bool Close(void) = 0; virtual bool Close(void) = 0;

View File

@ -91,9 +91,9 @@ bool cIptvProtocolUdp::Close(void)
return true; return true;
} }
int cIptvProtocolUdp::Read(unsigned char* *BufferAddr) int cIptvProtocolUdp::Read(unsigned char* BufferAddr, unsigned int BufferLen)
{ {
return cIptvUdpSocket::Read(BufferAddr); return cIptvUdpSocket::Read(BufferAddr, BufferLen);
} }
bool cIptvProtocolUdp::Set(const char* Location, const int Parameter, const int Index) bool cIptvProtocolUdp::Set(const char* Location, const int Parameter, const int Index)

View File

@ -23,7 +23,7 @@ private:
public: public:
cIptvProtocolUdp(); cIptvProtocolUdp();
virtual ~cIptvProtocolUdp(); virtual ~cIptvProtocolUdp();
int Read(unsigned char* *BufferAddr); int Read(unsigned char* BufferAddr, unsigned int BufferLen);
bool Set(const char* Location, const int Parameter, const int Index); bool Set(const char* Location, const int Parameter, const int Index);
bool Open(void); bool Open(void);
bool Close(void); bool Close(void);

106
socket.c
View File

@ -20,14 +20,9 @@
cIptvSocket::cIptvSocket() cIptvSocket::cIptvSocket()
: socketPort(0), : socketPort(0),
socketDesc(-1), socketDesc(-1),
readBufferLen(TS_SIZE * IptvConfig.GetReadBufferTsCount()),
isActive(false) isActive(false)
{ {
debug("cIptvSocket::cIptvSocket()\n"); debug("cIptvSocket::cIptvSocket()\n");
// Allocate receive buffer
readBuffer = MALLOC(unsigned char, readBufferLen);
if (!readBuffer)
error("ERROR: MALLOC() failed in socket()");
} }
cIptvSocket::~cIptvSocket() cIptvSocket::~cIptvSocket()
@ -35,8 +30,6 @@ cIptvSocket::~cIptvSocket()
debug("cIptvSocket::~cIptvSocket()\n"); debug("cIptvSocket::~cIptvSocket()\n");
// Close the socket // Close the socket
CloseSocket(); CloseSocket();
// Free allocated memory
free(readBuffer);
} }
bool cIptvSocket::OpenSocket(const int Port, const bool isUdp) bool cIptvSocket::OpenSocket(const int Port, const bool isUdp)
@ -50,7 +43,7 @@ bool cIptvSocket::OpenSocket(const int Port, const bool isUdp)
} }
// Bind to the socket if it is not active already // Bind to the socket if it is not active already
if (socketDesc < 0) { if (socketDesc < 0) {
int yes = 1; int yes = 1;
// Create socket // Create socket
if (isUdp) if (isUdp)
socketDesc = socket(PF_INET, SOCK_DGRAM, 0); socketDesc = socket(PF_INET, SOCK_DGRAM, 0);
@ -104,7 +97,7 @@ bool cIptvUdpSocket::OpenSocket(const int Port)
return cIptvSocket::OpenSocket(Port, true); return cIptvSocket::OpenSocket(Port, true);
} }
int cIptvUdpSocket::Read(unsigned char* *BufferAddr) int cIptvUdpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen)
{ {
//debug("cIptvUdpSocket::Read()\n"); //debug("cIptvUdpSocket::Read()\n");
// Error out if socket not initialized // Error out if socket not initialized
@ -113,51 +106,38 @@ int cIptvUdpSocket::Read(unsigned char* *BufferAddr)
return -1; return -1;
} }
socklen_t addrlen = sizeof(sockAddr); socklen_t addrlen = sizeof(sockAddr);
// Set argument point to read buffer int len = 0;
*BufferAddr = readBuffer; // Read data from socket
// Wait 500ms for data if (isActive)
int retval = select_single_desc(socketDesc, 500000, false); len = recvfrom(socketDesc, BufferAddr, BufferLen, MSG_DONTWAIT,
// Check if error (struct sockaddr *)&sockAddr, &addrlen);
if (retval < 0) if ((len > 0) && (BufferAddr[0] == 0x47)) {
return retval; return len;
// Check if data available }
else if (retval) { else if (len > 3) {
int len = 0; // http://www.networksorcery.com/enp/rfc/rfc2250.txt
// Read data from socket // version
if (isActive) unsigned int v = (BufferAddr[0] >> 6) & 0x03;
len = recvfrom(socketDesc, readBuffer, readBufferLen, MSG_DONTWAIT, // extension bit
(struct sockaddr *)&sockAddr, &addrlen); unsigned int x = (BufferAddr[0] >> 4) & 0x01;
ERROR_IF_RET(len < 0, "recvfrom()", return len); // cscr count
if ((len > 0) && (readBuffer[0] == 0x47)) { unsigned int cc = BufferAddr[0] & 0x0F;
// Set argument point to read buffer // payload type: MPEG2 TS = 33
*BufferAddr = &readBuffer[0]; //unsigned int pt = readBuffer[1] & 0x7F;
return len; // header lenght
unsigned int headerlen = (3 + cc) * sizeof(uint32_t);
// check if extension
if (x) {
// extension header length
unsigned int ehl = (((BufferAddr[headerlen + 2] & 0xFF) << 8) | (BufferAddr[headerlen + 3] & 0xFF));
// update header length
headerlen += (ehl + 1) * sizeof(uint32_t);
} }
else if (len > 3) { // Check that rtp is version 2 and payload contains multiple of TS packet data
// http://www.networksorcery.com/enp/rfc/rfc2250.txt if ((v == 2) && (((len - headerlen) % TS_SIZE) == 0) && (BufferAddr[headerlen] == 0x47)) {
// version // Set argument point to payload in read buffer
unsigned int v = (readBuffer[0] >> 6) & 0x03; memmove(BufferAddr, &BufferAddr[headerlen], (len - headerlen));
// extension bit return (len - headerlen);
unsigned int x = (readBuffer[0] >> 4) & 0x01;
// cscr count
unsigned int cc = readBuffer[0] & 0x0F;
// payload type: MPEG2 TS = 33
//unsigned int pt = readBuffer[1] & 0x7F;
// header lenght
unsigned int headerlen = (3 + cc) * sizeof(uint32_t);
// check if extension
if (x) {
// extension header length
unsigned int ehl = (((readBuffer[headerlen + 2] & 0xFF) << 8) | (readBuffer[headerlen + 3] & 0xFF));
// update header length
headerlen += (ehl + 1) * sizeof(uint32_t);
}
// Check that rtp is version 2 and payload contains multiple of TS packet data
if ((v == 2) && (((len - headerlen) % TS_SIZE) == 0) && (readBuffer[headerlen] == 0x47)) {
// Set argument point to payload in read buffer
*BufferAddr = &readBuffer[headerlen];
return (len - headerlen);
}
} }
} }
return 0; return 0;
@ -180,7 +160,7 @@ bool cIptvTcpSocket::OpenSocket(const int Port)
return cIptvSocket::OpenSocket(Port, false); return cIptvSocket::OpenSocket(Port, false);
} }
int cIptvTcpSocket::Read(unsigned char* *BufferAddr) int cIptvTcpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen)
{ {
//debug("cIptvTcpSocket::Read()\n"); //debug("cIptvTcpSocket::Read()\n");
// Error out if socket not initialized // Error out if socket not initialized
@ -189,19 +169,9 @@ int cIptvTcpSocket::Read(unsigned char* *BufferAddr)
return -1; return -1;
} }
socklen_t addrlen = sizeof(sockAddr); socklen_t addrlen = sizeof(sockAddr);
// Set argument point to read buffer // Read data from socket
*BufferAddr = readBuffer; if (isActive)
// Wait 500ms for data return recvfrom(socketDesc, BufferAddr, BufferLen, MSG_DONTWAIT,
int retval = select_single_desc(socketDesc, 500000, false); (struct sockaddr *)&sockAddr, &addrlen);
// Check if error
if (retval < 0)
return retval;
// Check if data available
else if (retval) {
// Read data from socket
if (isActive)
return recvfrom(socketDesc, readBuffer, readBufferLen, MSG_DONTWAIT,
(struct sockaddr *)&sockAddr, &addrlen);
}
return 0; return 0;
} }

View File

@ -14,8 +14,6 @@ class cIptvSocket {
protected: protected:
int socketPort; int socketPort;
int socketDesc; int socketDesc;
unsigned char* readBuffer;
unsigned int readBufferLen;
struct sockaddr_in sockAddr; struct sockaddr_in sockAddr;
bool isActive; bool isActive;
@ -32,7 +30,7 @@ class cIptvUdpSocket : public cIptvSocket {
public: public:
cIptvUdpSocket(); cIptvUdpSocket();
virtual ~cIptvUdpSocket(); virtual ~cIptvUdpSocket();
virtual int Read(unsigned char* *BufferAddr); virtual int Read(unsigned char* BufferAddr, unsigned int BufferLen);
bool OpenSocket(const int Port); bool OpenSocket(const int Port);
}; };
@ -40,7 +38,7 @@ class cIptvTcpSocket : public cIptvSocket {
public: public:
cIptvTcpSocket(); cIptvTcpSocket();
virtual ~cIptvTcpSocket(); virtual ~cIptvTcpSocket();
virtual int Read(unsigned char* *BufferAddr); virtual int Read(unsigned char* BufferAddr, unsigned int BufferLen);
bool OpenSocket(const int Port); bool OpenSocket(const int Port);
}; };

View File

@ -11,13 +11,19 @@
#include "common.h" #include "common.h"
#include "streamer.h" #include "streamer.h"
cIptvStreamer::cIptvStreamer(cRingBufferLinear* RingBuffer, cMutex* Mutex) cIptvStreamer::cIptvStreamer(cRingBufferLinear* RingBuffer, unsigned int PacketLen)
: cThread("IPTV streamer"), : cThread("IPTV streamer"),
ringBuffer(RingBuffer), ringBuffer(RingBuffer),
mutex(Mutex), packetBufferLen(PacketLen),
protocol(NULL) protocol(NULL)
{ {
debug("cIptvStreamer::cIptvStreamer()\n"); debug("cIptvStreamer::cIptvStreamer(%d)\n", packetBufferLen);
// Allocate packet buffer
packetBuffer = MALLOC(unsigned char, packetBufferLen);
if (packetBuffer)
memset(packetBuffer, 0, packetBufferLen);
else
error("ERROR: MALLOC() failed for packet buffer");
} }
cIptvStreamer::~cIptvStreamer() cIptvStreamer::~cIptvStreamer()
@ -25,32 +31,31 @@ cIptvStreamer::~cIptvStreamer()
debug("cIptvStreamer::~cIptvStreamer()\n"); debug("cIptvStreamer::~cIptvStreamer()\n");
// Close the protocol // Close the protocol
Close(); Close();
// Free allocated memory
free(packetBuffer);
} }
void cIptvStreamer::Action(void) void cIptvStreamer::Action(void)
{ {
debug("cIptvStreamer::Action(): Entering\n"); debug("cIptvStreamer::Action(): Entering\n");
// Increase priority
//SetPriority(-1);
// Do the thread loop // Do the thread loop
while (Running()) { while (packetBuffer && Running()) {
if (ringBuffer && mutex && protocol && ringBuffer->Free()) { int length = -1;
unsigned char *buffer = NULL; if (protocol)
mutex->Lock(); length = protocol->Read(packetBuffer, packetBufferLen);
int length = protocol->Read(&buffer); if (length >= 0) {
if (length >= 0) { AddStreamerStatistic(length);
AddStreamerStatistic(length); if (ringBuffer) {
int p = ringBuffer->Put(buffer, length); int p = ringBuffer->Put(packetBuffer, length);
if (p != length && Running()) if (p != length)
ringBuffer->ReportOverflow(length - p); ringBuffer->ReportOverflow(length - p);
mutex->Unlock(); }
} }
else { else
mutex->Unlock(); sleep.Wait(10); // to avoid busy loop and reduce cpu load
sleep.Wait(100); // to reduce cpu load }
}
}
else
sleep.Wait(100); // and avoid busy loop
}
debug("cIptvStreamer::Action(): Exiting\n"); debug("cIptvStreamer::Action(): Exiting\n");
} }
@ -72,15 +77,9 @@ bool cIptvStreamer::Close(void)
sleep.Signal(); sleep.Signal();
if (Running()) if (Running())
Cancel(3); Cancel(3);
// Close the protocol. A mutex should be taken here to avoid a race condition // Close the protocol
// where thread Action() may be in the process of accessing the protocol.
// Taking a mutex serializes the Close() and Action() -calls.
if (mutex)
mutex->Lock();
if (protocol) if (protocol)
protocol->Close(); protocol->Close();
if (mutex)
mutex->Unlock();
return true; return true;
} }

View File

@ -19,14 +19,13 @@
class cIptvStreamer : public cThread, public cIptvStreamerStatistics { class cIptvStreamer : public cThread, public cIptvStreamerStatistics {
private: private:
cRingBufferLinear* ringBuffer; cRingBufferLinear* ringBuffer;
cMutex* mutex;
cCondWait sleep; cCondWait sleep;
unsigned char* readBuffer; unsigned char* packetBuffer;
unsigned int readBufferLen; unsigned int packetBufferLen;
cIptvProtocolIf* protocol; cIptvProtocolIf* protocol;
public: public:
cIptvStreamer(cRingBufferLinear* RingBuffer, cMutex* Mutex); cIptvStreamer(cRingBufferLinear* RingBuffer, unsigned int PacketLen);
virtual ~cIptvStreamer(); virtual ~cIptvStreamer();
virtual void Action(void); virtual void Action(void);
bool Set(const char* Location, const int Parameter, const int Index, cIptvProtocolIf* Protocol); bool Set(const char* Location, const int Parameter, const int Index, cIptvProtocolIf* Protocol);