summaryrefslogtreecommitdiff
path: root/server/livestreamer.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/livestreamer.c')
-rw-r--r--server/livestreamer.c242
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;
+}