diff options
Diffstat (limited to 'server/livestreamer.c')
-rw-r--r-- | server/livestreamer.c | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/server/livestreamer.c b/server/livestreamer.c new file mode 100644 index 0000000..4204ea3 --- /dev/null +++ b/server/livestreamer.c @@ -0,0 +1,242 @@ +#include <vdr/ringbuffer.h> + +#include "server/livestreamer.h" +#include "remux/ts2ps.h" +#include "remux/ts2es.h" +#include "common.h" + +cStreamdevLiveReceiver::cStreamdevLiveReceiver(cStreamdevLiveStreamer *Streamer, + int Ca, int Priority, + int Pid1, int Pid2, int Pid3, int Pid4, + int Pid5, int Pid6, int Pid7, int Pid8, + int Pid9, int Pid10, int Pid11, int Pid12, + int Pid13, int Pid14, int Pid15, int Pid16): + cReceiver(Ca, Priority, 16, + Pid1, Pid2, Pid3, Pid4, Pid5, Pid6, Pid7, Pid8, + Pid9, Pid10, Pid11, Pid12, Pid13, Pid14, Pid15, Pid16) { + m_Streamer = Streamer; +} + +cStreamdevLiveReceiver::~cStreamdevLiveReceiver() { + Dprintf("Killing live receiver\n"); + Detach(); +} + +void cStreamdevLiveReceiver::Receive(uchar *Data, int Length) { + static time_t firsterr = 0; + static int errcnt = 0; + static bool showerr = true; + + int p = m_Streamer->Put(Data, Length); + if (p != Length) { + ++errcnt; + if (showerr) { + if (firsterr == 0) + firsterr = time_ms(); + else if (firsterr + BUFOVERTIME > time_ms() && errcnt > BUFOVERCOUNT) { + esyslog("ERROR: too many buffer overflows, logging stopped"); + showerr = false; + firsterr = time_ms(); + } + } else if (firsterr + BUFOVERTIME < time_ms()) { + showerr = true; + firsterr = 0; + errcnt = 0; + } + + if (showerr) + esyslog("ERROR: ring buffer overflow (%d bytes dropped)", Length - p); + else + firsterr = time_ms(); + } +} + +cStreamdevLiveStreamer::cStreamdevLiveStreamer(int Priority): + cStreamdevStreamer("Live streamer") { + m_Priority = Priority; + m_Channel = NULL; + m_Device = NULL; + m_Receiver = NULL; + m_Remux = NULL; + m_Buffer = NULL; + m_Sequence = 0; +#if VDRVERSNUM >= 10300 + m_Filter = NULL; +#endif + memset(m_Pids, 0, sizeof(m_Pids)); +} + +cStreamdevLiveStreamer::~cStreamdevLiveStreamer() { + Dprintf("Desctructing Live streamer\n"); + delete m_Receiver; + delete m_Remux; +#if VDRVERSNUM >= 10300 + delete m_Filter; +#endif + free(m_Buffer); +} + +void cStreamdevLiveStreamer::Detach(void) { + m_Device->Detach(m_Receiver); +} + +void cStreamdevLiveStreamer::Attach(void) { + m_Device->AttachReceiver(m_Receiver); +} + +void cStreamdevLiveStreamer::Start(cTBSocket *Socket) { + Dprintf("LIVESTREAMER START\n"); + cStreamdevStreamer::Start(Socket); +} + +bool cStreamdevLiveStreamer::SetPid(int Pid, bool On) { + int idx; + bool haspids = false; + + if (On) { + for (idx = 0; idx < MAXRECEIVEPIDS; ++idx) { + if (m_Pids[idx] == Pid) + return true; // No change needed + else if (m_Pids[idx] == 0) { + m_Pids[idx] = Pid; + haspids = true; + break; + } + } + + if (idx == MAXRECEIVEPIDS) { + esyslog("ERROR: Streamdev: No free slot to receive pid %d\n", Pid); + return false; + } + } else { + for (idx = 0; idx < MAXRECEIVEPIDS; ++idx) { + if (m_Pids[idx] == Pid) + m_Pids[idx] = 0; + else if (m_Pids[idx] != 0) + haspids = true; + } + } + + DELETENULL(m_Receiver); + if (haspids) { + Dprintf("Creating Receiver to respect changed pids\n"); + m_Receiver = new cStreamdevLiveReceiver(this, m_Channel->Ca(), m_Priority, + m_Pids[0], m_Pids[1], m_Pids[2], m_Pids[3], + m_Pids[4], m_Pids[5], m_Pids[6], m_Pids[7], + m_Pids[8], m_Pids[9], m_Pids[10], m_Pids[11], + m_Pids[12], m_Pids[13], m_Pids[14], m_Pids[15]); + if (m_Device != NULL) { + Dprintf("Attaching new receiver\n"); + m_Device->AttachReceiver(m_Receiver); + } + } + return true; +} + +bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, int StreamType, + bool StreamPIDS) { + Dprintf("Initializing Remuxer for full channel transfer\n"); + printf("ca pid: %d\n", Channel->Ca()); + m_Channel = Channel; + switch (StreamType) { + case stES: + { + int pid = ISRADIO(Channel) ? Channel->Apid1() : Channel->Vpid(); + m_Remux = new cTS2ESRemux(pid); + return SetPid(pid, true); + } + + case stPES: + m_Remux = new cTS2PSRemux(Channel->Vpid(), Channel->Apid1(), + Channel->Apid2(), Channel->Dpid1(), 0, false); + return SetPid(Channel->Vpid(), true) + && SetPid(Channel->Apid1(), true) + && SetPid(Channel->Apid2(), true) + && SetPid(Channel->Dpid1(), true); + break; + + case stPS: + m_Remux = new cTS2PSRemux(Channel->Vpid(), Channel->Apid1(), 0, 0, 0, true); + return SetPid(Channel->Vpid(), true) + && SetPid(Channel->Apid1(), true); + break; + + case stTS: + if (!StreamPIDS) { + return SetPid(Channel->Vpid(), true) + && SetPid(Channel->Apid1(), true) + && SetPid(Channel->Apid2(), true) + && SetPid(Channel->Dpid1(), true); + } + Dprintf("pid streaming mode\n"); + return true; + break; + } + return false; +} + +bool cStreamdevLiveStreamer::SetFilter(u_short Pid, u_char Tid, u_char Mask, + bool On) { +#if VDRVERSNUM >= 10300 + Dprintf("setting filter\n"); + if (On) { + if (m_Filter == NULL) { + m_Filter = new cStreamdevLiveFilter(this); + Dprintf("attaching filter to device\n"); + m_Device->AttachFilter(m_Filter); + } + m_Filter->Set(Pid, Tid, Mask); + } else if (m_Filter != NULL) + m_Filter->Del(Pid, Tid, Mask); + return true; +#else + return false; +#endif +} + +uchar *cStreamdevLiveStreamer::Process(const uchar *Data, int &Count, + int &Result) { + uchar *remuxed = m_Remux != NULL ? m_Remux->Process(Data, Count, Result) + : cStreamdevStreamer::Process(Data, Count, Result); + if (remuxed) { + /*if (Socket()->Type() == SOCK_DGRAM) { + free(m_Buffer); + Result += 12; + m_Buffer = MALLOC(uchar, Result); + m_Buffer[0] = 0x01; + m_Buffer[1] = 0x02; + m_Buffer[2] = 0x03; + m_Buffer[3] = 0x04; + m_Buffer[4] = (Result & 0xff000000) >> 24; + m_Buffer[5] = (Result & 0xff0000) >> 16; + m_Buffer[6] = (Result & 0xff00) >> 8; + m_Buffer[7] = (Result & 0xff); + m_Buffer[8] = (m_Sequence & 0xff000000) >> 24; + m_Buffer[9] = (m_Sequence & 0xff0000) >> 16; + m_Buffer[10] = (m_Sequence & 0xff00) >> 8; + m_Buffer[11] = (m_Sequence & 0xff); + memcpy(m_Buffer + 12, Data, Result - 12); + if (m_Sequence++ == 0x7fffffff) + m_Sequence = 0; + return m_Buffer; + }*/ + return remuxed; + } + return NULL; +} + +cTBString cStreamdevLiveStreamer::Report(void) { + cTBString result; + + if (m_Device != NULL) + result += "+- Device is " + cTBString::Number(m_Device->CardIndex()) + "\n"; + if (m_Receiver != NULL) + result += "+- Receiver is allocated\n"; + + result += "+- Pids are "; + for (int i = 0; i < MAXRECEIVEPIDS; ++i) + if (m_Pids[i] != 0) + result += cTBString::Number(m_Pids[i]) + ", "; + result += "\n"; + return result; +} |