diff options
author | cvs2svn <admin@example.com> | 2009-10-21 00:02:02 +0000 |
---|---|---|
committer | cvs2svn <admin@example.com> | 2009-10-21 00:02:02 +0000 |
commit | 97a97ca3358eb48de3eb7a222e487e800566569f (patch) | |
tree | 97c920d0225a1c9773a3bce2207f261d7d230123 /tools | |
parent | a61961358c5a2ec92340b3f8e056bab55438f103 (diff) | |
download | xineliboutput-CVS.tar.gz xineliboutput-CVS.tar.bz2 |
This commit was manufactured by cvs2svn to create branch 'CVS'.CVS
Diffstat (limited to 'tools')
44 files changed, 0 insertions, 9003 deletions
diff --git a/tools/backgroundwriter.c b/tools/backgroundwriter.c deleted file mode 100644 index 6b7c8ff4..00000000 --- a/tools/backgroundwriter.c +++ /dev/null @@ -1,500 +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.18 2009-07-24 18:11:20 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 <vdr/config.h> // VDRVERSNUM - -#include "../logdefs.h" -#include "../xine_input_vdr_net.h" // stream_tcp_header_t -#include "ts.h" -#include "pes.h" - -#include "backgroundwriter.h" - - -#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_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() -{ - 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; -} - -void cBackgroundWriterI::Cork(void) -{ - if (m_IsSocket) { -#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 - } -} - -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 && - Running() && - m_RingBuffer.Available() > 0) - cCondWait::SleepMs(3); - } - - int Available = m_RingBuffer.Available(); - if(m_IsSocket && Available <= 0) { - // flush corked data too - Cork(); - } - - return 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 = 0; - uint64_t GetPos = 0; - cPoller Poller (m_fd, true); - bool CorkReq = false; - - while (Running()) { - - if(Poller.Poll(100)) { - - if (CorkReq && m_RingBuffer.Available() <= 0) { - // Force TCP packet to avoid delaying control messages - Cork(); - CorkReq = false; - } - - uint64_t StartPos; - int Count = 0; - int n; - uchar *Data = m_RingBuffer.Get(Count); - - if(Data && Count > 0) { - - Lock(); // uint64_t m_DiscardStart can not be read atomically (IA32) - StartPos = m_DiscardEnd; - Unlock(); - - // Discard data ? - if(StartPos > GetPos) { - if(NextHeaderPos == GetPos) { - // we're at frame boundary - // drop only data packets, not control messages - uint8_t *pkt = TCP_PAYLOAD(Data); - if (DATA_IS_PES(pkt) || DATA_IS_TS(pkt)) { - Count = min(Count, (int)(StartPos - GetPos)); - - // size of next (complete) packet. - // drop only one packet at time. - stream_tcp_header_t *header = (stream_tcp_header_t*)Data; - int pkt_len = ntohl(header->len) + sizeof(stream_tcp_header_t); - if (Count >= pkt_len) { - // drop only complete packets. - // some packets are not dropped (packets overlapping end of ringbuffer) - Count = pkt_len; - - m_RingBuffer.Del(Count); - GetPos += Count; - NextHeaderPos = GetPos; - - CorkReq = true; // force sending last frame - - continue; - } - } - } - } - - // Next frame ? - if(GetPos == NextHeaderPos) { - if(Count < (int)sizeof(stream_tcp_header_t)) - LOGMSG("cBackgroundWriter @NextHeaderPos: Count < header size !"); - - // limit single write to size of next (complete) packet. - // (we need to track packet boundaries) - stream_tcp_header_t *header = (stream_tcp_header_t*)Data; - int pkt_len = ntohl(header->len) + sizeof(stream_tcp_header_t); - if (Count > pkt_len) - Count = pkt_len; - // next packet start position in stream - NextHeaderPos = GetPos + pkt_len; - - // check for control message - uint8_t *pkt = TCP_PAYLOAD(Data); - if (!DATA_IS_PES(pkt) && !DATA_IS_TS(pkt)) - CorkReq = true; - - } else { - Count = min(Count, (int)(NextHeaderPos-GetPos)); - } - - 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(); -} - -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 (Running()) { - - // 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(); - Cancel(-1); - 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(); - Cancel(-1); - } - - return 0; -} - - -// -// cRawWriter -// - -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 (Running()) { - - if(Poller.Poll(100)) { - - uint64_t StartPos; - int Count = 0; - int n; - uchar *Data = m_RingBuffer.Get(Count); - - if(Data && Count > 0) { - - Lock(); // uint64_t m_DiscardStart can not be read atomically (IA32) - StartPos = m_DiscardEnd; - Unlock(); - - // Discard data ? - if(StartPos > GetPos) { - if(NextHeaderPos == GetPos) { - // we're at frame boundary - Count = min(Count, (int)(StartPos - GetPos)); - - m_RingBuffer.Del(Count); - GetPos += Count; - NextHeaderPos = GetPos; - continue; - } - } - - // Next frame ? - if(GetPos == NextHeaderPos) { - if(Count < 6) - LOGMSG("cBackgroundWriter @NextHeaderPos: Count < header size !"); - - int packlen = DATA_IS_TS(Data) ? TS_SIZE : 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)); - } - - 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(); -} - -int cRawWriter::Put(uint64_t StreamPos, - const uchar *Data, int DataCount) -{ - if (Running()) { - - // 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(); - Cancel(-1); - 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(); - Cancel(-1); - } - - 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 d0ee5b30..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.6 2009-07-24 05:24:22 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; - - 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; - void Cork(void); - - 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 569c491b..00000000 --- a/tools/bitstream.h +++ /dev/null @@ -1,175 +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.3 2009-02-14 20:44:15 phintuka Exp $ - * - */ - -#ifndef _XINELIBOUTPUT_BITSTREAM_H_ -#define _XINELIBOUTPUT_BITSTREAM_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/gnome_screensaver.c b/tools/gnome_screensaver.c deleted file mode 100644 index a23d4236..00000000 --- a/tools/gnome_screensaver.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * gnome_screensaver.c v0.0.7 - * - * Enable/Disable the GNOME screensaver - * Supports GNOME screensaver API 2.14 and 2.15 - * - * Call gnome_screensaver_control(1) to enable and - * gnome_screensaver_control(0) to disable - * - */ -/* - * Orginally written for mplayer by Piotr Kaczuba - * (http://lists.mplayerhq.hu/pipermail/mplayer-dev-eng/2006-April/042661.html) - * - * Modified for xineliboutput by Alex Stansfield - * (http://www.linuxtv.org/pipermail/vdr/2007-July/013458.html) - */ - -#include <stdlib.h> -#include <unistd.h> -#include <dbus/dbus-glib.h> -#include <stdio.h> -#include <stdarg.h> -#include <string.h> - -#define LOG_MODULENAME "[vdr-fe] " -#include "../logdefs.h" - -#include "gnome_screensaver.h" - -#define GS_SERVICE "org.gnome.ScreenSaver" -#define GS_PATH "/org/gnome/ScreenSaver" -#define GS_INTERFACE "org.gnome.ScreenSaver" - -#define GS_APPLICATION_NAME "vdr-sxfe" -#define GS_REASON_FOR_INHIBIT "Watching TV" - -/* Log Messages */ -#define MSG_OpenBusConnectionError "Failed to open connection to bus: %s" -#define MSG_RemoteMethodException "Caught remote method exception %s: %s" -#define MSG_GnomeAPI215Failed "GNOME screensaver 2.15 API failed, trying 2.14 API" -#define MSG_GError "Error: %s" -#define MSG_GNOMEScreensaverEnabled "GNOME screensaver enabled" -#define MSG_GNOMEScreensaverDisabled "GNOME screensaver disabled" - -static guint32 cookie; - -void gnome_screensaver_control(int enable) -{ - DBusGConnection *connection; - GError *error; - DBusGProxy *proxy; - gboolean ret; - - g_type_init(); - - /* Get a connection to the session bus */ - error = NULL; - connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error); - if (!connection) { - LOGERR(MSG_OpenBusConnectionError, error ? error->message : "<null>"); - g_error_free(error); - return; - } - - /* Create a proxy object */ - proxy = dbus_g_proxy_new_for_name(connection, - GS_SERVICE, GS_PATH, GS_INTERFACE); - if (!proxy) { - LOGDBG("Failed to get a proxy for gnome-screensaver"); - return; - } - - /* Enable the screensaver */ - if (enable) { - /* First call the GNOME screensaver 2.15 API method */ - error = NULL; - ret = - dbus_g_proxy_call(proxy, "UnInhibit", &error, - G_TYPE_UINT, cookie, - G_TYPE_INVALID, G_TYPE_INVALID); - - /* If this fails, try the GNOME screensaver 2.14 API */ - if (!ret && error->domain == DBUS_GERROR - && error->code == DBUS_GERROR_UNKNOWN_METHOD) { - LOGERR(MSG_GnomeAPI215Failed); - g_error_free(error); - error = NULL; - ret = - dbus_g_proxy_call(proxy, "AllowActivation", &error, - G_TYPE_INVALID, G_TYPE_INVALID); - } - } - /* Disable the screensaver */ - else { - /* First call the GNOME screensaver 2.15 API method */ - error = NULL; - ret = - dbus_g_proxy_call(proxy, "Inhibit", &error, - G_TYPE_STRING, GS_APPLICATION_NAME, - G_TYPE_STRING, GS_REASON_FOR_INHIBIT, - G_TYPE_INVALID, - G_TYPE_UINT, &cookie, - G_TYPE_INVALID); - - /* If this fails, try the GNOME screensaver 2.14 API */ - if (!ret && error->domain == DBUS_GERROR - && error->code == DBUS_GERROR_UNKNOWN_METHOD) { - LOGERR(MSG_GnomeAPI215Failed); - g_error_free(error); - error = NULL; - ret = - dbus_g_proxy_call(proxy, "InhibitActivation", &error, - G_TYPE_STRING, GS_REASON_FOR_INHIBIT, - G_TYPE_INVALID, G_TYPE_INVALID); - } - } - - if (!ret) { - /* Check if it's a remote exception or a regular GError */ - if (error->domain == DBUS_GERROR - && error->code == DBUS_GERROR_REMOTE_EXCEPTION) { - LOGERR(MSG_RemoteMethodException, dbus_g_error_get_name(error), error->message); - } - else { - LOGERR(MSG_GError, error->message); - } - g_error_free(error); - } - else { - LOGMSG(enable ? MSG_GNOMEScreensaverEnabled : MSG_GNOMEScreensaverDisabled); - } - - g_object_unref(proxy); -} diff --git a/tools/gnome_screensaver.h b/tools/gnome_screensaver.h deleted file mode 100644 index 84dee38e..00000000 --- a/tools/gnome_screensaver.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _GNOME_SCREENSAVER_H -#define _GNOME_SCREENSAVER_H - -extern void gnome_screensaver_control(int enable); - -#endif /* !_GNOME_SCREENSAVER_H */ diff --git a/tools/h264.c b/tools/h264.c deleted file mode 100644 index a729a289..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.7 2009-03-31 11:33:05 phintuka Exp $ - * - */ - -#include <stdint.h> -#include <string.h> - -#ifndef LOG_MODULENAME -# define LOG_MODULENAME "[h264 ] " -# define SysLogLevel iSysLogLevel -# 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 mpeg_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(mpeg_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] == NAL_AUD) { - 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 (!IS_NAL_AUD(buf)) - 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; - memcpy(&size->pixel_aspect, &sps.pixel_aspect, sizeof(mpeg_rational_t)); - 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 df869e96..00000000 --- a/tools/h264.h +++ /dev/null @@ -1,68 +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.9 2009-06-29 15:49:43 phintuka Exp $ - * - */ - -#ifndef _XINELIBOUTPUT_H264_H_ -#define _XINELIBOUTPUT_H264_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "mpeg.h" - - -#define NAL_SPS 0x07 /* Sequence Parameter Set */ -#define NAL_AUD 0x09 /* Access Unit Delimiter */ -#define NAL_END_SEQ 0x0a /* End of Sequence */ - - -#if defined(__i386__) || defined(__x86_64__) -# define IS_NAL_SPS(buf) (*(uint32_t*)(buf) == 0x07010000U) -# define IS_NAL_AUD(buf) (*(uint32_t*)(buf) == 0x09010000U) -# define IS_NAL_END_SEQ(buf) (*(uint32_t*)(buf) == 0x0a010000U) -#else -# define IS_NAL_SPS(buf) ((buf)[0] == 0 && (buf)[1] == 0 && (buf)[2] == 1 && (buf)[3] == NAL_SPS) -# define IS_NAL_AUD(buf) ((buf)[0] == 0 && (buf)[1] == 0 && (buf)[2] == 1 && (buf)[3] == NAL_AUD) -# define IS_NAL_END_SEQ(buf) ((buf)[0] == 0 && (buf)[1] == 0 && (buf)[2] == 1 && (buf)[3] == NAL_END_SEQ) -#endif - - -typedef struct { - uint16_t width; - uint16_t height; - mpeg_rational_t pixel_aspect; - /* ... */ -} h264_sps_data_t; - -struct video_size_s; - - -/* - * 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, struct video_size_s *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 0e7de26a..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.7 2009-06-02 08:37:58 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 */ - const 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/iso639.h b/tools/iso639.h deleted file mode 100644 index ae30fa0e..00000000 --- a/tools/iso639.h +++ /dev/null @@ -1,186 +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.4 2009-05-29 14:25:06 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"}, - {"heb", "iw"}, - {"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 (!memcmp(ISO639_map[i].iso639_1, lang, 2)) - return ISO639_map[i].iso639_2; - LOGMSG("Unknown iso639-2 code: %s", lang); - } - return lang; - } - return NULL; -} - -static const char *iso639_1_to_iso639_2(const char *lang) -{ - if (lang && lang[0]) { - if (lang[1] && lang[2] && !lang[3]) { - for (unsigned int i = 0 ; i < sizeof(ISO639_map) / sizeof(ISO639_map[0]); i++) - if (!memcmp(ISO639_map[i].iso639_2, lang, 3)) - return ISO639_map[i].iso639_1; - LOGMSG("Unknown iso639-1 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.c b/tools/metainfo_menu.c deleted file mode 100644 index 4a31b18c..00000000 --- a/tools/metainfo_menu.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * metainfo_menu.c: Media file info menu - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: metainfo_menu.c,v 1.8 2009-08-18 10:35:45 phintuka Exp $ - * - */ - -#include "../features.h" - -#ifdef HAVE_LIBEXTRACTOR -# include <extractor.h> -#endif - -#include <vdr/status.h> -#include <vdr/i18n.h> - -#include "../config.h" - -#include "metainfo_menu.h" - - -// -// cMetainfoMenu -// - -cMetainfoMenu::cMetainfoMenu(cString Filename) : - cOsdMenu(Filename), - m_Filename(Filename) -{ - const char *Title = strrchr(Filename, '/'); - if(Title && *(Title+1)) - SetTitle(Title+1); -} - -cMetainfoMenu::~cMetainfoMenu() -{ -} - -void cMetainfoMenu::Display(void) -{ - cOsdMenu::Display(); - - char metadata[4096]; - metadata[0] = 0; - -#ifdef HAVE_LIBEXTRACTOR - EXTRACTOR_ExtractorList * plugins; - EXTRACTOR_KeywordList * md_list; - plugins = EXTRACTOR_loadDefaultLibraries(); - md_list = EXTRACTOR_getKeywords(plugins, m_Filename); - md_list = EXTRACTOR_removeEmptyKeywords (md_list); - md_list = EXTRACTOR_removeDuplicateKeywords(md_list, 0); - md_list = EXTRACTOR_removeKeywordsOfType(md_list, EXTRACTOR_THUMBNAILS); - - uint pos = 0; - int n; - while(md_list) { - const char *key = EXTRACTOR_getKeywordTypeAsString(md_list->keywordType); - if(key && pos < sizeof(metadata)) - if(0 < (n = snprintf(metadata+pos, sizeof(metadata)-pos, "%s: %s\n", key, md_list->keyword))) - pos += n; - md_list = md_list->next; - } - metadata[sizeof(metadata)-1] = 0; - - EXTRACTOR_freeKeywords(md_list); - EXTRACTOR_removeAll(plugins); /* unload plugins */ -#else - cString cmd; - if(xc.IsPlaylistFile(m_Filename)) - cmd = cString::sprintf("file -b '%s'; cat '%s'", *m_Filename, *m_Filename); - else if(xc.IsAudioFile(m_Filename)) - cmd = cString::sprintf("mp3info -x '%s' ; file -b '%s'", *m_Filename, *m_Filename); - else if(xc.IsVideoFile(m_Filename)) - cmd = cString::sprintf("file -b '%s'; midentify '%s'", *m_Filename, *m_Filename); - else if(xc.IsImageFile(m_Filename)) - cmd = cString::sprintf("file -b '%s'; identify '%s'", *m_Filename, *m_Filename); - else - cmd = cString::sprintf("file -b '%s'", *m_Filename); - - cPipe p; - if(p.Open(*cmd, "r")) { - int n = fread(metadata, 1, sizeof(metadata)-1, p); - if(n>0) { - metadata[n] = 0; - strreplace(metadata, ',', '\n'); - } - } -#endif - DisplayMenu()->SetText(metadata, false); - cStatus::MsgOsdTextItem(cString::sprintf("%s\n%s", tr("Metainfo"), *m_Filename)); -} - -eOSState cMetainfoMenu::ProcessKey(eKeys Key) -{ - eOSState state = cOsdMenu::ProcessKey(Key); - return state; -} 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 b827e096..00000000 --- a/tools/mpeg.c +++ /dev/null @@ -1,67 +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.3 2009-02-16 16:03:18 phintuka Exp $ - * - */ - -#include <inttypes.h> -#include <string.h> - -#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) { - static const mpeg_rational_t mpeg2_aspect[16] = { - {0,1}, {1,1}, {4,3}, {16,9}, {221,100}, - {0,1}, {0,1}, {0,1}, { 0,1}, { 0,1}, - {0,1}, {0,1}, {0,1}, { 0,1}, { 0,1}, - {0,1}, - }; - - int d = (buf[i+4] << 16) | (buf[i+5] << 8) | buf[i+6]; - int a = buf[i+7] >> 4; - - size->width = (d >> 12); - size->height = (d & 0xfff); - - memcpy(&size->pixel_aspect, &mpeg2_aspect[a], sizeof(mpeg_rational_t)); - size->pixel_aspect.num *= size->height; - size->pixel_aspect.den *= size->width; - - return 1; - } - } - } - return 0; -} - diff --git a/tools/mpeg.h b/tools/mpeg.h deleted file mode 100644 index 8a9b6493..00000000 --- a/tools/mpeg.h +++ /dev/null @@ -1,58 +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.6 2009-02-16 16:03:18 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 mpeg_rational_s { - int num; - int den; -} mpeg_rational_t; - -typedef struct video_size_s { - uint16_t width; - uint16_t height; - mpeg_rational_t 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 14773f2e..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.10 2009-07-01 09:31:17 phintuka Exp $ - * - */ - -#include <inttypes.h> -#include <string.h> - -#include "../logdefs.h" - -#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 NO_PTS; - if ((buf[6] & 0x30) != 0) - return NO_PTS; - - 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 NO_PTS; -} - -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 NO_PTS; - if ((buf[6] & 0x30) != 0) - return NO_PTS; - - 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 NO_PTS; -} - -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] &= 0x3f; /* clear pts and dts flags */ - buf[8] -= n; /* 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 (IS_NAL_AUD(buf)) - return 1; - return 0; -} - -uint8_t pes_get_picture_type(const uint8_t *buf, int len) -{ - int i = PES_HEADER_LEN(buf); - - buf += i; - len -= i; - - if (buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01) { - if (buf[3] == NAL_AUD) - return h264_get_picture_type(buf, len); - 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 = PES_HEADER_LEN(buf); - - buf += i; - len -= i; - - if (h264 || IS_NAL_AUD(buf)) - return h264_get_video_size(buf, len, size); - - return mpeg2_get_video_size(buf, len, size); -} - diff --git a/tools/pes.h b/tools/pes.h deleted file mode 100644 index d25374a7..00000000 --- a/tools/pes.h +++ /dev/null @@ -1,120 +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.13 2009-07-01 09:56:26 phintuka Exp $ - * - */ - -#ifndef _XINELIBOUTPUT_PES_H_ -#define _XINELIBOUTPUT_PES_H_ - -#ifdef __cplusplus -extern "C" { -#endif - - -/* - * Constants - */ - -#define PES_CHUNK_SIZE 2048 - -#define MAX_SCR ((int64_t)0x1ffffffffLL) - -#define NO_PTS (INT64_C(-1)) - -/* 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_MPEG_AUDIO_PACKET(data) (AUDIO_STREAM == ((data)[3] & ~AUDIO_STREAM_MASK)) -#define IS_PS1_PACKET(data) (PRIVATE_STREAM1 == (data)[3]) -#define IS_PADDING_PACKET(data) (PADDING_STREAM == (data)[3]) -#define IS_AUDIO_PACKET(data) (IS_MPEG_AUDIO_PACKET(data) || IS_PS1_PACKET(data)) - -#define PES_HAS_PTS(data) ((data)[7] & 0x80) -#define PES_HAS_DTS(data) ((data)[7] & 0x40) - -#define DATA_IS_PES(data) (!(data)[0] && !(data)[1] && (data)[2] == 1) - -#define PES_HEADER_LEN(data) (8 + (data)[8] + 1) - - -/* - * timestamps - */ - -static inline int pts_to_ms(int64_t pts) { return (int)(pts/INT64_C(90)); } -static inline int64_t ms_to_pts(int ms) { return ((int64_t)(ms)) * INT64_C(90); } - -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 - */ - -struct video_size_s; - -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, struct video_size_s *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])); -} - - -#ifdef __cplusplus -} /* extern "C" { */ -#endif - -#endif /* _XINELIBOUTPUT_PES_H_ */ diff --git a/tools/playlist.c b/tools/playlist.c deleted file mode 100644 index e227b9c9..00000000 --- a/tools/playlist.c +++ /dev/null @@ -1,1005 +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.23 2009-06-02 08:36:16 phintuka Exp $ - * - */ - -#include "../features.h" - -#include <stdlib.h> - -#ifdef HAVE_LIBEXTRACTOR -# 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_LIBEXTRACTOR -# 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 - -static void strip_extension(cString& fname) -{ - const char *ext = strrchr(fname, '.'); - if (ext) - fname.Truncate(ext - fname); -} - -// -// cPlaylistItem -// - -cPlaylistItem::cPlaylistItem(const char *filename) -{ - const char *pt; - - Filename = filename; - Position = -1; - - if(NULL != (pt = strrchr(filename, '/'))) - Title = pt + 1; - else - Title = filename; - - strip_extension(Title); -} - -cPlaylistItem::cPlaylistItem(const char *filename, - const char *path, - const char *title, - int position) -{ - 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) - strip_extension(Title); -} - -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_LIBEXTRACTOR -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; - const int priority = 10; - errno = 0; - if((nice(priority) == -1) && errno) - LOGDBG("ID3Scanner: Can't nice to value: %d", priority); - - 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_LIBEXTRACTOR - 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 = md_list->keyword; - else if (!strcasecmp(key,"artist")) - Item->Artist = md_list->keyword; - else if (!strcasecmp(key,"album")) - Item->Album = 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; - const 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); - const char *ext = strrchr(file, '.'); - if(!strcasecmp(ext, ".pls")) - parser = new cPlsReader(*this); - else if(!strcasecmp(ext, ".asx")) - parser = new cAsxReader(*this); - else /*if(!strcasecmp(ext, ".m3u"))*/ - parser = new cM3uReader(*this); /* parses plain lists (.ram, ...) too ...*/ - - /* get folder */ - cString Folder = file; - const char *folder = strrchr(Folder, '/'); - if (folder) - Folder.Truncate(folder - Folder + 1); - - int n = 0; - cReadLine r; - char *pt; - while(NULL != (pt = r.Read(f)) && n < MAX_PLAYLIST_FILES) { - if(NULL != (pt = parser->Parse(pt))) { - - 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", *Folder, 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, Folder, 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 = path; - const char *pt = strrchr(tmp, '/'); - if(pt && pt > *tmp) { - tmp.Truncate(pt - tmp); - 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) { - const char *pt; - m_Folder = PlaylistFile; - if (NULL != (pt=strrchr(m_Folder, '/'))) - m_Folder.Truncate(pt - m_Folder + 1); - } - - if(xc.IsPlaylistFile(PlaylistFile)) { - // Read playlist file - Result = ReadPlaylist(PlaylistFile); - m_Origin = ePlaylist; - - cString dir = LastDir(m_Folder); - const char *name = strrchr(PlaylistFile, '/'); - name = name ? name+1 : NULL; - if(*dir && name) - m_Name = cString::sprintf("%s - %s", *dir, name); - else - m_Name = name ?: ""; - - strip_extension(m_Name); - - } else if(PlaylistFile[ 0] == '/' && - PlaylistFile[strlen(PlaylistFile)-1] == '/') { - // Scan folder - Result = ScanFolder(PlaylistFile, Recursive) > 0; - m_Origin = eImplicit; - Sort(); - - if(!*m_Name) { - m_Name = PlaylistFile; - m_Name.Truncate( strrchr(m_Name, '/') - m_Name); - 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; - char *buf = (char *)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 = (char *)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(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/rle.c b/tools/rle.c deleted file mode 100644 index 2425630b..00000000 --- a/tools/rle.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * rle.c: RLE utils - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: rle.c,v 1.3 2009-02-16 16:14:58 phintuka Exp $ - * - */ - -#include <stdint.h> -#include <stdlib.h> - -#include "../xine_osd_command.h" - -#include "rle.h" - - -#undef MAX -#define MAX(a,b) ((a) > (b) ? (a) : (b)) - -/* - * rle_compress() - * - */ -int rle_compress(xine_rle_elem_t **rle_data, const uint8_t *data, uint w, uint h) -{ - xine_rle_elem_t rle, *rle_p = 0, *rle_base; - int x, y, num_rle = 0, rle_size = 8128; - const uint8_t *c; - - rle_p = (xine_rle_elem_t*)malloc(4*rle_size); - rle_base = rle_p; - - for (y = 0; y < h; y++) { - rle.len = 0; - rle.color = 0; - c = data + y * w; - for (x = 0; x < w; x++, c++) { - if (rle.color != *c) { - if (rle.len) { - if ( (num_rle + h-y+1) > rle_size ) { - rle_size *= 2; - rle_base = (xine_rle_elem_t*)realloc( rle_base, 4*rle_size ); - rle_p = rle_base + num_rle; - } - *rle_p++ = rle; - num_rle++; - } - rle.color = *c; - rle.len = 1; - } else { - rle.len++; - } - } - *rle_p++ = rle; - num_rle++; - } - - *rle_data = rle_base; - return num_rle; -} - -/* - * rle_scale_nearest() - * - * - Simple nearest-neighbour scaling for RLE-compressed image - * - fast scaling in compressed form without decompression - */ -xine_rle_elem_t *rle_scale_nearest(const xine_rle_elem_t *old_rle, int *rle_elems, - uint w, uint h, uint new_w, uint new_h) -{ - #define FACTORBASE 0x100 - #define FACTOR2PIXEL(f) ((f)>>8) - #define SCALEX(x) FACTOR2PIXEL(factor_x*(x)) - #define SCALEY(y) FACTOR2PIXEL(factor_y*(y)) - - uint old_w = w, old_h = h; - uint old_y = 0, new_y = 0; - uint factor_x = FACTORBASE*new_w/old_w; - uint factor_y = FACTORBASE*new_h/old_h; - uint rle_size = MAX(8128, *rle_elems * new_h/h ); /* guess ... */ - uint num_rle = 0; - xine_rle_elem_t *new_rle = (xine_rle_elem_t*)malloc(sizeof(xine_rle_elem_t)*rle_size); - xine_rle_elem_t *new_rle_start = new_rle; - - /* we assume rle elements are breaked at end of line */ - while (old_y < old_h) { - uint elems_current_line = 0; - uint old_x = 0, new_x = 0; - - while (old_x < old_w) { - uint new_x_end = SCALEX(old_x + old_rle->len); - - if (new_x_end > new_w) { - new_x_end = new_w; - } - - new_rle->len = new_x_end - new_x; - new_rle->color = old_rle->color; - - old_x += old_rle->len; - old_rle++; /* may be incremented to last element + 1 (element is not accessed anymore) */ - - if (new_rle->len > 0) { - new_x += new_rle->len; - new_rle++; - - num_rle++; - elems_current_line++; - - if ( (num_rle + 1) >= rle_size ) { - rle_size *= 2; - new_rle_start = (xine_rle_elem_t*)realloc( new_rle_start, 4*rle_size); - new_rle = new_rle_start + num_rle; - } - } - } - if (new_x < new_w) - (new_rle-1)->len += new_w - new_x; - old_y++; - new_y++; - - if (factor_y > FACTORBASE) { - /* scale up -- duplicate current line ? */ - int dup = SCALEY(old_y) - new_y; - - /* if no lines left in (old) rle, copy all lines still missing from new */ - if (old_y == old_h) - dup = new_h - new_y - 1; - - while (dup-- && (new_y+1<new_h)) { - xine_rle_elem_t *prevline; - uint n; - if ( (num_rle + elems_current_line + 1) >= rle_size ) { - rle_size *= 2; - new_rle_start = (xine_rle_elem_t*)realloc( new_rle_start, 4*rle_size); - new_rle = new_rle_start + num_rle; - } - - /* duplicate previous line */ - prevline = new_rle - elems_current_line; - for (n = 0; n < elems_current_line; n++) { - *new_rle++ = *prevline++; - num_rle++; - } - new_y++; - } - - } else if (factor_y < FACTORBASE) { - /* scale down -- drop next line ? */ - uint skip = new_y - SCALEY(old_y); - if (old_y == old_h-1) { - /* one (old) line left ; don't skip it if new rle is not complete */ - if (new_y < new_h) - skip = 0; - } - while (skip-- && - old_y<old_h /* rounding error may add one line, filter it out */) { - for (old_x = 0; old_x < old_w;) { - old_x += old_rle->len; - old_rle++; - } - old_y++; - } - } - } - - *rle_elems = num_rle; - return new_rle_start; -} diff --git a/tools/rle.h b/tools/rle.h deleted file mode 100644 index d6900e8f..00000000 --- a/tools/rle.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * rle.h: RLE utils - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: rle.h,v 1.2 2009-02-16 16:14:58 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_RLE_H_ -#define XINELIBOUTPUT_RLE_H_ - -#if defined __cplusplus -extern "C" { -#endif - -typedef enum { - scale_fast = 0, /* simple pixel doubling/dropping */ - scale_good_BW = 1, /* linear interpolation, palette re-generation */ -} scale_mode_t; - - -struct xine_rle_elem_s; -struct xine_clut_s; - - -int rle_compress(struct xine_rle_elem_s **rle_data, const uint8_t *data, uint w, uint h); - -void rle_uncompress_lut8(const struct xine_rle_elem_s *rle_data, - uint8_t *data, uint w, uint h); -void rle_uncompress_argb(uint32_t *dst, - const struct xine_rle_elem_s *rle_data, uint num_rle, - uint w, uint h, uint stride, - struct xine_clut_s *palette); - -/* - * rle_scale_nearest() - * - * - Simple nearest-neighbour scaling for RLE-compressed image - * - fast scaling in compressed form without decompression - */ -struct xine_rle_elem_s *rle_scale_nearest(const struct xine_rle_elem_s *old_rle, - int *rle_elems, - uint w, uint h, uint new_w, uint new_h); - - -#if defined __cplusplus -} -#endif - -#endif /* XINELIBOUTPUT_RLE_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 514c29c1..00000000 --- a/tools/sdp.h +++ /dev/null @@ -1,112 +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.5 2009-02-10 12:42:38 phintuka Exp $ - * - */ - -#ifndef XINELIBOUTPUT_SDP_H_ -#define XINELIBOUTPUT_SDP_H_ - - -#define SDP_MIME_TYPE "application/sdp" - -#define SDP_PAYLOAD_MPEG_PES 96 -#define SDP_PAYLOAD_MPEG_TS 33 - -static const char *vdr_sdp_description(const char *vdr_ip, - int vdr_svdrp_port, - int vdr_xineliboutput_port, - const char *rtp_ip, - uint32_t rtp_ssrc, - uint32_t payload_type, - int rtp_port, - int rtp_ttl) -{ - static uint8_t s_serial = 0; - static cString s_data; - static char s_hostname[257] = {0}; - - uint64_t serial = (time(NULL) << 2) + ((s_serial++) & 0x03); - cString payload; - - if (!s_hostname[0]) - gethostname(s_hostname, 256); - - if (payload_type == SDP_PAYLOAD_MPEG_PES) { - payload = cString::sprintf( - /* video/mp2p udp/rtp */ - /* media */ "m=video %d RTP/AVP 96" - /* */ "\r\n" "a=rtpmap:96 MP2P/90000" - , rtp_port - ); - } else { - payload = cString::sprintf( - /* video/mp2t udp/rtp */ - /* media */ "m=video %d RTP/AVP 33" - , rtp_port - ); - } - - s_data = cString::sprintf( - /*** 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" "%s" - - /* 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 - - /* media */ - , rtp_ip, rtp_ttl - , *payload - -#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/ts.c b/tools/ts.c deleted file mode 100644 index 0f6e2576..00000000 --- a/tools/ts.c +++ /dev/null @@ -1,682 +0,0 @@ -/* - * ts.c: MPEG-TS - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: ts.c,v 1.14 2009-09-09 11:58:40 phintuka Exp $ - * - */ - -/*#define LOG_PCR*/ -/*#define LOG_PMT*/ - -#include <inttypes.h> -#include <stdlib.h> -#include <string.h> - -#ifndef LOG_MODULENAME -# define LOG_MODULENAME "[mpeg-ts ] " -# define SysLogLevel iSysLogLevel -# include "../logdefs.h" -#endif - -#include "mpeg.h" -#include "ts.h" -#include "pes.h" - -#ifdef LOG_PMT -# define LOGPMT LOGMSG -#else -# define LOGPMT(x...) -#endif - -#ifdef LOG_PCR -# define LOGPCR LOGMSG -#else -# define LOGPCR(x...) -#endif - - -/* - * ts_compute_crc32() - * - * taken from xine-lib demux_ts.c - */ -static uint32_t ts_compute_crc32(const uint8_t *data, uint32_t length, uint32_t crc32) -{ - static uint32_t crc32_table[256]; - static uint init_done = 0; - - if (!init_done) { - uint32_t i, j, k; - init_done = 1; - for (i = 0 ; i < 256 ; i++) { - k = 0; - for (j = (i << 24) | 0x800000 ; j != 0x80000000 ; j <<= 1) - k = (k << 1) ^ (((k ^ j) & 0x80000000) ? 0x04c11db7 : 0); - crc32_table[i] = k; - } - } - - uint32_t i; - for(i = 0; i < length; i++) - crc32 = (crc32 << 8) ^ crc32_table[(crc32 >> 24) ^ data[i]]; - - return crc32; -} - -/* - * parse_pat() - * - * - parse PAT for PMT pid and program number - * - * modified from xine-lib demux_ts.c - */ -int ts_parse_pat(pat_data_t *pat, const uint8_t *pkt) -{ - const uint8_t *original_pkt = pkt; - - if (! ts_PAYLOAD_START(pkt)) { - LOGMSG ("parse_pat: PAT without payload unit start indicator"); - return 0; - } - - /* jump to payload */ - pkt += pkt[4]; /* pointer */ - if (pkt - original_pkt > TS_SIZE) { - LOGMSG("parse_pat: PAT with invalid pointer"); - return 0; - } - - uint section_syntax_indicator = ((pkt[6] >> 7) & 0x01) ; - uint section_length = ((pkt[6] & 0x03) << 8) | pkt[7]; -/*uint transport_stream_id = (pkt[8] << 8) | pkt[9];*/ -/*uint version_number = (pkt[10] >> 1) & 0x1f;*/ - uint current_next_indicator = pkt[10] & 0x01; - uint section_number = pkt[11]; - uint last_section_number = pkt[12]; - uint32_t crc32, calc_crc32; - - crc32 = pkt[section_length + 4] << 24; - crc32 |= pkt[section_length + 5] << 16; - crc32 |= pkt[section_length + 6] << 8; - crc32 |= pkt[section_length + 7] ; - - if ((section_syntax_indicator != 1) || !(current_next_indicator)) { - LOGMSG("parse_pat: ssi error"); - return 0; - } - - if (pkt - original_pkt > TS_SIZE - 4 - 1 - 3 - (int)section_length) { - LOGMSG("parse_pat: unsupported PAT does not fit to single TS packet"); - return 0; - } - - if ((section_number != 0) || (last_section_number != 0)) { - LOGMSG("parse_pat: unsoupported PAT consists of multiple (%d) sections", last_section_number); - return 0; - } - - /* Check CRC */ - calc_crc32 = ts_compute_crc32 (pkt + 5, section_length + 3 - 4, 0xffffffff); - if (crc32 != calc_crc32) { - LOGMSG("parse_pat: invalid CRC"); - return 0; - } - - /* - * Process all programs in the program loop - */ - - const uint8_t *program; - uint program_count; - - program_count = 0; - for (program = pkt + 13; - program < pkt + 13 + section_length - 9; - program += 4) { - uint program_number = (program[0] << 8) | program[1]; - uint pmt_pid = ((program[2] & 0x1f) << 8) | program[3]; - - /* skip NIT pids */ - if (program_number == 0x0000) - continue; - - pat->program_number[program_count] = program_number; - pat->pmt_pid[program_count] = pmt_pid; - - LOGPMT("PAT acquired count=%d programNumber=0x%04x pmtPid=0x%04x", - program_count, - pat->program_number[program_count], - pat->pmt_pid[program_count]); - - program_count++; - } - - pat->program_number[program_count] = 0; - - return program_count; -} - -/* - * ts_get_reg_desc() - * - * Find the registration code (tag=5) and return it as a uint32_t - * This should return "AC-3" or 0x41432d33 for AC3/A52 audio tracks. - * - * taken from xine-lib demux_ts.c - */ -static void ts_get_reg_desc(uint32_t *dest, const uint8_t *data, int length) -{ - const unsigned char *d = data; - - while (d < (data + length)) { - if (d[0] == 5 && d[1] >= 4) { - *dest = (d[2] << 24) | (d[3] << 16) | (d[4] << 8) | d[5]; - LOGPMT("parse_pmt: found registration format identifier 0x%.4x", *dest); - return; - } - d += 2 + d[1]; - } - LOGPMT("pare_pmt: found no format id"); - *dest = 0; -} - -static int find_audio_track(pmt_data_t *pmt, uint pid) -{ - int i; - for (i = 0; i < pmt->audio_tracks_count; i++) { - if (pmt->audio_tracks[i].pid == pid) - return i; - } - return -1; -} - -/* - * ts_parse_pmt() - * - * modified from xine-lib demux_ts.c - */ -int ts_parse_pmt (pmt_data_t *pmt, uint program_no, const uint8_t *pkt) -{ - const uint8_t *originalPkt = pkt; - const uint8_t *ptr = NULL; - uint pusi = ts_PAYLOAD_START(pkt); - - uint32_t section_syntax_indicator; - uint32_t section_length = 0; /* to calm down gcc */ - uint32_t program_number; - uint32_t version_number; - uint32_t current_next_indicator; - uint32_t section_number; - uint32_t last_section_number; - uint32_t program_info_length; - uint32_t crc32; - uint32_t calc_crc32; - uint32_t coded_length; - uint pid; - uint8_t *stream; - uint i; - int count; - uint8_t len; - uint offset = 0; - - /* - * A new section should start with the payload unit start - * indicator set. We allocate some mem (max. allowed for a PM section) - * to copy the complete section into one chunk. - */ - if (pusi) { - pkt += pkt[4]; /* pointer */ - offset = 1; - - if (pmt->pmt != NULL) - free(pmt->pmt); - pmt->pmt = (uint8_t *) calloc(4096, sizeof(uint8_t)); - pmt->pmt_write_ptr = pmt->pmt; - - section_syntax_indicator = (pkt[6] >> 7) & 0x01; - section_length = ((pkt[6] << 8) | pkt[7]) & 0x03ff; - program_number = (pkt[8] << 8) | pkt[9]; - version_number = (pkt[10] >> 1) & 0x1f; - current_next_indicator = pkt[10] & 0x01; - section_number = pkt[11]; - last_section_number = pkt[12]; - - LOGPMT("PMT: section_syntax: %d", section_syntax_indicator); - LOGPMT(" section_length: %d", section_length); - LOGPMT(" program_number: %#.4x", program_number); - LOGPMT(" version_number: %d", version_number); - LOGPMT(" c/n indicator: %d", current_next_indicator); - LOGPMT(" section_number: %d", section_number); - LOGPMT(" last_section_number: %d", last_section_number); - - if ((section_syntax_indicator != 1) || !current_next_indicator) { - LOGMSG("parse_pmt: ssi error"); - return 0; - } - - if (program_number != program_no) { - /* several programs can share the same PMT pid */ - LOGMSG("parse_pmt: program number %i, looking for %i", program_number, program_no); - return 0; - } - - if ((section_number != 0) || (last_section_number != 0)) { - LOGMSG("parse_pmt: unsupported PMT (%d sections)", last_section_number); - return 0; - } - } - - if (!pusi) { - section_length = (pmt->pmt[1] << 8 | pmt->pmt[2]) & 0x03ff; - version_number = (pkt[10] >> 1) & 0x1f; - } - - count = ts_PAYLOAD_SIZE(originalPkt); - - ptr = originalPkt + offset + (TS_SIZE - count); - len = count - offset; - memcpy(pmt->pmt_write_ptr, ptr, len); - pmt->pmt_write_ptr += len; - - if (pmt->pmt_write_ptr < pmt->pmt + section_length) { - LOGPMT("parse_pmt: didn't get all PMT TS packets yet..."); - return 0; - } - - if (!section_length) { - free(pmt->pmt); - pmt->pmt = NULL; - LOGMSG("parse_pmt: zero-length section"); - return 0; - } - - LOGPMT("parse_pmt: have all TS packets for the PMT section"); - - crc32 = (uint32_t) pmt->pmt[section_length+3-4] << 24; - crc32 |= (uint32_t) pmt->pmt[section_length+3-3] << 16; - crc32 |= (uint32_t) pmt->pmt[section_length+3-2] << 8; - crc32 |= (uint32_t) pmt->pmt[section_length+3-1] ; - - /* Check CRC. */ - calc_crc32 = ts_compute_crc32 (pmt->pmt, section_length + 3 - 4, 0xffffffff); - if (crc32 != calc_crc32) { - LOGMSG("parse_pmt: invalid CRC32"); - return 0; - } - - if (crc32 == pmt->crc32 && version_number == pmt->version_number) { - LOGPMT("parse_pmt: PMT with CRC32=%d already parsed. Skipping.", crc32); - return 0; - } - - LOGPMT("parse_pmt: new PMT, parsing..."); - pmt->crc32 = crc32; - pmt->version_number = version_number; - - /* reset PIDs */ - pmt->audio_tracks_count = 0; - pmt->spu_tracks_count = 0; - pmt->video_pid = INVALID_PID; - - /* ES definitions start here */ - program_info_length = ((pmt->pmt[10] << 8) | pmt->pmt[11]) & 0x0fff; - - stream = &pmt->pmt[12] + program_info_length; - coded_length = 13 + program_info_length; - if (coded_length > section_length) { - LOGMSG("parse_pmt: PMT with inconsistent progInfo length"); - return 0; - } - section_length -= coded_length; - - - /* - * Extract the elementary streams. - */ - while (section_length > 0) { - unsigned int stream_info_length; - - pid = ((stream[1] << 8) | stream[2]) & 0x1fff; - stream_info_length = ((stream[3] << 8) | stream[4]) & 0x0fff; - coded_length = 5 + stream_info_length; - if (coded_length > section_length) { - LOGMSG("parse_pmt: PMT with inconsistent streamInfo length"); - return 0; - } - - switch (stream[0]) { - case ISO_11172_VIDEO: - case ISO_13818_VIDEO: - case ISO_14496_PART2_VIDEO: - case ISO_14496_PART10_VIDEO: - LOGPMT("parse_pmt: video pid 0x%.4x type %2.2x", pid, stream[0]); - if (pmt->video_pid == INVALID_PID) { - pmt->video_pid = pid; - pmt->video_type = (ts_stream_type)stream[0]; - } - break; - - case ISO_11172_AUDIO: - case ISO_13818_AUDIO: - case ISO_13818_PART7_AUDIO: - case ISO_14496_PART3_AUDIO: - if (pmt->audio_tracks_count < TS_MAX_AUDIO_TRACKS) { - if (find_audio_track(pmt, pid) < 0) { - LOGPMT("parse_pmt: audio pid 0x%.4x type %2.2x", pid, stream[0]); - pmt->audio_tracks[pmt->audio_tracks_count].pid = pid; - pmt->audio_tracks[pmt->audio_tracks_count].type = (ts_stream_type)stream[0]; - /* ts_get_lang_desc(pmt->audio_tracks[pmt->audio_tracks_count].lang, */ - /* stream + 5, stream_info_length); */ - pmt->audio_tracks_count++; - } - } - break; - - case ISO_13818_PRIVATE: - case ISO_13818_TYPE_C: - break; - case ISO_13818_PES_PRIVATE: - for (i = 5; i < coded_length; i += stream[i+1] + 2) { - if ((stream[i] == STREAM_DESCR_AC3) && (pmt->audio_tracks_count < TS_MAX_AUDIO_TRACKS)) { - if (find_audio_track(pmt, pid) < 0) { - LOGPMT("parse_pmt: AC3 audio pid 0x%.4x type %2.2x", pid, stream[0]); - pmt->audio_tracks[pmt->audio_tracks_count].pid = pid; - pmt->audio_tracks[pmt->audio_tracks_count].type = STREAM_AUDIO_AC3; - /* demux_ts_get_lang_desc(pmt->audio_tracks[pmt->audio_tracks_count].lang, */ - /* stream + 5, stream_info_length); */ - pmt->audio_tracks_count++; - break; - } - } - /* DVBSUB */ - else if (stream[i] == STREAM_DESCR_DVBSUB) { - uint pos; - for (pos = i + 2; - pos + 8 <= i + 2 + stream[i + 1] - && pmt->spu_tracks_count < TS_MAX_SPU_TRACKS; - pos += 8) { - int no = pmt->spu_tracks_count; - - pmt->spu_tracks_count++; - - memcpy(pmt->spu_tracks[no].lang, &stream[pos], 3); - pmt->spu_tracks[no].lang[3] = 0; - pmt->spu_tracks[no].comp_page_id = (stream[pos + 4] << 8) | stream[pos + 5]; - pmt->spu_tracks[no].aux_page_id = (stream[pos + 6] << 8) | stream[pos + 7]; - pmt->spu_tracks[no].pid = pid; - - LOGPMT("parse_pmt: DVBSUB pid 0x%.4x: %s page %d %d type %2.2x", pid, - pmt->spu_tracks[no].lang, pmt->spu_tracks[no].comp_page_id, - pmt->spu_tracks[no].aux_page_id, stream[0]); - } - } - } - break; - - default: - - /* This following section handles all the cases where the audio track info is stored - * in PMT user info with stream id >= 0x80 - * We first check that the stream id >= 0x80, because all values below that are - * invalid if not handled above, then we check the registration format identifier - * to see if it holds "AC-3" (0x41432d33) and if is does, we tag this as an audio stream. - */ - if ((pmt->audio_tracks_count < TS_MAX_AUDIO_TRACKS) && (stream[0] >= 0x80) ) { - if (find_audio_track(pmt, pid) < 0) { - uint32_t format_identifier = 0; - ts_get_reg_desc(&format_identifier, stream + 5, stream_info_length); - /* If no format identifier, assume A52 */ - if ((format_identifier == 0x41432d33) || (format_identifier == 0)) { - pmt->audio_tracks[pmt->audio_tracks_count].pid = pid; - pmt->audio_tracks[pmt->audio_tracks_count].type = (ts_stream_type)stream[0]; - /* ts_get_lang_desc(pmt->audio_tracks[pmt->audio_tracks_count].lang, */ - /* stream + 5, stream_info_length); */ - pmt->audio_tracks_count++; - break; - } - } - } else { - LOGPMT("parse_pmt: unknown stream_type: 0x%.2x pid: 0x%.4x", stream[0], pid); - } - break; - } - stream += coded_length; - section_length -= coded_length; - } - - - /* - * Get the current PCR PID. - */ - pid = ((pmt->pmt[8] << 8) | pmt->pmt[9]) & 0x1fff; - if (pmt->pcr_pid != pid) { - - if (pmt->pcr_pid == INVALID_PID) - LOGPMT("parse_pmt: pcr pid 0x%.4x", pid); - else - LOGPMT("parse_pmt: pcr pid changed 0x%.4x", pid); - - pmt->pcr_pid = pid; - } - - return 1; -} - -/* - * ts_get_pcr() - */ -static int ts_get_pcr_1(const uint8_t *pkt, int64_t *ppcr) -{ - if (!ts_ADAPT_FIELD_EXISTS(pkt)) { - return 0; - } - - if (ts_HAS_ERROR(pkt)) { - LOGMSG("ts_get_pcr: transport error"); - return 0; - } - - /* pcr flag ? */ - if (! (pkt[5] & 0x10)) - return 0; - - int64_t pcr; - uint epcr; - - pcr = ((int64_t) pkt[6]) << 25; - pcr += (int64_t) (pkt[7] << 17); - pcr += (int64_t) (pkt[8] << 9); - pcr += (int64_t) (pkt[9] << 1); - pcr += (int64_t) ((pkt[10] & 0x80) >> 7); - - epcr = ((pkt[10] & 0x1) << 8) | pkt[11]; - - LOGPCR("ts_get_pcr: PCR: %"PRId64", EPCR: %u", pcr, epcr); - *ppcr = pcr; - return 1; -} - -int64_t ts_get_pcr(const uint8_t *pkt) -{ - int64_t pcr = NO_PTS; - ts_get_pcr_1(pkt, &pcr); - return pcr; -} - -int ts_get_pcr_n(const uint8_t *pkt, int npkt, int64_t *pcr) -{ - pkt += TS_SIZE * npkt; - while (npkt > 0) { - npkt--; - pkt -= TS_SIZE; - if (ts_get_pcr_1(pkt, pcr)) - return 1; - } - return 0; -} - - -/* - * ts_state_t - */ - -struct ts_state_s { - - uint8_t pusi_seen; - - uint8_t inside_pes; /* Scanning ES (PES start code seen and skipped) */ - - uint32_t buf_len; /* bytes queued */ - uint32_t buf_size; /* buffer size */ - uint8_t buf[0]; /* payload: partial PES / video stream header etc. */ -}; - -ts_state_t *ts_state_init(int buffer_size) -{ - if (buffer_size < 8 * TS_SIZE) - buffer_size = 8 * TS_SIZE; - - ts_state_t *ts = (ts_state_t*)calloc(1, sizeof(ts_state_t) + buffer_size); - ts->buf_size = buffer_size; - return ts; -} - -void ts_state_reset(ts_state_t *ts) -{ - int buf_size = ts->buf_size; - memset(ts, 0, sizeof(ts_state_t)); - ts->buf_size = buf_size; -} - -void ts_state_dispose(ts_state_t *ts) -{ - free(ts); -} - -/* - * ts_add_payload() - * - * Add TS packet payload to buffer. - * - PUSI resets the buffer - * - all data before first PUSI is discarded - */ -static int ts_add_payload(ts_state_t *ts, const uint8_t *data) -{ - /* start from PUSI */ - if (!ts->pusi_seen) { - if (!ts_PAYLOAD_START(data)) - return 0; - ts->pusi_seen = 1; - ts->buf_len = 0; - } - - if (ts->buf_len >= ts->buf_size - TS_SIZE) { - LOGMSG("ts_add_payload: buffer full"); - ts->buf_len -= TS_SIZE; - memcpy(ts->buf, ts->buf+TS_SIZE, ts->buf_len); - } - - int len = ts_PAYLOAD_SIZE(data); - if (len > 0) { - memcpy(ts->buf + ts->buf_len, ts_GET_PAYLOAD(data), len); - ts->buf_len += len; - } - - return ts->buf_len; -} - -/* - * ts_skip_payload() - */ -static void ts_skip_payload(ts_state_t *ts, unsigned int n) -{ - if (n < ts->buf_len) { - ts->buf_len -= n; - memcpy(ts->buf, ts->buf + n, ts->buf_len); - } else { - ts->buf_len = 0; - } -} - -/* - * ts_scan_startcode() - * - * - discard all data until startcode (00 00 01) is found - * - returns number of bytes left - */ -static int ts_scan_startcode(ts_state_t *ts) -{ - if (ts->buf_len > 2) { - /* scan for PES or MPEG 00 00 01 */ - unsigned int i = 0, n = ts->buf_len - 2; - while (i < n) { - if (ts->buf[i+2] != 1) - i += 3; - else if(ts->buf[i+1]) - i += 2; - else if(ts->buf[i]) - i++; - else - break; - } - - /* skip data until start code */ - ts_skip_payload(ts, i); - } - - return ts->buf_len; -} - -/* - * ts_get_pes() - * - * - scan for PES start - * - return (PES) bytes queued - */ -static int ts_get_pes(ts_state_t *ts, const uint8_t *data) -{ - if (ts_add_payload(ts, data) > 0) - return ts_scan_startcode(ts); - return 0; -} - -/* - * ts_get_pts() - */ - -int64_t ts_get_pts(ts_state_t *ts, const uint8_t *data) -{ - int64_t pts = NO_PTS; - int cnt = ts_get_pes(ts, data); - - if (cnt > 14) { - pts = pes_get_pts(ts->buf, ts->buf_len); - - if (pts < 0 && cnt > 2*TS_SIZE) - ts_state_reset(ts); - } - - return pts; -} - -/* - * ts_get_picture_type() - */ - -int ts_get_picture_type(ts_state_t *ts, const uint8_t *data, int h264) -{ - int pic = NO_PICTURE; - return pic; -} - -/* - * ts_get_video_size() - */ - -int ts_get_video_size(ts_state_t *ts, const uint8_t *data, video_size_t *size, int h264) -{ - return 0; -} diff --git a/tools/ts.h b/tools/ts.h deleted file mode 100644 index 98fa3f9e..00000000 --- a/tools/ts.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * ts.h: MPEG-TS header definitions - * - * See the main source file 'xineliboutput.c' for copyright information and - * how to reach the author. - * - * $Id: ts.h,v 1.12 2009-09-09 11:51:21 phintuka Exp $ - * - */ - -#ifndef _XINELIBOUTPUT_TS_H_ -#define _XINELIBOUTPUT_TS_H_ - -#ifdef __cplusplus -extern "C" { -#endif - - -/* Avoid warnings when included to VDR plugin */ -#undef TS_SYNC_BYTE -#undef TS_SIZE -#undef TS_PAYLOAD_EXISTS -#undef TS_ADAPT_FIELD_EXISTS -#undef TS_PAYLOAD_START -#undef TS_ERROR -#undef TS_PID_MASK_HI - -/* - * Constants - */ - -#define TS_SYNC_BYTE 0x47 -#define TS_SIZE 188 -#define TS_ADAPT_FIELD_EXISTS 0x20 -#define TS_PAYLOAD_EXISTS 0x10 -#define TS_PAYLOAD_START 0x40 -#define TS_ERROR 0x80 -#define TS_PID_MASK_HI 0x1F - -#define ts_HAS_PAYLOAD(ts) ((ts)[3] & TS_PAYLOAD_EXISTS) -#define ts_PAYLOAD_START(ts) ((ts)[1] & TS_PAYLOAD_START) -#define ts_HAS_ERROR(ts) ((ts)[1] & TS_ERROR) -#define ts_PID(ts) ((((ts)[1] & TS_PID_MASK_HI) << 8) + (ts)[2]) -#define ts_PAYLOAD_OFFSET(ts) (((ts)[3] & TS_ADAPT_FIELD_EXISTS) ? (ts)[4] + 5 : 4) - -#define ts_GET_PAYLOAD(ts) ((ts) + ts_PAYLOAD_OFFSET(ts)) -#define ts_PAYLOAD_SIZE(ts) (TS_SIZE - ts_PAYLOAD_OFFSET(ts)) - -#define ts_ADAPT_FIELD_EXISTS(ts) ((ts)[3] & TS_ADAPT_FIELD_EXISTS) -#define ts_ADAPT_FIELD_LENGTH(ts) (ts_ADAPT_FIELD_EXISTS(ts) ? (ts)[4] : 0) - - -#define DATA_IS_TS(data) ((data)[0] == TS_SYNC_BYTE) - -/* - * stream types (PMT) - */ - -typedef enum { - ISO_11172_VIDEO = 0x01, /* ISO/IEC 11172 Video */ - ISO_13818_VIDEO = 0x02, /* ISO/IEC 13818-2 Video */ - ISO_11172_AUDIO = 0x03, /* ISO/IEC 11172 Audio */ - ISO_13818_AUDIO = 0x04, /* ISO/IEC 13818-3 Audi */ - ISO_13818_PRIVATE = 0x05, /* ISO/IEC 13818-1 private sections */ - ISO_13818_PES_PRIVATE = 0x06, /* ISO/IEC 13818-1 PES packets containing private data */ - ISO_13522_MHEG = 0x07, /* ISO/IEC 13512 MHEG */ - ISO_13818_DSMCC = 0x08, /* ISO/IEC 13818-1 Annex A DSM CC */ - ISO_13818_TYPE_A = 0x0a, /* ISO/IEC 13818-6 Multiprotocol encapsulation */ - ISO_13818_TYPE_B = 0x0b, /* ISO/IEC 13818-6 DSM-CC U-N Messages */ - ISO_13818_TYPE_C = 0x0c, /* ISO/IEC 13818-6 Stream Descriptors */ - ISO_13818_TYPE_D = 0x0d, /* ISO/IEC 13818-6 Sections (any type, including private data) */ - ISO_13818_AUX = 0x0e, /* ISO/IEC 13818-1 auxiliary */ - ISO_13818_PART7_AUDIO = 0x0f, /* ISO/IEC 13818-7 Audio with ADTS transport sytax */ - ISO_14496_PART2_VIDEO = 0x10, /* ISO/IEC 14496-2 Visual (MPEG-4) */ - ISO_14496_PART3_AUDIO = 0x11, /* ISO/IEC 14496-3 Audio with LATM transport syntax */ - ISO_14496_PART10_VIDEO = 0x1b, /* ISO/IEC 14496-10 Video (MPEG-4 part 10/AVC, aka H.264) */ - STREAM_VIDEO_MPEG = 0x80, - STREAM_AUDIO_AC3 = 0x81, - STREAM_DVBSUB = 0x100 -} ts_stream_type; - -/* stream info descriptors */ -#define STREAM_DESCR_AC3 0x6a -#define STREAM_DESCR_DVBSUB 0x59 - -/* - * PAT - */ - -#define TS_MAX_PROGRAMS 64 -#define TS_MAX_PMTS 32 -#define TS_MAX_AUDIO_TRACKS 32 -#define TS_MAX_SPU_TRACKS 32 - -typedef struct { - int program_number[TS_MAX_PROGRAMS]; - uint16_t pmt_pid[TS_MAX_PROGRAMS]; -} pat_data_t; - -int ts_parse_pat(pat_data_t *pat_data, const uint8_t *ts_data); - - -/* - * PMT - */ - -#define INVALID_PID 0xffff - -typedef struct { - uint8_t *pmt; /* raw data */ - uint8_t *pmt_write_ptr; - - uint32_t crc32; - uint version_number; - - uint16_t pcr_pid; - uint16_t video_pid; - ts_stream_type video_type; - - uint8_t audio_tracks_count; - uint8_t spu_tracks_count; - - struct { - uint16_t pid; - ts_stream_type type; - /*uint8_t lang[8];*/ - } audio_tracks[TS_MAX_AUDIO_TRACKS]; - - struct { - uint16_t pid; - uint8_t lang[8]; - uint16_t comp_page_id; - uint16_t aux_page_id; - } spu_tracks[TS_MAX_SPU_TRACKS]; - -} pmt_data_t; - -/* - * parse_pmt() - * - * returns 1 : PMT parsed and changed - * 0 : error or unchanged pmt - */ -int ts_parse_pmt(pmt_data_t *pmt, uint program_no, const uint8_t *ts_data); - -/* - * PCR - */ - -int64_t ts_get_pcr(const uint8_t *data); -int ts_get_pcr_n(const uint8_t *pkt, int npkt, int64_t *pcr); - -/* - * TS->ES, simple ES parsers - */ - -typedef struct ts_state_s ts_state_t; -struct video_size_s; - -ts_state_t *ts_state_init(int buffer_size); -void ts_state_reset(ts_state_t *ts); -void ts_state_dispose(ts_state_t *ts); - -int64_t ts_get_pts(ts_state_t *ts, const uint8_t *data); -int ts_get_picture_type(ts_state_t *ts, const uint8_t *data, int h264); -int ts_get_video_size(ts_state_t *ts, const uint8_t *data, struct video_size_s *size, int h264); - - -#ifdef __cplusplus -} /* extern "C" { */ -#endif - -#endif // _XINELIBOUTPUT_TS_H_ diff --git a/tools/udp_buffer.h b/tools/udp_buffer.h deleted file mode 100644 index 6044b794..00000000 --- a/tools/udp_buffer.h +++ /dev/null @@ -1,144 +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.6 2009-03-24 19:35:23 phintuka Exp $ - * - */ - -#ifndef __UDP_BUFFER_H -#define __UDP_BUFFER_H - -#include <stdint.h> - -#include <vdr/config.h> // VDRVERSNUM - -#include "../xine_input_vdr_net.h" // frame headers -#include "ts.h" - -#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; -#if VDRVERSNUM >= 10701 - if (DATA_IS_TS(Data)) - header->rtp_hdr.raw[1] = RTP_PAYLOAD_TYPE_TS; - else - header->rtp_hdr.raw[1] = RTP_PAYLOAD_TYPE_PES; -#else - header->rtp_hdr.raw[1] = RTP_PAYLOAD_TYPE_PES; -#endif - 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; - - 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 d46a99a8..00000000 --- a/tools/udp_pes_scheduler.c +++ /dev/null @@ -1,938 +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.52 2009-08-19 12:19:43 phintuka Exp $ - * - */ - -//#define LOG_UDP_RATE -//#define LOG_RESEND -//#define LOG_SCR - -#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 "ts.h" -#include "pes.h" -#include "udp_buffer.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 - -#include "udp_pes_scheduler.h" - - -#ifdef LOG_RESEND -# define LOGRESEND LOGDBG -#else -# define LOGRESEND(x...) -#endif - -#ifdef LOG_SCR -# define LOGSCR LOGDBG -#else -# define LOGSCR(x...) -#endif - -/* - * constants - */ - -const uint MAX_QUEUE_SIZE = 64; // ~ 65 ms with typical DVB stream -const uint MAX_LIVE_QUEUE_SIZE = (64+60); // ~ 100 ms with typical DVB stream -const uint HARD_LIMIT = (4*1024); // ~ 40 Mbit/s === 4 Mb/s - -const uint MAX_BURST_BYTES = 32768; // 32 kb -const uint MAX_BURST_FRAMES = 15; // 15 UDP packets - -const uint RTCP_MIN_INTERVAL = 45000; // 500 ms (pts units) - -// initial burst length after seek (500ms = ~13 video frames) -const int64_t INITIAL_BURST_TIME = INT64_C(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_C(225000); // pts units (90kHz) - -const uint SCHEDULER_MIN_DELAY_MS = 3; -const uint SCHEDULER_MAX_DELAY_MS = 20; - -static inline int64_t abs64(int64_t val) { return val<0 ? -val : val; } - -cUdpScheduler::cUdpScheduler() -{ - - // Scheduler data - - m_ScrSource = eScrDetect; - m_CurrentAudioVtime = 0; - m_CurrentVideoVtime = 0; - m_CurrentPcr = 0; - - m_MasterClock.Set(INT64_C(0)); - - m_BurstBytes = 0; - m_BurstFrames = 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; - m_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 - - Start(); -} - -cUdpScheduler::~cUdpScheduler() -{ - m_Lock.Lock(); - - Cancel(-1); - m_Cond.Broadcast(); - m_CondWait.Signal(); - m_Lock.Unlock(); - - Cancel(3); - - if(m_fd_rtcp.open() || m_fd_rtp.open()) - Send_SAP(false); - - CLOSESOCKET(m_fd_sap); - - delete m_BackLog; -} - -void cUdpScheduler::Scheduler_Sleep(int ms) -{ - m_CondWait.Wait(ms); - m_BurstBytes = 0; - m_BurstFrames = 0; -} - -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; - } - - uint 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 && - Running() && - m_QueuePending >= limit) - m_Cond.TimedWait(m_Lock, 5); - } - - return limit > m_QueuePending ? 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 && - 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(); - - m_ScrSource = eScrDetect; -} - -void cUdpScheduler::Pause(bool On) -{ - cMutexLock ml(&m_Lock); - - if(On) - m_MasterClock.Pause(); - else - m_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 - - m_MasterClock.TrickSpeed(Multiplier); - - m_TrickSpeed = (Multiplier==-1 || Multiplier==1) ? false : true; -} - -void cUdpScheduler::SetScrSpeed(const int Speed) -{ - cMutexLock ml(&m_Lock); - - m_MasterClock.SetScrSpeed(Speed); - m_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; - - uint 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; -} - -void cUdpScheduler::QueuePadding(void) -{ - cMutexLock ml(&m_Lock); - - if (m_Handles[0] < 0) - return; - - if (m_QueuePending > 2) - return; - - QueuePaddingInternal(); - - m_Cond.Broadcast(); -} - -void cUdpScheduler::QueuePaddingInternal(void) -{ - static unsigned const 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++; -} - -int cUdpScheduler::CalcElapsedVtime(int64_t pts, ScrSource_t ScrSource) -{ - int64_t diff = 0; - - switch (ScrSource) { - - case eScrFromVideo: - diff = pts - m_CurrentVideoVtime; - if (diff > JUMP_LIMIT_TIME || (-diff) > JUMP_LIMIT_TIME) { // 1 s (must be > GOP) - // RESET - LOGSCR("cUdpScheduler SCR RESET (Video jump %lld->%lld)", m_CurrentVideoVtime, pts); - m_CurrentVideoVtime = pts; - - // Use video pts for sync only in audioless trickspeeds - // (audio has smaller, constant and increasing intervals) - if (m_TrickSpeed) - m_MasterClock.Set(m_CurrentVideoVtime + INITIAL_BURST_TIME); - - return -1; - } - if (diff < 0) /* ignore small negative differences (B/P frames are sent out-of-order) */ - diff = 0; - else - m_CurrentVideoVtime = pts; - break; - - case eScrFromAudio: - diff = abs64(pts - m_CurrentAudioVtime); - if (diff > JUMP_LIMIT_TIME) { // 1 sec - // RESET - LOGSCR("cUdpScheduler SCR RESET (Audio jump %lld->%lld)", m_CurrentAudioVtime, pts); - m_CurrentAudioVtime = pts; - m_MasterClock.Set(m_CurrentAudioVtime + INITIAL_BURST_TIME); - return -1; - } - m_CurrentAudioVtime = pts; - break; - - case eScrFromPcr: - diff = pts - m_CurrentPcr; - if (diff > JUMP_LIMIT_TIME || diff < 0) { // 1 sec - // RESET - LOGSCR("cUdpScheduler RESET (PCR jump %lld->%lld)", m_CurrentPcr, pts); - m_CurrentPcr = pts; - m_MasterClock.Set(m_CurrentPcr + INITIAL_BURST_TIME); - return -1; - } - m_CurrentPcr = pts; - break; - - default: break; - } - - return (int) diff; -} - -void cUdpScheduler::Send_RTCP(void) -{ - if(!m_fd_rtcp.open()) - return; - - uint64_t scr = m_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()) - return; - - char ip[64] = ""; - uint32_t local_addr = m_fd_rtp.get_local_address(ip); - - if(!local_addr) - return; - - uint32_t payload_type = VDRVERSNUM > 10702 ? SDP_PAYLOAD_MPEG_TS : SDP_PAYLOAD_MPEG_PES; - const char *sdp_descr = vdr_sdp_description(ip, - 2001, - xc.listen_port, - xc.remote_rtp_addr, - payload_type, - m_ssrc, - xc.remote_rtp_port, - xc.remote_rtp_ttl); - if(!sdp_descr) - return; - -#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); -} - -#ifdef LOG_SCR -static const char ScrSourceName[][6] = {"???", "VIDEO", "PS1", "AUDIO", "PCR"}; -#endif - -void cUdpScheduler::Schedule(const uchar *Data, int Length) -{ - int64_t pts = NO_PTS; - int elapsed = 0; - ScrSource_t ScrSource = eScrDetect; - - // Get timestamp from data - - if (DATA_IS_TS(Data)) { - if (ts_get_pcr_n(Data, Length/TS_SIZE, &pts)) { - LOGSCR("UDP PCR: %"PRId64, pts); - ScrSource = eScrFromPcr; - elapsed = CalcElapsedVtime(pts, eScrFromPcr); - } - } else /* if (DATA_IS_PES(Data)) */ { - if (PES_HAS_PTS(Data)) { - ScrSource = IS_VIDEO_PACKET(Data) ? eScrFromVideo : IS_AUDIO_PACKET(Data) ? eScrFromAudio : eScrDetect; - pts = pes_get_pts(Data, Length); - elapsed = CalcElapsedVtime(pts, ScrSource); - } - } - - if (m_ScrSource < ScrSource) - m_ScrSource = ScrSource; - - if(elapsed > 0) { - - int64_t now = m_MasterClock.Now(); - int64_t SendTime = ScrSource==eScrFromVideo ? m_CurrentVideoVtime : - ScrSource==eScrFromAudio ? m_CurrentAudioVtime : - ScrSource==eScrFromPcr ? m_CurrentPcr : now; - - LOGSCR("PTS: %lld (%s) elapsed %d ms (PID %02x)", pts, ScrSourceStr[ScrSource], - pts_to_ms(elapsed), DATA_IS_TS(Data) ? TS_PID(Data) : Data[3]); - - // - // Detect discontinuity (against SCR) - // - if (now > SendTime && (now - SendTime) > JUMP_LIMIT_TIME) { - LOGSCR("cUdpScheduler MasterClock init (was in past) %s", ScrSourceStr[ScrSource]); - now = SendTime + INITIAL_BURST_TIME; - m_MasterClock.Set(now); - } else if (now < SendTime && (SendTime - now) > JUMP_LIMIT_TIME) { - LOGSCR("cUdpScheduler MasterClock init (was in future) %s", ScrSourceStr[ScrSource]); - now = SendTime + INITIAL_BURST_TIME; - m_MasterClock.Set(now); - } - - // - // Delay - // - while (SendTime > now) { - - uint delay_ms = pts_to_ms(SendTime - now); - if (delay_ms < SCHEDULER_MIN_DELAY_MS) - break; - - LOGSCR("cUdpScheduler sleeping %d ms (time ref: %s, beat interval %d ms)", - delay_ms, ScrSourceStr[ScrSource], pts_to_ms(elapsed)); - - if (delay_ms > SCHEDULER_MAX_DELAY_MS) - delay_ms = SCHEDULER_MAX_DELAY_MS; - - Scheduler_Sleep(delay_ms); - - now = m_MasterClock.Now(); - } - } -} - -void cUdpScheduler::Action(void) -{ - /* UDP Scheduler needs high priority */ - const int priority = -5; - SetPriority(priority); - errno = 0; - if ((nice(priority) == -1) && errno) - LOGDBG("cUdpScheduler: Can't nice to value: %d", priority); - - m_Lock.Lock(); - - while (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_BurstFrames = m_BurstBytes = 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 - QueuePaddingInternal(); - } - continue; // to check 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). - // Hard limit for used bandwidth: - // - ~1 frames/ms & 8kb/ms -> 8mb/s -> ~ 80 Mbit/s ( / client) - // - max burst 15 frames or 32 kb - m_BurstFrames ++; - m_BurstBytes += PayloadSize; - if (m_BurstFrames >= MAX_BURST_FRAMES && m_BurstBytes >= MAX_BURST_BYTES) { - Scheduler_Sleep(4); -#ifdef LOG_UDP_RATE - static uint64_t dbg_timer = cTimeMs::Now(); - static int dbg_bytes = 0; - dbg_bytes += bytes; - if (dbg_timer + 60000 <= cTimeMs::Now()) { - LOGDBG("UDP rate: %4d Kbps (queue %d)", dbg_bytes/(60*1024/8), m_QueuePending); - dbg_bytes = 0; - dbg_timer = cTimeMs::Now(); - } -#endif - } - - /* tag frame with ssrc and timestamp */ - frame->rtp_hdr.ts = htonl((uint32_t)(m_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 - // - uint 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); - Scheduler_Sleep(2); - } - } else { - if(m_QueuePending > (MAX_QUEUE_SIZE-5)) - LOGDBG("cUdpScheduler: kernel transmit queue > ~30kb ! (master=%d ; Queue=%d)", - m_Master, m_QueuePending); - Scheduler_Sleep(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], RTP_UDP_PAYLOAD(frame), 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; - - struct { - stream_udp_header_t hdr; - char payload[64-sizeof(stream_udp_header_t)]; - } udp_ctrl = {{(uint64_t)INT64_C(-1), (uint16_t)-1}, {0}}; - - // 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); - snprintf(udp_ctrl.payload, sizeof(udp_ctrl.payload), - "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 !"); - Scheduler_Sleep(2); - } - - stream_rtp_header_impl_t *frame = m_BackLog->Get(Seq1); - - if(frame) { - if(ntohull(frame->hdr_ext.pos) - Pos < 100000) { - send(fd, - RTP_UDP_PAYLOAD(frame), - 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, udp_ctrl.hdr.pos, udp_ctrl.hdr.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; - } - - snprintf(udp_ctrl.payload, sizeof(udp_ctrl.payload), - "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 99f1861b..00000000 --- a/tools/udp_pes_scheduler.h +++ /dev/null @@ -1,130 +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.22 2009-08-19 11:32:21 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 QueuePadding(void); - 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: - - // Signalling - - cCondVar m_Cond; - cMutex m_Lock; - - // Clients - - int m_Handles[MAX_UDP_HANDLES]; - uint m_wmem[MAX_UDP_HANDLES]; /* kernel buffer size */ - - cxSocket m_fd_rtp; - cxSocket m_fd_rtcp; - - // Queue - - uint m_QueueNextSeq; /* next outgoing */ - uint m_QueuePending; /* outgoing queue size */ - cUdpBackLog *m_BackLog; /* queue for incoming data (not yet send) and retransmissions */ - cMutex m_BackLogDeleteMutex; - - // Scheduling - - typedef enum { - /* from worst to best */ - eScrDetect = 0, - eScrFromVideo = 1, - eScrFromPS1 = 2, - eScrFromAudio = 3, - eScrFromPcr = 4, - } ScrSource_t; - - cTimePts m_MasterClock; /* Current MPEG PTS (synchronized to current stream) */ - bool m_TrickSpeed; /* current (replay) speed */ - bool m_Master; /* if true, we are master metronom for playback */ - - ScrSource_t m_ScrSource; - int64_t m_CurrentAudioVtime; - int64_t m_CurrentVideoVtime; - int64_t m_CurrentPcr; - - uint m_BurstBytes; /* number of bytes sent without sleeps */ - uint m_BurstFrames; /* number of frames sent without sleeps */ - - cCondWait m_CondWait; - - int CalcElapsedVtime(int64_t pts, ScrSource_t ScrSource); - void Schedule(const uchar *Data, int Length); - void Scheduler_Sleep(int ms); - void QueuePaddingInternal(void); - - // RTP - - uint32_t m_ssrc; /* RTP synchronization source id */ - cTimePts m_RtpScr; /* 90 kHz monotonic time source for RTP timestamps */ - - // RTCP - - uint64_t m_LastRtcpTime; - uint32_t m_Frames; - uint32_t m_Octets; - - void Send_RTCP(void); - - // SAP - - int m_fd_sap; - - void Send_SAP(bool Announce = true); - - // Thread - - virtual void Action(void); -}; - -#endif diff --git a/tools/vdrdiscovery.c b/tools/vdrdiscovery.c deleted file mode 100644 index e301056d..00000000 --- a/tools/vdrdiscovery.c +++ /dev/null @@ -1,273 +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.9 2009-06-29 21:23:33 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> - -#define LOG_MODULENAME "[discovery] " -#include "../logdefs.h" - -#include "vdrdiscovery.h" - -/* - * constants - */ - -#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; - int iBroadcast = 1, iReuse = 1; - struct sockaddr_in sin; - - if ((fd_discovery = socket(PF_INET, SOCK_DGRAM, 0/*IPPROTO_TCP*/)) < 0) { - LOGERR("discovery_init: socket() failed"); - return -1; - } - - if (setsockopt(fd_discovery, SOL_SOCKET, SO_BROADCAST, &iBroadcast, sizeof(int)) < 0) - LOGERR("discovery_init: setsockopt(SO_BROADCAST) failed"); - - if (setsockopt(fd_discovery, SOL_SOCKET, SO_REUSEADDR, &iReuse, sizeof(int)) < 0) - LOGERR("discovery_init: 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("discovery_init: bind() failed"); - close(fd_discovery); - return -1; - } - - return fd_discovery; -} - -int udp_discovery_init(void) -{ - return discovery_init(DISCOVERY_PORT); -} - -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; -} - -int udp_discovery_broadcast(int fd_discovery, int server_port, const char *server_address) -{ - char *msg = NULL; - int result; - - if(server_address && *server_address) { - result = 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 { - result = 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); - } - - if (result >= 0) { - result = udp_discovery_send(fd_discovery, DISCOVERY_PORT, msg); - free(msg); - } - - return result; -} - -static inline int udp_discovery_search(int fd_discovery, int port) -{ - char *msg = NULL; - int result; - - 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); - - if (result >= 0) { - result = udp_discovery_send(fd_discovery, port, msg); - free(msg); - } - - return result; -} - -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; -} - -int udp_discovery_is_valid_search(const char *buf) -{ - static 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; -} - -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; -} - - diff --git a/tools/vdrdiscovery.h b/tools/vdrdiscovery.h deleted file mode 100644 index de612733..00000000 --- a/tools/vdrdiscovery.h +++ /dev/null @@ -1,81 +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.5 2009-02-10 15:26:11 phintuka Exp $ - * - */ - -#ifndef _VDRDISCOVERY_H_ -#define _VDRDISCOVERY_H_ - -#define DISCOVERY_MSG_MAXSIZE 1024 - -#ifdef __cplusplus -extern "C" { -#endif - -struct sockaddr_in; - -/* - * Client interface - */ - -/* - * udp_discovery_find_server() - * - * Search for server. Return address and port. - * Returns 0 on success. - */ -int udp_discovery_find_server(int *port, char *address); - -/* - * Server interface - */ - -/* - * udp_discovery_init() - * - * Initialize server socket. Return value is the socket file descriptor, - * and can be used for polling. - * Returns < 0 on error. - */ -int udp_discovery_init(void); - -/* - * udp_discovery_broadcast() - * - * Send server announcement. - * Returns 0 on success. - */ -int udp_discovery_broadcast(int fd_discovery, int server_port, const char *server_address); - -/* - * udp_discovery_recv() - * - * Receive query or announcement. - * Returns number of bytes received, <= 0 on error. - * Result is null-terminated string, not more than DISCOVERY_MSG_MAXSIZE bytes. - */ -int udp_discovery_recv(int fd_discovery, char *buf, int timeout, - struct sockaddr_in *source); - -/* - * udp_discovery_is_valid_search() - * - * Check if string is valid search message. - * Returns 1 for valid messages, 0 for invalid messages. - */ -int udp_discovery_is_valid_search(const char *buf); - -#ifdef __cplusplus -}; -#endif - - -#endif // _VDRDISCOVERY_H_ |