diff options
Diffstat (limited to 'tools')
38 files changed, 0 insertions, 7576 deletions
diff --git a/tools/backgroundwriter.c b/tools/backgroundwriter.c deleted file mode 100644 index f13a52a7..00000000 --- a/tools/backgroundwriter.c +++ /dev/null @@ -1,486 +0,0 @@ -/* - * backgroundwriter.h: Buffered socket/file writing thread - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: backgroundwriter.c,v 1.6 2008-02-04 23:54:06 phintuka Exp $ - * - */ - -#define __STDC_FORMAT_MACROS -#define __STDC_CONSTANT_MACROS -#include <inttypes.h> - -#include <stdint.h> -#include <unistd.h> -#include <netinet/tcp.h> // CORK, NODELAY - -#include <vdr/tools.h> - -#include "../logdefs.h" -#include "../xine_input_vdr_net.h" // stream_tcp_header_t - -#include "backgroundwriter.h" - -//#define DISABLE_DISCARD -//#define LOG_DISCARDS - -#define MAX_OVERFLOWS_BEFORE_DISCONNECT 1000 // ~ 1 second - - -// -// cBackgroundWriterI -// - -cBackgroundWriterI::cBackgroundWriterI(int fd, int Size, int Margin) - : m_RingBuffer(Size, Margin) -{ - m_fd = fd; - m_RingBuffer.SetTimeouts(0, 100); - m_Active = true; - - m_PutPos = 0; - m_DiscardStart = 0; - m_DiscardEnd = 0; - - m_BufferOverflows = 0; - -#if defined(TCP_CORK) - int iCork = 1; - if(setsockopt(m_fd, IPPROTO_TCP, TCP_CORK, &iCork, sizeof(int))) { - if(errno != ENOTSOCK) - LOGERR("cBackgroundWriter: setsockopt(TCP_CORK) failed"); - m_IsSocket = false; - errno = 0; - } else { - m_IsSocket = true; - } -#elif defined(TCP_NOPUSH) - int iCork = 1; - if(setsockopt(m_fd, IPPROTO_TCP, TCP_NOPUSH, &iCork, sizeof(int))) { - if(errno != ENOTSOCK) - LOGERR("cBackgroundWriter: setsockopt(TCP_NOPUSH) failed"); - m_IsSocket = false; - errno = 0; - } else { - m_IsSocket = true; - } -#endif - - LOGDBG("cBackgroundWriterI initialized (buffer %d kb)", Size/1024); -} - -cBackgroundWriterI::~cBackgroundWriterI() -{ - m_Active = false; - Cancel(3); -} - -int cBackgroundWriterI::Free(void) -{ - return m_RingBuffer.Free(); -} - -void cBackgroundWriterI::Clear(void) -{ - // Can't just drop buffer contents or PES frames will be broken. - // Serialize with Put - LOCK_THREAD; - m_DiscardEnd = m_PutPos; -} - -bool cBackgroundWriterI::Flush(int TimeoutMs) -{ - uint64_t WaitEnd = cTimeMs::Now(); - - // wait for ring buffer to drain - if(TimeoutMs > 0) { - WaitEnd += (uint64_t)TimeoutMs; - - while(cTimeMs::Now() < WaitEnd && - m_Active && - m_RingBuffer.Available() > 0) - cCondWait::SleepMs(3); - } - - if(m_IsSocket && m_RingBuffer.Available() <= 0) { - // flush corked data too -#if defined(TCP_CORK) - int i = 1; - if(setsockopt(m_fd, IPPROTO_TCP, TCP_NODELAY, &i, sizeof(int))) { - LOGERR("cBackgroundWriter: setsockopt(TCP_NODELAY) failed"); - errno = 0; - } -#elif defined(TCP_NOPUSH) - int On = 1, Off = 0; - if(setsockopt(m_fd, IPPROTO_TCP, TCP_NOPUSH, &Off, sizeof(int)) || - setsockopt(m_fd, IPPROTO_TCP, TCP_NOPUSH, &On, sizeof(int))) { - LOGERR("cBackgroundWriter: setsockopt(TCP_NOPUSH) failed"); - errno = 0; - } -#endif - } - - return m_RingBuffer.Available() <= 0; -} - - -// -// cTcpWriter -// - -cTcpWriter::cTcpWriter(int fd, int Size) : - cBackgroundWriterI(fd, Size, sizeof(stream_tcp_header_t)) -{ - LOGDBG("cTcpWriter initialized (buffer %d kb)", Size/1024); - Start(); -} - -void cTcpWriter::Action(void) -{ - uint64_t NextHeaderPos = 0ULL; - uint64_t GetPos = 0ULL; - cPoller Poller(m_fd, true); - - while(m_Active) { - - if(Poller.Poll(100)) { - - int Count = 0, n; - uchar *Data = m_RingBuffer.Get(Count); - - if(Data && Count > 0) { - -#ifndef DISABLE_DISCARD - Lock(); // uint64_t m_DiscardStart can not be read atomically (IA32) - if(m_DiscardEnd > GetPos) { - -# ifdef LOG_DISCARDS - LOGMSG("TCP: queue: discard request: queue %d bytes, " - "next point %d bytes forward (Count=%d)", - m_RingBuffer.Available(), - NextHeaderPos - GetPos, - Count); -# endif - if(NextHeaderPos == GetPos) { - // we're at frame boundary -# ifdef LOG_DISCARDS - uint8_t *pkt = TCP_PAYLOAD(Data); - if(pkt[0] || pkt[1] || pkt[2] != 1 || hdr->len > 2100) { - LOGMSG(" -> %x %x %x %x", pkt[0], pkt[1], pkt[2], pkt[3]); - } -# endif - Count = min(Count, (int)(m_DiscardEnd - GetPos)); -# ifdef LOG_DISCARDS - LOGMSG("Flushing %d bytes", Count); -#endif - Unlock(); - - m_RingBuffer.Del(Count); - GetPos += Count; - NextHeaderPos = GetPos; -# ifdef LOG_DISCARDS - LOGMSG("Queue now %d bytes", m_RingBuffer.Available()); - pkt = TCP_PAYLOAD(Data); - if(pkt[0] || pkt[1] || pkt[2] != 1 || hdr->len > 2100) { - LOGMSG(" -> %x %x %x %x", pkt[0], pkt[1], pkt[2], pkt[3]); -# endif - continue; - } - } - Unlock(); -#endif - -#ifndef DISABLE_DISCARD - if(GetPos == NextHeaderPos) { - if(Count < (int)sizeof(stream_tcp_header_t)) - LOGMSG("cBackgroundWriter @NextHeaderPos: Count < header size !"); - - stream_tcp_header_t *header = (stream_tcp_header_t*)Data; - if(Count < (int)(ntohl(header->len) + sizeof(stream_tcp_header_t))) - ;//LOGMSG("Count = %d < %d", Count, - // header->len + sizeof(stream_tcp_header_t)); - else - Count = ntohl(header->len) + sizeof(stream_tcp_header_t); - NextHeaderPos = GetPos + ntohl(header->len) + sizeof(stream_tcp_header_t); - } else { - Count = min(Count, (int)(NextHeaderPos-GetPos)); - } -#endif - - errno = 0; - n = write(m_fd, Data, Count); - - if(n == 0) { - LOGERR("cBackgroundWriter: Client disconnected data stream ?"); - break; - - } else if(n < 0) { - - if (errno == EINTR || errno == EWOULDBLOCK) { - TRACE("cBackgroundWriter: EINTR while writing to file handle " - <<m_fd<<" - retrying"); - continue; - - } else { - LOGERR("cBackgroundWriter: TCP write error"); - break; - } - } - - GetPos += n; - m_RingBuffer.Del(n); - } - } - } - - m_RingBuffer.Clear(); - m_Active = false; -} - -int cTcpWriter::Put(uint64_t StreamPos, - const uchar *Data, int DataCount) -{ - stream_tcp_header_t header; - header.pos = htonull(StreamPos); - header.len = htonl(DataCount); - return Put((uchar*)&header, sizeof(header), Data, DataCount); -} - -int cTcpWriter::Put(const uchar *Header, int HeaderCount, - const uchar *Data, int DataCount) -{ - if(m_Active) { - - // Serialize Put access to keep Data and Header together - LOCK_THREAD; - - if(m_RingBuffer.Free() < HeaderCount+DataCount) { - //LOGMSG("cXinelibServer: TCP buffer overflow !"); - if(m_BufferOverflows++ > MAX_OVERFLOWS_BEFORE_DISCONNECT) { - LOGMSG("cXinelibServer: Too many TCP buffer overflows, dropping client"); - m_RingBuffer.Clear(); - m_Active = false; - return 0; - } - return -HeaderCount-DataCount; - } - int n = m_RingBuffer.Put(Header, HeaderCount) + - m_RingBuffer.Put(Data, DataCount); - if(n == HeaderCount+DataCount) { - m_BufferOverflows = 0; - m_PutPos += n; - return n; - } - - LOGMSG("cXinelibServer: TCP buffer internal error ?!?"); - m_RingBuffer.Clear(); - m_Active = false; - } - - return 0; -} - - -// -// cRawWriter -// - -#include "pes.h" - -cRawWriter::cRawWriter(int fd, int Size) : - cBackgroundWriterI(fd, Size, 6) -{ - LOGDBG("cRawWriter initialized (buffer %d kb)", Size/1024); - Start(); -} - -void cRawWriter::Action(void) -{ - uint64_t NextHeaderPos = 0ULL; - uint64_t GetPos = 0ULL; - cPoller Poller(m_fd, true); - - while(m_Active) { - - if(Poller.Poll(100)) { - - int Count = 0, n; - uchar *Data = m_RingBuffer.Get(Count); - - if(Data && Count > 0) { - -#ifndef DISABLE_DISCARD - Lock(); // uint64_t m_DiscardStart can not be read atomically (IA32) - if(m_DiscardEnd > GetPos) { - - if(NextHeaderPos == GetPos) { - // we're at frame boundary - Count = min(Count, (int)(m_DiscardEnd - GetPos)); - Unlock(); - - m_RingBuffer.Del(Count); - GetPos += Count; - NextHeaderPos = GetPos; - continue; - } - } - Unlock(); -#endif - -#ifndef DISABLE_DISCARD - if(GetPos == NextHeaderPos) { - if(Count < 6) - LOGMSG("cBackgroundWriter @NextHeaderPos: Count < header size !"); - int packlen = pes_packet_len(Data, Count); - if(Count < packlen) - ;//LOGMSG("Count = %d < %d", Count, - // header->len + sizeof(stream_tcp_header_t)); - else - Count = packlen; - NextHeaderPos = GetPos + packlen; - } else { - Count = min(Count, (int)(NextHeaderPos-GetPos)); - } -#endif - - errno = 0; - n = write(m_fd, Data, Count); - - if(n == 0) { - LOGERR("cBackgroundWriter: Client disconnected data stream ?"); - break; - - } else if(n < 0) { - - if (errno == EINTR || errno == EWOULDBLOCK) { - TRACE("cBackgroundWriter: EINTR while writing to file handle " - <<m_fd<<" - retrying"); - continue; - - } else { - LOGERR("cBackgroundWriter: TCP write error"); - break; - } - } - - GetPos += n; - m_RingBuffer.Del(n); - } - } - } - - m_RingBuffer.Clear(); - m_Active = false; -} - -int cRawWriter::Put(uint64_t StreamPos, - const uchar *Data, int DataCount) -{ - if(m_Active) { - - // Serialize Put access to keep Data and Header together - LOCK_THREAD; - - if(m_RingBuffer.Free() < DataCount) { - if(m_BufferOverflows++ > MAX_OVERFLOWS_BEFORE_DISCONNECT) { - LOGMSG("cXinelibServer: Too many TCP buffer overflows, dropping client"); - m_RingBuffer.Clear(); - m_Active = false; - return 0; - } - return -DataCount; - } - int n = m_RingBuffer.Put(Data, DataCount); - if(n == DataCount) { - m_BufferOverflows = 0; - m_PutPos += n; - return n; - } - - LOGMSG("cXinelibServer: TCP buffer internal error ?!?"); - m_RingBuffer.Clear(); - m_Active = false; - } - - return 0; -} - - -// -// cTsWriter -// - Demux PES stream to PS -// - -cTsWriter::cTsWriter(int fd, int Size) : - cBackgroundWriterI(fd, Size, 6) -{ - LOGDBG("cTsWriter initialized (buffer %d kb)", Size/1024); - Start(); -} - - -void cTsWriter::Action(void) -{ -} - -int cTsWriter::Put(uint64_t StreamPos, const uchar *Data, int DataCount) -{ - return 0; -} - - -// -// cRtspMuxWriter -// - RTSP multiplexed control+data -// - Each encapsulated PES frame is written atomically to socket buffer -// - Atomic control data can be written directly to socket -// from another thread to bypass buffer -// - -cRtspMuxWriter::cRtspMuxWriter(int fd, int Size) : - cBackgroundWriterI(fd, Size, 6) -{ - LOGDBG("cRtspMuxWriter initialized (buffer %d kb)", Size/1024); - Start(); -} - -void cRtspMuxWriter::Action(void) -{ -} - -int cRtspMuxWriter::Put(uint64_t StreamPos, const uchar *Data, int DataCount) -{ - return 0; -} - - -// -// cRtspRemuxWriter -// - RTSP multiplexed control+data -// - Demux PES stream to independent ES streams -// - encapsulate ES to RTP/AVP compatible frames -// - Mux RTP/AVP ES streams to pipelined RTCP control connection -// - Each encapsulated frame is written atomically to socket buffer -// - Atomic control data can be written directly to socket -// from another thread to bypass buffer -// - -cRtspRemuxWriter::cRtspRemuxWriter(int fd, int Size) : - cBackgroundWriterI(fd, Size, 6) -{ - LOGDBG("cRtspRemuxWriter initialized (buffer %d kb)", Size/1024); - Start(); -} - -void cRtspRemuxWriter::Action(void) -{ -} - -int cRtspRemuxWriter::Put(uint64_t StreamPos, const uchar *Data, int DataCount) -{ - return 0; -} - - diff --git a/tools/backgroundwriter.h b/tools/backgroundwriter.h deleted file mode 100644 index 7119047e..00000000 --- a/tools/backgroundwriter.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * backgroundwriter.h: Buffered socket/file writing thread - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: backgroundwriter.h,v 1.4 2007-01-07 05:36:30 phintuka Exp $ - * - */ - -#ifndef __BACKGROUNDWRITER_H -#define __BACKGROUNDWRITER_H - -#include <stdint.h> - -#include <vdr/thread.h> -#include <vdr/ringbuffer.h> - -// -// cBackgroundWriterI -// - generic interface for buffered output -// -class cBackgroundWriterI : public cThread -{ - protected: - cRingBufferLinear m_RingBuffer; - - volatile bool m_Active; - int m_fd; - bool m_IsSocket; - - uint64_t m_PutPos; - uint64_t m_DiscardStart; - uint64_t m_DiscardEnd; - - int m_BufferOverflows; - - protected: - virtual void Action(void) = 0; - - public: - cBackgroundWriterI(int fd, int Size = KILOBYTE(512), int Margin = 0); - virtual ~cBackgroundWriterI(); - - // Add PES frame to buffer - // - // Return value: - // Success: Count (all bytes pushed to queue) - // Error: 0 (write error ; socket disconnected) - // Buffer full: -Count (no bytes will be pushed to queue) - // - virtual int Put(uint64_t StreamPos, const uchar *Data, int DataCount) = 0; - - int Free(void); // Return largest possible Put size - void Clear(void); // Drop all data (only complete frames) from buffer - bool Flush(int TimeoutMs); // Flush buffer (wait for data to be sent) -}; - - -// -// cTcpWriter -// - xineliboutput TCP data steam -// - stream_tcp_header_t encapsulated PES frames -// -class cTcpWriter : public cBackgroundWriterI -{ - protected: - virtual void Action(void); - - int Put(const uchar *Header, int HeaderCount, - const uchar *Data, int DataCount); - - public: - cTcpWriter(int fd, int Size = KILOBYTE(512)); - virtual ~cTcpWriter() {}; - - virtual int Put(uint64_t StreamPos, const uchar *Data, int DataCount); -}; - - -// -// cRawWriter -// - Raw PES stream -// - Used with HTTP -// -class cRawWriter : public cBackgroundWriterI -{ - protected: - virtual void Action(void); - - public: - cRawWriter(int fd, int Size = KILOBYTE(512)); - virtual ~cRawWriter() {}; - - virtual int Put(uint64_t StreamPos, const uchar *Data, int DataCount); -}; - - -// -// cTsWriter -// - Demux PES stream to PS -// -class cTsWriter : public cBackgroundWriterI -{ - protected: - virtual void Action(void); - - public: - cTsWriter(int fd, int Size = KILOBYTE(512)); - virtual ~cTsWriter() {}; - - virtual int Put(uint64_t StreamPos, const uchar *Data, int DataCount); -}; - - -// -// cRtspMuxWriter -// - RTSP multiplexed control+data -// - Each encapsulated PES frame is written atomically to socket buffer -// - Atomic control data can be written directly to socket -// from another thread to bypass buffer -// - -class cRtspMuxWriter : public cBackgroundWriterI -{ - protected: - virtual void Action(void); - - public: - cRtspMuxWriter(int fd, int Size = KILOBYTE(512)); - virtual ~cRtspMuxWriter() {}; - - virtual int Put(uint64_t StreamPos, const uchar *Data, int DataCount); -}; - - -// -// cRtspRemuxWriter -// - RTSP multiplexed control+data -// - Demux PES stream to independent ES streams -// - encapsulate ES to RTP/AVP compatible frames -// - Mux RTP/AVP ES streams to pipelined RTCP control connection -// - Each encapsulated frame is written atomically to socket buffer -// - Atomic control data can be written directly to socket -// from another thread to bypass buffer -// - -class cRtspRemuxWriter : public cBackgroundWriterI -{ - protected: - virtual void Action(void); - - public: - cRtspRemuxWriter(int fd, int Size = KILOBYTE(512)); - virtual ~cRtspRemuxWriter() {}; - - virtual int Put(uint64_t StreamPos, const uchar *Data, int DataCount); -}; - - -#endif diff --git a/tools/bitstream.h b/tools/bitstream.h deleted file mode 100644 index 066fb2fe..00000000 --- a/tools/bitstream.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * bitstream.h: generic bitstream parsing - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: bitstream.h,v 1.2 2008-02-04 22:41:14 phintuka Exp $ - * - */ - -#ifndef _XINELIBOUTPUT_BITSTREAM_H_ -#define _XINELIBOUTPUT_BITSTREAM_H_ - -#include <stdint.h> - - -# ifdef NOCACHE - -typedef struct { - const uint8_t *data; - int count; /* in bits */ - int index; /* in bits */ -} br_state; - -#define BR_INIT(data,bytes) { (data), 8*(bytes), 0 } - -#define BR_EOF(br) ((br)->index >= (br)->count) - -static inline void br_init(br_state *br, const uint8_t *data, int bytes) -{ - br->data = data; - br->count = 8*bytes; - br->index = 0; -} - -static inline int br_get_bit(br_state *br) -{ - if(br->index >= br->count) - return 1; /* -> no infinite colomb's ... */ - - int r = (br->data[br->index>>3] >> (7 - (br->index&7))) & 1; - br->index++; - return r; -} - -static inline uint32_t br_get_bits(br_state *br, uint32_t n) -{ - uint32_t r = 0; - while(n--) - r = r | (br_get_bit(br) << n); - return r; -} - -#define br_skip_bit(br) br_skip_bits(br,1) - -static inline void br_skip_bits(br_state *br, int n) -{ - br->index += n; -} - - -# else /* NOCACHE */ - - -typedef struct { - uint8_t *data; - uint8_t *data_end; - uint32_t cache; - uint32_t cache_bits; -} br_state; - -#define BR_INIT(data,bytes) { (data), (data)+(bytes), 0, 0 } - -static inline void br_init(br_state *br, const uint8_t *data, int bytes) -{ - br->data = data; - br->data_end = data + bytes; - br->cache = 0; - br->cache_bits = 0; -} - -#define BR_GET_BYTE(br) \ - (br->data < br->data_end ? *br->data++ : 0xff) - -#define BR_EOF(br) ((br)->data >= (br)->data_end) - -static inline uint32_t br_get_bits(br_state *br, uint32_t n) -{ - if(n > 24) - return (br_get_bits(br, 16) << 16) | br_get_bits(br, n-16); - - while (br->cache_bits < 24) { - br->cache = (br->cache<<8) | BR_GET_BYTE(br); - br->cache_bits += 8; - } - - br->cache_bits -= n; - return (br->cache >> br->cache_bits) & ((1<<n) - 1); -} - -static inline int br_get_bit(br_state *br) -{ - if(!br->cache_bits) { - br->cache = BR_GET_BYTE(br); - br->cache_bits = 7; - } else { - br->cache_bits--; - } - return (br->cache >> br->cache_bits) & 1; -} - -static inline void br_skip_bit(br_state *br) -{ - if(!br->cache_bits) { - br->cache = BR_GET_BYTE(br); - br->cache_bits = 7; - } else { - br->cache_bits--; - } -} - -static inline void br_skip_bits(br_state *br, int n) -{ - if(br->cache_bits >= n) { - br->cache_bits -= n; - } else { - /* drop cached bits */ - n -= br->cache_bits; - - /* drop full bytes */ - br->data += (n >> 3); - n &= 7; - - /* update cache */ - if(n) { - br->cache = BR_GET_BYTE(br); - br->cache_bits = 8 - n; - } else { - br->cache_bits = 0; - } - } -} - - -# endif /* NOCACHE */ - - -#define br_get_u8(br) br_get_bits(br, 8) -#define br_get_u16(br) ((br_get_bits(br, 8)<<8) | br_get_bits(br, 8)) - -static inline uint32_t br_get_ue_golomb(br_state *br) -{ - int n = 0; - while (!br_get_bit(br) && n < 32) - n++; - return n ? ((1<<n) - 1) + br_get_bits(br, n) : 0; -} - -static inline int32_t br_get_se_golomb(br_state *br) -{ - uint32_t r = br_get_ue_golomb(br) + 1; - return (r&1) ? -(r>>1) : (r>>1); -} - -static inline void br_skip_golomb(br_state *br) -{ - int n = 0; - while (!br_get_bit(br) && n < 32) - n++; - br_skip_bits(br, n); -} - -#define br_skip_ue_golomb(br) br_skip_golomb(br) -#define br_skip_se_golomb(br) br_skip_golomb(br) - - -#endif /* _XINELIBOUTPUT_BITSTREAM_H_ */ diff --git a/tools/cxsocket.c b/tools/cxsocket.c deleted file mode 100644 index e6a95a72..00000000 --- a/tools/cxsocket.c +++ /dev/null @@ -1,430 +0,0 @@ -/* - * cxsocket.c: Socket wrapper classes - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: cxsocket.c,v 1.11 2007-03-27 02:45:48 phintuka Exp $ - * - */ - -#define __STDC_FORMAT_MACROS -#include <inttypes.h> - -#include <stdlib.h> -#include <stdarg.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/ioctl.h> -#ifndef __APPLE__ -# include <sys/sendfile.h> -#endif -#include <netinet/tcp.h> - -#include <vdr/config.h> -#include <vdr/tools.h> - -#include "../logdefs.h" - -#include "cxsocket.h" - -bool cxSocket::connect(struct sockaddr *addr, socklen_t len) -{ - return ::connect(m_fd, addr, len) == 0; -} - -bool cxSocket::connect(const char *ip, int port) -{ - struct sockaddr_in sin; - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - sin.sin_addr.s_addr = inet_addr(ip); - return connect((struct sockaddr *)&sin, sizeof(sin)); -} - -bool cxSocket::set_blocking(bool state) -{ - int flags = fcntl (m_fd, F_GETFL); - - if(flags == -1) { - LOGERR("cxSocket::SetBlocking: fcntl(F_GETFL) failed"); - return false; - } - - flags = state ? (flags&(~O_NONBLOCK)) : (flags|O_NONBLOCK); - - if(fcntl (m_fd, F_SETFL, flags) == -1) { - LOGERR("cxSocket::SetBlocking: fcntl(F_SETFL) failed"); - return false; - } - - return true; -} - -bool cxSocket::set_buffers(int Tx, int Rx) -{ - int max_buf = Tx; - /*while(max_buf) {*/ - errno = 0; - if(setsockopt(m_fd, SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(int))) { - LOGERR("cxSocket: setsockopt(SO_SNDBUF,%d) failed", max_buf); - /*max_buf >>= 1;*/ - } - /*else {*/ - int tmp = 0; - int len = sizeof(int); - errno = 0; - if(getsockopt(m_fd, SOL_SOCKET, SO_SNDBUF, &tmp, (socklen_t*)&len)) { - LOGERR("cxSocket: getsockopt(SO_SNDBUF,%d) failed", max_buf); - /*break;*/ - } else if(tmp != max_buf) { - LOGDBG("cxSocket: setsockopt(SO_SNDBUF): got %d bytes", tmp); - /*max_buf >>= 1;*/ - /*continue;*/ - } - /*}*/ - /*}*/ - - max_buf = Rx; - setsockopt(m_fd, SOL_SOCKET, SO_RCVBUF, &max_buf, sizeof(int)); - - return true; -} - -bool cxSocket::set_multicast(int ttl) -{ - int iReuse = 1, iLoop = 1, iTtl = ttl; - - errno = 0; - - if(setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, &iReuse, sizeof(int)) < 0) { - LOGERR("cxSocket: setsockopt(SO_REUSEADDR) failed"); - return false; - } - - if(setsockopt(m_fd, IPPROTO_IP, IP_MULTICAST_TTL, &iTtl, sizeof(int))) { - LOGERR("cxSocket: setsockopt(IP_MULTICAST_TTL, %d) failed", iTtl); - return false; - } - - if(setsockopt(m_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &iLoop, sizeof(int))) { - LOGERR("cxSocket: setsockopt(IP_MULTICAST_LOOP) failed"); - return false; - } - - return true; -} - -ssize_t cxSocket::sendfile(int fd_file, off_t *offset, size_t count) -{ - int r; -#ifndef __APPLE__ - r = ::sendfile(m_fd, fd_file, offset, count); - if(r<0 && (errno == ENOSYS || errno == EINVAL)) { - // fall back to read/write - LOGERR("sendfile failed - using simple read/write"); -#endif - cxPoller p(*this, true); - char buf[0x10000]; - int todor = count, todow, done = 0; - if(offset) - if((r=::lseek(fd_file, *offset, SEEK_SET)) < 0) - return r; - todow = ::read(fd_file, buf, count>sizeof(buf) ? sizeof(buf) : count); - if(todow <= 0) - return todow; - todor -= todow; - while(todow > 0) { - if(p.Poll(100)) { - r = write(buf+done, todow); - if(r <= 0) - return r; - todow -= r; - done += r; - } - } - return done; -#ifndef __APPLE__ - } - return r; -#endif -} - -bool cxSocket::set_cork(bool state) -{ -#ifdef __APPLE__ - return false; -#else - int iCork = state ? 1 : 0; - if(setsockopt(m_fd, IPPROTO_TCP, TCP_CORK, &iCork, sizeof(int))) { - LOGERR("cxSocket: setsockopt(TCP_CORK) failed"); - return false; - } - return true; -#endif -} - -bool cxSocket::set_nodelay(bool state) -{ - int i = state ? 1 : 0; - if(setsockopt(m_fd, IPPROTO_TCP, TCP_NODELAY, &i, sizeof(int))) { - LOGERR("cxSocket: setsockopt(TCP_NODELAY) failed"); - return false; - } - return true; -} - -ssize_t cxSocket::tx_buffer_size(void) -{ - socklen_t l = sizeof(int); - int wmem = -1; - if(getsockopt(m_fd, SOL_SOCKET, SO_SNDBUF, &wmem, &l)) { - LOGERR("getsockopt(SO_SNDBUF) failed"); - return (ssize_t)-1; - } - return (ssize_t)wmem; -} - -ssize_t cxSocket::tx_buffer_free(void) -{ - int wmem = tx_buffer_size(); - int size = -1; - if(ioctl(m_fd, TIOCOUTQ, &size)) { - LOGERR("ioctl(TIOCOUTQ) failed"); - return (ssize_t)-1; - } - - return (ssize_t)(wmem - size); -} - -int cxSocket::getsockname(struct sockaddr *name, socklen_t *namelen) -{ - return ::getsockname(m_fd, name, namelen); -} - -int cxSocket::getpeername(struct sockaddr *name, socklen_t *namelen) -{ - return ::getpeername(m_fd, name, namelen); -} - -ssize_t cxSocket::send(const void *buf, size_t size, int flags, - const struct sockaddr *to, socklen_t tolen) -{ - return ::sendto(m_fd, buf, size, flags, to, tolen); -} - -ssize_t cxSocket::recv(void *buf, size_t size, int flags, - struct sockaddr *from, socklen_t *fromlen) -{ - return ::recvfrom(m_fd, buf, size, flags, from, fromlen); -} - -ssize_t cxSocket::write(const void *buffer, size_t size, - int timeout_ms) -{ - ssize_t written = (ssize_t)size; - const unsigned char *ptr = (const unsigned char *)buffer; - cPoller poller(m_fd, true); - - while (size > 0) { - errno = 0; - if(!poller.Poll(timeout_ms)) { - LOGERR("cxSocket::write: poll() failed"); - return written-size; - } - - errno = 0; - ssize_t p = ::write(m_fd, ptr, size); - - if (p <= 0) { - if (errno == EINTR || errno == EAGAIN) { - LOGDBG("cxSocket::write: EINTR during write(), retrying"); - continue; - } - LOGERR("cxSocket::write: write() error"); - return p; - } - - ptr += p; - size -= p; - } - - return written; -} - -ssize_t cxSocket::read(void *buffer, size_t size, int timeout_ms) -{ - ssize_t missing = (ssize_t)size; - unsigned char *ptr = (unsigned char *)buffer; - cPoller poller(m_fd); - - while (missing > 0) { - - if(!poller.Poll(timeout_ms)) { - LOGERR("cxSocket::read: poll() failed at %d/%d", (int)(size-missing), (int)size); - return size-missing; - } - - errno = 0; - ssize_t p = ::read(m_fd, ptr, missing); - - if (p <= 0) { - if (errno == EINTR || errno == EAGAIN) { - LOGDBG("cxSocket::read: EINTR/EAGAIN during read(), retrying"); - continue; - } - LOGERR("cxSocket::read: read() error at %d/%d", (int)(size-missing), (int)size); - return size-missing; - } - - ptr += p; - missing -= p; - } - - return size; -} - -ssize_t cxSocket::printf(const char *fmt, ...) -{ - va_list argp; - char buf[1024]; - int r; - - va_start(argp, fmt); - r = vsnprintf(buf, sizeof(buf), fmt, argp); - if(r<0) - LOGERR("cxSocket::printf: vsnprintf failed"); - else if(r >= (int)sizeof(buf)) - LOGMSG("cxSocket::printf: vsnprintf overflow (%20s)", buf); - else - return write(buf, r); - - return (ssize_t)-1; -} - -/* readline return value: - * <0 : failed - * >=maxsize : buffer overflow - * >=0 : if errno = EAGAIN -> line is not complete (there was timeout) - * if errno = 0 -> succeed - * (return value 0 indicates empty line "\r\n") - */ -ssize_t cxSocket::readline(char *buf, int bufsize, int timeout, int bufpos) -{ - int n = -1, cnt = bufpos; - cPoller p(m_fd); - - do { - if(timeout>0 && !p.Poll(timeout)) { - errno = EAGAIN; - return cnt; - } - - while((n = ::read(m_fd, buf+cnt, 1)) == 1) { - buf[++cnt] = 0; - - if( cnt > 1 && buf[cnt - 2] == '\r' && buf[cnt - 1] == '\n') { - cnt -= 2; - buf[cnt] = 0; - errno = 0; - return cnt; - } - - if( cnt >= bufsize) { - LOGMSG("cxSocket::readline: too long control message (%d bytes): %20s", cnt, buf); - errno = 0; - return bufsize; - } - } - - /* connection closed ? */ - if (n == 0) { - LOGMSG("cxSocket::readline: disconnected"); - if(errno == EAGAIN) - errno = ENOTCONN; - return -1; - } - - } while (timeout>0 && n<0 && errno == EAGAIN); - - if(errno == EAGAIN) - return cnt; - - LOGERR("cxSocket::readline: read failed"); - return n; -} - -#include <sys/ioctl.h> -#include <net/if.h> - -uint32_t cxSocket::get_local_address(char *ip_address) -{ - uint32_t local_addr = 0; - struct ifconf conf; - struct ifreq buf[3]; - unsigned int n; - - struct sockaddr_in sin; - socklen_t len = sizeof(sin); - - if(!getsockname((struct sockaddr *)&sin, &len)) { - local_addr = sin.sin_addr.s_addr; - - } else { - //LOGERR("getsockname failed"); - - // scan network interfaces - - conf.ifc_len = sizeof(buf); - conf.ifc_req = buf; - memset(buf, 0, sizeof(buf)); - - errno = 0; - if(ioctl(m_fd, SIOCGIFCONF, &conf) < 0) - LOGERR("cxSocket: can't obtain socket local address"); - else { - for(n=0; n<conf.ifc_len/sizeof(struct ifreq); n++) { - struct sockaddr_in *in = (struct sockaddr_in *) &buf[n].ifr_addr; -# if 0 - uint32_t tmp = ntohl(in->sin_addr.s_addr); - LOGMSG("Local address %6s %d.%d.%d.%d", - conf.ifc_req[n].ifr_name, - ((tmp>>24)&0xff), ((tmp>>16)&0xff), - ((tmp>>8)&0xff), ((tmp)&0xff)); -# endif - if(n==0 || local_addr == htonl(INADDR_LOOPBACK)) - local_addr = in->sin_addr.s_addr; - else - break; - } - } - } - - if(!local_addr) - LOGERR("No local address found"); - - if(ip_address) - cxSocket::ip2txt(local_addr, 0, ip_address); - - return local_addr; -} - -char *cxSocket::ip2txt(uint32_t ip, unsigned int port, char *str) -{ - // inet_ntoa is not thread-safe (?) - if(str) { - unsigned int iph =(unsigned int)ntohl(ip); - unsigned int porth =(unsigned int)ntohs(port); - if(!porth) - sprintf(str, "%d.%d.%d.%d", - ((iph>>24)&0xff), ((iph>>16)&0xff), - ((iph>>8)&0xff), ((iph)&0xff)); - else - sprintf(str, "%u.%u.%u.%u:%u", - ((iph>>24)&0xff), ((iph>>16)&0xff), - ((iph>>8)&0xff), ((iph)&0xff), - porth); - } - return str; -} diff --git a/tools/cxsocket.h b/tools/cxsocket.h deleted file mode 100644 index 92954f3c..00000000 --- a/tools/cxsocket.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * cxsocket.h: Socket wrapper classes - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: cxsocket.h,v 1.20 2007-01-20 17:24:40 phintuka Exp $ - * - */ - -#ifndef __CXSOCKET_H -#define __CXSOCKET_H - -#include <inttypes.h> -#include <sys/types.h> -#include <sys/socket.h> - -#define CLOSESOCKET(fd) do { if(fd>=0) { ::close(fd); fd=-1; } } while(0) - -class cxSocket { - private: - int m_fd; - - cxSocket(const cxSocket& s) ;//{ m_fd = s.m_fd>=0 ? dup(s.m_fd) : -1; } - cxSocket &operator=(const cxSocket &S) - ;// { close(); m_fd = S.m_fd >= 0 ? dup(S.m_fd) : -1; return *this; }; - - public: - - typedef enum { - estSTREAM = SOCK_STREAM, - estDGRAM = SOCK_DGRAM - } eSockType; - - cxSocket() : m_fd(-1) {} - cxSocket(eSockType type) : m_fd(::socket(PF_INET, (int)type, 0)) {} - - ~cxSocket() { CLOSESOCKET(m_fd); } - - //operator int () const { return Handle(); } - //operator bool () const { return open(); } - //bool operator==(const cxSocket &s) { return m_fd == s.m_fd; } - - int handle(bool take_ownership=false) - { int r=m_fd; if(take_ownership) m_fd=-1; return r; } - void set_handle(int h) { if(h != m_fd) {close(); m_fd = h;} } - bool create(eSockType type) { close(); return (m_fd=::socket(PF_INET, (int)type, 0)) >= 0; } - bool open(void) const { return m_fd>0; } - void close(void) { CLOSESOCKET(m_fd); } - - ssize_t send(const void *buf, size_t size, int flags=0, - const struct sockaddr *to = NULL, socklen_t tolen = 0); - ssize_t recv(void *buf, size_t size, int flags = 0, - struct sockaddr *from = NULL, socklen_t *fromlen = NULL); - ssize_t sendfile(int fd_file, off_t *offset, size_t count); - - ssize_t read(void *buffer, size_t size, int timeout_ms = -1); - ssize_t write(const void *buffer, size_t size, int timeout_ms = -1); - - ssize_t printf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); - ssize_t write_str(const char *str, int timeout_ms=-1, int len=0) - { return write(str, len ?: strlen(str), timeout_ms); } - ssize_t write_cmd(const char *str, int len=0) - { return write(str, len ?: strlen(str), 10); } - -/* readline return value: - * <0 : failed - * >=maxsize : buffer overflow - * >=0 : if errno = EAGAIN -> line is not complete (there was timeout) - * if errno = 0 -> succeed - * (return value 0 indicates empty line "\r\n") - */ - ssize_t readline(char *buf, int bufsize, int timeout=0, int bufpos=0); - - bool set_buffers(int Tx, int Rx); - bool set_multicast(int ttl); - bool set_blocking(bool state); - bool set_cork(bool state); - bool flush_cork(void) { return set_nodelay(true); }; - bool set_nodelay(bool state); - ssize_t tx_buffer_size(void); - ssize_t tx_buffer_free(void); - int getsockname(struct sockaddr *name, socklen_t *namelen); - int getpeername(struct sockaddr *name, socklen_t *namelen); - - - bool connect(struct sockaddr *addr, socklen_t len); - bool connect(const char *ip, int port); - - uint32_t get_local_address(char *ip_address); - - static char *ip2txt(uint32_t ip, unsigned int port, char *str); -}; - - -#include <vdr/tools.h> - -class cxPoller : public cPoller { - public: - cxPoller(cxSocket& Sock, bool Out=false) : cPoller(Sock.handle(), Out) {}; - - cxPoller(cxSocket* Socks, int count, bool Out=false) - { - for(int i=0; i<count; i++) - Add(Socks[i].handle(), Out); - } -}; - -// -// Set socket buffers -// -static inline void set_socket_buffers(int s, int txbuf, int rxbuf) -{ - int max_buf = txbuf; - /*while(max_buf) {*/ - errno = 0; - if(setsockopt(s, SOL_SOCKET, SO_SNDBUF, &max_buf, sizeof(int))) { - LOGERR("setsockopt(SO_SNDBUF,%d) failed", max_buf); - /*max_buf >>= 1;*/ - } - /*else {*/ - int tmp = 0; - int len = sizeof(int); - errno = 0; - if(getsockopt(s, SOL_SOCKET, SO_SNDBUF, &tmp, (socklen_t*)&len)) { - LOGERR("getsockopt(SO_SNDBUF,%d) failed", max_buf); - /*break;*/ - } else if(tmp != max_buf) { - LOGDBG("setsockopt(SO_SNDBUF): got %d bytes", tmp); - /*max_buf >>= 1;*/ - /*continue;*/ - } - /*}*/ - /*}*/ - - max_buf = rxbuf; - setsockopt(s, SOL_SOCKET, SO_RCVBUF, &max_buf, sizeof(int)); -} - -// -// Connect data socket to client (take address from fd_control) -// -static inline int sock_connect(int fd_control, int port, int type) -{ - struct sockaddr_in sin; - socklen_t len = sizeof(sin); - int s, one = 1; - - if(getpeername(fd_control, (struct sockaddr *)&sin, &len)) { - LOGERR("sock_connect: getpeername failed"); - return -1; - } - - uint32_t tmp = ntohl(sin.sin_addr.s_addr); - LOGMSG("Client address: %d.%d.%d.%d", - ((tmp>>24)&0xff), ((tmp>>16)&0xff), - ((tmp>>8)&0xff), ((tmp)&0xff)); - -#if 0 - if ((h = gethostbyname(tmp)) == NULL) { - LOGDBG("sock_connect: unable to resolve host name", tmp); - } -#endif - - if ((s = socket(PF_INET, type, - type==SOCK_DGRAM?IPPROTO_UDP:IPPROTO_TCP)) < 0) { - LOGERR("sock_connect: failed to create socket"); - return -1; - } - - // Set socket buffers: large send buffer, small receive buffer - set_socket_buffers(s, KILOBYTE(256), 2048); - - if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)) < 0) - LOGERR("sock_connect: setsockopt(SO_REUSEADDR) failed"); - - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - - if (connect(s, (struct sockaddr *)&sin, sizeof(sin))==-1 && - errno != EINPROGRESS) { - LOGERR("connect() failed"); - CLOSESOCKET(s); - } - - if (fcntl (s, F_SETFL, fcntl (s, F_GETFL) | O_NONBLOCK) == -1) { - LOGERR("can't put socket in non-blocking mode"); - CLOSESOCKET(s); - return -1; - } - - return s; -} - -#endif // __CXSOCKET_H diff --git a/tools/debug_mutex.h b/tools/debug_mutex.h deleted file mode 100644 index 0802c7cc..00000000 --- a/tools/debug_mutex.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * debug_mutex.h: debugging wrappers for pthread_mutex_ functions - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: debug_mutex.h,v 1.3 2007-03-14 11:50:08 phintuka Exp $ - * - */ - -#ifndef DEBUG_MUTEX_H -#define DEBUG_MUTEX_H - -#ifndef _PTHREAD_H -# error pthread.h must be included before debug_mutex.h -#endif - -/* - * Override pthread_mutex_ calls: - * - * Change type of each mutex to PTHREAD_MUTEX_ERRORCHECK_NP - * - * Store line number of last succeed pthread_mutex_lock call - * for each initialized mutex - * - * Check every pthread_mutex_ call for errors and log all errors - * - * To help detecting deadlocks and minimize logging: - * - Try locking first in pthread_mutex_lock - * - If pthread_mutex_trylock fails, log a message and retry. - * - When trylock failed, log another message when lock is acquired. - * - * - * NOTE: debugging itself is not thread-safe and may indicate wrong line numbers ! - * - */ - -#define MAX_DBG_MUTEX 64 -static struct { - pthread_mutex_t *lock; - int line; - int tid; -} dbgdata[MAX_DBG_MUTEX+1] = {{NULL,0}}; - -static void dbg_setdata(pthread_mutex_t *mutex, int line) -{ - int i; - for(i=0; i<MAX_DBG_MUTEX; i++) - if(dbgdata[i].lock == mutex) { - dbgdata[i].line = line; - dbgdata[i].tid = syscall(__NR_gettid); - return; - } - - LOGMSG("********** dbg_setdata: new entry (0x%lx at %d)", (unsigned long int)mutex, line); - for(i=0; i<MAX_DBG_MUTEX; i++) - if(!dbgdata[i].lock) { - dbgdata[i].lock = mutex; - dbgdata[i].line = line; - dbgdata[i].tid = syscall(__NR_gettid); - return; - } - - LOGMSG("********** dbg_setdata: table full !"); -} - -static int dbg_getdata(pthread_mutex_t *mutex, int line) -{ - int i; - for(i=0; i<MAX_DBG_MUTEX; i++) - if(dbgdata[i].lock == mutex) - return dbgdata[i].line; - - LOGMSG("********** dbg_getdata: NO ENTRY ! (%d)", line); - return -1; -} - -static void dbg_deldata(pthread_mutex_t *mutex, int line) -{ - int i; - for(i=0; i<MAX_DBG_MUTEX; i++) - if(dbgdata[i].lock == mutex) { - dbgdata[i].lock = NULL; - return; - } - - LOGMSG("********** dbg_deldata: NO ENTRY ! (%d)", line); - return; -} - -static int dbg_init(pthread_mutex_t *mutex, pthread_mutexattr_t *pattr, int line) -{ - int r; - - errno = 0; - if(!pattr) { - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP); - r = pthread_mutex_init(mutex, &attr); - } else { - LOGMSG("********** dbg_init: mutex attribute already given !"); - r = pthread_mutex_init(mutex, pattr); - } - - if(r) - LOGERR("********** dbg_init: pthread_mutex_init FAILED at %d", line); - - dbg_setdata(mutex, line); - - return r; -} - -static int dbg_free(pthread_mutex_t *mutex, int line) -{ - int r; - - errno = 0; - r = pthread_mutex_destroy(mutex); - - if(r) - LOGERR("********** dbg_free: pthread_mutex_destroy FAILED at %d ; last lock at %d", - line, dbg_getdata(mutex, line)); - dbg_deldata(mutex, line); - - return r; -} - -static int dbg_lock(pthread_mutex_t *mutex, int line) -{ - int r; - /*struct timespec abs_timeout;*/ - - /* try lock first to reduce logging */ - errno = 0; - r = pthread_mutex_trylock(mutex); - if(!r) { - dbg_setdata(mutex,line); - return r; - } - - /* try failed - we're going to wait, so log at wait start and end to detect deadlocks */ - LOGERR("********** dbg_lock: pthread_mutex_trylock failed at %d (locked at %d)", - line, dbg_getdata(mutex, line)); - - /* int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, - const struct timespec *restrict abs_timeout); */ - - errno = 0; - r = pthread_mutex_lock(mutex); - - if(r) - LOGERR("********** dbg_lock: pthread_mutex_lock FAILED at %d", line); - - dbg_setdata(mutex, line); - LOGMSG("********** dbg_lock: pthread_mutex_lock done at %d", line); - - return r; -} - -static int dbg_trylock(pthread_mutex_t *mutex, int line) -{ - int r; - /*struct timespec abs_timeout;*/ - - /* try lock first to reduce logging */ - errno = 0; - r = pthread_mutex_trylock(mutex); - if(!r) { - dbg_setdata(mutex,line); - return r; - } - - LOGERR("********** dbg_trylock: pthread_mutex_trylock failed at %d (locked at %d)", - line, dbg_getdata(mutex, line)); - - return r; -} - -static int dbg_unlock(pthread_mutex_t *mutex, int line) -{ - int r; - - errno = 0; - r = pthread_mutex_unlock(mutex); - - if(r) - LOGERR("********** dbg_unlock: pthread_mutex_unlock FAILED at %d (last locket at %d)", - line, dbg_getdata(mutex, line)); - - //else - // dbg_setdata(mutex, 0); - - return r; -} - -/* override pthread_ functions with own ones */ -#define pthread_mutex_init(l,a) dbg_init(l, a, __LINE__) -#define pthread_mutex_lock(l) dbg_lock(l, __LINE__) -#define pthread_mutex_trylock(l) dbg_trylock(l, __LINE__) -#define pthread_mutex_unlock(l) dbg_unlock(l, __LINE__) -#define pthread_mutex_destroy(l) dbg_free(l, __LINE__) - -#else -# error debug_mutex.h included twice -#endif /* DEBUG_MUTEX_H */ diff --git a/tools/display_message.h b/tools/display_message.h deleted file mode 100644 index 407f07c8..00000000 --- a/tools/display_message.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * display_message.h: Display simple message - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: display_message.h,v 1.2 2007-01-06 04:28:08 phintuka Exp $ - * - */ - -#ifndef __DISPLAY_MESSAGE_H -#define __DISPLAY_MESSAGE_H - -#include <vdr/osdbase.h> -#include <vdr/skins.h> - -class cDisplayMessage : public cOsdObject -{ - cSkinDisplayMessage *displayMessage; - char *Message; - int Timer; - int Timeout; - - public: - - cDisplayMessage(const char *message, int timeout = 3) - { - displayMessage = NULL; - Message = strdup(message); - Timer = 0; - Timeout = timeout; - } - - virtual ~cDisplayMessage() - { - delete displayMessage; - free(Message); - } - - void Update(const char *message) - { - Timer = 0; - free(Message); - Message = strdup(message); - Show(); - } - - virtual eOSState ProcessKey(eKeys Key) - { - if(Key == kNone && Timer++ > Timeout) - return osEnd; - - if(Key != kNone) { - // put back and close - cRemote::Put(Key, true); - return osEnd; - } - - return osContinue; - } - - virtual void Show(void) - { - if(!displayMessage) - displayMessage = Skins.Current()->DisplayMessage(); - - displayMessage->SetMessage(mtInfo, Message); - displayMessage->Flush(); - } - -}; - -#endif diff --git a/tools/functor.h b/tools/functor.h deleted file mode 100644 index 0dadf1fc..00000000 --- a/tools/functor.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * functor.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: functor.h,v 1.1 2006-08-24 23:25:07 phintuka Exp $ - * - */ - -#ifndef __XINELIB_FUNCTOR_H -#define __XINELIB_FUNCTOR_H - -#include <vdr/tools.h> - - -class cFunctor : public cListObject -{ - public: - cFunctor() : cListObject() {} - virtual ~cFunctor() {} - virtual void Execute(void) = 0; -}; - -#if 1 /* gcc 3.3.x (?) does not accept class TRESULT=void */ -template<class TCLASS> -cFunctor *CreateFunctor(TCLASS *c, - void (TCLASS::*fp)(void)); - -template<class TCLASS, class TARG1> -cFunctor *CreateFunctor(TCLASS *c, - void (TCLASS::*fp)(TARG1), - TARG1 arg1); -#endif - -template<class TCLASS, class TRESULT> -cFunctor *CreateFunctor(TCLASS *c, - TRESULT (TCLASS::*fp)(void)); - -template<class TCLASS, class TRESULT, class TARG1> -cFunctor *CreateFunctor(TCLASS *c, - TRESULT (TCLASS::*fp)(TARG1), - TARG1 arg1); - -#include "functorimpl.h" - -#endif diff --git a/tools/functorimpl.h b/tools/functorimpl.h deleted file mode 100644 index 2d3504e6..00000000 --- a/tools/functorimpl.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * functorimpl.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: functorimpl.h,v 1.1 2006-08-24 23:25:07 phintuka Exp $ - * - */ - -#ifndef __XINELIB_FUNCTORIMPL_H - -#ifndef __XINELIB_FUNCTOR_H -# error functorimpl.h should not be included, use functor.h instead -#endif - -#if 1 /* gcc 3.3.x (?) does not accept class TRESULT=void */ -template <class TCLASS> -class cFunctor0 : public cFunctor { - - public: - protected: - - typedef void (TCLASS::*TFUNC)(void); - - cFunctor0(TCLASS *obj, TFUNC f) : m_obj(obj), m_f(f) {} - virtual ~cFunctor0() {}; - - virtual void Execute(void) - { - (*m_obj.*m_f)(); - } - - private: - TCLASS *m_obj; - TFUNC m_f; - - friend cFunctor *CreateFunctor<TCLASS>(TCLASS*,TFUNC); -}; - -template <class TCLASS, class TARG1> -class cFunctor1 : public cFunctor { - - public: - - protected: - typedef void (TCLASS::*TFUNC)(TARG1); - - cFunctor1(TCLASS *obj, TFUNC f, TARG1 arg1) : - m_obj(obj), m_f(f), m_arg1(arg1) {} - virtual ~cFunctor1() {}; - - virtual void Execute(void) - { - (*m_obj.*m_f)(m_arg1); - } - - private: - TCLASS *m_obj; - TFUNC m_f; - TARG1 m_arg1; - - friend cFunctor *CreateFunctor<TCLASS,TARG1>(TCLASS*,TFUNC,TARG1); -}; -#endif - -template <class TCLASS, class TRESULT> -class cFunctorR0 : public cFunctor { - - public: - protected: - - typedef TRESULT (TCLASS::*TFUNC)(void); - - cFunctorR0(TCLASS *obj, TFUNC f) : m_obj(obj), m_f(f) {} - virtual ~cFunctorR0() {}; - - virtual void Execute(void) - { - // TODO: use future to pass back value - (void) (*m_obj.*m_f)(); - } - - private: - TCLASS *m_obj; - TFUNC m_f; - - friend cFunctor *CreateFunctor<TCLASS,TRESULT>(TCLASS*,TFUNC); -}; - -template <class TCLASS, class TRESULT, class TARG1> -class cFunctorR1 : public cFunctor { - - public: - protected: - - typedef TRESULT (TCLASS::*TFUNC)(TARG1); - - cFunctorR1(TCLASS *obj, TFUNC f, TARG1 arg1) : - m_obj(obj), m_f(f), m_arg1(arg1) {} - virtual ~cFunctorR1() {}; - - virtual void Execute(void) - { - // TODO: use future to pass back value - (void) (*m_obj.*m_f)(m_arg1); - } - - private: - TCLASS *m_obj; - TFUNC m_f; - TARG1 m_arg1; - - friend cFunctor *CreateFunctor<TCLASS,TRESULT>(TCLASS*,TFUNC,TARG1); -}; - -#if 1 /* gcc 3.3.x (?) does not accept class TRESULT=void */ -template<class TCLASS> -cFunctor *CreateFunctor(TCLASS *c, - void (TCLASS::*fp)(void)) -{ - return new cFunctor0<TCLASS>(c, fp); -} - -template<class TCLASS, class TARG1> -cFunctor *CreateFunctor(TCLASS *c, - void (TCLASS::*fp)(TARG1), - TARG1 arg1) -{ - return new cFunctor1<TCLASS,TARG1>(c, fp, arg1); -} -#endif - -template<class TCLASS, class TRESULT> -cFunctor *CreateFunctor(TCLASS *c, - TRESULT (TCLASS::*fp)(void)) -{ - return new cFunctorR0<TCLASS,TRESULT>(c, fp); -} - -template<class TCLASS, class TRESULT, class TARG1> -cFunctor *CreateFunctor(TCLASS *c, - TRESULT (TCLASS::*fp)(TARG1), - TARG1 arg1) -{ - return new cFunctorR1<TCLASS,TRESULT,TARG1>(c, fp, arg1); -} - - -#endif diff --git a/tools/future.h b/tools/future.h deleted file mode 100644 index bdd0498c..00000000 --- a/tools/future.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * future.h: A variable that gets its value in future. - * Used to convert asynchronous IPCs to synchronous. - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: future.h,v 1.2 2006-08-19 23:44:07 phintuka Exp $ - * - */ - -#ifndef __FUTURE_H -#define __FUTURE_H - -#include <vdr/thread.h> - -template <class T> -class cFuture { - - private: - cMutex mutex; - cCondVar cond; - bool m_Ready; - T m_Value; - - public: - - cFuture() - { - m_Ready = false; - } - - void Reset(void) - { - cMutexLock l(&mutex); - m_Ready = false; - } - - // - // Producer interface - // - - void Set(T& Value) - { - cMutexLock l(&mutex); - m_Value = Value; - m_Ready = true; - cond.Broadcast(); - } - - // - // Consumer interface - // - - bool Wait(int Timeout = -1) - { - cMutexLock l(&mutex); - - if(Timeout==0 || m_Ready) - return m_Ready; - - if(Timeout >= 0) - return cond.TimedWait(mutex, Timeout) && m_Ready; - - while(!m_Ready) - cond.Wait(mutex); - - return m_Ready; - } - - bool IsReady(void) - { - cMutexLock l(&mutex); - return m_Ready; - } - - T Value(void) - { - cMutexLock l(&mutex); - while(!m_Ready) - cond.Wait(mutex); - return m_Value; - } -}; - - -#endif // __FUTURE_H diff --git a/tools/general_remote.h b/tools/general_remote.h deleted file mode 100644 index aed60463..00000000 --- a/tools/general_remote.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * general_remote.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: general_remote.h,v 1.1 2006-06-03 10:04:27 phintuka Exp $ - * - */ - -#ifndef __GENERAL_REMOTE_H -#define __GENERAL_REMOTE_H - - -//----------------------------- cGeneralRemote -------------------------------- - -#include <vdr/remote.h> - -class cGeneralRemote : public cRemote { - public: - cGeneralRemote(const char *Name) : cRemote(Name) {}; - bool Put(const char *Code, bool Repeat=false, bool Release=false) - { return cRemote::Put(Code, Repeat, Release); }; -}; - - -#endif diff --git a/tools/h264.c b/tools/h264.c deleted file mode 100644 index 90a35e83..00000000 --- a/tools/h264.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * h264.c: H.264 bitstream decoding - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: h264.c,v 1.2 2008-05-20 11:00:42 phintuka Exp $ - * - */ - - -#ifndef LOGDBG -# include <vdr/tools.h> -# include "../logdefs.h" -#endif - -#define NOCACHE 1 -#include "bitstream.h" - -#include "mpeg.h" -#include "h264.h" - - -int h264_parse_sps(const uint8_t *buf, int len, h264_sps_data_t *sps) -{ - br_state br = BR_INIT(buf, len); - int profile_idc, pic_order_cnt_type; - int frame_mbs_only; - int i, j; - - profile_idc = br_get_u8(&br); - LOGDBG("H.264 SPS: profile_idc %d", profile_idc); - /* constraint_set0_flag = br_get_bit(br); */ - /* constraint_set1_flag = br_get_bit(br); */ - /* constraint_set2_flag = br_get_bit(br); */ - /* constraint_set3_flag = br_get_bit(br); */ - /* reserved = br_get_bits(br,4); */ - /* level_idc = br_get_u8(br); */ - br_skip_bits(&br, 16); - br_skip_ue_golomb(&br); /* seq_parameter_set_id */ - if (profile_idc >= 100) { - if (br_get_ue_golomb(&br) == 3) /* chroma_format_idc */ - br_skip_bit(&br); /* residual_colour_transform_flag */ - br_skip_ue_golomb(&br); /* bit_depth_luma - 8 */ - br_skip_ue_golomb(&br); /* bit_depth_chroma - 8 */ - br_skip_bit(&br); /* transform_bypass */ - if (br_get_bit(&br)) /* seq_scaling_matrix_present */ - for (i = 0; i < 8; i++) - if (br_get_bit(&br)) { /* seq_scaling_list_present */ - int last = 8, next = 8, size = (i<6) ? 16 : 64; - for (j = 0; j < size; j++) { - if (next) - next = (last + br_get_se_golomb(&br)) & 0xff; - last = next ?: last; - } - } - } - - br_skip_ue_golomb(&br); /* log2_max_frame_num - 4 */ - pic_order_cnt_type = br_get_ue_golomb(&br); - if (pic_order_cnt_type == 0) - br_skip_ue_golomb(&br); /* log2_max_poc_lsb - 4 */ - else if (pic_order_cnt_type == 1) { - br_skip_bit(&br); /* delta_pic_order_always_zero */ - br_skip_se_golomb(&br); /* offset_for_non_ref_pic */ - br_skip_se_golomb(&br); /* offset_for_top_to_bottom_field */ - j = br_get_ue_golomb(&br); /* num_ref_frames_in_pic_order_cnt_cycle */ - for (i = 0; i < j; i++) - br_skip_se_golomb(&br); /* offset_for_ref_frame[i] */ - } - br_skip_ue_golomb(&br); /* ref_frames */ - br_skip_bit(&br); /* gaps_in_frame_num_allowed */ - sps->width /* mbs */ = br_get_ue_golomb(&br) + 1; - sps->height /* mbs */ = br_get_ue_golomb(&br) + 1; - frame_mbs_only = br_get_bit(&br); - LOGDBG("H.264 SPS: pic_width: %u mbs", (unsigned) sps->width); - LOGDBG("H.264 SPS: pic_height: %u mbs", (unsigned) sps->height); - LOGDBG("H.264 SPS: frame only flag: %d", frame_mbs_only); - - sps->width *= 16; - sps->height *= 16 * (2-frame_mbs_only); - - if (!frame_mbs_only) - if (br_get_bit(&br)) /* mb_adaptive_frame_field_flag */ - LOGDBG("H.264 SPS: MBAFF"); - br_skip_bit(&br); /* direct_8x8_inference_flag */ - if (br_get_bit(&br)) { /* frame_cropping_flag */ - uint32_t crop_left = br_get_ue_golomb(&br); - uint32_t crop_right = br_get_ue_golomb(&br); - uint32_t crop_top = br_get_ue_golomb(&br); - uint32_t crop_bottom = br_get_ue_golomb(&br); - LOGDBG("H.264 SPS: cropping %d %d %d %d", - crop_left, crop_top, crop_right, crop_bottom); - - sps->width -= 2*(crop_left + crop_right); - if (frame_mbs_only) - sps->height -= 2*(crop_top + crop_bottom); - else - sps->height -= 4*(crop_top + crop_bottom); - } - - /* VUI parameters */ - sps->pixel_aspect.num = 0; - if (br_get_bit(&br)) { /* vui_parameters_present flag */ - if (br_get_bit(&br)) { /* aspect_ratio_info_present */ - uint32_t aspect_ratio_idc = br_get_u8(&br); - LOGDBG("H.264 SPS: aspect_ratio_idc %d", aspect_ratio_idc); - - if (aspect_ratio_idc == 255 /* Extended_SAR */) { - sps->pixel_aspect.num = br_get_u16(&br); /* sar_width */ - sps->pixel_aspect.den = br_get_u16(&br); /* sar_height */ - LOGDBG("H.264 SPS: -> sar %dx%d", sps->pixel_aspect.num, sps->pixel_aspect.den); - } else { - static const h264_rational_t aspect_ratios[] = - { /* page 213: */ - /* 0: unknown */ - {0, 1}, - /* 1...16: */ - { 1, 1}, {12, 11}, {10, 11}, {16, 11}, { 40, 33}, {24, 11}, {20, 11}, {32, 11}, - {80, 33}, {18, 11}, {15, 11}, {64, 33}, {160, 99}, { 4, 3}, { 3, 2}, { 2, 1} - }; - - if (aspect_ratio_idc < sizeof(aspect_ratios)/sizeof(aspect_ratios[0])) { - memcpy(&sps->pixel_aspect, &aspect_ratios[aspect_ratio_idc], sizeof(h264_rational_t)); - LOGDBG("H.264 SPS: -> aspect ratio %d / %d", sps->pixel_aspect.num, sps->pixel_aspect.den); - } else { - LOGMSG("H.264 SPS: aspect_ratio_idc out of range !"); - } - } - } - } - - LOGDBG("H.264 SPS: -> video size %dx%d, aspect %d:%d", - sps->width, sps->height, sps->pixel_aspect.num, sps->pixel_aspect.den); - - if(BR_EOF(&br)) { - LOGDBG("H.264 SPS: not enough data ?"); - return 0; - } - return 1; -} - -static int h264_nal_unescape(uint8_t *dst, const uint8_t *src, int len) -{ - int s = 0, d = 0; - while (s < len) { - if (!src[s] && !src[s+1]) { - /* hit 00 00 xx */ - dst[d] = dst[d+1] = 0; - s += 2; - d += 2; - if (src[s] == 3) { - s++; /* 00 00 03 xx --> 00 00 xx */ - /*LOGDBG("h264_nal_unescape: hit 00 00 03 %02x", src[s]);*/ - if (s >= len) - return d; - } /* else if (src[s] == 0 || src[s] == 1) { - LOGDBG("h264_nal_unescape: invalid NAL sequence 00 00 %02x %02x", src[s], src[s+1]); - return -1; - }*/ - } - dst[d++] = src[s++]; - } - return d; -} - -int h264_get_picture_type(const uint8_t *buf, int len) -{ - int i; - for (i = 0; i < len-5; i++) { - if (buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 1 && buf[i + 3] == 9) { - uint8_t type = (buf[i + 4] >> 5); - switch (type) { - case 0: case 3: case 5: return I_FRAME; - case 1: case 4: case 6: return P_FRAME; - case 2: case 7: return B_FRAME; - default:; - } - } - } - return NO_PICTURE; -} - -int h264_get_video_size(const uint8_t *buf, int len, video_size_t *size) -{ - int i; - - /* H.264 detection, search for NAL AUD */ - if (!(buf[0] == 0 && buf[1] == 0 && buf[2] == 1 && buf[3] == NAL_AUD)) - return 0; - - /* if I-frame, search for NAL SPS */ - if (h264_get_picture_type(buf, len) != I_FRAME) - return 0; - - /* scan video packet for sequence parameter set */ - for (i = 5; i < len-4; i++) - if (buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 1 && (buf[i + 3] & 0x1f) == NAL_SPS) { - - uint8_t nal_data[len]; - int nal_len; - - LOGDBG("H.264: Found NAL SPS at offset %d/%d", i, len); - - if (0 < (nal_len = h264_nal_unescape(nal_data, buf+i+4, len-i-4))) { - - h264_sps_data_t sps = {0}; - - if (h264_parse_sps(nal_data, nal_len, &sps)) { - size->width = sps.width; - size->height = sps.height; - if(sps.pixel_aspect.den) - size->pixel_aspect = (double)sps.pixel_aspect.num / (double)sps.pixel_aspect.den; - else - size->pixel_aspect = 0.0; - return 1; - } - LOGMSG("h264_get_video_size: not enough data ?"); - } - } - - return 0; -} - diff --git a/tools/h264.h b/tools/h264.h deleted file mode 100644 index f3f32281..00000000 --- a/tools/h264.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * h264.h: H.264 bitstream decoding - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: h264.h,v 1.3 2008-05-20 11:00:42 phintuka Exp $ - * - */ - -#ifndef _XINELIBOUTPUT_H264_H_ -#define _XINELIBOUTPUT_H264_H_ - - -#ifdef __cplusplus -extern "C" { -#endif - -#include "mpeg.h" - -#define NAL_SPS 0x07 -#define NAL_AUD 0x09 - -typedef struct { - int num; - int den; -} h264_rational_t; - -typedef struct { - int width; - int height; - h264_rational_t pixel_aspect; - /* ... */ -} h264_sps_data_t; - -/* - * input: start of NAL SPS (without 00 00 01 07) - */ -int h264_parse_sps(const uint8_t *buf, int len, h264_sps_data_t *sps); - -/* - * input: start of H.264 video data (not PES) - */ -int h264_get_picture_type(const uint8_t *buf, int len); - -/* - * input: start of H.264 video data (not PES) - */ -int h264_get_video_size(const uint8_t *buf, int len, video_size_t *size); - - -#ifdef __cplusplus -} /* extern "C" { */ -#endif - - -#endif /* _XINELIBOUTPUT_H264_H_ */ diff --git a/tools/http.c b/tools/http.c deleted file mode 100644 index 4a529550..00000000 --- a/tools/http.c +++ /dev/null @@ -1,434 +0,0 @@ -/* - * http.c: HTTP (/RTSP) helper classes - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: http.c,v 1.6 2007-06-21 09:12:52 phintuka Exp $ - * - */ - -#define __STDC_FORMAT_MACROS -#include <inttypes.h> - -#include <string.h> - -#include <vdr/config.h> -#include <vdr/tools.h> - -#include "../logdefs.h" - -#include "http.h" - -// -// cHttpReq -// - -bool cHttpReq::SetCommand(const char *Command) -{ - char *tmp = strdup(Command); - char *pt = strchr(tmp, ' '), *uri; - - m_Valid = false; - if(pt) { - *pt++ = 0; - m_Name = tmp; - - while(*pt && *pt == ' ') pt++; - - uri = pt; - pt = strrchr(uri, ' '); - if(pt) { - m_Version = pt+1; - while(*pt && *pt == ' ') *pt-- = 0; - m_Uri = uri; - m_Valid = true; - } - } - - free(tmp); - return m_Valid; -} - -cHeader *cHttpReq::Header(const char *Name) -{ - for(cHeader *i = m_Headers.First(); i; i = m_Headers.Next(i)) - if(!strcmp(Name, i->Name())) - return i; - return NULL; -} - -void cHttpReq::AddHeader(const char *Header, bool Duplicate) -{ - if(strlen(Header) < 4096) { - char *name = strdup(Header); - char *val = strchr(name, ':'); - if(val) { - *val++ = 0; - while(*val == ' ') val++; - AddHeader(name, val, Duplicate); - } - free(name); - } else { - LOGMSG("cConnState::AddHeader: header length exceeds 4096 !"); - } -} - -void cHttpReq::AddHeader(const char *Name, const char *Value, bool Duplicate) -{ - if(strlen(Name) > 64 || strlen(Value) > 4096) { - LOGMSG("cConnState::AddHeader: header length exceeds limit !"); - } else { - cHeader *h = Header(Name); - if(!Duplicate && h) - h->SetValue(Value); - else { - if(m_Headers.Count() < 50) - m_Headers.Add(new cHeader(Name, Value)); - else - LOGMSG("cConnState::AddHeader: header count exceeds 50 !"); - } - } -} - -void cHttpReq::Reset(void) -{ - m_Name = NULL; - m_Uri = NULL; - m_Version = NULL; - m_Valid = false; - m_Headers.Clear(); -} - -// -// Map file extensions to mime types -// - -static const char *mimetype(const char *ext) -{ - static const struct { - const char *ext; - const char *mime; - } ext2mime[] = { - {"avi", "video/avi"}, - {"vob", "video/mpeg"}, - {"mpg", "video/mpeg"}, - {"mpeg", "video/mpeg"}, - {"vdr", "video/mp2p"}, - - {"mp3", "audio/mp3"}, - {"flac", "audio/flac"}, - - {"jpg", "image/jpeg"}, - {"jpeg", "image/jpeg"}, - {"gif", "image/gif"}, - - {NULL, NULL} - }; - - int i = -1; - while(ext2mime[++i].ext) - if(!strcmp(ext, ext2mime[i].ext)) - return ext2mime[i].mime; - return NULL; -} - -static char *unescape_uri(const char *uri) -{ - char *d = strdup(uri), *s = d, *result = d; - while(*s) { - if(s[0] == '%' && s[1] && s[2]) { - unsigned int c; - if (sscanf(s+1, "%02x", &c) == 1) { - *d++ = (char)c; - s += 3; - continue; - } - } - *d++ = *s++; - } - *d = 0; - return result; -} - -// -// cHttpStreamer -// - -cList<cHttpStreamer> cHttpStreamer::m_Streamers; - -void cHttpStreamer::CloseAll(bool OnlyFinished) -{ - if(!OnlyFinished) { - while(m_Streamers.First()) - m_Streamers.Del(m_Streamers.First()); - - } else { - /* purge finished streamers from list */ - cHttpStreamer *it = m_Streamers.First(); - while(it) { - if(it->Active()) { - it = (cHttpStreamer*)it->Next(); - } else { - m_Streamers.Del(it); - it = m_Streamers.First(); - } - } - } -} - -cHttpStreamer::cHttpStreamer(int fd_http, const char *filename, - cConnState *Request) : - m_Filename(unescape_uri(filename), true) -{ - m_fds.set_handle(fd_http); - m_fds.set_cork(true); - m_fdf = -1; - - //m_Filename = filename; - m_FileSize = -1; - m_Start = 0; - m_End = -1; - m_KeepOpen = true; - - m_ConnState = Request; - - m_Finished = false; - - CloseAll(true); - - m_Streamers.Add(this); - - if(m_Streamers.Count() > 5) { - LOGMSG("WARNING: There are %d running HTTP streamers !", m_Streamers.Count()); - if(m_Streamers.Count() > 20) { - errno = 0; - LOGERR("ERROR: There are %d running HTTP streamers, cancelling first", - m_Streamers.Count()); - m_Streamers.Del(m_Streamers.First()); - } - } - - Start(); -} - -cHttpStreamer::~cHttpStreamer() -{ - Cancel(3); - if(m_ConnState) - delete m_ConnState; - if(m_fdf >= 0) - close(m_fdf); - m_fdf = -1; -} - -void cHttpStreamer::ParseRange(const char *Range) -{ - m_Start = 0; - m_End = -1; - if(Range) { - LOGDBG("cHttpStreamer: Request range is \'%s\'", Range); - switch(sscanf(Range, "bytes=%" PRId64 "-%" PRId64, &m_Start, &m_End)) { - case 2: LOGMSG(" Range: %s (%" PRId64 " - %" PRId64 ")", Range, m_Start, m_End); - break; - case 1: m_End = -1; - LOGMSG(" Range start: %s (%" PRId64 " - )", Range, m_Start); - break; - default: - case 0: m_Start = 0; - m_End = -1; - break; - } - } -} - -bool cHttpStreamer::ParseRequest(void) -{ - cHeader *h; - - if((h = m_ConnState->Header("Range")) != NULL) - ParseRange(h->Value()); - - m_KeepOpen = false; - if((h = m_ConnState->Header("Connection")) != NULL) { - m_KeepOpen = !strcasecmp(h->Value(), "keep-alive"); - if(m_KeepOpen) - LOGDBG("cHttpStreamer: client wants to keep connection open"); - } - - return true; -} - -bool cHttpStreamer::Seek(void) -{ - if(m_fdf < 0) { - m_fdf = open(m_Filename, O_RDONLY); - if(m_fdf < 0) { - LOGERR("cHttpStreamer: error opening %s", *m_Filename); - m_fds.write_cmd(HTTP_REPLY_401); // 401 Not Found - return false; - } - - m_FileSize = lseek(m_fdf, 0, SEEK_END); - if(m_FileSize <= 0) { - LOGERR("cHttpStreamer: error seeking %s to end", *m_Filename); - m_fds.write_cmd(HTTP_REPLY_401); // 401 Not Found - return false; - } - } - - if(m_Start >= m_FileSize) { - LOGERR("cHttpStreamer: Requested range not available " - "(%s:%" PRId64 "-%" PRId64 " ; len=%" PRIu64 ")", - *m_Filename, m_Start, m_End, (uint64_t)m_FileSize); - m_fds.write_cmd(HTTP_REPLY_416); // 416 Requested Range Not Satisfiable - return false; - } - - if(m_Start > 0) { - if(m_End >= m_FileSize || m_End < 0) - m_End = m_FileSize-1; - - m_fds.write_cmd("HTTP/1.1 206 Partial Content\r\n"); - m_fds.printf("Content-Range: bytes %" PRId64 "-%" PRId64 "/%" PRIu64 "\r\n", - m_Start, m_End, (uint64_t)m_FileSize); - } else { - m_fds.write_cmd("HTTP/1.1 200 OK\r\n"); - } - - /* content type */ - char *ext = strrchr(m_Filename, '.'); - if(ext) { - const char *mime = mimetype(ext+1); - if(mime) - m_fds.printf("Content-Type: %s\r\n", mime); - } - - /* Content-Length */ - if(m_FileSize >= 0) { - int64_t len = m_FileSize; - if(m_End >= 0) - len = m_End + 1; - if(m_Start >= 0) - len -= m_Start; - m_fds.printf("Content-Length: %" PRId64 "\r\n", len); - } - - /* Connection and end of reply */ - if(m_KeepOpen) - m_fds.write_cmd("Connection: Keep-Alive\r\n" - "\r\n"); - else - m_fds.write_cmd("Connection: Close\r\n" - "\r\n"); - - if(m_Start) - lseek(m_fdf, (off_t)m_Start, SEEK_SET); - else - lseek(m_fdf, 0, SEEK_SET); - - return true; -} - -bool cHttpStreamer::ReadPipelined(void) -{ - char buf[2048]; - int r; - - if(m_ConnState) - delete m_ConnState; - m_ConnState = new cConnState; - - do { - r = m_fds.readline(buf, sizeof(buf), 1000); - if(r < 0 || errno == EAGAIN || r >= (int)sizeof(buf)) { - LOGMSG("cHttpStreamer: disconnected"); - return false; - } - - LOGMSG("cHttpStreamer: pipelined request: %s", buf); - - if(!*m_ConnState->Name()) { - if(!m_ConnState->SetCommand(buf) || - strcmp(m_ConnState->Name(), "GET") || - strncmp(m_ConnState->Uri(), "/PLAYFILE", 9) || - strncmp(m_ConnState->Version(), "HTTP/1.", 7)) { - LOGMSG("Incorrect HTTP request: %s", buf); - return false; - } - } - else if(r > 0) - m_ConnState->AddHeader(buf); - } while(r>0); - - return true; -} - -void cHttpStreamer::Action(void) -{ - int n = 0; - cxPoller p(m_fds); - bool Disc = !(ParseRequest() && Seek()); - uint64_t pos = m_Start; - off_t start = (off_t)m_Start; - - while(Running() && !Disc) { - - n = m_End>0 ? (m_End-start+1) : m_FileSize - start; - if(n > 0) { - errno = 0; - pthread_testcancel(); - n = m_fds.sendfile(m_fdf, &start, n); - pthread_testcancel(); - if(n <= 0) { - if(errno == EAGAIN || errno == EINTR) { - p.Poll(100); - pthread_testcancel(); - } else { - LOGERR("cHttpStreamer: sendfile() failed"); - Disc=true; - } - } else if(n == 0) { - LOGMSG("cHttpStreamer: disconnected at %" PRId64, (int64_t)start); - Disc = true; - } - continue; - } - - LOGDBG("cHttpStreamer: Hit to EOF or end of requested range"); - - m_fds.flush_cork(); - - if(!m_KeepOpen) { - LOGMSG("cHttpStreamer: disconnecting (request complete)"); - Disc = true; - continue; - } - - // keep connection open for new range for max. 30 sec - n = 30; - do { - pthread_testcancel(); - //cxPoller p(m_fds); - LOGDBG("cHttpStreamer: Request complete, waiting..."); - if(p.Poll(1000)) { - LOGDBG("cHttpStreamer: Reading pipelined request"); - pthread_testcancel(); - Disc = !(ReadPipelined() && ParseRequest() && Seek()); - pos = m_Start; - } - } while(--n && Running() && !Disc); - - if(n <= 0) { - LOGMSG("cHttpStreamer: Disconnecting (timeout)"); - Disc = true; - } - } - - close(m_fdf); - m_fdf = -1; - - m_fds.close(); - - m_Finished = true; -} diff --git a/tools/http.h b/tools/http.h deleted file mode 100644 index 2adcf8e3..00000000 --- a/tools/http.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * http.h: HTTP (/RTSP) helper classes - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: http.h,v 1.5 2007-01-07 09:45:48 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_HTTP_H_ -#define XINELIBOUTPUT_HTTP_H_ - -#include <vdr/tools.h> - - -#define HTTP_REPLY_401 \ - "HTTP/1.1 401 Unauthorized\r\n" \ - "Connection: Close\r\n" \ - "\r\n" - -#define HTTP_REPLY_404 \ - "HTTP/1.1 404 Not Found\r\n" \ - "Connection: Close\r\n" \ - "\r\n" - -#define HTTP_REPLY_416 \ - "HTTP/1.1 416 Requested Range Not Satisfiable\r\n" \ - "Connection: Close\r\n" \ - "\r\n" - -#define HTTP_REPLY_200_PRIMARY \ - "HTTP/1.1 200 OK\r\n" \ - "Content-Type: video/mpeg\r\n" \ - "Connection: Close\r\n" \ - "\r\n" -//"Content-Type: video/mp2p\r\n" - - -// -// cHeader -// - -class cHeader : public cListObject -{ - protected: - cString m_Name; - cString m_Value; - - private: - cHeader(); - - public: - cHeader(const char *Name, const char *Value) : - m_Name(Name), m_Value(Value) {}; - - const cString& Name(void) { return m_Name; } - const cString& Value(void) { return m_Value; } - int IntValue(void) { return *m_Value?atoi(m_Value):-1; } - void SetValue(const char *Value) { m_Value = Value; } -}; - - -// -// cHttpReq -// - -class cHttpReq -{ - private: - cString m_Name; - cString m_Uri; - cString m_Version; - cList<cHeader> m_Headers; - - bool m_Valid; - - public: - cHttpReq() : m_Valid(false) {} - - bool SetCommand(const char *Command); - const cString& Name(void) { return m_Name; } - const cString& Uri(void) { return m_Uri; } - const cString& Version(void) { return m_Version; } - bool Valid(void) { return m_Valid; } - - void AddHeader(const char *Header, bool Duplicate=false); - void AddHeader(const char *Name, const char *Value, bool Duplicate=false); - cHeader *Header(const char *Name); - - void Reset(void); -}; - - -// -// cConnState -// - -class cConnState : public cHttpReq -{ - public: -}; - - -// -// cHttpStreamer -// - -#include <vdr/tools.h> -#include <vdr/thread.h> - -#include "cxsocket.h" - -class cHttpStreamer : protected cListObject, cThread -{ - public: - cHttpStreamer(int fd_http, const char *filename, cConnState *Request); - virtual ~cHttpStreamer(); - - static void CloseAll(bool OnlyFinished = false); - - private: - static cList<cHttpStreamer> m_Streamers; - - cxSocket m_fds; - int m_fdf; - - cString m_Filename; - int64_t m_FileSize; - int64_t m_Start; - int64_t m_End; - bool m_KeepOpen; - - cConnState *m_ConnState; - - bool m_Finished; - - virtual void Action(void); - - bool ParseRequest(void); - void ParseRange(const char *Range); - bool ReadPipelined(void); - bool Seek(void); -}; - -#endif // XINELIBOUTPUT_HTTP_H_ - diff --git a/tools/iconv.h b/tools/iconv.h deleted file mode 100644 index 3ce0fb28..00000000 --- a/tools/iconv.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * iconv.h: iconv library wrapper - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: iconv.h,v 1.5 2007-09-18 09:13:13 phintuka Exp $ - * - */ - -#ifndef _XINELIBOUTPUT_ICONV_H_ -#define _XINELIBOUTPUT_ICONV_H_ - -#if defined(USE_ICONV) && USE_ICONV == 0 -# undef USE_ICONV -# warning iconv disabled -#endif - -#ifdef USE_ICONV -# include <iconv.h> -#endif - -class cIConv -{ -#ifdef USE_ICONV - private: - iconv_t m_ic; -#endif - - public: - cIConv(const char *SrcCharset = NULL, const char * DstCharset = NULL); - virtual ~cIConv(); - - cString Translate(const char *Text) const; -}; - -cIConv::cIConv(const char *SrcCharset, const char * DstCharset) -{ -#ifdef USE_ICONV - if(!SrcCharset) - SrcCharset = "UTF-8"; - if(!DstCharset) { -#if APIVERSNUM >= 10503 - DstCharset = cCharSetConv::SystemCharacterTable(); -#else - DstCharset = I18nCharSets()[Setup.OSDLanguage]; -#endif - } - m_ic = (iconv_t)-1; - - if(DstCharset) { - m_ic = iconv_open(DstCharset, SrcCharset); - - if(m_ic == (iconv_t)-1) - LOGERR("cIConv: iconv_open(\"%s\",\"%s\") failed", - SrcCharset, DstCharset); - } -#endif -} - -cIConv::~cIConv() -{ -#ifdef USE_ICONV - if(m_ic != (iconv_t)-1) - iconv_close(m_ic); -#endif -} - -cString cIConv::Translate(const char *Text) const -{ -#ifdef USE_ICONV - if(m_ic == (iconv_t)-1) - return cString(Text); - - size_t inc = strlen(Text); - size_t outc = inc<2048 ? 2048 : inc+1; -#ifdef __APPLE__ - const char *in = Text; -#else - char *in = (char*)Text; -#endif - char *buf = (char*)malloc(outc+1); - char *out = buf; - - size_t n = iconv(m_ic, &in, &inc, &out, &outc); - - if(n != (size_t)-1) { - *out = 0; - return cString(buf, true); - } - - LOGERR("cIConv: iconv(%s) failed at %d", Text, (int)(in - Text)); - free(buf); -#endif - - return cString(Text); -} - - -#endif // _XINELIBOUTPUT_ICONV_H_ diff --git a/tools/iso639.h b/tools/iso639.h deleted file mode 100644 index 66438f13..00000000 --- a/tools/iso639.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * iso639.h: iso-639-1 <-> iso-639-2 language code translations - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: iso639.h,v 1.1 2008-02-20 03:55:11 phintuka Exp $ - * - */ - -#ifndef __ISO_639_H -#define __ISO_639_H - -static const struct { - const char iso639_2[4]; - const char iso639_1[4]; -} ISO639_map[] = -{ - {"???", "??"}, - {"abk", "ab"}, - {"aar", "aa"}, - {"afr", "af"}, - {"alb", "sq"}, - {"amh", "am"}, - {"ara", "ar"}, - {"arm", "hy"}, - {"ast", "as"}, - {"aym", "ay"}, - {"aze", "az"}, - {"bak", "ba"}, - {"baq", "eu"}, - {"bel", "be"}, - {"ben", "bn"}, - {"bih", "bh"}, - {"bis", "bi"}, - {"bre", "br"}, - {"bul", "bg"}, - {"bur", "my"}, - {"cat", "ca"}, - {"chi", "zh"}, - {"cos", "co"}, - {"scr", "hr"}, - {"cze", "cs"}, - {"dan", "da"}, - {"dut", "nl"}, - {"dzo", "dz"}, - {"eng", "en"}, - {"epo", "eo"}, - {"est", "et"}, - {"fao", "fo"}, - {"fij", "fj"}, - {"fin", "fi"}, - {"fre", "fr"}, - {"fry", "fy"}, - {"glg", "gl"}, - {"geo", "ka"}, - {"ger", "de"}, - {"gre", "el"}, - {"grn", "gn"}, - {"guj", "gu"}, - {"hau", "ha"}, - {"heb", "he"}, - {"hin", "hi"}, - {"hun", "hu"}, - {"ice", "is"}, - {"ind", "id"}, - {"ina", "ia"}, - {"iku", "iu"}, - {"ipk", "ik"}, - {"gle", "ga"}, - {"ita", "it"}, - {"jpn", "ja"}, - {"jav", "jv"}, - {"kal", "kl"}, - {"kan", "kn"}, - {"kas", "ks"}, - {"kaz", "kk"}, - {"khm", "km"}, - {"kin", "rw"}, - {"kir", "ky"}, - {"kor", "ko"}, - {"kur", "ku"}, - {"lao", "lo"}, - {"lat", "la"}, - {"lav", "lv"}, - {"lin", "ln"}, - {"lit", "lt"}, - {"mac", "mk"}, - {"mlg", "mg"}, - {"may", "ms"}, - {"mlt", "ml"}, - {"mao", "mi"}, - {"mar", "mr"}, - {"mol", "mo"}, - {"mon", "mn"}, - {"nau", "na"}, - {"nep", "ne"}, - {"nor", "no"}, - {"oci", "oc"}, - {"ori", "or"}, - {"orm", "om"}, - {"per", "fa"}, - {"pol", "pl"}, - {"por", "pt"}, - {"pus", "ps"}, - {"que", "qu"}, - {"roh", "rm"}, - {"rum", "ro"}, - {"run", "rn"}, - {"rus", "ru"}, - {"smo", "sm"}, - {"sag", "sg"}, - {"san", "sa"}, - {"srp", "sr"}, - {"scr", "sh"}, - {"sna", "sn"}, - {"snd", "sd"}, - {"sin", "si"}, - {"slo", "sk"}, - {"slv", "sl"}, - {"som", "so"}, - {"sot", "st"}, - {"spa", "es"}, - {"sun", "su"}, - {"swa", "sw"}, - {"ssw", "ss"}, - {"swe", "sv"}, - {"tgl", "tl"}, - {"tgk", "tg"}, - {"tam", "ta"}, - {"tat", "tt"}, - {"tel", "te"}, - {"tha", "th"}, - {"tib", "bo"}, - {"tir", "ti"}, - {"tog", "to"}, - {"tso", "ts"}, - {"tsn", "tn"}, - {"tur", "tr"}, - {"tuk", "tk"}, - {"twi", "tw"}, - {"uig", "ug"}, - {"ukr", "uk"}, - {"urd", "ur"}, - {"uzb", "uz"}, - {"vie", "vi"}, - {"vol", "vo"}, - {"wel", "cy"}, - {"wol", "wo"}, - {"xho", "xh"}, - {"yid", "yi"}, - {"yor", "yo"}, - {"zha", "za"}, - {"zul", "zu"}, -}; - -static const char *iso639_2_to_iso639_1(const char *lang) -{ - if (lang && lang[0]) { - if(lang[1] && !lang[2]) { - for (unsigned int i = 0 ; i < sizeof(ISO639_map) / sizeof(ISO639_map[0]); i++) - if (((uint16_t*)ISO639_map[i].iso639_1)[0] == ((uint16_t*)lang)[0]) - return ISO639_map[i].iso639_2; - LOGMSG("Unknown iso639-2 code: %s", lang); - } - return lang; - } - return NULL; -} - -#endif diff --git a/tools/listiter.h b/tools/listiter.h deleted file mode 100644 index 9c88940e..00000000 --- a/tools/listiter.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * listiter.h: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: listiter.h,v 1.1 2006-06-03 10:04:27 phintuka Exp $ - * - */ - - -#ifndef _LISTITER_H_ -#define _LISTITER_H_ - -//------------------------------ list ---------------------------------------- - -template <class LIST,class ITEM, class RESULT> -void ForEach(LIST& List, RESULT (ITEM::*f)()) -{ - for(ITEM *it = List.First(); it; it = List.Next(it)) - (*it.*f)(); -} - -template <class LIST,class ITEM, class ARG1, class RESULT> -void ForEach(LIST& List, RESULT (ITEM::*f)(ARG1), ARG1 arg1) -{ - for(ITEM *it = List.First(); it; it = List.Next(it)) - (*it.*f)(arg1); -} - -template <class LIST,class ITEM, class ARG1, class ARG2> -void ForEach(LIST& List, void (ITEM::*f)(ARG1,ARG2), ARG1 arg1, ARG2 arg2) -{ - for(ITEM *it = List.First(); it; it = List.Next(it)) - (*it.*f)(arg1,arg2); -} - -template <class LIST,class ITEM, class ARG1, class RESULT> -RESULT ForEach(LIST& List, RESULT (ITEM::*f)(ARG1), ARG1 arg1, - RESULT (*combiner)(RESULT,RESULT), RESULT def) -{ - RESULT result = def; - for(ITEM *it = List.First(); it; it = List.Next(it)) - result = (*combiner)((*it.*f)(arg1),result); - return result; -} - -template <class LIST,class ITEM, class ARG1, class ARG2, class RESULT> -RESULT ForEach(LIST& List, RESULT (ITEM::*f)(ARG1,ARG2), - ARG1 arg1, ARG2 arg2, - RESULT (*combiner)(RESULT,RESULT), RESULT def) -{ - RESULT result = def; - for(ITEM *it = List.First(); it; it = List.Next(it)) - result = (*combiner)((*it.*f)(arg1,arg2),result); - return result; -} - -template <class LIST,class ITEM, class ARG1, class ARG2, class ARG3, - class RESULT> -RESULT ForEach(LIST& List, RESULT (ITEM::*f)(ARG1,ARG2,ARG3), - ARG1 arg1, ARG2 arg2, ARG3 arg3, - RESULT (*combiner)(RESULT,RESULT), RESULT def) -{ - RESULT result = def; - for(ITEM *it = List.First(); it; it = List.Next(it)) - result = (*combiner)((*it.*f)(arg1,arg2,arg3),result); - return result; -} - -template<class T> -T mmin(T a, T b) {return a<b ? a : b;} - -template<class T> -T mmax(T a, T b) {return a>b ? a : b;} - -template<class T> -T mand(T a, T b) {return a&&b;} - -template<class T> -T mor(T a, T b) {return a||b;} - -#endif diff --git a/tools/metainfo_menu.h b/tools/metainfo_menu.h deleted file mode 100644 index 45d60f22..00000000 --- a/tools/metainfo_menu.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * metainfo_menu.h: Media file info menu - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: metainfo_menu.h,v 1.1 2008-05-07 13:27:15 phintuka Exp $ - * - */ - -#ifndef __XINELIB_INFO_MENU_H_ -#define __XINELIB_INFO_MENU_H_ - -// -// cMetainfoMenu -// - -#include <vdr/osdbase.h> - -class cMetainfoMenu : public cOsdMenu -{ - protected: - - cString m_Filename; - - public: - - cMetainfoMenu(cString Filename); - virtual ~cMetainfoMenu(); - - virtual void Display(void); - - // cOsdMenu - virtual eOSState ProcessKey(eKeys Key); - -}; - -#endif // __XINELIB_INFO_MENU_H_ diff --git a/tools/mpeg.c b/tools/mpeg.c deleted file mode 100644 index 35e95da3..00000000 --- a/tools/mpeg.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * mpeg.c: - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: mpeg.c,v 1.1 2008-02-04 22:42:13 phintuka Exp $ - * - */ - -#include "mpeg.h" - - -const char * const picture_type_str[] = { - "(none)", - "I-Frame", - "B-Frame", - "P-Frame" -}; - - -int mpeg2_get_picture_type(const uint8_t *buf, int len) -{ - int i; - for (i = 0; i < len-5; i++) { - if (buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 1) { - switch (buf[i + 3]) { - case SC_PICTURE: - return (buf[i + 5] >> 3) & 0x07; - } - } - } - return NO_PICTURE; -} - -int mpeg2_get_video_size(const uint8_t *buf, int len, video_size_t *size) -{ - int i; - for (i = 0; i < len-6; i++) { - if (buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 1) { - if (buf[i + 3] == SC_SEQUENCE) { - int d = (buf[i+4] << 16) | (buf[i+5] << 8) | buf[i+6]; - size->width = (d >> 12); - size->height = (d & 0xfff); - return 1; - } - } - } - return 0; -} - diff --git a/tools/mpeg.h b/tools/mpeg.h deleted file mode 100644 index c17ee0ec..00000000 --- a/tools/mpeg.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * mpeg.h: MPEG definitions - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: mpeg.h,v 1.2 2008-03-16 22:12:56 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_MPEG_H_ -#define XINELIBOUTPUT_MPEG_H_ - - -#ifdef __cplusplus -extern "C" { -#endif - - -#define SC_PICTURE 0x00 /* picture atart code */ -#define SC_SEQUENCE 0xb3 /* sequence header */ - -/* Picture types */ -#define NO_PICTURE 0 -#define I_FRAME 1 -#define P_FRAME 2 -#define B_FRAME 3 - - -typedef struct { - int width; - int height; - double pixel_aspect; -} video_size_t; - - -extern const char * const picture_type_str[]; - -/* - * input: start of MPEG video data (not PES) - */ -int mpeg2_get_picture_type(const uint8_t *buf, int len); - -/* - * input: start of MPEG video data (not PES) - */ -int mpeg2_get_video_size(const uint8_t *buf, int len, video_size_t *size); - - -#ifdef __cplusplus -} /* extern "C" { */ -#endif - - -#endif diff --git a/tools/pes.c b/tools/pes.c deleted file mode 100644 index 2b68c55b..00000000 --- a/tools/pes.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * pes.h: PES header definitions - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: pes.c,v 1.4 2008-05-20 11:09:52 phintuka Exp $ - * - */ - -#include "mpeg.h" -#include "h264.h" - -#include "pes.h" - - -int64_t pes_get_pts(const uint8_t *buf, int len) -{ - /* assume mpeg2 pes header ... */ - if (IS_VIDEO_PACKET(buf) || IS_AUDIO_PACKET(buf)) { - - if ((buf[6] & 0xC0) != 0x80) - return INT64_C(-1); - if ((buf[6] & 0x30) != 0) - return INT64_C(-1); - - if ((len > 13) && (buf[7] & 0x80)) { /* pts avail */ - int64_t pts; - pts = ((int64_t)(buf[ 9] & 0x0E)) << 29 ; - pts |= ((int64_t) buf[10]) << 22 ; - pts |= ((int64_t)(buf[11] & 0xFE)) << 14 ; - pts |= ((int64_t) buf[12]) << 7 ; - pts |= ((int64_t)(buf[13] & 0xFE)) >> 1 ; - return pts; - } - } - return INT64_C(-1); -} - -int64_t pes_get_dts(const uint8_t *buf, int len) -{ - if (IS_VIDEO_PACKET(buf) || IS_AUDIO_PACKET(buf)) { - - if ((buf[6] & 0xC0) != 0x80) - return INT64_C(-1); - if ((buf[6] & 0x30) != 0) - return INT64_C(-1); - - if (len > 18 && (buf[7] & 0x40)) { /* dts avail */ - int64_t dts; - dts = ((int64_t)( buf[14] & 0x0E)) << 29 ; - dts |= (int64_t)( buf[15] << 22 ); - dts |= (int64_t)((buf[16] & 0xFE) << 14 ); - dts |= (int64_t)( buf[17] << 7 ); - dts |= (int64_t)((buf[18] & 0xFE) >> 1 ); - return dts; - } - } - return INT64_C(-1); -} - -void pes_change_pts(uint8_t *buf, int len, int64_t new_pts) -{ - /* assume mpeg2 pes header ... Assume header already HAS pts */ - if (IS_VIDEO_PACKET(buf) || IS_AUDIO_PACKET(buf)) { - - if ((buf[6] & 0xC0) != 0x80) - return; - if ((buf[6] & 0x30) != 0) - return; - - if ((len > 13) && (buf[7] & 0x80)) { /* pts avail */ - buf[ 9] = ((new_pts >> 29) & 0x0E) | (buf[ 9] & 0xf1); - buf[10] = ((new_pts >> 22) & 0xFF); - buf[11] = ((new_pts >> 14) & 0xFE) | (buf[11] & 0x01); - buf[12] = ((new_pts >> 7 ) & 0xFF); - buf[13] = ((new_pts << 1 ) & 0xFE) | (buf[13] & 0x01); - } - } -} - -int pes_strip_pts_dts(uint8_t *buf, int size) -{ - if(size > 13 && buf[7] & 0x80) { /* pts avail */ - int n = 5; - int pes_len = (buf[4] << 8) | buf[5]; - if ((buf[6] & 0xC0) != 0x80) - return size; - if ((buf[6] & 0x30) != 0) /* scrambling control */ - return size; - /* dts too ? */ - if(size > 18 && buf[7] & 0x40) - n += 5; - pes_len -= n; /* update packet len */ - buf[4] = pes_len >> 8; /* packet len (hi) */ - buf[5] = pes_len & 0xff; /* packet len (lo) */ - buf[7] &= 0x7f; /* clear pts flag */ - buf[8] -= 5; /* update header len */ - memmove(buf+4+n, buf+9+n, size-9-n); - return size - n; - } - return size; -} - -int pes_is_frame_h264(const uint8_t *buf, int len) -{ - if (len < 9 || len < 9 + buf[8]) - return 0; - if ( (buf[6] & 0xC0) != 0x80) /* MPEG 2 PES */ - return 0; - - buf += 9 + buf[8]; - - if (!buf[0] && !buf[1] && buf[2] == 0x01 && buf[3] == NAL_AUD) - return 1; - return 0; -} - -uint8_t pes_get_picture_type(const uint8_t *buf, int len) -{ - int i = 8; /* the minimum length of the video packet header */ - i += buf[i] + 1; /* possible additional header bytes */ - - buf += i; - len -= i; - - if (!buf[0] && !buf[1] && buf[2]) { - if (buf[3] == NAL_AUD) - return h264_get_picture_type(buf, len); - else - return mpeg2_get_picture_type(buf, len); - } - return NO_PICTURE; -} - -int pes_get_video_size(const uint8_t *buf, int len, video_size_t *size, int h264) -{ - int i = 8; - - i += buf[i] + 1; /* possible additional header bytes */ - - buf += i; - len -= i; - - if (h264 || (!buf[0] && !buf[1] && buf[2] == 0x01 && buf[3] == NAL_AUD)) - return h264_get_video_size(buf, len, size); - else - return mpeg2_get_video_size(buf, len, size); - - return 0; -} - diff --git a/tools/pes.h b/tools/pes.h deleted file mode 100644 index c55a4ed5..00000000 --- a/tools/pes.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * pes.h: PES header definitions - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: pes.h,v 1.6 2008-02-04 23:59:30 phintuka Exp $ - * - */ - -#ifndef _PES_H_ -#define _PES_H_ - -#include "mpeg.h" - - -/* - * Constants - */ - -#define PES_CHUNK_SIZE 2048 - -#define MAX_SCR ((int64_t)0x1ffffffffLL) - -/* PES PIDs */ -#define PRIVATE_STREAM1 0xBD -#define PADDING_STREAM 0xBE -#define PRIVATE_STREAM2 0xBF -#define AUDIO_STREAM_S 0xC0 /* 1100 0000 */ -#define AUDIO_STREAM_E 0xDF /* 1101 1111 */ -#define VIDEO_STREAM_S 0xE0 /* 1110 0000 */ -#define VIDEO_STREAM_E 0xEF /* 1110 1111 */ - -#define AUDIO_STREAM_MASK 0x1F /* 0001 1111 */ -#define VIDEO_STREAM_MASK 0x0F /* 0000 1111 */ -#define AUDIO_STREAM 0xC0 /* 1100 0000 */ -#define VIDEO_STREAM 0xE0 /* 1110 0000 */ - -#define ECM_STREAM 0xF0 -#define EMM_STREAM 0xF1 -#define DSM_CC_STREAM 0xF2 -#define ISO13522_STREAM 0xF3 -#define PROG_STREAM_DIR 0xFF - -#define IS_VIDEO_PACKET(data) (VIDEO_STREAM == ((data)[3] & ~VIDEO_STREAM_MASK)) -#define IS_AUDIO_PACKET(data) ((AUDIO_STREAM == ((data)[3] & ~AUDIO_STREAM_MASK)) || \ - (PRIVATE_STREAM1 == (data)[3])) - -#define PES_HAS_PTS(data) ((data)[7] & 0x80) -#define PES_HAS_DTS(data) ((data)[7] & 0x40) - -/* - * timestamps - */ - - -int64_t pes_get_pts(const uint8_t *buf, int len); -int64_t pes_get_dts(const uint8_t *buf, int len); -void pes_change_pts(uint8_t *buf, int len, int64_t new_pts); -int pes_strip_pts_dts(uint8_t *buf, int len); - -/* - * payload - */ - -int pes_is_frame_h264(const uint8_t *buf, int len); -uint8_t pes_get_picture_type(const uint8_t *buf, int len); -int pes_get_video_size(const uint8_t *buf, int len, video_size_t *size, int h264); - -static inline int pes_is_mpeg1(const uint8_t *header) -{ - if (IS_VIDEO_PACKET(header) || IS_AUDIO_PACKET(header)) - return ((header[6] & 0xC0) != 0x80); - if (header[3] == 0xBA) - return ((header[4] & 0x40) == 0); /* mpeg1 */ - return 0; -} - -/* - * Extract PES packet length - */ - -static inline int pes_packet_len(const uint8_t *data, const int len) -{ - if (IS_VIDEO_PACKET(data) || IS_AUDIO_PACKET(data)) { - return 6 + (data[4] << 8 | data[5]); - } else if (data[3] == PADDING_STREAM) { - return 6 + (data[4] << 8 | data[5]); - } else if (data[3] == 0xBA) { - if ((data[4] & 0x40) == 0) /* mpeg1 */ - return 12; - else /* mpeg 2 */ - return 14 + (data[0xD] & 0x07); - } else if (data[3] <= 0xB9) { - return -3; - } - return -(6 + (data[4] << 8 | data[5])); -} - - -#endif /* _PES_H_ */ diff --git a/tools/playlist.c b/tools/playlist.c deleted file mode 100644 index 9f4c85c3..00000000 --- a/tools/playlist.c +++ /dev/null @@ -1,1000 +0,0 @@ -/* - * playlist.c: Media player playlist - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: playlist.c,v 1.17 2008-04-03 15:11:26 phelin Exp $ - * - */ - -#include <stdlib.h> - -#ifdef HAVE_EXTRACTOR_H -# include <extractor.h> - // libextractor 0.5.20 (2008-03-20) adds support for track numbers -# if EXTRACTOR_VERSION < 0x00052000 -# warning libextractor version too old (0.5.20 required for track numbers) -# undef HAVE_EXTRACTOR_H -# endif -#endif - -#include <vdr/config.h> -#include <vdr/tools.h> -#include <vdr/thread.h> - -#include "../config.h" - -#include "playlist.h" - -#include "../logdefs.h" - - -#ifndef PLAYLIST_CACHE -# define PLAYLIST_CACHE ".xineliboutput-playlist.pls" -#endif - -#define MAX_PLAYLIST_FILES 1024 - - -// -// cPlaylistItem -// - -cPlaylistItem::cPlaylistItem(const char *filename) -{ - char *pt; - - Filename = filename; - Position = -1; - - if(NULL != (pt = strrchr(filename, '/'))) - Title = pt + 1; - else - Title = filename; - - if(NULL != (pt = strrchr(Title, '.'))) - *pt = 0; -} - -cPlaylistItem::cPlaylistItem(const char *filename, - const char *path, - const char *title, - int position) -{ - char *pt; - - if(path[strlen(path)-1] != '/') - Filename = cString::sprintf("%s/%s", path, filename); - else - Filename = cString::sprintf("%s%s", path, filename); - Position = position; - Title = title ?: filename; - - if(!title && (pt = strrchr(Title, '.'))) - *pt = 0; -} - -int cPlaylistItem::Compare(const cListObject &ListObject) const -{ - ///< Must return 0 if this object is equal to ListObject, a positive value - ///< if it is "greater", and a negative value if it is "smaller". - - const cPlaylistItem *o = (cPlaylistItem *)&ListObject; - - // Use Position (if defined in playlist file) - // compare as unsigned --> -1 goes to last position - if(Position != o->Position) - return ((unsigned int)Position) > ((unsigned int)o->Position) ? 1 : -1; - - // same position (or no positions definend) -> alphabetical order -#if 0 - return strcmp(Title, o->Title); -#else - // use filename, because: - // - implicit playlist has no track names available when sorting - // (track names are read during playback), so track name is - // just file name without path. - // using full path allows sorting of each album and tracks inside albums... - // - "normal" playlist is ordered using Position, - // so track names are never compared anyway ... - return strcmp(Filename, o->Filename); -#endif -} - - -// -// cID3Scanner -// - -#ifndef HAVE_EXTRACTOR_H -static const char *shell_escape(char *buf, int buflen, const cString& src, char ch) -{ - const char *pt = *src; - int n = 0; - - if(pt) { - while(*pt && n < buflen-2) { - if(*pt == ch || *pt == '\\' /*|| *pt == '\"' || *pt == '\''*/) { - buf[n++] = '\\'; - } - buf[n++] = *pt++; - } - buf[n] = 0; - return buf; - } - return ""; -} -#endif - -class cID3Scanner : public cThread -{ - public: - cPlaylist& m_List; - cID3Scanner(cPlaylist& List) : cThread("Metadata scanner"), m_List(List), m_Done(false) {}; - - void CancelScanner(void) { Cancel(3); } - - private: - bool m_Done; - - virtual void Action(void) - { - cPlaylistItem *Item = NULL; - unsigned int Version = 0; - - (void)nice(10); - - LOGDBG("ID3Scanner Started"); - while(Running()) { - - cMutexLock ml(&m_List.m_Lock); - - if(Version < m_List.m_Version) { - // restart after sort, add, del - Item = NULL; - Version = m_List.m_Version; - } - - if(!(Item = m_List.Next(Item))) - break; - - if(xc.IsAudioFile(Item->Filename)) { - LOGDBG("Scanning metainfo for file %s", *Item->Filename); -#ifdef HAVE_EXTRACTOR_H - EXTRACTOR_ExtractorList * plugins; - EXTRACTOR_KeywordList * md_list; - plugins = EXTRACTOR_loadDefaultLibraries(); - md_list = EXTRACTOR_getKeywords(plugins, *Item->Filename); - const char *key; - while(md_list) { - if ((key=EXTRACTOR_getKeywordTypeAsString(md_list->keywordType))) { - if (!strcasecmp(key,"title")) - Item->Title = strdup(md_list->keyword); - else if (!strcasecmp(key,"artist")) - Item->Artist = strdup(md_list->keyword); - else if (!strcasecmp(key,"album")) - Item->Album = strdup(md_list->keyword); - else if (!strcasecmp(key,"track number")) - Item->Tracknumber = cString::sprintf("%s%s", strlen(md_list->keyword) == 1 ? "0" : "", md_list->keyword); - md_list=md_list->next; - } - } - EXTRACTOR_freeKeywords(md_list); - EXTRACTOR_removeAll(plugins); /* unload plugins */ -#else - char buf[4096]; - cString Cmd = ""; - if(!strcasecmp((Item->Filename) + strlen(Item->Filename) - 5, ".flac")) - Cmd = cString::sprintf("metaflac " - " --show-tag=TITLE " - " --show-tag=ALBUM " - " --show-tag=ARTIST " - " --show-tag=TRACKNUMBER " - " \"%s\"", - shell_escape(buf, sizeof(buf)-1, Item->Filename, '\"')); - else - Cmd = cString::sprintf("mp3info -p \"" - "ARTIST=%%a\\r\\n" - "ALBUM=%%l\\r\\n" - "TITLE=%%t\\r\\n" - "TRACKNUMBER=%%n\\r\\n\"" - " \"%s\"", - shell_escape(buf, sizeof(buf)-1, Item->Filename, '\"')); - - cPipe p; - if(p.Open(*Cmd, "r")) { - cReadLine r; - char *pt; - while(NULL != (pt = r.Read(p))) { - if(!strncasecmp(pt, "ARTIST=", 7) && strlen(pt) > 8) - Item->Artist = (pt+7); - else if(!strncasecmp(pt, "ALBUM=", 6) && strlen(pt) > 7) - Item->Album = (pt+6); - else if(!strncasecmp(pt, "TITLE=", 6) && strlen(pt) > 7) - Item->Title = (pt+6); - else if(!strncasecmp(pt, "TRACKNUMBER=", 12) && strlen(pt) > 12) - Item->Tracknumber = cString::sprintf("%s%s", strlen(pt) == 13 ? "0" : "", (pt+12)); - } - } -#endif - } - } - LOGDBG("ID3Scanner Done."); - - m_List.PlaylistChanged(Item); - m_Done = true; - } -}; - -// -// cPlaylistReader -// - -class cPlaylistReader -{ - private: - cPlaylist& m_Playlist; - - protected: - cString m_Title; - int m_Position; - - cPlaylistItem *Prev(void) { return m_Playlist.Last(); } - - public: - cPlaylistReader(cPlaylist& Playlist) : m_Playlist(Playlist) {} - virtual ~cPlaylistReader() {} - - virtual char *Parse(char *line) = 0; - - void ResetCache(void) { m_Title = NULL; m_Position = -1; } - const char *Title(void) { return m_Title; } - int Position(void) { return m_Position; } -}; - -class cM3uReader : public cPlaylistReader -{ - public: - cM3uReader(cPlaylist& Playlist) : cPlaylistReader(Playlist), m_Next(1) {} - - protected: - int m_Next; - virtual char *Parse(char *line) { - if(!*line) - return NULL; - if(*line == '#') { - if(!strncmp(line, "#EXTINF:", 8)) { - int len = -1; - sscanf(line+8,"%d", &len); - while(*line && *line != ',') - line++; - m_Title = *line ? (line+1) : NULL; - m_Position = m_Next++; - } - return NULL; - } - return *line ? line : NULL; - } -}; - -class cPlsReader : public cPlaylistReader -{ - public: - cPlsReader(cPlaylist& Playlist) : cPlaylistReader(Playlist), m_Current(0) {} - - protected: - int m_Current; - virtual char *Parse(char *line) { - char *t = strchr(line, '='); - if(t) { - int n; - if(!strncasecmp(line, "file", 4) && - 1 == sscanf(line + 4, "%d=", &n)) { - m_Current = n; - m_Position = n; - if(*(t+1)) - return t+1; - } - else if(!strncasecmp(line, "title", 5) && - 1 == sscanf(line + 5, "%d=", &n)) { - if(*(t+1)) { - if(n == m_Current) - Prev()->Title = t; - else - m_Title = t; - } - } - //else if(!strncasecmp(line, "length", 6) && - // 1 == sscanf(line + 4, "%d=", &n)) { - //} - } - return NULL; - } -}; - -class cAsxReader : public cPlaylistReader -{ - public: - cAsxReader(cPlaylist& Playlist) : cPlaylistReader(Playlist) {} - - protected: - virtual char *Parse(char *line) { - char *pt = strstr(line, "<REF HREF"); - if(!pt) - pt = strstr(line, "<ref href"); - if(!pt) - pt = strstr(line, "<ENTRY HREF"); - if(!pt) - pt = strstr(line, "<entry href"); - if(pt) { - pt = strchr(pt, '='); - if(pt) { - pt = strchr(pt, '\"'); - if(pt) { - pt++; - if(strchr(pt, '\"')) - *strchr(pt, '\"') = 0; - return pt; - } - } - } - - pt = strstr(line, "<TITLE>"); - if(!pt) - pt = strstr(line, "<title>"); - if(pt) { - pt += 7; - if(strstr(line, "</")) - *strstr(line, "</") = 0; - m_Title = pt; - } - - if(*m_Title) { - pt = strstr(line, "<ENTRY>"); - if(!pt) - pt = strstr(line, "<entry>"); - if(pt) { - if(*m_Title && Prev()) { - Prev()->Title = m_Title; - m_Title = NULL; - } - } - } - return NULL; - } -}; - - -// -// cPlaylist -// - -cPlaylist::cPlaylist() -{ - m_Origin = eImplicit; - m_Menu = NULL; - m_Scanner = NULL; - m_Current = NULL; - m_Version = 1; -} - -cPlaylist::~cPlaylist() -{ - if(m_Scanner) { - m_Scanner->CancelScanner(); - delete m_Scanner; - } - - if(m_Origin == eImplicit) - StoreCache(); -} - -void cPlaylist::Listen(cPlaylistChangeNotify *Menu) -{ - cMutexLock ml(&m_Lock); - m_Menu = Menu; -} - -void cPlaylist::PlaylistChanged(const cPlaylistItem *Item) -{ - cMutexLock ml(&m_Lock); - /*if(m_Origin == eImplicit)*/ - Sort(); - if(m_Menu) - m_Menu->PlaylistChanged(Item); -} - -void cPlaylist::Sort(void) -{ - cMutexLock ml(&m_Lock); - cListBase::Sort(); - m_Version++; -} - -int cPlaylist::Count(void) const -{ - return cListBase::Count(); -} - -cPlaylistItem *cPlaylist::Next(const cPlaylistItem *i) -{ - cMutexLock ml(&m_Lock); - return i ? cList<cPlaylistItem>::Next(i) : cList<cPlaylistItem>::First(); -} - -cPlaylistItem *cPlaylist::Current(void) -{ - cMutexLock ml(&m_Lock); - return m_Current ?: First(); -} - -void cPlaylist::Del(cPlaylistItem *it) -{ - cMutexLock ml(&m_Lock); - - if(!it || Count() < 2) - return; - - if(m_Current == it) - m_Current = cList<cPlaylistItem>::Next(Current()) ?: - cList<cPlaylistItem>::Prev(Current()); - - cListBase::Del(it); - m_Version++; -} - -void cPlaylist::SetCurrent(cPlaylistItem *current) -{ - cMutexLock ml(&m_Lock); - m_Current = current; -} - -cPlaylistItem *cPlaylist::Next(void) -{ - cMutexLock ml(&m_Lock); - if(Current()) - return m_Current = (cList<cPlaylistItem>::Next(Current()) ?: First()); - return NULL; -} - -cPlaylistItem *cPlaylist::Prev(void) -{ - cMutexLock ml(&m_Lock); - if(Current()) - return m_Current = (cList<cPlaylistItem>::Prev(Current()) ?: Last()); - return NULL; -} - -bool cPlaylist::StoreCache(void) -{ - if(!xc.cache_implicit_playlists || - m_Origin != eImplicit || - !*m_Folder) - return false; - - cString Name = cString::sprintf("%s%s", *m_Folder, PLAYLIST_CACHE); - int len = strlen(m_Folder), entries = 0; - FILE *f = NULL; - - for(cPlaylistItem *i = First(); i; i=Next(i)) { - // store only items in "current" root folder - if(!strncmp(i->Filename, m_Folder, len)) { - if(/**i->Title ||*/ *i->Artist || *i->Album) { - cString Filename = ((*i->Filename) + len); // relative - if(entries < 1) { - f = fopen(Name, "w"); - if(!f) { - LOGERR("creation of metadata cache %s%s failed", - *m_Folder, PLAYLIST_CACHE); - return false; - } - fprintf(f, "[playlist]\r\n"); - } - entries++; - fprintf(f, "File%d=%s\r\n", entries, *Filename); - if(*i->Title && (*i->Title)[0]) - fprintf(f, "Title%d=%s\r\n", entries, *i->Title); - if(*i->Tracknumber && (*i->Tracknumber)[0]) - fprintf(f, "Tracknumber%d=%s\r\n", entries, *i->Tracknumber); - if(*i->Artist && (*i->Artist)[0]) - fprintf(f, "Artist%d=%s\r\n", entries, *i->Artist); - if(*i->Album && (*i->Album)[0]) - fprintf(f, "Album%d=%s\r\n", entries, *i->Album); - } - } - } - - if(entries > 0) { - fprintf(f, "NumberOfEntries=%d\r\nVersion=2\r\n", entries); - fclose(f); - return true; - } - - return false; -} - -static const char *strchrnext(const char *s, char c) -{ - return (s = strchr(s, c)) ? ((*(s+1))?(s+1):NULL) : NULL; -} - -bool cPlaylist::ReadCache(void) -{ - if(xc.cache_implicit_playlists && m_Origin == eImplicit && *m_Folder) { - - cString Name = cString::sprintf("%s%s", *m_Folder, PLAYLIST_CACHE); - FILE *f = fopen(Name, "r"); - if(f) { - int len = strlen(m_Folder); - cPlaylistItem *it = NULL; - cReadLine r; - char *pt; - while(NULL != (pt = r.Read(f))) { - if(!strncmp(pt, "File", 4)) { - it = NULL; - const char *Filename = strchrnext(pt+4, '='); - if(Filename && *Filename) { - for(cPlaylistItem *i = First(); i; i=Next(i)) { - if(!strncmp(i->Filename, m_Folder, len)) { - if(!strcmp(*i->Filename + len, Filename)) { - it = i; - break; - } - } - } - } - } else if(it && !strncmp(pt, "Title", 5)) { - it->Title = strchrnext(pt, '='); - } else if(it && !strncmp(pt, "Tracknumber", 11)) { - it->Tracknumber = strchrnext(pt, '='); - } else if(it && !strncmp(pt, "Artist", 6)) { - it->Artist = strchrnext(pt, '='); - } else if(it && !strncmp(pt, "Album", 5)) { - it->Album = strchrnext(pt, '='); - } else { - /*it = NULL;*/ - } - } - fclose(f); - return true; - } - } - - return false; -} - -#if 0 -static FILE *open_http(const char *PlaylistFile) -{ - char file[1024] = "", host[128] = "", pt; - int fd, port = 80; - - strn0cpy(host, PlaylistFile+strlen("http://"), sizeof(host)-1); - pt = strchr(host, '/'); - if(pt) { - strn0cpy(file, pt, sizeof(file)-1); - *pt = 0; - } - pt = strchr(host, ':'); - if(pt) { - *pt++ = 0; - port = atoi(pt); - } - - fd = tcp_connect(host, port); - if(fd < 0) { - LOGERR("TCP connect failed"); - return NULL; - } - - int len = asprintf(&pt, - "GET %s HTTP/1.1" "\r\n" - "Host: %s" "\r\n" - "\r\n", - file, host); - if(len != write(fd, pt, len)) { - LOGERR("HTTP request write failed"); - free(pt); - close(fd); - return NULL; - } - free(pt); - - int state = 0; - FILE *f = fdopen(fd, "r"); - cReadLine r; - while(state >= 0 && NULL != (pt = r.Read(f))) { - switch(state) { - case 0: if(!strncmp(pt, "HTTP/1", 6) || !strstr(pt, " 200 ")) { - LOGERR("HTTP error: %s", pt); - fclose(f); - return NULL; - } - state = 1; - break; - case 1: if(strcmp(pt, "\r\n")) - break; - return f; - default: break; - } - } - - fclose(f); - return NULL; -} -#endif - -int cPlaylist::ScanFolder(const char *FolderName, - bool Recursive, - bool (config_t::*Filter)(const char *)) -{ - cMutexLock ml(&m_Lock); - static int depth = 0; - - DIR *d = opendir(FolderName); - - if (d) { - LOGDBG("ScanFolder(%s)", FolderName); - struct dirent *e; - int n = 0, warn = -1; - while ((e = readdir(d)) != NULL) { - cString Buffer = cString::sprintf("%s%s", FolderName, e->d_name); - struct stat st; - if (stat(Buffer, &st) == 0) { - if(S_ISDIR(st.st_mode)) { - if (Recursive && !S_ISLNK(st.st_mode)) { /* don't want to loop ... */ - if(depth > 4) { - LOGMSG("ScanFolder: Too deep directory tree"); - } else if(e->d_name[0]=='.') { - } else { - if(n<MAX_PLAYLIST_FILES) { - depth++; /* limit depth */ - Buffer = cString::sprintf("%s/", *Buffer); - n += ScanFolder(Buffer, Recursive, Filter); - depth--; - } else { - if(!++warn) - LOGMSG("ScanFolder: Found over %d matching files, list truncated!", n); - break; - } - } - } - } else /* == if(!S_ISDIR(st.st_mode))*/ { - // check symlink destination - if (S_ISLNK(st.st_mode)) { - Buffer = ReadLink(Buffer); - if (!*Buffer) - continue; - if (stat(Buffer, &st) != 0) - continue; - } - if((xc.*Filter)(Buffer)) { - /* TODO: Should ScanDir add contents of playlist files ... ? */ - if(Filter == &config_t::IsPlaylistFile || !xc.IsPlaylistFile(Buffer)) { - n++; - if(n<MAX_PLAYLIST_FILES) { - Add(new cPlaylistItem(e->d_name, FolderName)); - //LOGDBG("ScanFolder: %s", e->d_name); - } else { - if(!++warn) - LOGMSG("ScanFolder: Found over %d matching files, list truncated!", n); - break; - } - } - } - } - } - } - LOGDBG("ScanFolder: Found %d matching files from %s", n, FolderName); - closedir(d); - - return n; - } - - LOGERR("ScanFolder: Error opening %s", FolderName); - return 0; -} - -void cPlaylist::StartScanner(void) -{ - cMutexLock ml(&m_Lock); - - if(m_Scanner) { - if(m_Scanner->Active()) - return; - delete m_Scanner; - m_Scanner = NULL; - } - - /* check if cache is already up-to-date */ - cString CacheName = cString::sprintf("%s%s", *m_Folder, PLAYLIST_CACHE); - struct stat stf, stc; - if(!stat(m_Folder, &stf)) { - if(!stat(CacheName, &stc)) { - //LOGDBG("ID3 Cache modified %d, folder modified %d, diff %d", - // (unsigned int)stc.st_mtime, (unsigned int)stf.st_mtime, - // (unsigned int)(stc.st_mtime - stf.st_mtime)); - if(stc.st_mtime >= stf.st_mtime) { - if(ReadCache()) { - LOGDBG("cPlaylist: using up-to-date ID3 cache"); - //LOGMSG(" Cache read OK."); - return; - } - LOGMSG("cPlaylist: ID3 cache read FAILED"); - } else { - LOGDBG("cPlaylist: ID3 cache not up-to-date, using old cache and scanning for changes"); - ReadCache(); - } - } - //else LOGERR("cPlaylist: stat(%s) failed"); - } - //else LOGERR("cPlaylist: stat(%s) failed"); - - if(xc.enable_id3_scanner) { - m_Scanner = new cID3Scanner(*this); - m_Scanner->Start(); - } -} - -int cPlaylist::ReadPlaylist(const char *file) -{ - static int depth = 0; /* limit recursion */ - cPipe p; - cPlaylistReader *parser = NULL; - FILE *f; - - if(strncmp(file, "http:", 5) && strncmp(file, "https:", 6)) { - f = fopen(file, "r"); - } else { - // fetch playlist from server using curl - LOGDBG("cPlaylist: fetching remote playlist from %s", file); - cString Cmd = cString::sprintf("curl %s", file); - if(!p.Open(Cmd, "r")) { - LOGERR("cPlaylist: CURL command (%s) failed", *Cmd); - return false; - } - // process as normal file - f = p; - } - - if(f) { - LOGDBG("cPlaylist: parsing %s", file); - char *pt = strrchr(file, '.'); - if(!strcasecmp(pt, ".pls")) - parser = new cPlsReader(*this); - else if(!strcasecmp(pt, ".asx")) - parser = new cAsxReader(*this); - else /*if(!strcasecmp(pt, ".m3u"))*/ - parser = new cM3uReader(*this); /* parses plain lists (.ram, ...) too ...*/ - - cString Base(file); - if(NULL != (pt=strrchr(Base,'/'))) - pt[1]=0; - - int n = 0; - cReadLine r; - while(NULL != (pt = r.Read(f)) && n < MAX_PLAYLIST_FILES) { - if(NULL != (pt = parser->Parse(pt))) { - - if(depth && n==0) { - // TODO - // - add "separator" item - // Add(new cPlaylistItem(NULL, Base, "---"); - } - - if(xc.IsPlaylistFile(pt)) { - parser->ResetCache(); - LOGDBG("cPlaylist: found playlist inside playlist"); - if(depth > 4) - LOGMSG("cPlaylist: recursion too deep, skipped %s", pt); - else { - depth++; - if(*pt == '/' || - (strstr(pt,"://")+1 == strchr(pt,'/') && - strchr(pt,'/') - pt < 8)) - n += ReadPlaylist(pt); - else - n += ReadPlaylist(cString::sprintf("%s%s", *Base, pt)); - depth--; - } - - } else { - if(*pt == '/' || - (strstr(pt,"://")+1 == strchr(pt,'/') && - strchr(pt,'/') - pt < 8)) { - // absolute path - Add(new cPlaylistItem(pt)); - if(parser->Title()) - Last()->Title = parser->Title(); - } else { - // relative path - Add(new cPlaylistItem(pt, Base, parser->Title())); - } - Last()->Position = parser->Position(); - parser->ResetCache(); - //LOGDBG("read_playlist: %s", pt); - n++; - } - } - } - - if(! (FILE*) p) - fclose(f); - - if(n >= MAX_PLAYLIST_FILES) - LOGMSG("cPlaylist: Found over %d matching files, list truncated!", n); - LOGDBG("cPlaylist: Found %d matching files", n); - return n; - } - - LOGERR("cPlaylist: Error opening %s", file); - return 0; -} - -static cString LastDir(cString& path) -{ - cString tmp = strdup(path); - char *pt = strrchr(tmp, '/'); - if(pt && pt > *tmp) { - *pt = 0; - pt = strrchr(tmp, '/'); - if(pt) - return cString(pt+1); - } - return cString(NULL); -} - -bool cPlaylist::Read(const char *PlaylistFile, bool Recursive) -{ - cMutexLock ml(&m_Lock); - bool Result = true; - - // extract playlist root folder - if(!*m_Folder) { - m_Folder = PlaylistFile; - if(strrchr(m_Folder, '/')) - *(strrchr(m_Folder, '/') + 1) = 0; - } - - if(xc.IsPlaylistFile(PlaylistFile)) { - // Read playlist file - Result = ReadPlaylist(PlaylistFile); - m_Origin = ePlaylist; - - cString dir = LastDir(m_Folder); - char *name = strrchr(PlaylistFile, '/'); - name = name ? name+1 : NULL; - if(*dir && name) - m_Name = cString::sprintf("%s - %s", *dir, name); - else - m_Name = name ?: ""; - - if(strrchr(m_Name, '.')) - *(strrchr(m_Name, '.')) = 0; - - } else if(PlaylistFile[strlen(PlaylistFile)-1] == '/') { - // Scan folder - Result = ScanFolder(PlaylistFile, Recursive) > 0; - m_Origin = eImplicit; - Sort(); - - if(!*m_Name) { - m_Name = PlaylistFile; - *(strrchr(m_Name, '/')) = 0; - if(strrchr(m_Name, '/')) { - cString dir = LastDir(m_Name); - if(*dir) - m_Name = cString::sprintf("%s - %s", *dir, strrchr(m_Name, '/')+1); - else - m_Name = strrchr(m_Name, '/')+1; - } - } - - } else { - // Single file - Add(new cPlaylistItem(PlaylistFile)); - m_Origin = eImplicit; - - if(!*m_Name) { - m_Name = LastDir(m_Folder); - if(!*m_Name) - m_Name = ""; - } - } - - if(Count() < 1) { - LOGMSG("Empty playlist %s !", PlaylistFile); - Add(new cPlaylistItem(PlaylistFile)); - } - - m_Version++; - return Result; -} - -cString cPlaylist::EscapeMrl(const char *mrl) -{ - static const uint8_t hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; - const uint8_t *fn = (const uint8_t*)mrl; - int size = strlen(mrl) + 16; - uint8_t *buf = (uint8_t*)malloc(size); - int i = 0, found = 0; - LOGDBG("cPlaylist::EscapeMrl('%s')", fn); - - // Wait for first '/' (do not escape mrl start dvd:/, http://a@b/, ...) - if (*fn == '/') - found = 3; - - while (*fn) { - if(size-7 < i) - buf = (uint8_t *)realloc(buf, (size=size+16)); - switch (*fn) { - case 1 ... ' ': - case 127 ... 255: - case '#': - case '%': - case ':': - case ';': - case '\'': - case '\"': - case '(': - case ')': - if (found > 2) { - buf[i++] = '%'; - buf[i++] = hex[(*fn & 0xf0)>>4]; - buf[i++] = hex[(*fn & 0x0f)]; - break; - } - default: - // file:/... -> only one '/' before escaping - // http://.../ --> three '/' before escaping - if(!found && (fn[0] == ':' && fn[1] == '/')) { - if(fn[2] == '/') { - // ex. http://user:pass@host/... --> wait for third '/' - buf[i++] = *fn++; - buf[i++] = *fn++; - found += 2; - } else { - // ex. file:/local_file - buf[i++] = *fn++; - found += 3; - } - } else if(*fn == '/') { - found++; - } - buf[i++] = *fn; - break; - } - fn++; - } - - buf[i] = 0; - LOGDBG(" --> '%s'", buf); - return cString((const char*)buf, true); -} - -cString cPlaylist::GetEntry(cPlaylistItem *i, bool isPlaylist, bool isCurrent) -{ - - cString Entry = ""; - if ((*i->Artist && xc.playlist_artist) || (*i->Album && xc.playlist_album)) { - Entry = cString::sprintf("%s%s%s%s%s%s(%s%s%s)", - isPlaylist ? (isCurrent ? "*" : " ") : "", - isPlaylist ? "\t" : " ", - xc.playlist_tracknumber ? (*i->Tracknumber ?: "") : "", - xc.playlist_tracknumber ? (*i->Tracknumber ? " - " : "") : "", - *i->Title, - isPlaylist ? "\t" : " ", - xc.playlist_artist ? (*i->Artist ?: "") : "", - xc.playlist_artist && xc.playlist_album ? (*i->Artist && *i->Album ? ":" : "") : "", - xc.playlist_album ? (*i->Album ?: "") : ""); - } else { - Entry = cString::sprintf("%s%s%s%s%s", - isPlaylist ? (isCurrent ? "*" : " ") : "", - isPlaylist ? "\t" : " ", - xc.playlist_tracknumber ? (*i->Tracknumber ?: "") : "", - xc.playlist_tracknumber ? (*i->Tracknumber ? " - " : "") : "", - *i->Title); - } - return Entry; -} diff --git a/tools/playlist.h b/tools/playlist.h deleted file mode 100644 index 50c3d97a..00000000 --- a/tools/playlist.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * playlist.h: Media player playlist - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: playlist.h,v 1.8 2008-02-19 04:24:34 phintuka Exp $ - * - */ - -#ifndef __XINELIBOUTPUT_PLAYLIST_H -#define __XINELIBOUTPUT_PLAYLIST_H - -#include <vdr/tools.h> // cString, cListObject, cList<> -#include <vdr/thread.h> // cMutex - - -// -// cPlaylistItem -// - -class cPlaylistItem : public cListObject -{ - private: - cPlaylistItem(); - - virtual int Compare(const cListObject &ListObject) const; - - public: - cPlaylistItem(const char *filename); /* file name with full path */ - cPlaylistItem(const char *filename, /* file name without path */ - const char *path, - const char *title = NULL, - int position = -1); - - cString Filename; /* file name and full path */ - - // Metainfo (ID3 etc.) - cString Title; - cString Tracknumber; - cString Artist; - cString Album; - - // position in playlist (if given in playlist file) - int Position; -}; - - -// -// cPlaylistChangeNotify interface -// - -class cPlaylistChangeNotify -{ - public: - virtual void PlaylistChanged(const cPlaylistItem *Item) = 0; - - virtual ~cPlaylistChangeNotify() {} -}; - - -// -// cPlaylist -// - - -class cID3Scanner; - -class cPlaylist : protected cList<cPlaylistItem> -{ - private: - - cMutex m_Lock; - cString m_Name; // playlist (or folder) name - cString m_Folder; // path to "root" of playlist - cPlaylistItem *m_Current; // now playing - unsigned int m_Version; - - enum { ePlaylist, eImplicit } m_Origin; - - cPlaylistChangeNotify *m_Menu; - cID3Scanner *m_Scanner; - - protected: - - bool StoreCache(void); - bool ReadCache(void); - - int ReadPlaylist(const char *PlaylistFile); - int ScanFolder(const char *FolderName, - bool Recursive = false, - bool (config_t::*Filter)(const char *) = &config_t::IsAudioFile); - - friend class cID3Scanner; - friend class cPlaylistReader; - void PlaylistChanged(const cPlaylistItem *Item); - cPlaylistItem *Last(void) { return cList<cPlaylistItem>::Last(); } - - public: - - cPlaylist(); - virtual ~cPlaylist(); - - const cString& Name(void) const { return m_Name; } - - // listen for changes in playlist - void Listen(cPlaylistChangeNotify *Menu = NULL); - - // read playlist from file or create playlist from directory tree - bool Read(const char *PlaylistFile, bool Recursive = false); - void StartScanner(void); - void Del(cPlaylistItem *it); - - void Sort(void); - int Count(void) const; - - // access/iterate playlist items - cPlaylistItem *First(void) { return Next(NULL); } - cPlaylistItem *Next(const cPlaylistItem *i); - - // get/set current (now playing) item - cPlaylistItem *Current(void); - void SetCurrent(cPlaylistItem *current); - cPlaylistItem *Next(void); - cPlaylistItem *Prev(void); - - static cString EscapeMrl(const char *name); - static cString GetEntry(cPlaylistItem *i, bool isPlaylist = false, bool isCurrent = false); -}; - - -#endif // __XINELIBOUTPUT_PLAYLIST_H diff --git a/tools/rtcp.h b/tools/rtcp.h deleted file mode 100644 index 608f2daf..00000000 --- a/tools/rtcp.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * rtcp.h: RFC1889: RTCP - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: rtcp.h,v 1.3 2007-03-29 14:22:31 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_RTCP_H_ -#define XINELIBOUTPUT_RTCP_H_ - -#ifdef __APPLE__ -# include <machine/endian.h> -#else -# include <endian.h> -#endif - - -#ifndef PACKED -# define PACKED __attribute__((packed)) -#endif - -#if __BYTE_ORDER == __BIG_ENDIAN -#elif __BYTE_ORDER == __LITTLE_ENDIAN -#else -# error __BYTE_ORDER not defined -#endif - -#if defined __cplusplus -extern "C" { -#endif - - -/* RTCP packet types */ -typedef enum { - RTCP_SR = 200, - RTCP_RR = 201, - RTCP_SDES = 202, - RTCP_BYE = 203, - RTCP_APP = 204 -} rtcp_type_t; - -/* RTCP SDES types */ -typedef enum { - RTCP_SDES_END = 0, - RTCP_SDES_CNAME = 1, - - RTCP_SDES_NAME = 2, - RTCP_SDES_EMAIL = 3, - RTCP_SDES_PHONE = 4, - RTCP_SDES_LOC = 5, - RTCP_SDES_TOOL = 6, - RTCP_SDES_NOTE = 7, - RTCP_SDES_PRIV = 8 -} rtcp_sdes_type_t; - -/* RTCP common header word */ -typedef struct { - union { - uint8_t raw[4]; - struct { -#if __BYTE_ORDER == __BIG_ENDIAN - unsigned int version:2; /* protocol version */ - unsigned int padding:1; /* padding flag */ - unsigned int count:5; /* varies by packet type */ -#else - unsigned int count:5; /* varies by packet type */ - unsigned int padding:1; /* padding flag */ - unsigned int version:2; /* protocol version */ -#endif - unsigned int ptype:8; /* RTCP packet type */ - - uint16_t length; /* pkt len in words, w/o this word */ - } PACKED; - } PACKED; -} PACKED rtcp_common_t; - -/* RTCP RR (Reception report) */ -typedef struct { - uint32_t ssrc; /* data source being reported */ - unsigned int fraction:8; /* fraction lost since last SR/RR */ - int lost:24; /* cumul. no. pkts lost (signed!) */ - uint32_t last_seq; /* extended last seq. no. received */ - uint32_t jitter; /* interarrival jitter */ - uint32_t lsr; /* last SR packet from this source */ - uint32_t dlsr; /* delay since last SR packet */ -} PACKED rtcp_rr_t; - -/* RTCP SR (Sender report) */ -typedef struct { - uint32_t ssrc; - uint32_t ntp_sec; /* NTP timestamp, most significant word / seconds */ - uint32_t ntp_frac; - uint32_t rtp_ts; - uint32_t psent; /* packets sent */ - uint32_t osent; /* octets sent */ - rtcp_rr_t rr[0]; /* variable-length list */ -} PACKED rtcp_sr_t; - -/* RTCP SDES item */ -typedef struct { - uint8_t type; /* type of item (rtcp_sdes_type_t) */ - uint8_t length; /* length of item (in octets) */ - char data[0]; /* text, not null-terminated */ -} PACKED rtcp_sdes_item_t; - -/* RTCP packet */ -typedef struct { - rtcp_common_t hdr; - union { - rtcp_sr_t sr; - struct { - uint32_t ssrc; - rtcp_rr_t rr[0]; - } PACKED rr; - struct { - uint32_t ssrc; /* first SSRC/CSRC */ - rtcp_sdes_item_t item[0]; /* list of SDES items */ - } PACKED sdes; - struct { - uint32_t src[0]; /* list of sources */ - /* can't express trailing text for reason */ - } PACKED bye; - } PACKED; -} PACKED rtcp_packet_t; - - -#if defined __cplusplus -}; -#endif - -#endif /* XINELIBOUTPUT_RTCP_H_ */ diff --git a/tools/rtp.h b/tools/rtp.h deleted file mode 100644 index fa2ccf63..00000000 --- a/tools/rtp.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * rtp.h: RFC1889: RTP - A Transport Protocol for Real-Time Applications - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: rtp.h,v 1.3 2007-03-29 14:22:31 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_RTP_H_ -#define XINELIBOUTPUT_RTP_H_ - -#ifdef __APPLE__ -# include <machine/endian.h> -#else -# include <endian.h> -#endif - - -#ifndef PACKED -# define PACKED __attribute__((packed)) -#endif - -#if __BYTE_ORDER == __BIG_ENDIAN -#elif __BYTE_ORDER == __LITTLE_ENDIAN -#else -# error __BYTE_ORDER not defined -#endif - -#if defined __cplusplus -extern "C" { -#endif - - -/* Generic RTP header extension */ -typedef struct stream_rtp_header_ext { - - union { - uint8_t raw[4]; - uint32_t rawd; - - struct { - uint16_t type; - uint16_t size; /* Size of ext_data field in DWORDS */ - } PACKED; - } PACKED; - - uint8_t ext_data[0]; - -} PACKED stream_rtp_header_ext_t; - - -/* Common RTP data header */ -typedef struct stream_rtp_header { - - union { - uint8_t raw[12]; - - struct { -#if __BYTE_ORDER == __BIG_ENDIAN - unsigned int version:2; /* protocol version */ - unsigned int padding:1; /* padding flag */ - unsigned int ext:1; /* header extension flag */ - unsigned int cc:4; /* CSRC count */ - - unsigned int marker:1; /* marker bit */ - unsigned int paytype:7; /* payload type */ -#else - unsigned int cc:4; /* CSRC count */ - unsigned int ext:1; /* header extension flag */ - unsigned int padding:1; /* padding flag */ - unsigned int version:2; /* protocol version */ - - unsigned int paytype:7; /* payload type */ - unsigned int marker:1; /* marker bit */ -#endif - uint16_t seq; /* sequence number */ - uint32_t ts; /* timestamp */ - uint32_t ssrc; /* synchronization source */ - - /*uint32_t csrc[0];*/ /* optional CSRC list */ - } PACKED; - } PACKED; - - - union { - stream_rtp_header_ext_t hdr_ext[0]; - uint8_t payload[0]; - } PACKED; - - -} PACKED stream_rtp_header_t; - -#if defined __cplusplus -}; -#endif - -#endif /* XINELIBOUTPUT_RTP_H_ */ - diff --git a/tools/sap.h b/tools/sap.h deleted file mode 100644 index 6b341efc..00000000 --- a/tools/sap.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - * sap.h: RFC2974 Session Announcement Protocol (SAP) version 2 - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: sap.h,v 1.8 2007-03-29 14:22:30 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_SAP_H_ -#define XINELIBOUTPUT_SAP_H_ - -#include <arpa/inet.h> -#ifdef __APPLE__ -# include <machine/endian.h> -#else -# include <endian.h> -#endif - - -#ifndef PACKED -# define PACKED __attribute__((packed)) -#endif - -/*#define LOG_SAP*/ - -/* SAP IPv4 multicast addresses */ -#define SAP_IP_ADDRESS_GLOBAL "224.2.127.254" /* SAPv1 IP4 global scope multicast address */ -#define SAP_IP_ADDRESS_ORG "239.195.255.255" /* organization-local */ -#define SAP_IP_ADDRESS_LOCAL "239.255.255.255" /* local */ -#define SAP_IP_ADDRESS_LINK "224.0.0.255" /* link-local */ - -#define SAP_IP_TTL 255 -#define SAP_UDP_PORT 9875 - - -typedef struct { - - /* RFC2974: SAP (Session Announcement Protocol) version 2 PDU */ - - union { - uint8_t raw0; - struct { -#if __BYTE_ORDER == __BIG_ENDIAN - uint8_t version : 3; - uint8_t addr_type : 1; - uint8_t reserved : 1; - uint8_t msg_type : 1; - uint8_t encrypted : 1; - uint8_t compressed : 1; -#else - uint8_t compressed : 1; - uint8_t encrypted : 1; - uint8_t msg_type : 1; - uint8_t reserved : 1; - uint8_t addr_type : 1; - uint8_t version : 3; -#endif - } PACKED; - } PACKED; - - uint8_t auth_len; - uint16_t msgid_hash; - - union { - uint8_t u8[4]; - uint32_t u32; - } PACKED ip4_source; - - char payload[0]; - -} PACKED sap_pdu_t; - - -static inline sap_pdu_t *sap_create_pdu(uint32_t src_ip, - uint16_t msgid, - int announce, - const char *payload_type, - const char *payload) -{ - sap_pdu_t *pdu; - int length = sizeof(sap_pdu_t) + strlen(payload) + 3; - - if(payload_type) - length += strlen(payload_type); - - if(! (pdu = (sap_pdu_t*)malloc(length))) - return NULL; - - memset(pdu, 0, sizeof(sap_pdu_t)); - pdu->version = 1; /* SAP v1 / v2 */ - pdu->msg_type = announce ? 0 : 1; - pdu->msgid_hash = msgid; - pdu->ip4_source.u32 = src_ip; - - if(payload_type) { - char *tmp = &pdu->payload[0]; - strcpy(tmp, payload_type); - tmp += strlen(tmp) + 1; - strcpy(tmp, payload); - } else { - /* payload type defaults to application/sdp */ - sprintf(&pdu->payload[0], "%s%c%c", payload, 0, 0); - } - - return pdu; -} - -static inline int sap_compress_pdu(sap_pdu_t *pdu) -{ -#ifdef HAVE_ZLIB_H - - /* zlib compression */ - - Compress(); - - /*pdu->compressed = 1;*/ - -#endif - - /* not implemented */ - - pdu->compressed = 0; - return -1; -} - -static inline int sap_send_pdu(int *pfd, sap_pdu_t *pdu, uint32_t dst_ip) -{ - int len = 0, r; - int iReuse = 1, iLoop = 1, iTtl = SAP_IP_TTL; - int fd; - - if(!pfd || *pfd < 0) { - fd = socket(AF_INET, SOCK_DGRAM, 0); - - if(fd < 0) { - LOGERR("socket() failed (UDP/SAP multicast)"); - return -1; - } - - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &iReuse, sizeof(int)); - setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &iTtl, sizeof(int)); - setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &iLoop, sizeof(int)); - - // Connect to multicast address - struct sockaddr_in sin; - sin.sin_family = AF_INET; - sin.sin_port = htons(SAP_UDP_PORT); - sin.sin_addr.s_addr = dst_ip ? dst_ip : inet_addr(SAP_IP_ADDRESS_GLOBAL); - - if(connect(fd, (struct sockaddr *)&sin, sizeof(sin))==-1) - LOGERR("UDP/SAP multicast connect() failed."); - - // Set to non-blocking mode - fcntl (fd, F_SETFL, fcntl (fd, F_GETFL) | O_NONBLOCK); - - if(pfd) - *pfd = fd; - - } else { - fd = *pfd; - } - - // size of PDU - len += strlen(&pdu->payload[0]); - if(!strstr(&pdu->payload[0], "\r\n")) { - /* assume mime content type is present */ - len += 1; - len += strlen(&pdu->payload[len]); - len += sizeof(sap_pdu_t); - } - - // network order - pdu->msgid_hash = htons(pdu->msgid_hash); - - // send - r = send(fd, pdu, len, 0); - if(r < 0) - LOGERR("UDP/SAP multicast send() failed."); - - if(!pfd) - close(fd); - -#ifdef LOG_SAP - /* log PDU */ - for(int i=0; i<len;) { - char x[4096]="", a[4096]=""; - for(int j=0; j<16 && i<len; i++, j++) { - char t[8], ch = ((char*)pdu)[i]; - sprintf(t, "%02X ", ((unsigned int)ch)&0xff); - strcat(x, t); - sprintf(t, "%c", (ch>=32 && ch<127) ? ch : '.'); - strcat(a, t); - } - LOGMSG("SAP: 0x%02x: %-50s%-18s", i/16-1, x, a); - } -#endif - - // back to host order - pdu->msgid_hash = ntohs(pdu->msgid_hash); - - return r == len ? len : -1; -} - - -#endif /* XINELIBOUTPUT_SAP_H_ */ diff --git a/tools/sdp.h b/tools/sdp.h deleted file mode 100644 index 47a3a409..00000000 --- a/tools/sdp.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * sdp.h: RFC2974 Session Description Protocol (SDP) - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: sdp.h,v 1.2 2006-12-14 12:52:49 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_SDP_H_ -#define XINELIBOUTPUT_SDP_H_ - - -#define SDP_MIME_TYPE "application/sdp" - - -static char *vdr_sdp_description(const char *vdr_ip, - int vdr_svdrp_port, - int vdr_xineliboutput_port, - const char *rtp_ip, - uint32_t rtp_ssrc, - int rtp_port, - int rtp_ttl) -{ - static uint8_t s_serial = 0; - static char *s_data = NULL; - static char s_hostname[257] = {0}; - - uint64_t serial = (time(NULL) << 2) + ((s_serial++) & 0x03); - - if(!s_hostname[0]) - gethostname(s_hostname, 256); - - free(s_data); - - asprintf(&s_data, - /*** session ***/ - /* version */ "v=0" - /* origin */ "\r\n" "o=%s %u %"PRIu64" IN IP4 %s" - /* name */ "\r\n" "s=%s@%s (multicast %s:%d)" - /* opt:info */ /*"\r\n" "i=vdr-xineliboutput primary device output"*/ - /* time */ "\r\n" "t=0 0" - - /*** data stream(s) ***/ - /* connection */ "\r\n" "c=IN IP4 %s/%d" - /* */ "\r\n" "a=recvonly" - /* */ "\r\n" "a=type:broadcast" - /* */ "\r\n" "a=x-plgroup:vdr" - /* media */ "\r\n" "m=video %d RTP/AVP 96" - /* */ "\r\n" "a=rtpmap:96 MP2P/90000" - /* media */ /*"\r\n" "m=video %d udp MP2P"*/ - /* */ /*"\r\n" "a=mux:ps"*/ - /* */ /*"\r\n" "a=packetformat:RAW"*/ -#if 0 - /*** rtsp control port ***/ - /* connection */ "\r\n" "c=IN IP4 %s" - /* media */ "\r\n" "m=control %d tcp/http rtsp" -#endif - /*** xineliboutput control port ***/ - /* connection */ "\r\n" "c=IN IP4 %s" - /* media */ "\r\n" "m=control %d tcp x-vdr-xineliboutput" - - /*** SVDRP control port ***/ - /* connection */ "\r\n" "c=IN IP4 %s" - /* media */ "\r\n" "m=control %d tcp x-svdrp" - - /* origin */ - , "vdr", rtp_ssrc, serial, vdr_ip - - /* name */ - , "vdr", s_hostname, rtp_ip, rtp_port - - /* video/mp2p udp/rtp */ - , rtp_ip, rtp_ttl - , rtp_port -#if 0 - /* tcp/http control/rtsp */ - , vdr_ip - , vdr_xineliboutput_port -#endif - /* tcp control/x-vdr-xineliboutput */ - , vdr_ip - , vdr_xineliboutput_port - - /* tcp control/x-svdrp */ - , vdr_ip - , vdr_svdrp_port - ); - - return s_data; -} - - -#endif /* XINELIBOUTPUT_SDP_H_ */ diff --git a/tools/time_pts.c b/tools/time_pts.c deleted file mode 100644 index 81ee7c73..00000000 --- a/tools/time_pts.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * time_pts.c: Adjustable clock in PTS units - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: time_pts.c,v 1.4 2008-04-28 20:48:05 phintuka Exp $ - * - */ - -#define __STDC_FORMAT_MACROS -#define __STDC_CONSTANT_MACROS -#include <inttypes.h> -#include <time.h> - -#include <vdr/config.h> - -#include "../logdefs.h" // logging - -#include "time_pts.h" - - -#define MAX_SCR ((int64_t)0x1ffffffffLL) - -#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK) -#else -# warning Posix monotonic clock not available -#endif - -int cTimePts::m_Monotonic = -1; - -void cTimePts::Init(void) -{ -#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK) - if(m_Monotonic >= 0) - return; - - m_Monotonic = 0; - - struct timespec resolution; - if(clock_getres(CLOCK_MONOTONIC, &resolution)) { - LOGERR("cTimePts: clock_getres(CLOCK_MONOTONIC) failed"); - return; - } - - LOGDBG("cTimePts: clock_gettime(CLOCK_MONOTONIC): clock resolution %d us", - ((int)resolution.tv_nsec) / 1000); - - if( resolution.tv_sec == 0 && resolution.tv_nsec <= 1000000 ) { - struct timespec tp; - if(clock_gettime(CLOCK_MONOTONIC, &tp)) { - LOGERR("cTimePts: clock_gettime(CLOCK_MONOTONIC) failed"); - } else { - LOGDBG("cTimePts: using monotonic clock"); - m_Monotonic = 1; - } - } -#endif -} - -cTimePts::cTimePts(void) -{ - m_Paused = false; - m_ScrSpeed = 90000; - m_Multiplier = 90000; - - Init(); - - Set(); -} - -int64_t cTimePts::Now(void) const -{ - if(m_Paused) - return begin; - - struct timeval t; - -#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK) - if(m_Monotonic) { - struct timespec tp; - - if(clock_gettime(CLOCK_MONOTONIC, &tp)) { - LOGERR("cTimePts: clock_gettime(CLOCK_MONOTONIC) failed"); - return -1; - } - - t.tv_sec = tp.tv_sec; - t.tv_usec = tp.tv_nsec/1000; - - } else if (gettimeofday(&t, NULL)) { - LOGERR("cTimePts: gettimeofday() failed"); - return -1; - } -#else - if (gettimeofday(&t, NULL)) { - LOGERR("cTimePts: gettimeofday() failed"); - return -1; - } -#endif - - t.tv_sec -= tbegin.tv_sec; - if(t.tv_usec < tbegin.tv_usec) { - t.tv_sec--; - t.tv_usec += 1000000; - } - t.tv_usec -= tbegin.tv_usec; - - int64_t pts = 0; - pts += (int64_t)t.tv_sec * (int64_t)m_ScrSpeed; - pts += (int64_t)t.tv_usec * (int64_t)m_ScrSpeed / INT64_C(1000000); - - if(m_Multiplier != 90000) - pts = pts * m_Multiplier / INT64_C(90000); - - return ( pts + begin ) & MAX_SCR; -} - -void cTimePts::Set(int64_t Pts) -{ - begin = Pts; - -#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK) - if(m_Monotonic) { - struct timespec tp; - - if(!clock_gettime(CLOCK_MONOTONIC, &tp)) { - tbegin.tv_sec = tp.tv_sec; - tbegin.tv_usec = tp.tv_nsec/1000; - return; - } - - LOGERR("cTimePts: clock_gettime(CLOCL_MONOTONIC) failed"); - m_Monotonic = 0; - } -#endif - - gettimeofday(&tbegin, NULL); -} - -void cTimePts::Pause(void) -{ - Set(Now()); - m_Paused = true; -} - -void cTimePts::Resume(void) -{ - if(m_Paused) { - Set(begin); - m_Paused = false; - } -} - -void cTimePts::TrickSpeed(const int Multiplier) -{ - Set(Now()); - - if(Multiplier < 0) - m_Multiplier = 90000 * (-Multiplier); - else if(Multiplier > 0) - m_Multiplier = 90000 / Multiplier; - else - LOGERR("cTimePts::SetSpeed: Multiplier=%d", Multiplier); -} - -void cTimePts::SetScrSpeed(const int ScrSpeed) -{ - Set(Now()); - - m_ScrSpeed = ScrSpeed; -} diff --git a/tools/time_pts.h b/tools/time_pts.h deleted file mode 100644 index fafc7199..00000000 --- a/tools/time_pts.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * time_pts.h: Adjustable clock in PTS units - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: time_pts.h,v 1.4 2008-04-28 20:48:05 phintuka Exp $ - * - */ - -#ifndef __TIME_PTS_H -#define __TIME_PTS_H - -#include <stdint.h> // int64_t -#include <sys/time.h> // struct timeval - - -class cTimePts -{ - private: - int64_t begin; /* Start time (PTS) */ - struct timeval tbegin; /* Start time (real time) */ - bool m_Paused; - int m_Multiplier; - int m_ScrSpeed; - - static int m_Monotonic; - static void Init(void); - - public: - cTimePts(void); - - int64_t Now(void) const; - void Set(int64_t Pts = 0LL); - - void Pause(void); - void Resume(void); - void TrickSpeed(const int Multiplier); - - void SetScrSpeed(const int ScrSpeed = 90000); -}; - -#endif // __TIME_PTS_H diff --git a/tools/timer.c b/tools/timer.c deleted file mode 100644 index f24e925a..00000000 --- a/tools/timer.c +++ /dev/null @@ -1,288 +0,0 @@ -/* - * timer.c: Threaded timer class - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: timer.c,v 1.2 2007-10-15 00:15:07 phintuka Exp $ - * - */ - -#include <sys/time.h> - -#include <vdr/config.h> -#include <vdr/tools.h> -#include <vdr/thread.h> - -#include "timer.h" - -//#define XINELIBOUTPUT_DEBUG -//#define XINELIBOUTPUT_DEBUG_STDOUT -#ifdef XINELIBOUTPUT_DEBUG -# include "logdefs.h" -#else -# define TRACE(x) -# define TRACEF(x) -#endif - -// ---------------------------- cTimerThreadEvent ---------------------------- - -class cTimerThreadEvent : public cListObject { - public: - cTimerThreadEvent(cTimerCallback *Handler, unsigned int TimeoutMs, - bool DeleteOnCancel = false) : - m_Handler(Handler), - m_DeleteOnCancel(DeleteOnCancel), - m_TimeoutMs(TimeoutMs) - { - m_NextEventTime = cTimeMs::Now(); - UpdateEventTime(); - } - - ~cTimerThreadEvent() - { - if(m_DeleteOnCancel && m_Handler) - delete m_Handler; - } - - void UpdateEventTime() - { - m_NextEventTime += m_TimeoutMs; - } - - int TimeToNextEvent(void) - { - return m_NextEventTime - cTimeMs::Now(); - } - - virtual bool operator< (const cListObject &ListObject) - { - const cTimerThreadEvent *o = (cTimerThreadEvent *)&ListObject; - return m_NextEventTime<o->m_NextEventTime; - } - - virtual int Compare(const cListObject &ListObject) const - { - const cTimerThreadEvent *o = (cTimerThreadEvent *)&ListObject; - if(m_NextEventTime<o->m_NextEventTime) - return -1; - else if(m_NextEventTime>o->m_NextEventTime) - return 1; - return 0; - } - - cTimerCallback *m_Handler; - - protected: - bool m_DeleteOnCancel; - unsigned int m_TimeoutMs; - int64_t m_NextEventTime; -}; - -// ------------------------------- cTimerThread ------------------------------ - -class cTimerThread : public cThread { - private: - cTimerThread(cTimerThread&); // copy not allowed - - static cMutex m_InstanceLock; - static cTimerThread *m_Instance; // singleton - - cMutex m_Lock; - cCondVar m_Signal; - cList<cTimerThreadEvent> m_Events; - cTimerThreadEvent *m_RunningEvent; - bool m_Finished; - bool m_HandlerRunning; - - cTimerThread() : - m_RunningEvent(NULL), - m_Finished(false), - m_HandlerRunning(false) - { - } - - virtual ~cTimerThread() - { - m_Lock.Lock(); - cTimerThreadEvent *ev; - while(NULL != (ev = m_Events.First())) { - m_Events.Del(ev,true); - } - m_Lock.Unlock(); - m_Signal.Broadcast(); - Cancel(1); - } - - protected: - - virtual void Action() - { - TRACEF("cTimerThread::Action"); - m_Lock.Lock(); - while(m_Events.First()) { - m_Signal.TimedWait(m_Lock, - max(1, m_Events.First()->TimeToNextEvent())); - TRACE("cTimerThread::Action waked up"); - while(NULL != (m_RunningEvent = m_Events.First()) && - m_RunningEvent->TimeToNextEvent() <= 0) { - TRACE("cTimerThread::Action calling handler"); - m_HandlerRunning=true; -// m_Lock.Unlock(); -// - can't unlock or running timer handler may be deleted while -// executing (or thread may be killed by Delete) - bool result = m_RunningEvent->m_Handler->TimerEvent(); -// m_Lock.Lock(); - m_HandlerRunning=false; - if(!result) { - if(m_RunningEvent) { // check if event was cancelled in handler... - TRACE("cTimerThread::Action handler cancelled timer"); - m_Events.Del(m_RunningEvent, true); - } - } else { - if(m_RunningEvent) { - TRACE("cTimerThread::Action timer re-scheduled"); - m_RunningEvent->UpdateEventTime(); - m_Events.Sort(); - } - } - m_RunningEvent = NULL; - } - } - m_Finished = true; - m_Lock.Unlock(); - } - - void Add(cTimerThreadEvent *Event) - { - TRACEF("cTimerThread::Add"); - //m_Events.Del(Event, false); - Event->Unlink(); - Del(Event->m_Handler); - m_Events.Add(Event); - m_Events.Sort(); - } - - bool Del(cTimerCallback *Handler, void *TargetId=NULL, - bool inDestructor=false) - { - TRACEF("cTimerThread::Del"); - cTimerThreadEvent *ev = m_Events.First(); - while(ev) { - if(ev->m_Handler == Handler || - (TargetId && ev->m_Handler->TargetId() == TargetId) || - (Handler && ev->m_Handler->is(Handler,Handler->size()))) { - cTimerThreadEvent *nev = m_Events.Next(ev); - if(inDestructor) ev->m_Handler=NULL; - m_Events.Del(ev, true); - ev = nev; - } else - ev = m_Events.Next(ev); - } - if(m_RunningEvent && - (m_RunningEvent->m_Handler == Handler || - m_RunningEvent->m_Handler->TargetId() == TargetId)) - m_RunningEvent = NULL; - return !m_HandlerRunning && !m_RunningEvent && !m_Events.First(); - } - - public: - - static void AddEvent(cTimerCallback *Handler, unsigned int TimeoutMs, - bool DeleteOnCancel=false) - { - TRACEF("cTimerThread::AddEvent"); - m_InstanceLock.Lock(); - if(m_Instance && m_Instance->m_Finished) { - delete m_Instance; - m_Instance = NULL; - } - if(!m_Instance) { - m_Instance = new cTimerThread; - m_Instance->m_Lock.Lock(); - m_Instance->Start(); - } else { - m_Instance->m_Lock.Lock(); - m_Instance->m_Signal.Broadcast(); - } - m_Instance->Add(new cTimerThreadEvent(Handler, max(1U,TimeoutMs), - DeleteOnCancel)); - m_Instance->m_Lock.Unlock(); - m_InstanceLock.Unlock(); - } - - static void CancelEvent(cTimerCallback *Handler, void *TargetId = NULL, - bool inDestructor=false) - { - TRACEF("cTimerThread::CancelEvent"); - m_InstanceLock.Lock(); - if(m_Instance && !m_Instance->m_Finished) { - m_Instance->m_Lock.Lock(); - if(m_Instance->Del(Handler, TargetId, inDestructor) && !inDestructor) { - m_Instance->m_Lock.Unlock(); - delete m_Instance; - m_Instance = NULL; - } else - m_Instance->m_Lock.Unlock(); - } - m_InstanceLock.Unlock(); - } - -}; - -cMutex cTimerThread::m_InstanceLock; -cTimerThread *cTimerThread::m_Instance = NULL; - -// ------------------------------ cTimerCallback ----------------------------- - -cTimerCallback::~cTimerCallback() -{ - TRACEF("cTimerCallback::~cTimerCallback"); - cTimerThread::CancelEvent(this, NULL, true); -} - -void cTimerCallback::Set(cTimerCallback *handler, unsigned int TimeoutMs) -{ - TRACEF("cTimerCallback::Set"); - cTimerThread::AddEvent(handler, TimeoutMs); -} - -void cTimerCallback::Cancel(cTimerCallback *handler) -{ - TRACEF("cTimerCallback::Cancel"); - cTimerThread::CancelEvent(handler); -} - -// ------------------------------- cTimerEvent ------------------------------- - -//cTimerEvent::cTimerEvent(unsigned int TimeoutMs) -//{ -// TRACEF("cTimerEvent::cTimerEvent"); -//// cTimerThread::AddEvent(this, TimeoutMs, true); -//} - -void cTimerEvent::AddEvent(unsigned int TimeoutMs) -{ - TRACEF("cTimerEvent::AddEvent"); - cTimerThread::AddEvent(this, TimeoutMs, true); -} - -void cTimerEvent::Cancel(cTimerEvent *&event) -{ - TRACEF("cTimerEvent::Cancel"); - cTimerThread::CancelEvent(event); - event = NULL; -} - -void cTimerEvent::CancelAll(void *Target) -{ - TRACEF("cTimerEvent::CancelAll"); - cTimerThread::CancelEvent(NULL, Target); -} - - - - - - - diff --git a/tools/timer.h b/tools/timer.h deleted file mode 100644 index 2ee8724b..00000000 --- a/tools/timer.h +++ /dev/null @@ -1,296 +0,0 @@ -/* - * timer.h: Threaded timer class - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: timer.h,v 1.1 2006-06-03 10:04:28 phintuka Exp $ - * - */ - -#ifndef __XINELIBOUTPUT_TIMER_H -#define __XINELIBOUTPUT_TIMER_H - -// -// cTimerCallback : timer callback handler interface -// -class cTimerCallback { - protected: - virtual bool TimerEvent() = 0; // return false to cancel timer - - virtual void *TargetId() { return (void*)this; } - virtual int size() { return sizeof(*this); } - virtual bool is(void *data, int len) - { - return len==sizeof(*this) && TargetId()==data; - } - - friend class cTimerThread; - - public: - static void Set(cTimerCallback *, unsigned int TimeoutMs); - static void Cancel(cTimerCallback *); - - virtual ~cTimerCallback(); -}; - -// -// cTimerEvent : base class for timer events -// -class cTimerEvent : protected cTimerCallback { - private: - cTimerEvent(cTimerEvent&); - - protected: - cTimerEvent() {}; - - virtual void AddEvent(unsigned int TimeoutMs); - - static void CancelAll(void *Target); - - template<class TCLASS> friend void CancelTimerEvents(TCLASS*); - friend class cTimerThread; - - public: - static void Cancel(cTimerEvent *&); -}; - -// -// make gcc 3.4.5 happy -// -template<class TCLASS, class TRESULT> -cTimerEvent *CreateTimerEvent(TCLASS *c, TRESULT (TCLASS::*fp)(void), - unsigned int TimeoutMs); -template<class TCLASS, class TRESULT, class TARG1> -cTimerEvent *CreateTimerEvent(TCLASS *c, TRESULT (TCLASS::*fp)(TARG1), - TARG1 arg1, - unsigned int TimeoutMs); -template<class TCLASS> -cTimerEvent *CreateTimerEvent(TCLASS *c, void (TCLASS::*fp)(void), - unsigned int TimeoutMs, bool runOnce = true); -template<class TCLASS, class TARG1> -cTimerEvent *CreateTimerEvent(TCLASS *c, void (TCLASS::*fp)(TARG1), - TARG1 arg1, - unsigned int TimeoutMs, bool runOnce = true); - -// -// Timer event templates -// - -template <class TCLASS, class TRESULT> -class cTimerFunctorR0 : public cTimerEvent { - - public: - - protected: - typedef TRESULT (TCLASS::*TFUNC)(void); - - cTimerFunctorR0(TCLASS *obj, TFUNC f, unsigned int TimeoutMs) : - m_obj(obj), m_f(f) - { - AddEvent(TimeoutMs); - } - - virtual ~cTimerFunctorR0() {}; - - virtual bool TimerEvent(void) - { - return (*m_obj.*m_f)(); - } - - virtual void *TargetId() { return (void*)m_obj; } - virtual int size() { return sizeof(*this); } - virtual bool is(void *data, int len) - { - return sizeof(*this)==len && !memcmp(this,data,len); - } - - private: - TCLASS *m_obj; - TFUNC m_f; - - friend cTimerEvent *CreateTimerEvent<TCLASS,TRESULT>(TCLASS*,TFUNC,unsigned int); -}; - -template <class TCLASS, class TRESULT, class TARG1> -class cTimerFunctorR1 : public cTimerEvent { - - public: - - protected: - typedef TRESULT (TCLASS::*TFUNC)(TARG1); - - cTimerFunctorR1(TCLASS *obj, TFUNC f, TARG1 arg1, unsigned int TimeoutMs) : - m_obj(obj), m_f(f), m_arg1(arg1) - { - AddEvent(TimeoutMs); - } - - virtual ~cTimerFunctorR1() {}; - - virtual bool TimerEvent(void) - { - return (*m_obj.*m_f)(m_arg1); - } - - virtual void *TargetId() { return (void*)m_obj; } - virtual int size() { return sizeof(*this); } - virtual bool is(void *data, int len) - { - return sizeof(*this)==len && !memcmp(this,data,len); - } - - private: - TCLASS *m_obj; - TFUNC m_f; - TARG1 m_arg1; - - friend cTimerEvent *CreateTimerEvent<TCLASS,TRESULT,TARG1>(TCLASS*,TFUNC,TARG1,unsigned int); -}; - -template <class TCLASS> -class cTimerFunctor0 : public cTimerEvent { - - public: - - protected: - typedef void (TCLASS::*TFUNC)(void); - - cTimerFunctor0(TCLASS *obj, TFUNC f, - unsigned int TimeoutMs, bool runOnce) : - m_obj(obj), m_f(f), m_runAgain(!runOnce) - { - AddEvent(TimeoutMs); - } - - virtual ~cTimerFunctor0() {}; - - virtual bool TimerEvent(void) - { - (*m_obj.*m_f)(); - return m_runAgain; - } - - virtual void *TargetId() { return (void*)m_obj; } - virtual int size() { return sizeof(*this); } - virtual bool is(void *data, int len) - { - return sizeof(*this)==len && !memcmp(this,data,len); - } - - private: - TCLASS *m_obj; - TFUNC m_f; - bool m_runAgain; - - friend cTimerEvent *CreateTimerEvent<TCLASS>(TCLASS*,TFUNC,unsigned int,bool); -}; - -template <class TCLASS, class TARG1> -class cTimerFunctor1 : public cTimerEvent { - - public: - - protected: - typedef void (TCLASS::*TFUNC)(TARG1); - - cTimerFunctor1(TCLASS *obj, TFUNC f, TARG1 arg1, - unsigned int TimeoutMs, bool runOnce) : - m_obj(obj), m_f(f), m_arg1(arg1), m_runAgain(!runOnce) - { - AddEvent(TimeoutMs); - } - - virtual ~cTimerFunctor1() {}; - - virtual bool TimerEvent(void) - { - (*m_obj.*m_f)(m_arg1); - return m_runAgain; - } - - virtual void *TargetId() { return (void*)m_obj; } - virtual int size() { return sizeof(*this); } - virtual bool is(void *data, int len) - { - return sizeof(*this)==len && !memcmp(this,data,len); - } - - private: - TCLASS *m_obj; - TFUNC m_f; - TARG1 m_arg1; - bool m_runAgain; - - friend cTimerEvent *CreateTimerEvent<TCLASS,TARG1>(TCLASS*,TFUNC,TARG1,unsigned int,bool); -}; - -// -// Function templates for timer event creation and cancellation -// - -template<class TCLASS, class TRESULT> -cTimerEvent *CreateTimerEvent(TCLASS *c, TRESULT (TCLASS::*fp)(void), - unsigned int TimeoutMs) -{ - return new cTimerFunctorR0<TCLASS,TRESULT>(c,fp,TimeoutMs); -} - -template<class TCLASS, class TRESULT, class TARG1> -cTimerEvent *CreateTimerEvent(TCLASS *c, TRESULT (TCLASS::*fp)(TARG1), - TARG1 arg1, - unsigned int TimeoutMs) -{ - return new cTimerFunctorR1<TCLASS,TRESULT,TARG1>(c,fp,arg1,TimeoutMs); -} - -template<class TCLASS> -cTimerEvent *CreateTimerEvent(TCLASS *c, void (TCLASS::*fp)(void), - unsigned int TimeoutMs, bool runOnce = true) -{ - return new cTimerFunctor0<TCLASS>(c,fp,TimeoutMs,runOnce); -} - -template<class TCLASS, class TARG1> -cTimerEvent *CreateTimerEvent(TCLASS *c, void (TCLASS::*fp)(TARG1), - TARG1 arg1, - unsigned int TimeoutMs, bool runOnce = true) -{ - return new cTimerFunctor1<TCLASS,TARG1>(c,fp,arg1,TimeoutMs,runOnce); -} - -template<class TCLASS> -void CancelTimerEvents(TCLASS *c) -{ - cTimerEvent::CancelAll((void*)c); -} - - -// usage: -// -// 'this' derived from cTimerHandler: -// Set timer: -// cTimerCallback::Set(this, TimeoutMs); -// Cancel timer: -// - return false from handler or -// - call cTimerCallback::Cancel(this); or -// - delete 'this' object -// -// any function of any class: -// Set timer: -// - cTimerEvent *event = CreateTimerEvent(...); -// example: -// CreateTimerEvent(this, &cXinelibDevice::TimerEvent, 1, 1000); -// -> calls this->cXinelibDevice::TimerEvent(1) every second until stopped. -// Cancel timer: -// - if handler returns bool: return false from handler -// - handler is type of void: timer runs only once -// - call cTimerEvent::Cancel(event) -// Cancel all timers for object: -// - Call CancelTimerEvents(object) -// - Call CancelTimerEvents(this) - - -#endif // __XINELIBOUTPUT_TIMER_H - - diff --git a/tools/udp_buffer.h b/tools/udp_buffer.h deleted file mode 100644 index 6284349a..00000000 --- a/tools/udp_buffer.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * udp_buffer.h: Ring buffer for UDP/RTP streams - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: udp_buffer.h,v 1.3 2006-12-14 12:30:25 phintuka Exp $ - * - */ - -#ifndef __UDP_BUFFER_H -#define __UDP_BUFFER_H - -#include <stdint.h> - -#include "../xine_input_vdr_net.h" // frame headers - - -#define UDP_BUFFER_SIZE 0x100 // 2^n -#define UDP_BUFFER_MASK 0xff // 2^n - 1 - -#if UDP_BUFFER_MASK != UDP_SEQ_MASK -# error Buffer handling error !!! -#endif - - -class cUdpBackLog -{ - friend class cUdpScheduler; - - private: - - cUdpBackLog(cUdpBackLog&); - - stream_rtp_header_impl_t *m_UdpBuffer[UDP_BUFFER_SIZE]; - int m_UdpBufLen[UDP_BUFFER_SIZE]; /* size of allocated memory, not frame */ - int m_PayloadSize[UDP_BUFFER_SIZE]; /* size of frame */ - unsigned int m_SeqNo; /* next (outgoing) sequence number */ - unsigned int m_RtpSeqNo; /* next (outgoing) RTP sequence number */ - - protected: - - cUdpBackLog() - { - memset(m_UdpBuffer, 0, sizeof(stream_rtp_header_impl_t *)*UDP_BUFFER_SIZE); - memset(m_UdpBufLen, 0, sizeof(int) * UDP_BUFFER_SIZE); - memset(m_PayloadSize, 0, sizeof(int) * UDP_BUFFER_SIZE); - m_SeqNo = 0; - m_RtpSeqNo = random(); - } - - void Clear(int HowManyFrames) - { - // Clear n last frames from buffer. - // (called to adjust sequence numbering when some - // already allocated frames won't be sent) - // - // Note: Nothing is freed. - // To completely reset buffer it must be deleted and re-created. - // - m_SeqNo = (m_SeqNo + UDP_BUFFER_SIZE - HowManyFrames) & UDP_BUFFER_MASK; - } - - virtual ~cUdpBackLog() - { - for(int i=0; i<UDP_BUFFER_SIZE; i++) - if(m_UdpBuffer[i]) { - //m_UdpBufLen[i] = 0; - delete[] m_UdpBuffer[i]; - m_UdpBuffer[i] = NULL; - } - } - - stream_rtp_header_impl_t *Get(int UdpSeqNo) - { - int BufIndex = UdpSeqNo & UDP_BUFFER_MASK; - return m_UdpBuffer[BufIndex]; - } - - int PayloadSize(int UdpSeqNo) - { - int BufIndex = UdpSeqNo & UDP_BUFFER_MASK; - return m_UdpBuffer[BufIndex] ? m_PayloadSize[BufIndex] : 0; - } - - stream_rtp_header_impl_t *MakeFrame(uint64_t StreamPos, - const uchar *Data, int DataLen) - { - int UdpPacketLen = DataLen + sizeof(stream_rtp_header_impl_t); - int BufIndex = m_SeqNo & UDP_BUFFER_MASK; - - // old buffer too small ? free it - if(m_UdpBuffer[BufIndex] && m_UdpBufLen[BufIndex] < UdpPacketLen) { - delete[] m_UdpBuffer[BufIndex]; - m_UdpBuffer[BufIndex] = NULL; - } - - // no buffer ? alloc it - if(!m_UdpBuffer[BufIndex]) { - m_UdpBuffer[BufIndex] = (stream_rtp_header_impl_t*)new uchar[UdpPacketLen]; - m_UdpBufLen[BufIndex] = UdpPacketLen; - } - m_PayloadSize[BufIndex] = DataLen; - - // Fill frame to buffer - stream_rtp_header_impl_t *header = m_UdpBuffer[BufIndex]; - - memcpy(header->payload, Data, DataLen); - - // RTP header - header->rtp_hdr.raw[0] = RTP_VERSION_BYTE | RTP_HDREXT_BIT; - header->rtp_hdr.raw[1] = RTP_PAYLOAD_TYPE; - header->rtp_hdr.seq = htons(m_RtpSeqNo & 0xFFFF); - /*header->rtp_hdr.ts = htonl((uint32_t)(RtpScr.Now() & 0xffffffff));*/ - /*header->rtp_hdr.ssrc = htonl(m_ssrc);*/ - - // RTP header extension - header->hdr_ext.hdr.size = htons(RTP_HEADER_EXT_X_SIZE); - header->hdr_ext.hdr.type = htons(RTP_HEADER_EXT_X_TYPE); - - // UDP header - header->hdr_ext.pos = htonull(StreamPos); - header->hdr_ext.seq = htons(m_SeqNo); - - header->hdr_ext.padding1[0] = 0; - header->hdr_ext.padding1[1] = 0; - - m_RtpSeqNo = (m_RtpSeqNo + 1) & 0xFFFF; - m_SeqNo = (m_SeqNo + 1) & UDP_SEQ_MASK; - - return header; - } -}; - - -#endif diff --git a/tools/udp_pes_scheduler.c b/tools/udp_pes_scheduler.c deleted file mode 100644 index 57b20a0b..00000000 --- a/tools/udp_pes_scheduler.c +++ /dev/null @@ -1,895 +0,0 @@ -/* - * udp_pes_scheduler.h: PES scheduler for UDP/RTP streams - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: udp_pes_scheduler.c,v 1.34 2008-04-28 20:53:07 phintuka Exp $ - * - */ - -#define __STDC_FORMAT_MACROS -#define __STDC_CONSTANT_MACROS -#include <inttypes.h> - -#include <stdint.h> -#include <stdlib.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/ioctl.h> - -#include <vdr/config.h> -#include <vdr/tools.h> -#include <vdr/videodir.h> - -#include "../logdefs.h" // logging -#include "../config.h" // configuration data -#include "../xine_input_vdr_net.h" // frame headers and constants - -#include "pes.h" -#include "udp_buffer.h" -#include "udp_pes_scheduler.h" -#include "time_pts.h" -#include "cxsocket.h" -#include "sap.h" // SAP - Session Announcement Protocol -#include "sdp.h" // SDP - Session Description Protocol -#include "rtcp.h" // RTCP - - -#ifdef LOG_RESEND -# define LOGRESEND LOGDBG -#else -# define LOGRESEND(x...) -#endif - -#ifdef LOG_SCR -# define LOGSCR LOGDBG -#else -# define LOGSCR(x...) -#endif - - -const int MAX_QUEUE_SIZE = 64; // ~ 65 ms with typical DVB stream -const int MAX_LIVE_QUEUE_SIZE = (64+60); // ~ 100 ms with typical DVB stream -const int HARD_LIMIT = (4*1024); // ~ 40 Mbit/s === 4 Mb/s - -// initial burst length after seek (500ms = ~13 video frames) -const int64_t INITIAL_BURST_TIME = (int64_t)(45000); // pts units (90kHz) - -// assume seek when when pts difference between two frames exceeds this (2,5 seconds) -const int64_t JUMP_LIMIT_TIME = (int64_t)(5*90000/2); // pts units (90kHz) - -const int RTCP_MIN_INTERVAL = 45000; // max. twice in second - - -typedef enum { - eScrDetect, - eScrFromAudio, - eScrFromPS1, - eScrFromVideo -} ScrSource_t; - - -cUdpScheduler::cUdpScheduler() -{ - - // Scheduler data - - current_audio_vtime = 0; - current_video_vtime = 0; - MasterClock.Set(INT64_C(0)); - - m_Master = false; - m_TrickSpeed = false; - - // RTP - - srandom(time(NULL) ^ getpid()); - - m_ssrc = random(); - LOGDBG("RTP SSRC: 0x%08x", m_ssrc); - m_LastRtcpTime = 0; - m_Frames = 0; - m_Octets = 0; - RtpScr.Set((int64_t)random()); - - m_fd_sap = -1; - - // Queuing - - int i; - for(i=0; i<MAX_UDP_HANDLES; i++) - m_Handles[i] = -1; - - m_BackLog = new cUdpBackLog; - - m_QueueNextSeq = 0; - m_QueuePending = 0; - - // Thread - - m_Running = 1; - - Start(); -} - -cUdpScheduler::~cUdpScheduler() -{ - m_Lock.Lock(); - - m_Running = 0; - m_Cond.Broadcast(); - m_Lock.Unlock(); - - Cancel(3); - - if(m_fd_rtcp.open() || m_fd_rtp.open()) - Send_SAP(false); - - CLOSESOCKET(m_fd_sap); - - delete m_BackLog; -} - -bool cUdpScheduler::AddRtp(void) -{ - cMutexLock ml(&m_Lock); - - if(m_fd_rtcp.open()) { - LOGERR("cUdpScheduler::AddHandle: RTCP socket already open !"); - Send_SAP(false); - m_fd_rtcp.close(); - } - - /* need new ssrc */ - m_ssrc = random(); - LOGDBG("RTP SSRC: 0x%08x", m_ssrc); - - // - // RTP - // - if(! m_fd_rtp.create(cxSocket::estDGRAM)) { - LOGERR("socket() failed (UDP/RTP multicast)"); - return false; - } - - // Set buffer sizes - m_fd_rtp.set_buffers(KILOBYTE(256), 2048); - - // Set multicast socket options - if(!m_fd_rtp.set_multicast(xc.remote_rtp_ttl)) { - m_fd_rtp.close(); - return false; - } - - if(xc.remote_local_ip[0]) { - struct sockaddr_in name; - name.sin_family = AF_INET; - name.sin_addr.s_addr = inet_addr(xc.remote_local_ip); - if(name.sin_addr.s_addr == INADDR_NONE) - LOGERR("Local address %s is invalid", xc.remote_local_ip); - name.sin_port = htons(xc.remote_rtp_port); - if (bind(m_fd_rtp.handle(), (struct sockaddr *)&name, sizeof(name)) < 0) - LOGERR("bind(%s:%d) failed for udp/rtp multicast", xc.remote_local_ip, xc.remote_rtp_port); -#if 0 - struct ip_mreqn mreqn; - mreqn.imr_multiaddr.s_addr = inet_addr(xc.remote_rtp_addr); - mreqn.imr_address.s_addr = inet_addr(xc.remote_local_ip); /* IP address of local interface */ - //mreqn.imr_ifindex = ; /* interface index */ - if(setsockopt(m_fd_rtp.handle(), IPPROTO_IP, IP_MULTICAST_IF, &mreqn, sizeof(mreqn))) - LOGERR("setting multicast source address/interface failed"); -#endif - } - - // Connect to multicast address - if(!m_fd_rtp.connect(xc.remote_rtp_addr, xc.remote_rtp_port) && - errno != EINPROGRESS) { - LOGERR("connect(fd_rtp) failed. Address=%s, port=%d", - xc.remote_rtp_addr, xc.remote_rtp_port); - m_fd_rtp.close(); - return false; - } - - // Set to non-blocking mode - m_fd_rtp.set_blocking(false); - - // - // RTCP - // - if(! m_fd_rtcp.create(cxSocket::estDGRAM)) - LOGERR("socket() failed (RTCP multicast)"); - - m_fd_rtcp.set_buffers(16384, 16384); - if(!m_fd_rtcp.set_multicast(xc.remote_rtp_ttl)) - m_fd_rtcp.close(); - - if(xc.remote_local_ip[0]) { - struct sockaddr_in name; - name.sin_family = AF_INET; - name.sin_addr.s_addr = inet_addr(xc.remote_local_ip); - name.sin_port = htons(xc.remote_rtp_port+1); - if (bind(m_fd_rtcp.handle(), (struct sockaddr *)&name, sizeof(name)) < 0) - LOGERR("bind(%s:%d) failed for udp/rtp multicast", xc.remote_local_ip, xc.remote_rtp_port); -#if 0 - struct ip_mreqn mreqn; - mreqn.imr_multiaddr.s_addr = inet_addr(xc.remote_rtp_addr); - mreqn.imr_address.s_addr = inet_addr(xc.remote_local_ip); /* IP address of local interface */ - //mreqn.imr_ifindex = ; /* interface index */ - if(setsockopt(m_fd_rtp.handle(), IPPROTO_IP, IP_MULTICAST_IF, &mreqn, sizeof(mreqn))) - LOGERR("setting multicast source address/interface failed"); -#endif - } - - /* RTCP port (RFC 1889) */ - if(!m_fd_rtcp.connect(xc.remote_rtp_addr, xc.remote_rtp_port + 1) && - errno != EINPROGRESS) { - LOGERR("connect(fd_rtcp) failed. Address=%s, port=%d", - xc.remote_rtp_addr, xc.remote_rtp_port + - (xc.remote_rtp_port&1)?-1:1); - m_fd_rtcp.close(); - } - - // Set to non-blocking mode - m_fd_rtcp.set_blocking(false); - - // Finished - - if(!AddHandle(m_fd_rtp)) - LOGERR("cUdpScheduler::AddHandle(fd_rtp) failed"); - - Send_SAP(true); - - return true; -} - -bool cUdpScheduler::AddHandle(int fd) -{ - cMutexLock ml(&m_Lock); - - int i; - - for(i=0; i<MAX_UDP_HANDLES; i++) - if(m_Handles[i] < 0 || m_Handles[i] == fd) { - m_Handles[i] = fd; - - /* query socket send buffer size */ - m_wmem[i] = 0x10000; /* default to 64k */ - socklen_t l = sizeof(int); - if(getsockopt(m_Handles[i], SOL_SOCKET, SO_SNDBUF, &m_wmem[i], &l)) - LOGERR("getsockopt(SO_SNDBUF) failed"); - m_wmem[i] /= 2; /* man 7 socket */ - - m_Cond.Broadcast(); - - return true; - } - - return false; -} - -void cUdpScheduler::RemoveRtp(void) -{ - cMutexLock ml(&m_Lock); - - if(m_fd_rtp.open() || m_fd_rtcp.open()) { - Send_SAP(false); - - RemoveHandle(m_fd_rtp); - - m_fd_rtp.close(); - m_fd_rtcp.close(); - CLOSESOCKET(m_fd_sap); - } -} - -void cUdpScheduler::RemoveHandle(int fd) -{ - cMutexLock ml(&m_Lock); - - int i; - for(i=0; i<MAX_UDP_HANDLES; i++) - if(m_Handles[i] == fd) - break; - - for(; i<MAX_UDP_HANDLES-1; i++) - m_Handles[i] = m_Handles[i+1]; - - m_Handles[MAX_UDP_HANDLES-1] = -1; - - if(m_Handles[0] < 0) { - // No clients left ... - - // Flush all buffers - m_QueueNextSeq = 0; - m_QueuePending = 0; - - m_BackLogDeleteMutex.Lock(); - delete m_BackLog; - m_BackLog = new cUdpBackLog; - m_BackLogDeleteMutex.Unlock(); - - m_Frames = 0; - m_Octets = 0; - } -} - -int cUdpScheduler::Poll(int TimeoutMs, bool Master) -{ - cMutexLock ml(&m_Lock); - - m_Master = Master; - - if(m_Handles[0] < 0) { - // no clients, so we can eat all data we are given ... - return DEFAULT_POLL_SIZE; - } - - int limit = m_Master ? MAX_QUEUE_SIZE : MAX_LIVE_QUEUE_SIZE; - if(m_QueuePending >= limit) { - uint64_t WaitEnd = cTimeMs::Now(); - if(TimeoutMs >= 0) - WaitEnd += (uint64_t)TimeoutMs; - - while(cTimeMs::Now() < WaitEnd && - m_Running && - m_QueuePending >= limit) - m_Cond.TimedWait(m_Lock, 5); - } - - return max(limit - m_QueuePending, 0); -} - -bool cUdpScheduler::Flush(int TimeoutMs) -{ - cMutexLock ml(&m_Lock); - - if(m_Handles[0] < 0) - return true; - - if(m_QueuePending > 0) { - uint64_t WaitEnd = cTimeMs::Now(); - if(TimeoutMs >= 0) - WaitEnd += (uint64_t)TimeoutMs; - - while(cTimeMs::Now() < WaitEnd && - m_Running && - m_QueuePending > 0) - m_Cond.TimedWait(m_Lock, 5); - } - return m_QueuePending == 0; -} - -void cUdpScheduler::Clear(void) -{ - cMutexLock ml(&m_Lock); - - m_BackLog->Clear(m_QueuePending); - - m_QueuePending = 0; - m_Cond.Broadcast(); -} - -void cUdpScheduler::Pause(bool On) -{ - cMutexLock ml(&m_Lock); - - if(On) - MasterClock.Pause(); - else - MasterClock.Resume(); - - m_TrickSpeed = false; -} - -void cUdpScheduler::TrickSpeed(const int Multiplier) -{ - cMutexLock ml(&m_Lock); - -#ifdef LOG_SCR - if(Multiplier == 1 || Multiplier == -1) { - LOGMSG("UDP clock --> normal"); - } else if(Multiplier < 0) - LOGMSG("UDP clock --> %dx", -Multiplier); - else - LOGMSG("UDP clock --> 1/%d", Multiplier); -#endif - - MasterClock.TrickSpeed(Multiplier); - - m_TrickSpeed = (Multiplier==-1 || Multiplier==1) ? false : true; -} - -void cUdpScheduler::SetScrSpeed(const int Speed) -{ - cMutexLock ml(&m_Lock); - - MasterClock.SetScrSpeed(Speed); - RtpScr.SetScrSpeed(Speed); -} - -bool cUdpScheduler::Queue(uint64_t StreamPos, const uchar *Data, int Length) -{ - cMutexLock ml(&m_Lock); - - if(m_Handles[0] < 0) - return true; - - int limit = m_Master ? MAX_QUEUE_SIZE : MAX_LIVE_QUEUE_SIZE; - if(m_QueuePending >= limit) - return false; - - m_BackLog->MakeFrame(StreamPos, Data, Length); - m_QueuePending++; - - m_Cond.Broadcast(); - - return true; -} - -int cUdpScheduler::calc_elapsed_vtime(int64_t pts, bool Audio) -{ - int64_t diff = 0; - - if(!Audio) { - diff = pts - current_video_vtime; - if(diff > JUMP_LIMIT_TIME || (-diff) > JUMP_LIMIT_TIME) { // 1 s (must be > GOP) - // RESET -#ifdef LOG_SCR - LOGDBG("cUdpScheduler RESET (Video jump %lld->%lld)", - current_video_vtime, pts); -#endif - current_video_vtime = pts; - - // Use video pts for sync only in audioless trickspeeds - // (audio has smaller, constant and increasing intervals) - if(m_TrickSpeed) - MasterClock.Set(current_video_vtime + INITIAL_BURST_TIME); - - return -1; - } - if(diff < 0) /* ignore small negative differences (B/P frames are sent out-of-order) */ - diff = 0; - else - current_video_vtime = pts; - - } else if(Audio) { - diff = pts - current_audio_vtime; - if(diff < 0) diff = -diff; - if(diff > JUMP_LIMIT_TIME) { // 1 sec - // RESET -#ifdef LOG_SCR - LOGDBG("cUdpScheduler RESET (Audio jump %lld->%lld)", - current_audio_vtime, pts); -#endif - current_audio_vtime = pts; - - // Use audio pts for sync (audio has constant and increasing intervals) - MasterClock.Set(current_audio_vtime + INITIAL_BURST_TIME); - - return -1; - } - current_audio_vtime = pts; - } - - return (int) diff; -} - -void cUdpScheduler::Send_RTCP(void) -{ - if(!m_fd_rtcp.open()) - return; - - uint64_t scr = RtpScr.Now(); - - if(scr > (m_LastRtcpTime + RTCP_MIN_INTERVAL)) { - uint8_t frame[2048], *content = frame; - char hostname[64] = ""; - rtcp_packet_t *msg = (rtcp_packet_t *)content; - struct timeval tv; - - gettimeofday(&tv, NULL); - gethostname(hostname, sizeof(hostname)-1); - hostname[sizeof(hostname)-1] = 0; - - // SR (Sender report) - msg->hdr.raw[0] = 0x81; // RTP version = 2, Report count = 1 */ - msg->hdr.ptype = RTCP_SR; - msg->hdr.length = htons(6); // length 6 dwords - - msg->sr.ssrc = htonl(m_ssrc); - msg->sr.ntp_sec = htonl(tv.tv_sec + 0x83AA7E80); - msg->sr.ntp_frac = htonl((uint32_t)((double)tv.tv_usec*(double)(1LL<<32)*1.0e-6)); - msg->sr.rtp_ts = htonl((uint32_t)(scr & 0xffffffff)); - msg->sr.psent = htonl((uint32_t)(m_Frames & 0xffffffff)); - msg->sr.osent = htonl((uint32_t)(m_Octets & 0xffffffff)); - - content += sizeof(rtcp_common_t) + sizeof(rtcp_sr_t); - msg = (rtcp_packet_t *)content; - - // SDES - msg->hdr.raw[0] = 0x81; // RTP version = 2, Report count = 1 */ - msg->hdr.ptype = RTCP_SDES; - msg->hdr.count = 1; - - msg->sdes.ssrc = m_ssrc; - msg->sdes.item[0].type = RTCP_SDES_CNAME; - sprintf(msg->sdes.item[0].data, "VDR@%s:%d%c%c%c", - hostname[0] ? hostname : xc.remote_rtp_addr, - xc.remote_rtp_port, 0, 0, 0); - msg->sdes.item[0].length = strlen(msg->sdes.item[0].data); - msg->hdr.length = htons(1 + 1 + ((msg->sdes.item[0].length - 2) + 3) / 4); - - content += sizeof(rtcp_common_t) + 4*ntohs(msg->hdr.length); - msg = (rtcp_packet_t *)content; - - // Send -#ifndef LOG_RTCP - (void) m_fd_rtcp.send(frame, content - frame); -#else - LOGMSG("RTCP send (%d)", m_fd_rtcp.send(frame, content - frame)); - for(int i=0; i<content-frame; i+=16) - LOGMSG("%02X %02X %02X %02X %02X %02X %02X %02X " - "%02X %02X %02X %02X %02X %02X %02X %02X " - " %c%c%c%c%c%c%c%c %c%c%c%c%c%c%c%c", - frame[i+0],frame[i+1],frame[i+2],frame[i+3], - frame[i+4],frame[i+5],frame[i+6],frame[i+7], - frame[i+8],frame[i+9],frame[i+10],frame[i+11], - frame[i+12],frame[i+13],frame[i+14],frame[i+15], - frame[i+0],frame[i+1],frame[i+2],frame[i+3], - frame[i+4],frame[i+5],frame[i+6],frame[i+7], - frame[i+8],frame[i+9],frame[i+10],frame[i+11], - frame[i+12],frame[i+13],frame[i+14],frame[i+15]); -#endif - - m_LastRtcpTime = scr; - } -} - - -void cUdpScheduler::Send_SAP(bool Announce) -{ - if(xc.remote_rtp_sap && m_fd_rtp.open()) { - char ip[64] = ""; - uint32_t local_addr = m_fd_rtp.get_local_address(ip); - if(local_addr) { - const char *sdp_descr = vdr_sdp_description(ip, - 2001, - xc.listen_port, - xc.remote_rtp_addr, - m_ssrc, - xc.remote_rtp_port, - xc.remote_rtp_ttl); -#if 1 - /* store copy of SDP data */ - if(m_fd_sap < 0) { - cString fname = AddDirectory(VideoDirectory, - cString::sprintf("xineliboutput@%s.sdp", - ip)); - FILE *fp = fopen(fname, "w"); - if(fp) { - fprintf(fp, "%s", sdp_descr); - fclose(fp); - } - } -#endif - sap_pdu_t *pdu = sap_create_pdu(local_addr, - Announce, - (m_ssrc >> 16 | m_ssrc) & 0xffff, - "application/sdp", - sdp_descr); - - if(!sap_send_pdu(&m_fd_sap, pdu, 0)) - LOGERR("SAP/SDP announce failed"); - free(pdu); - - if(!Announce) - CLOSESOCKET(m_fd_sap); - } - } -} - -void cUdpScheduler::Schedule(const uchar *Data, int Length) -{ - bool Audio = IS_AUDIO_PACKET(Data), Video = IS_VIDEO_PACKET(Data); - int64_t pts = PES_HAS_PTS(Data) ? pes_get_pts(Data, Length) : INT64_C(-1); - int elapsed = pts>0 ? calc_elapsed_vtime(pts, Audio) : 0; - - if(elapsed > 0) { - int64_t now = MasterClock.Now(); - LOGSCR("PTS: %lld (%s) elapsed %d ms (PID %02x)", - pts, Video?"Video":Audio?"Audio":"?", elapsed/90, Data[3]); - - // - // Detect discontinuity - // - if(Audio) { - if(now > current_audio_vtime && (now - current_audio_vtime)>JUMP_LIMIT_TIME) { - LOGSCR("cUdpScheduler MasterClock init (was in past)"); - MasterClock.Set(current_audio_vtime + INITIAL_BURST_TIME); - } else if(now < current_audio_vtime && (current_audio_vtime-now)>JUMP_LIMIT_TIME) { - LOGSCR("cUdpScheduler MasterClock init (was in future)"); - MasterClock.Set(current_audio_vtime + INITIAL_BURST_TIME); - } - } - - else if(Video && m_TrickSpeed) { - if(now > current_video_vtime && (now - current_video_vtime)>JUMP_LIMIT_TIME) { - LOGSCR("cUdpScheduler MasterClock init (was in past) - VIDEO"); - MasterClock.Set(current_video_vtime + INITIAL_BURST_TIME); - } else if(now < current_video_vtime && (current_video_vtime-now)>JUMP_LIMIT_TIME) { - LOGSCR("cUdpScheduler MasterClock init (was in future) - VIDEO"); - MasterClock.Set(current_video_vtime + INITIAL_BURST_TIME); - } - } - - // - // Delay - // - int delay_ms = 0; - if(m_TrickSpeed ) { - if(current_video_vtime > now) { - delay_ms = (int)(current_video_vtime - now)/90; - LOGSCR("cUdpScheduler sleeping %d ms " - "(time reference: %s, beat interval %d ms)", - delay_ms, (Audio?"Audio PTS":"Video PTS"), elapsed/90); - } - } else { - if(current_audio_vtime > now) { - delay_ms = (int)(current_audio_vtime - now)/90; - LOGSCR("cUdpScheduler sleeping %d ms " - "(time reference: %s, beat interval %d ms)", - delay_ms, (Audio?"Audio PTS":"Video PTS"), elapsed/90); - } - } - while(delay_ms > 3) { - if(delay_ms > 20) - delay_ms = 20; - LOGSCR(" -> cUdpScheduler sleeping %d ms ", delay_ms); - CondWait.Wait(delay_ms); - now = MasterClock.Now(); - delay_ms = (int)(current_video_vtime - now)/90; - } - } -} - -void cUdpScheduler::Action(void) -{ -#if 0 - { - // Request real-time scheduling - sched_param temp; - temp.sched_priority = 2; - - if (!pthread_setschedparam(pthread_self(), SCHED_RR, &temp)) { - LOGMSG("cUdpScheduler priority set successful SCHED_RR %d [%d,%d]", - temp.sched_priority, - sched_get_priority_min(SCHED_RR), - sched_get_priority_max(SCHED_RR)); - } else { - LOGMSG("cUdpScheduer: Can't set priority to SCHED_RR %d [%d,%d]", - temp.sched_priority, - sched_get_priority_min(SCHED_RR), - sched_get_priority_max(SCHED_RR)); - } - } -#endif - - /* UDP Scheduler needs high priority */ - SetPriority(-5); - (void)nice(-5); - errno = 0; - - m_Lock.Lock(); - - while(m_Running) { - - if(m_Handles[0] < 0) { - m_Cond.TimedWait(m_Lock, 5000); - continue; - } - - // Wait until we have outgoing data in queue - if(m_QueuePending <= 0) { - m_Cond.TimedWait(m_Lock, 100); - if(m_QueuePending <= 0) { - // Still nothing... - // Send padding frame once in 100ms so clients can detect - // possible missing frames and server shutdown - static unsigned char padding[] = {0x00,0x00,0x01,0xBE,0x00,0x02,0xff,0xff}; - int prevseq = (m_QueueNextSeq + UDP_BUFFER_SIZE - 1) & UDP_BUFFER_MASK; - stream_rtp_header_impl_t *frame = m_BackLog->Get(prevseq); - if(frame) { - int prevlen = m_BackLog->PayloadSize(prevseq); - uint64_t pos = ntohll(frame->hdr_ext.pos) + prevlen - 8; - m_BackLog->MakeFrame(pos, padding, 8); - } else - m_BackLog->MakeFrame(0, padding, 8); - m_QueuePending++; - } - continue; // to check m_Running - } - - // Take next frame from queue - stream_rtp_header_impl_t *frame = m_BackLog->Get(m_QueueNextSeq); - int PayloadSize = m_BackLog->PayloadSize(m_QueueNextSeq); - int UdpPacketLen = PayloadSize + sizeof(stream_udp_header_t); - int RtpPacketLen = PayloadSize + sizeof(stream_rtp_header_impl_t); - - m_QueueNextSeq = (m_QueueNextSeq + 1) & UDP_BUFFER_MASK; - m_QueuePending--; - - m_Cond.Broadcast(); - m_BackLogDeleteMutex.Lock(); /* ensure frame will not be deleted from queue */ - m_Lock.Unlock(); - - // Schedule frame - if(m_Master) - Schedule(frame->payload, PayloadSize); - - // Need some bandwidth limit for ex. sequence of still frames when - // moving cutting marks very fast (no audio or PTS available) -#if 1 - // hard limit for used bandwidth: - // - ~1 frames/ms & 8kb/ms -> 8mb/s -> ~ 80 Mbit/s ( / client) - // - max burst 15 frames or 30kb - static int cnt = 0, bytes = 0; - static uint64_t dbg_timer = cTimeMs::Now(); - static int dbg_bytes = 0; - cnt++; - bytes += PayloadSize; - if(cnt>=15 && bytes >= 30000) { - CondWait.Wait(4); - dbg_bytes += bytes; - cnt = 0; - bytes = 0; - if(dbg_timer+60000 <= cTimeMs::Now()) { -# if 0 - LOGDBG("UDP rate: %4d Kbps (queue %d)", dbg_bytes/(60*1024/8), - m_QueuePending); -# endif - dbg_bytes = 0; - dbg_timer = cTimeMs::Now(); - } - } -#endif - - /* tag frame with ssrc and timestamp */ - frame->rtp_hdr.ts = htonl((uint32_t)(RtpScr.Now() & 0xffffffff)); - frame->rtp_hdr.ssrc = htonl(m_ssrc); - - /* deliver to all active sockets */ - for(int i=0; i<MAX_UDP_HANDLES && m_Handles[i]>=0; i++) { - - // - // use TIOCOUTQ ioctl instead of poll/select. - // - poll/select for UDP/RTP may return true even when queue - // is (almost) full - // - kernel silently drops frames it cant send - // -> poll() + send() just causes frames to be dropped - // - int size = 0; - if(!ioctl(m_Handles[i], TIOCOUTQ, &size)) { - if(size >= (m_wmem[i] - 2*RtpPacketLen)) { - LOGMSG("cUdpScheduler: kernel transmit queue > ~%dkb (max %dkb) ! (master=%d)", - (m_wmem[i] - 2*RtpPacketLen)/1024, m_wmem[i]/1024, m_Master); - CondWait.Wait(2); - } - } else { - if(m_QueuePending > (MAX_QUEUE_SIZE-5)) - LOGDBG("cUdpScheduler: kernel transmit queue > ~30kb ! (master=%d ; Queue=%d)", - m_Master, m_QueuePending); - CondWait.Wait(2); - } - - if(m_Handles[i] == m_fd_rtp.handle()) { - if(send(m_Handles[i], frame, RtpPacketLen, 0) <= 0) - LOGERR("cUdpScheduler: UDP/RTP send() failed !"); - } else { - /* UDP: send without rtp header */ - if(send(m_Handles[i], - ((uint8_t*)frame) + sizeof(stream_rtp_header_impl_t) - sizeof(stream_udp_header_t), - UdpPacketLen, 0) <= 0) - LOGERR("cUdpScheduler: UDP send() failed !"); - } - } - - m_BackLogDeleteMutex.Unlock(); /* release queue */ - m_Lock.Lock(); - - m_Frames ++; - m_Octets += PayloadSize; - if(m_fd_rtcp.open() && (m_Frames & 0xff) == 1) { // every 256th frame - Send_RTCP(); -#if 0 - if((m_Frames & 0xff00) == 0) // every 65536th frame (~ 2 min) - Send_SAP(); -#else - if((m_Frames & 0x0300) == 0) // every 1024th frame (~ 2...4 sec) - Send_SAP(); -#endif - } - } - - m_Lock.Unlock(); -} - -void cUdpScheduler::ReSend(int fd, uint64_t Pos, int Seq1, int Seq2) -{ - if(fd < 0) /* no re-send for RTP */ - return; - - char udp_ctrl[64] = {0}; - ((stream_udp_header_t *)udp_ctrl)->seq = (uint16_t)(-1); - ((stream_udp_header_t *)udp_ctrl)->pos = (uint64_t)(-1); - - // Handle buffer wrap - if(Seq1 > Seq2) - Seq2 += UDP_BUFFER_SIZE; - - cMutexLock ml(&m_Lock); // keeps also scheduler thread suspended ... - - if(Seq2-Seq1 > 64) { - LOGDBG("cUdpScheduler::ReSend: requested range too large (%d-%d)", - Seq1, Seq2); - - sprintf((udp_ctrl+sizeof(stream_udp_header_t)), - "UDP MISSING %d-%d %" PRIu64, - Seq1, (Seq2 & UDP_BUFFER_MASK), Pos); - send(fd, udp_ctrl, sizeof(udp_ctrl), 0); - return; - } - - // re-send whole range - for(; Seq1 <= Seq2; Seq1++) { - - // Wait if kernel queue is full - int size = 0; - if(!ioctl(fd, TIOCOUTQ, &size)) - if(size > ((0x10000)/2 - 2048)) { // assume 64k kernel buffer - LOGDBG("cUdpScheduler::ReSend: kernel transmit queue > ~30kb !"); - cCondWait::SleepMs(2); - } - - stream_rtp_header_impl_t *frame = m_BackLog->Get(Seq1); - - if(frame) { - if(ntohull(frame->hdr_ext.pos) - Pos < 100000) { - send(fd, - ((uint8_t*)frame) + sizeof(stream_rtp_header_impl_t) - sizeof(stream_udp_header_t), - m_BackLog->PayloadSize(Seq1) + sizeof(stream_udp_header_t), - 0); - LOGRESEND("cUdpScheduler::ReSend: %d (%d bytes) @%lld sent", - Seq1, m_BackLog->PayloadSize(Seq1), Pos); - Pos = ntohull(frame->hdr_ext.pos) + m_BackLog->PayloadSize(Seq1); - continue; - } else { - // buffer has been lost long time ago... - LOGRESEND("cUdpScheduler::ReSend: Requested position does not match " - "(%lld ; has %lld)", Pos, ntohll(frame->hdr_ext.pos)); - } - } else { - LOGRESEND("cUdpScheduler::ReSend: %d @%lld missing", Seq1, Pos); - } - - // buffer has been lost - send packet missing info - - LOGRESEND("cUdpScheduler::ReSend: missing %d-%d @%d (hdr 0x%llx 0x%x)", - Seq1, Seq1, Pos, - ((stream_udp_header_t *)udp_ctrl)->pos, - ((stream_udp_header_t *)udp_ctrl)->seq); - - int Seq0 = Seq1; - for(; Seq1 <= Seq2; Seq1++) { - stream_rtp_header_impl_t *frame = m_BackLog->Get(Seq1+1); - if(frame && (ntohull(frame->hdr_ext.pos) - Pos < 100000)) - break; - } - - sprintf((udp_ctrl+sizeof(stream_udp_header_t)), - "UDP MISSING %d-%d %" PRIu64, - Seq0, (Seq1 & UDP_BUFFER_MASK), Pos); - - send(fd, udp_ctrl, sizeof(udp_ctrl), 0); - } -} diff --git a/tools/udp_pes_scheduler.h b/tools/udp_pes_scheduler.h deleted file mode 100644 index fd24f57a..00000000 --- a/tools/udp_pes_scheduler.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * udp_pes_scheduler.h: PES scheduler for UDP/RTP streams - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: udp_pes_scheduler.h,v 1.13 2008-04-28 20:53:07 phintuka Exp $ - * - */ - -#ifndef __UDP_PES_SCHEDULER_H -#define __UDP_PES_SCHEDULER_H - -#include <stdint.h> - -#include <vdr/tools.h> // uchar -#include <vdr/thread.h> - -#include "cxsocket.h" -#include "time_pts.h" - -#define MAX_UDP_HANDLES 16 - -class cUdpBackLog; - -class cUdpScheduler : public cThread -{ - public: - - cUdpScheduler(); - virtual ~cUdpScheduler(); - - // fd should be binded & connected to IP:PORT (local+remote) pair ! - bool AddHandle(int fd); /* UDP unicast */ - void RemoveHandle(int fd); /* UDP unicast */ - bool AddRtp(void); /* UDP/RTP multicast */ - void RemoveRtp(void); /* UDP/RTP multicast */ - bool AddHandle(cxSocket& s) { return AddHandle(s.handle()); } - void RemoveHandle(cxSocket& s) { RemoveHandle(s.handle()); } - - bool Clients(void) { return m_Handles[0] >= 0; } - int Poll(int TimeoutMs, bool Master); - bool Queue(uint64_t StreamPos, const uchar *Data, int Length); - void ReSend(int fd, uint64_t Pos, int Seq1, int Seq2); - - void Clear(void); - bool Flush(int TimeoutMs); - - void Pause(bool On); - void TrickSpeed(const int Multiplier); - void SetScrSpeed(const int Speed = 90000); - - protected: - - // Data for payload handling & buffering - - // Signalling - cCondVar m_Cond; - cMutex m_Lock; - - // Clients - int m_Handles[MAX_UDP_HANDLES]; - int m_wmem[MAX_UDP_HANDLES]; /* kernel buffer size */ - - cxSocket m_fd_rtp; - cxSocket m_fd_rtcp; - - // Queue - int m_QueueNextSeq; /* next outgoing */ - int m_QueuePending; /* outgoing queue size */ - cUdpBackLog *m_BackLog; /* queue for incoming data (not yet send) and retransmissions */ - cMutex m_BackLogDeleteMutex; - - // Data for scheduling algorithm - cTimePts MasterClock; /* Current MPEG PTS (synchronized to current stream) */ - cCondWait CondWait; - - int64_t current_audio_vtime; - int64_t current_video_vtime; - - // RTP - uint32_t m_ssrc; /* RTP synchronization source id */ - cTimePts RtpScr; /* 90 kHz monotonic time source for RTP timestamps */ - - // RTCP - uint64_t m_LastRtcpTime; - uint32_t m_Frames; - uint32_t m_Octets; - - // Scheduling - - bool m_TrickSpeed; - bool m_Master; /* if true, we are master metronom for playback */ - - int calc_elapsed_vtime(int64_t pts, bool Audio); - void Schedule(const uchar *Data, int Length); - - bool m_Running; - virtual void Action(void); - - void Send_RTCP(void); - - int m_fd_sap; - - void Send_SAP(bool Announce = true); -}; - -#endif diff --git a/tools/vdrdiscovery.c b/tools/vdrdiscovery.c deleted file mode 100644 index 82a9a109..00000000 --- a/tools/vdrdiscovery.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * vdrdiscovery.c - * - * Simple broadcast protocol to search VDR with xineliboutput server - * from (local) network. - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vdrdiscovery.c,v 1.5 2008-04-03 13:59:37 phintuka Exp $ - * - */ - -#include <stdlib.h> -#include <stdio.h> -#include <poll.h> -#include <unistd.h> -#include <netinet/in.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <arpa/inet.h> - -#ifdef FE_STANDALONE -# define LOG_MODULENAME "[discovery] " -#else -# define LogToSysLog 1 -#endif - -#define NEED_x_syslog -#include "../logdefs.h" - -#include "vdrdiscovery.h" - -/* - * - */ - -#ifndef DISCOVERY_PORT -# define DISCOVERY_PORT 37890 -#endif - -/* discovery protocol strings (v1.0) */ -#define DISCOVERY_1_0_HDR "VDR xineliboutput DISCOVERY 1.0" "\r\n" -#define DISCOVERY_1_0_CLI "Client: %s:%d" "\r\n" -#define DISCOVERY_1_0_SVR "Server port: %d" "\r\n" -#define DISCOVERY_1_0_ADDR "Server address: %s" "\r\n" -#define DISCOVERY_1_0_VERSION "Server version: " /*vdr-" VDRVERSION "\r\n\t"*/ \ - "xineliboutput-" XINELIBOUTPUT_VERSION "\r\n" - -/* - * - */ - -static inline int discovery_init(int port) -{ - int fd_discovery = -1; - struct sockaddr_in sin; - - if ((fd_discovery = socket(PF_INET, SOCK_DGRAM, 0/*IPPROTO_TCP*/)) < 0) { - LOGERR("socket() failed (UDP discovery)"); - } else { - int iBroadcast = 1, iReuse = 1; - if(setsockopt(fd_discovery, SOL_SOCKET, SO_BROADCAST, &iBroadcast, sizeof(int)) < 0) - LOGERR("setsockopt(SO_BROADCAST) failed"); - if(setsockopt(fd_discovery, SOL_SOCKET, SO_REUSEADDR, &iReuse, sizeof(int)) < 0) - LOGERR("setsockopt(SO_REUSEADDR) failed"); - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - sin.sin_addr.s_addr = htonl(INADDR_BROADCAST); - - if (bind(fd_discovery, (struct sockaddr *)&sin, sizeof(sin)) < 0) { - LOGERR("bind() failed (UDP discovery)"); - } else { - return fd_discovery; - } - } - - close(fd_discovery); - return -1; -} - -#ifndef FE_STANDALONE -int udp_discovery_init(void) -{ - return discovery_init(DISCOVERY_PORT); -} -#endif - -static inline int udp_discovery_send(int fd_discovery, int port, char *msg) -{ - struct sockaddr_in sin; - int len = strlen(msg); - - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - sin.sin_addr.s_addr = INADDR_BROADCAST; - - if(len != sendto(fd_discovery, msg, len, 0, - (struct sockaddr *)&sin, sizeof(sin))) { - LOGERR("UDP broadcast send failed (discovery)"); - return -1; - } - - //LOGDBG("UDP broadcast send succeed (discovery)"); - return 0; -} - -#ifndef FE_STANDALONE -int udp_discovery_broadcast(int fd_discovery, int server_port, const char *server_address) -{ - char *msg = NULL; - int result; - - if(server_address && *server_address) - asprintf(&msg, - DISCOVERY_1_0_HDR //"VDR xineliboutput DISCOVERY 1.0" "\r\n" - DISCOVERY_1_0_SVR //"Server port: %d" "\r\n" - DISCOVERY_1_0_ADDR //"Server Address: %d.%d.%d.%d \r\n" - DISCOVERY_1_0_VERSION //"Server version: xineliboutput-" XINELIBOUTPUT_VERSION "\r\n" - "\r\n", - server_port, server_address); - else - asprintf(&msg, - DISCOVERY_1_0_HDR //"VDR xineliboutput DISCOVERY 1.0" "\r\n" - DISCOVERY_1_0_SVR //"Server port: %d" "\r\n" - DISCOVERY_1_0_VERSION //"Server version: xineliboutput-" XINELIBOUTPUT_VERSION "\r\n" - "\r\n", - server_port); - - result = udp_discovery_send(fd_discovery, DISCOVERY_PORT, msg); - - free(msg); - return result; -} -#else -static inline int udp_discovery_search(int fd_discovery, int port) -{ - char *msg = NULL; - int result; - - asprintf(&msg, - DISCOVERY_1_0_HDR /* "VDR xineliboutput DISCOVERY 1.0" "\r\n" */ - DISCOVERY_1_0_CLI /* "Client: %s:%d" "\r\n" */ - "\r\n", - "255.255.255.255", - port); - - result = udp_discovery_send(fd_discovery, port, msg); - - free(msg); - return result; -} -#endif - -#ifdef FE_STANDALONE -static -#endif -int udp_discovery_recv(int fd_discovery, char *buf, int timeout, - struct sockaddr_in *source) -{ - socklen_t sourcelen = sizeof(struct sockaddr_in); - struct pollfd pfd; - int err; - - pfd.fd = fd_discovery; - pfd.events = POLLIN; - - errno = 0; - err = poll(&pfd, 1, timeout); - if(err < 1) { - if(err < 0) - LOGERR("broadcast poll error"); - return err; - } - - memset(source, 0, sourcelen); - memset(buf, 0, DISCOVERY_MSG_MAXSIZE); - - err = recvfrom(fd_discovery, buf, DISCOVERY_MSG_MAXSIZE-1, 0, - (struct sockaddr *)source, &sourcelen); - - if(err <= 0) - LOGDBG("fd_discovery recvfrom() error"); - - return err; -} - -#ifndef FE_STANDALONE -int udp_discovery_is_valid_search(const char *buf) -{ - const char *id_string = DISCOVERY_1_0_HDR "Client:"; - - if(!strncmp(id_string, buf, strlen(id_string))) { - LOGMSG("Received valid discovery message %s", buf); - return 1; - } - - LOGDBG("BROADCAST: %s", buf); - return 0; -} -#else -int udp_discovery_find_server(int *port, char *address) -{ - static const char mystring[] = DISCOVERY_1_0_HDR "Server port: "; - struct sockaddr_in from; - char buf[DISCOVERY_MSG_MAXSIZE]; - int fd_discovery = -1; - int trycount = 0; - int err = 0; - - *port = DISCOVERY_PORT; - strcpy(address, "vdr"); - - if((fd_discovery = discovery_init(DISCOVERY_PORT)) < 0) - return 0; - - while(err >= 0 && ++trycount < 4) { - - if((err = udp_discovery_search(fd_discovery, DISCOVERY_PORT) >= 0)) { - - errno = 0; - while( (err = udp_discovery_recv(fd_discovery, buf, 500, &from)) > 0) { - - uint32_t tmp = ntohl(from.sin_addr.s_addr); - - buf[err] = 0; - LOGDBG("Reveived broadcast: %d bytes from %d.%d.%d.%d \n%s", - err, - ((tmp>>24)&0xff), ((tmp>>16)&0xff), - ((tmp>>8)&0xff), ((tmp)&0xff), - buf); - if(!strncmp(mystring, buf, strlen(mystring))) { - char *iploc; - LOGDBG("Valid discovery message"); - close(fd_discovery); - - // default: use broadcast source address - sprintf(address, "%d.%d.%d.%d", - ((tmp>>24)&0xff), ((tmp>>16)&0xff), - ((tmp>>8)&0xff), ((tmp)&0xff)); - - // Check if announce message includes alternative server address - iploc = strstr(buf + strlen(mystring), "Server address: "); - if(iploc) { - uint32_t svraddr; - iploc += strlen("Server address: "); - svraddr = inet_addr(iploc); - if(svraddr == INADDR_NONE) { - LOGMSG("Server provided invalid address !"); - } else { - svraddr = ntohl(svraddr); - sprintf(address, "%d.%d.%d.%d", - ((svraddr>>24)&0xff), ((svraddr>>16)&0xff), - ((svraddr>>8)&0xff), ((svraddr)&0xff)); - LOGMSG("Replacing broadcast source address %d.%d.%d.%d " - "with server-given address %s", - ((tmp>>24)&0xff), ((tmp>>16)&0xff), - ((tmp>>8)&0xff), ((tmp)&0xff), - address); - } - } - - *port = -1; - if(1 == sscanf(buf + strlen(mystring), "%d", port) && - *port >= 1000 && *port <= 0xffff) - return 1; - LOGMSG("Server-given port is invalid !"); - } else { - LOGDBG("NOT valid discovery message"); - } - } - } - } - - /* failed */ - close(fd_discovery); - return 0; -} -#endif - diff --git a/tools/vdrdiscovery.h b/tools/vdrdiscovery.h deleted file mode 100644 index 7c4d18ae..00000000 --- a/tools/vdrdiscovery.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * vdrdiscovery.h - * - * Simple broadcast protocol to search VDR with xineliboutput server - * from (local) network. - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: vdrdiscovery.h,v 1.3 2007-06-11 19:39:06 phintuka Exp $ - * - */ - -#ifndef _VDRDISCOVERY_H_ -#define _VDRDISCOVERY_H_ - -#define DISCOVERY_MSG_MAXSIZE 1024 - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef FE_STANDALONE -int udp_discovery_find_server(int *port, char *address); -#else -int udp_discovery_init(void); -int udp_discovery_broadcast(int fd_discovery, int server_port, const char *server_address); -int udp_discovery_recv(int fd_discovery, char *buf, int timeout, - struct sockaddr_in *source); -int udp_discovery_is_valid_search(const char *buf); -#endif - -#ifdef __cplusplus -}; -#endif - - -#endif // _VDRDISCOVERY_H_ |
