- transfer

This commit is contained in:
lordjaxom 2005-02-11 16:44:14 +00:00
parent ab8f0c75f3
commit ad70fe8c64
15 changed files with 532 additions and 382 deletions

View File

@ -1,7 +1,7 @@
# #
# Makefile for a Video Disk Recorder plugin # Makefile for a Video Disk Recorder plugin
# #
# $Id: Makefile,v 1.3 2005/02/10 22:24:26 lordjaxom Exp $ # $Id: Makefile,v 1.4 2005/02/11 16:44:14 lordjaxom Exp $
# The official name of this plugin. # The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin. # This name will be used in the '-P...' option of VDR to load the plugin.
@ -63,7 +63,7 @@ SERVEROBJS = $(PLUGIN)-server.o \
server/component.o server/suspend.o server/setup.o server/streamer.o \ server/component.o server/suspend.o server/setup.o server/streamer.o \
server/livestreamer.o server/livefilter.o \ server/livestreamer.o server/livefilter.o \
\ \
remux/tsremux.o remux/ts2ps.o remux/ts2es.o remux/tsremux.o remux/ts2ps.o remux/ts2es.o remux/extern.o
ifdef DEBUG ifdef DEBUG
DEFINES += -DDEBUG DEFINES += -DDEBUG

View File

@ -1,5 +1,5 @@
/* /*
* $Id: common.c,v 1.3 2005/02/10 22:24:26 lordjaxom Exp $ * $Id: common.c,v 1.4 2005/02/11 16:44:14 lordjaxom Exp $
*/ */
#include <vdr/channels.h> #include <vdr/channels.h>
@ -18,6 +18,7 @@ const char *StreamTypes[st_Count] = {
"PES", "PES",
"PS", "PS",
"ES", "ES",
"Extern",
"", // used internally only "", // used internally only
}; };
@ -47,23 +48,24 @@ char *GetNextLine(char *String, uint Length, uint &Offset) {
return NULL; return NULL;
} }
const cChannel *ChannelFromString(char *String, int *Apid) { const cChannel *ChannelFromString(const char *String, int *Apid) {
cChannel *channel = NULL; const cChannel *channel = NULL;
char *string = strdup(String);
char *ptr, *end; char *ptr, *end;
int apididx = 0; int apididx = 0;
if ((ptr = strrchr(String, '+')) != NULL) { if ((ptr = strrchr(string, '+')) != NULL) {
*(ptr++) = '\0'; *(ptr++) = '\0';
apididx = strtoul(ptr, &end, 10); apididx = strtoul(ptr, &end, 10);
Dprintf("found apididx: %d\n", apididx); Dprintf("found apididx: %d\n", apididx);
} }
if (isnumber(String)) { if (isnumber(string)) {
int temp = strtol(String, NULL, 10); int temp = strtol(String, NULL, 10);
if (temp >= 1 && temp <= Channels.MaxNumber()) if (temp >= 1 && temp <= Channels.MaxNumber())
channel = Channels.GetByNumber(temp); channel = Channels.GetByNumber(temp);
} else { } else {
channel = Channels.GetByChannelID(tChannelID::FromString(String)); channel = Channels.GetByChannelID(tChannelID::FromString(string));
if (channel == NULL) { if (channel == NULL) {
int i = 1; int i = 1;
@ -78,22 +80,18 @@ const cChannel *ChannelFromString(char *String, int *Apid) {
if (channel != NULL && apididx > 0) { if (channel != NULL && apididx > 0) {
int apid = 0, index = 1; int apid = 0, index = 1;
const int *apids = channel->Apids();
const int *dpids = channel->Dpids();
for (int i = 0; apids[i] != 0; ++i, ++index) { for (int i = 0; channel->Apid(i) != 0; ++i, ++index) {
Dprintf("checking apid %d\n", apids[i]);
if (index == apididx) { if (index == apididx) {
apid = apids[i]; apid = channel->Apid(i);
break; break;
} }
} }
if (apid == 0) { if (apid == 0) {
for (int i = 0; dpids[i] != 0; ++i, ++index) { for (int i = 0; channel->Dpid(i) != 0; ++i, ++index) {
Dprintf("checking dpid %d\n", dpids[i]);
if (index == apididx) { if (index == apididx) {
apid = dpids[i]; apid = channel->Dpid(i);
break; break;
} }
} }
@ -103,6 +101,7 @@ const cChannel *ChannelFromString(char *String, int *Apid) {
*Apid = apid; *Apid = apid;
} }
free(string);
return channel; return channel;
} }

View File

@ -1,5 +1,5 @@
/* /*
* $Id: common.h,v 1.4 2005/02/10 22:24:26 lordjaxom Exp $ * $Id: common.h,v 1.5 2005/02/11 16:44:14 lordjaxom Exp $
*/ */
#ifndef VDR_STREAMDEV_COMMON_H #ifndef VDR_STREAMDEV_COMMON_H
@ -42,7 +42,7 @@ class cChannel;
char *GetNextLine(char *String, uint Length, uint &Offset); char *GetNextLine(char *String, uint Length, uint &Offset);
const cChannel *ChannelFromString(char *String, int *Apid = NULL); const cChannel *ChannelFromString(const char *String, int *Apid = NULL);
/* Disable logging if BUFCOUNT buffer overflows occur within BUFOVERTIME /* Disable logging if BUFCOUNT buffer overflows occur within BUFOVERTIME
milliseconds. Enable logging again if there is no error within BUFOVERTIME milliseconds. Enable logging again if there is no error within BUFOVERTIME
@ -65,9 +65,10 @@ enum eStreamType {
stPES, stPES,
stPS, stPS,
stES, stES,
stExtern,
stTSPIDS, stTSPIDS,
#define st_CountSetup (stES+1) #define st_CountSetup (stExtern+1)
#define st_Count (stTSPIDS+1) #define st_Count (stTSPIDS+1)
}; };

View File

@ -1,4 +1,6 @@
#include "remux/ts2es.h" #include "remux/ts2es.h"
#include "server/streamer.h"
#include "libdvbmpeg/transform.h"
#include "common.h" #include "common.h"
// from VDR's remux.c // from VDR's remux.c
@ -8,40 +10,38 @@ class cTS2ES: public ipack {
friend void PutES(uint8_t *Buffer, int Size, void *Data); friend void PutES(uint8_t *Buffer, int Size, void *Data);
private: private:
uint8_t *m_ResultBuffer; cRingBufferLinear *m_ResultBuffer;
int *m_ResultCount;
public: public:
cTS2ES(uint8_t *ResultBuffer, int *ResultCount); cTS2ES(cRingBufferLinear *ResultBuffer);
~cTS2ES(); ~cTS2ES();
void PutTSPacket(const uint8_t *Buffer); void PutTSPacket(const uint8_t *Buffer);
}; };
void PutES(uint8_t *Buffer, int Size, void *Data) { void PutES(uint8_t *Buffer, int Size, void *Data)
{
cTS2ES *This = (cTS2ES*)Data; cTS2ES *This = (cTS2ES*)Data;
uint8_t payl = Buffer[8] + 9 + This->start - 1; uint8_t payl = Buffer[8] + 9 + This->start - 1;
int count = Size - payl; int count = Size - payl;
if (*This->m_ResultCount + count > RESULTBUFFERSIZE) { int n = This->m_ResultBuffer->Put(Buffer + payl, count);
esyslog("ERROR: result buffer overflow (%d + %d > %d)", if (n != count)
*This->m_ResultCount, count, RESULTBUFFERSIZE); esyslog("ERROR: result buffer overflow, dropped %d out of %d byte", count - n, count);
count = RESULTBUFFERSIZE - *This->m_ResultCount;
}
memcpy(This->m_ResultBuffer + *This->m_ResultCount, Buffer + payl, count);
*This->m_ResultCount += count;
This->start = 1; This->start = 1;
} }
cTS2ES::cTS2ES(uint8_t *ResultBuffer, int *ResultCount) { cTS2ES::cTS2ES(cRingBufferLinear *ResultBuffer)
{
m_ResultBuffer = ResultBuffer; m_ResultBuffer = ResultBuffer;
m_ResultCount = ResultCount;
init_ipack(this, IPACKS, PutES, 0); init_ipack(this, IPACKS, PutES, 0);
data = (void*)this; data = (void*)this;
} }
cTS2ES::~cTS2ES() { cTS2ES::~cTS2ES()
{
free_ipack(this);
} }
void cTS2ES::PutTSPacket(const uint8_t *Buffer) { void cTS2ES::PutTSPacket(const uint8_t *Buffer) {
@ -73,16 +73,67 @@ void cTS2ES::PutTSPacket(const uint8_t *Buffer) {
} }
cTS2ESRemux::cTS2ESRemux(int Pid): cTS2ESRemux::cTS2ESRemux(int Pid):
cTSRemux(false) { m_Pid(Pid),
m_Pid = Pid; m_ResultBuffer(new cRingBufferLinear(WRITERBUFSIZE, IPACKS)),
m_Remux = new cTS2ES(m_ResultBuffer, &m_ResultCount); m_Remux(new cTS2ES(m_ResultBuffer))
{
m_ResultBuffer->SetTimeouts(0, 100);
} }
cTS2ESRemux::~cTS2ESRemux() { cTS2ESRemux::~cTS2ESRemux()
{
delete m_Remux; delete m_Remux;
delete m_ResultBuffer;
} }
void cTS2ESRemux::PutTSPacket(int Pid, const uint8_t *Data) { int cTS2ESRemux::Put(const uchar *Data, int Count)
if (Pid == m_Pid) m_Remux->PutTSPacket(Data); {
int used = 0;
// Make sure we are looking at a TS packet:
while (Count > TS_SIZE) {
if (Data[0] == TS_SYNC_BYTE && Data[TS_SIZE] == TS_SYNC_BYTE)
break;
Data++;
Count--;
used++;
}
if (used)
esyslog("ERROR: skipped %d byte to sync on TS packet", used);
// Convert incoming TS data into ES:
for (int i = 0; i < Count; i += TS_SIZE) {
if (Count - i < TS_SIZE)
break;
if (Data[i] != TS_SYNC_BYTE)
break;
if (m_ResultBuffer->Free() < 2 * IPACKS)
break; // A cTS2ES might write one full packet and also a small rest
int pid = cTSRemux::GetPid(Data + i + 1);
if (Data[i + 3] & 0x10) { // got payload
if (m_Pid == pid)
m_Remux->PutTSPacket(Data + i);
}
used += TS_SIZE;
}
/*
// Check if we're getting anywhere here:
if (!synced && skipped >= 0) {
if (skipped > MAXNONUSEFULDATA) {
esyslog("ERROR: no useful data seen within %d byte of video stream", skipped);
skipped = -1;
if (exitOnFailure)
cThread::EmergencyExit(true);
}
else
skipped += used;
}
*/
return used;
} }

View File

@ -2,20 +2,24 @@
#define VDR_STREAMDEV_TS2ESREMUX_H #define VDR_STREAMDEV_TS2ESREMUX_H
#include "remux/tsremux.h" #include "remux/tsremux.h"
#include <vdr/ringbuffer.h>
class cTS2ES; class cTS2ES;
class cRingBufferLinear;
class cTS2ESRemux: public cTSRemux { class cTS2ESRemux: public cTSRemux {
private: private:
int m_Pid; int m_Pid;
cTS2ES *m_Remux; cRingBufferLinear *m_ResultBuffer;
cTS2ES *m_Remux;
protected:
virtual void PutTSPacket(int Pid, const uint8_t *Data);
public: public:
cTS2ESRemux(int Pid); cTS2ESRemux(int Pid);
virtual ~cTS2ESRemux(); virtual ~cTS2ESRemux();
int Put(const uchar *Data, int Count);
uchar *Get(int &Count) { return m_ResultBuffer->Get(Count); }
void Del(int Count) { m_ResultBuffer->Del(Count); }
}; };
#endif // VDR_STREAMDEV_TS2ESREMUX_H #endif // VDR_STREAMDEV_TS2ESREMUX_H

View File

@ -1,46 +1,49 @@
#include "remux/ts2ps.h" #include "remux/ts2ps.h"
#include "server/streamer.h"
#include <vdr/channels.h>
class cTS2PS { class cTS2PS {
friend void PutPES(uint8_t *Buffer, int Size, void *Data); friend void PutPES(uint8_t *Buffer, int Size, void *Data);
private: private:
ipack m_Ipack; ipack m_Ipack;
uint8_t *m_ResultBuffer; int m_Pid;
int *m_ResultCount; cRingBufferLinear *m_ResultBuffer;
public: public:
cTS2PS(uint8_t *ResultBuffer, int *ResultCount, uint8_t AudioCid = 0x00, cTS2PS(cRingBufferLinear *ResultBuffer, int Pid, uint8_t AudioCid = 0x00);
bool PS = false);
~cTS2PS(); ~cTS2PS();
void PutTSPacket(const uint8_t *Buffer); void PutTSPacket(const uint8_t *Buffer);
int Pid(void) const { return m_Pid; }
}; };
void PutPES(uint8_t *Buffer, int Size, void *Data) { void PutPES(uint8_t *Buffer, int Size, void *Data)
{
cTS2PS *This = (cTS2PS*)Data; cTS2PS *This = (cTS2PS*)Data;
if (*This->m_ResultCount + Size > RESULTBUFFERSIZE) { int n = This->m_ResultBuffer->Put(Buffer, Size);
esyslog("ERROR: result buffer overflow (%d + %d > %d)", if (n != Size)
*This->m_ResultCount, Size, RESULTBUFFERSIZE); esyslog("ERROR: result buffer overflow, dropped %d out of %d byte", Size - n, Size);
Size = RESULTBUFFERSIZE - *This->m_ResultCount;
}
memcpy(This->m_ResultBuffer + *This->m_ResultCount, Buffer, Size);
*This->m_ResultCount += Size;
} }
cTS2PS::cTS2PS(uint8_t *ResultBuffer, int *ResultCount, uint8_t AudioCid, cTS2PS::cTS2PS(cRingBufferLinear *ResultBuffer, int Pid, uint8_t AudioCid)
bool PS) { {
m_ResultBuffer = ResultBuffer; m_ResultBuffer = ResultBuffer;
m_ResultCount = ResultCount; m_Pid = Pid;
init_ipack(&m_Ipack, IPACKS, PutPES, PS); init_ipack(&m_Ipack, IPACKS, PutPES, false);
m_Ipack.cid = AudioCid; m_Ipack.cid = AudioCid;
m_Ipack.data = (void*)this; m_Ipack.data = (void*)this;
} }
cTS2PS::~cTS2PS() { cTS2PS::~cTS2PS()
{
free_ipack(&m_Ipack);
} }
void cTS2PS::PutTSPacket(const uint8_t *Buffer) { void cTS2PS::PutTSPacket(const uint8_t *Buffer)
{
if (!Buffer) if (!Buffer)
return; return;
@ -68,37 +71,140 @@ void cTS2PS::PutTSPacket(const uint8_t *Buffer) {
instant_repack((uint8_t*)(Buffer + 4 + off), TS_SIZE - 4 - off, &m_Ipack); instant_repack((uint8_t*)(Buffer + 4 + off), TS_SIZE - 4 - off, &m_Ipack);
} }
cTS2PSRemux::cTS2PSRemux(int VPid, int APid1, int APid2, int DPid1, cTS2PSRemux::cTS2PSRemux(int VPid, const int *APids, const int *DPids, const int *SPids):
int DPid2, bool PS) { m_NumTracks(0),
m_VPid = VPid; m_ResultBuffer(new cRingBufferLinear(WRITERBUFSIZE, IPACKS)),
m_APid1 = APid1; m_ResultSkipped(0),
m_APid2 = APid2; m_Skipped(0),
m_DPid1 = DPid1; m_Synced(false),
m_DPid2 = DPid2; m_IsRadio(VPid == 0 || VPid == 1 || VPid == 0x1FFF)
m_VRemux = new cTS2PS(m_ResultBuffer, &m_ResultCount, 0x00, PS); {
m_ARemux1 = new cTS2PS(m_ResultBuffer, &m_ResultCount, 0xC0, PS); m_ResultBuffer->SetTimeouts(0, 100);
m_ARemux2 = APid2 ? new cTS2PS(m_ResultBuffer, &m_ResultCount, 0xC1, PS)
: NULL; if (VPid)
m_DRemux1 = DPid1 ? new cTS2PS(m_ResultBuffer, &m_ResultCount, 0x00, PS) m_Remux[m_NumTracks++] = new cTS2PS(m_ResultBuffer, VPid);
: NULL; if (APids) {
//XXX don't yet know how to tell apart primary and secondary DD data... int n = 0;
m_DRemux2 = /*XXX m_DPid2 ? new cTS2PS(m_ResultBuffer, &m_ResultCount, while (*APids && m_NumTracks < MAXTRACKS && n < MAXAPIDS)
0x00, PS) : XXX*/ NULL; m_Remux[m_NumTracks++] = new cTS2PS(m_ResultBuffer, *APids++, 0xC0 + n++);
}
if (DPids) {
int n = 0;
while (*DPids && m_NumTracks < MAXTRACKS && n < MAXDPIDS)
m_Remux[m_NumTracks++] = new cTS2PS(m_ResultBuffer, *DPids++, 0x80 + n++);
}
} }
cTS2PSRemux::~cTS2PSRemux() { cTS2PSRemux::~cTS2PSRemux() {
if (m_DRemux2) delete m_DRemux2; for (int i = 0; i < m_NumTracks; ++i)
if (m_DRemux1) delete m_DRemux1; delete m_Remux[i];
if (m_ARemux2) delete m_ARemux2; delete m_ResultBuffer;
delete m_ARemux1;
delete m_VRemux;
} }
void cTS2PSRemux::PutTSPacket(int Pid, const uint8_t *Data) { int cTS2PSRemux::Put(const uchar *Data, int Count)
if (Pid == m_VPid) m_VRemux->PutTSPacket(Data); {
else if (Pid == m_APid1) m_ARemux1->PutTSPacket(Data); int used = 0;
else if (Pid == m_APid2 && m_ARemux2) m_ARemux2->PutTSPacket(Data);
else if (Pid == m_DPid1 && m_DRemux1) m_DRemux1->PutTSPacket(Data); // Make sure we are looking at a TS packet:
else if (Pid == m_DPid2 && m_DRemux2) m_DRemux2->PutTSPacket(Data); while (Count > TS_SIZE) {
if (Data[0] == TS_SYNC_BYTE && Data[TS_SIZE] == TS_SYNC_BYTE)
break;
Data++;
Count--;
used++;
}
if (used)
esyslog("ERROR: m_Skipped %d byte to sync on TS packet", used);
// Convert incoming TS data into multiplexed PS:
for (int i = 0; i < Count; i += TS_SIZE) {
if (Count - i < TS_SIZE)
break;
if (Data[i] != TS_SYNC_BYTE)
break;
if (m_ResultBuffer->Free() < 2 * IPACKS)
break; // A cTS2PS might write one full packet and also a small rest
int pid = GetPid(Data + i + 1);
if (Data[i + 3] & 0x10) { // got payload
for (int t = 0; t < m_NumTracks; t++) {
if (m_Remux[t]->Pid() == pid) {
m_Remux[t]->PutTSPacket(Data + i);
break;
}
}
}
used += TS_SIZE;
}
// Check if we're getting anywhere here:
if (!m_Synced && m_Skipped >= 0)
m_Skipped += used;
return used;
}
uchar *cTS2PSRemux::Get(int &Count)
{
// Remove any previously skipped data from the result buffer:
if (m_ResultSkipped > 0) {
m_ResultBuffer->Del(m_ResultSkipped);
m_ResultSkipped = 0;
}
// Special VPID case to enable recording radio channels:
if (m_IsRadio) {
// Force syncing of radio channels to avoid "no useful data" error
m_Synced = true;
return m_ResultBuffer->Get(Count);
}
// Check for frame borders:
Count = 0;
uchar *resultData = NULL;
int resultCount = 0;
uchar *data = m_ResultBuffer->Get(resultCount);
if (data) {
for (int i = 0; i < resultCount - 3; i++) {
if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1) {
int l = 0;
uchar StreamType = data[i + 3];
if (VIDEO_STREAM_S <= StreamType && StreamType <= VIDEO_STREAM_E) {
uchar pt = NO_PICTURE;
l = ScanVideoPacket(data, resultCount, i, pt);
if (l < 0)
return resultData;
if (pt != NO_PICTURE) {
if (pt < I_FRAME || B_FRAME < pt) {
esyslog("ERROR: unknown picture type '%d'", pt);
}
else if (!m_Synced) {
if (pt == I_FRAME) {
m_ResultSkipped = i; // will drop everything before this position
SetBrokenLink(data + i, l);
m_Synced = true;
}
}
else if (Count)
return resultData;
}
} else {
l = GetPacketLength(data, resultCount, i);
if (l < 0)
return resultData;
}
if (m_Synced) {
if (!Count)
resultData = data + i;
Count += l;
} else
m_ResultSkipped = i + l;
if (l > 0)
i += l - 1; // the loop increments, too
}
}
}
return resultData;
} }

View File

@ -2,21 +2,28 @@
#define VDR_STREAMDEV_TS2PESREMUX_H #define VDR_STREAMDEV_TS2PESREMUX_H
#include "remux/tsremux.h" #include "remux/tsremux.h"
#include <vdr/remux.h>
#include <vdr/ringbuffer.h>
class cTS2PS; class cTS2PS;
class cTS2PSRemux: public cTSRemux { class cTS2PSRemux: public cTSRemux {
private: private:
int m_VPid, m_APid1, m_APid2, m_DPid1, m_DPid2; int m_NumTracks;
cTS2PS *m_VRemux, *m_ARemux1, *m_ARemux2, *m_DRemux1, *m_DRemux2; cTS2PS *m_Remux[MAXTRACKS];
cRingBufferLinear *m_ResultBuffer;
protected: int m_ResultSkipped;
virtual void PutTSPacket(int Pid, const uint8_t *Data); int m_Skipped;
bool m_Synced;
bool m_IsRadio;
public: public:
cTS2PSRemux(int VPid, int APid1, int APid2, int DPid1, int DPid2, cTS2PSRemux(int VPid, const int *Apids, const int *Dpids, const int *Spids);
bool PS = false);
virtual ~cTS2PSRemux(); virtual ~cTS2PSRemux();
int Put(const uchar *Data, int Count);
uchar *Get(int &Count);
void Del(int Count) { m_ResultBuffer->Del(Count); }
}; };
#endif // VDR_STREAMDEV_TS2PESREMUX_H #endif // VDR_STREAMDEV_TS2PESREMUX_H

View File

@ -1,176 +1,10 @@
#include "remux/tsremux.h" #include "remux/tsremux.h"
// from VDR's remux.c
#define MAXNONUSEFULDATA (10*1024*1024)
#define SC_PICTURE 0x00 // "picture header" #define SC_PICTURE 0x00 // "picture header"
#define VIDEO_STREAM_S 0xE0
cTSRemux::cTSRemux(bool Sync) { void cTSRemux::SetBrokenLink(uchar *Data, int Length)
m_ResultCount = 0; {
m_ResultDelivered = 0; if (Length > 9 && Data[0] == 0 && Data[1] == 0 && Data[2] == 1 && (Data[3] & 0xF0) == VIDEO_STREAM_S) {
m_Synced = false;
m_Skipped = 0;
m_Sync = Sync;
}
cTSRemux::~cTSRemux(void) {
}
uchar *cTSRemux::Process(const uchar *Data, int &Count, int &Result) {
// Remove any previously delivered data from the result buffer:
if (m_ResultDelivered) {
if (m_ResultDelivered < m_ResultCount)
memmove(m_ResultBuffer, m_ResultBuffer + m_ResultDelivered, m_ResultCount
- m_ResultDelivered);
m_ResultCount -= m_ResultDelivered;
m_ResultDelivered = 0;
}
int used = 0;
// Make sure we are looking at a TS packet:
while (Count > TS_SIZE) {
if (Data[0] == 0x47 && Data[TS_SIZE] == 0x47)
break;
Data++;
Count--;
used++;
}
if (used)
esyslog("ERROR: skipped %d byte to sync on TS packet", used);
// Convert incoming TS data
for (int i = 0; i < Count; i += TS_SIZE) {
if (Count - i < TS_SIZE)
break;
if (Data[i] != 0x47)
break;
int pid = get_pid((uint8_t*)(Data + i + 1));
if (Data[i + 3] & 0x10) // got payload
PutTSPacket(pid, Data + i);
/*if (pid == m_VPid) m_VRemux->ConvertTSPacket(Data + i);
else if (pid == m_APid1) m_ARemux1->ConvertTSPacket(Data + i);
else if (pid == m_APid2 && m_ARemux2) m_ARemux2->ConvertTSPacket(Data + i);
else if (pid == m_DPid1 && m_DRemux1) m_DRemux1->ConvertTSPacket(Data + i);
else if (pid == m_DPid2 && m_DRemux2) m_DRemux2->ConvertTSPacket(Data + i);*/
used += TS_SIZE;
if (m_ResultCount > (int)sizeof(m_ResultBuffer) / 2)
break;
}
Count = used;
// When we don't need to sync, we don't need to sync :-)
if (!m_Sync) {
Result = m_ResultDelivered = m_ResultCount;
return Result ? m_ResultBuffer : NULL;
}
// Check if we're getting anywhere here:
if (!m_Synced && m_Skipped >= 0) {
if (m_Skipped > MAXNONUSEFULDATA) {
esyslog("ERROR: no useful data seen within %d byte of video stream", m_Skipped);
m_Skipped = -1;
//if (exitOnFailure)
//cThread::EmergencyExit(true);
}
else
m_Skipped += Count;
}
// Check for frame borders:
if (m_ResultCount > 0) {
for (int i = 0; i < m_ResultCount; i++) {
if (m_ResultBuffer[i] == 0 && m_ResultBuffer[i + 1] == 0 && m_ResultBuffer[i + 2] == 1) {
switch (m_ResultBuffer[i + 3]) {
case VIDEO_STREAM_S ... VIDEO_STREAM_E:
{
uchar pt = NO_PICTURE;
int l = ScanVideoPacket(m_ResultBuffer, m_ResultCount, i, pt);
if (l < 0)
return NULL; // no useful data found, wait for more
if (pt != NO_PICTURE) {
if (pt < I_FRAME || B_FRAME < pt)
esyslog("ERROR: unknown picture type '%d'", pt);
else if (!m_Synced) {
if (pt == I_FRAME) {
m_ResultDelivered = i; // will drop everything before this position
SetBrokenLink(m_ResultBuffer + i, l);
m_Synced = true;
}
else {
m_ResultDelivered = i + l; // will drop everything before and including this packet
return NULL;
}
}
}
if (m_Synced) {
Result = l;
uchar *p = m_ResultBuffer + m_ResultDelivered;
m_ResultDelivered += l;
return p;
}
else {
m_ResultDelivered = i + l; // will drop everything before and including this packet
return NULL;
}
}
break;
case PRIVATE_STREAM1:
case AUDIO_STREAM_S ... AUDIO_STREAM_E:
{
int l = GetPacketLength(m_ResultBuffer, m_ResultCount, i);
if (l < 0)
return NULL; // no useful data found, wait for more
if (m_Synced) {
Result = l;
uchar *p = m_ResultBuffer + m_ResultDelivered;
m_ResultDelivered += l;
return p;
}
else {
m_ResultDelivered = i + l; // will drop everything before and including this packet
return NULL;
}
}
break;
}
}
}
}
return NULL; // no useful data found, wait for more
}
int cTSRemux::ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType) {
// Scans the video packet starting at Offset and returns its length.
// If the return value is -1 the packet was not completely in the buffer.
int Length = GetPacketLength(Data, Count, Offset);
if (Length > 0 && Offset + Length <= Count) {
int i = Offset + 8; // the minimum length of the video packet header
i += Data[i] + 1; // possible additional header bytes
for (; i < Offset + Length; i++) {
if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1) {
switch (Data[i + 3]) {
case SC_PICTURE: PictureType = (Data[i + 5] >> 3) & 0x07;
return Length;
}
}
}
PictureType = NO_PICTURE;
return Length;
}
return -1;
}
int cTSRemux::GetPacketLength(const uchar *Data, int Count, int Offset) {
// Returns the entire length of the packet starting at offset, or -1 in case of error.
return (Offset + 5 < Count) ? (Data[Offset + 4] << 8) + Data[Offset + 5] + 6 : -1;
}
void cTSRemux::SetBrokenLink(uchar *Data, int Length) {
if (Length > 9 && Data[0] == 0 && Data[1] == 0 && Data[2] == 1 && (Data[3] & VIDEO_STREAM_S) == VIDEO_STREAM_S) {
for (int i = Data[8] + 9; i < Length - 7; i++) { // +9 to skip video packet header for (int i = Data[8] + 9; i < Length - 7; i++) { // +9 to skip video packet header
if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1 && Data[i + 3] == 0xB8) { if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1 && Data[i + 3] == 0xB8) {
if (!(Data[i + 7] & 0x40)) // set flag only if GOP is not closed if (!(Data[i + 7] & 0x40)) // set flag only if GOP is not closed
@ -183,3 +17,43 @@ void cTSRemux::SetBrokenLink(uchar *Data, int Length) {
else else
dsyslog("SetBrokenLink: no video packet in frame"); dsyslog("SetBrokenLink: no video packet in frame");
} }
int cTSRemux::GetPid(const uchar *Data)
{
return (((uint16_t)Data[0] & PID_MASK_HI) << 8) | (Data[1] & 0xFF);
}
int cTSRemux::GetPacketLength(const uchar *Data, int Count, int Offset)
{
// Returns the length of the packet starting at Offset, or -1 if Count is
// too small to contain the entire packet.
int Length = (Offset + 5 < Count) ? (Data[Offset + 4] << 8) + Data[Offset + 5] + 6 : -1;
if (Length > 0 && Offset + Length <= Count)
return Length;
return -1;
}
int cTSRemux::ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType)
{
// Scans the video packet starting at Offset and returns its length.
// If the return value is -1 the packet was not completely in the buffer.
int Length = GetPacketLength(Data, Count, Offset);
if (Length > 0) {
if (Length >= 8) {
int i = Offset + 8; // the minimum length of the video packet header
i += Data[i] + 1; // possible additional header bytes
for (; i < Offset + Length - 5; i++) {
if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1) {
switch (Data[i + 3]) {
case SC_PICTURE: PictureType = (Data[i + 5] >> 3) & 0x07;
return Length;
}
}
}
}
PictureType = NO_PICTURE;
return Length;
}
return -1;
}

View File

@ -8,15 +8,13 @@
class cTSRemux { class cTSRemux {
protected: protected:
uchar m_ResultBuffer[RESULTBUFFERSIZE]; /*uchar m_ResultBuffer[RESULTBUFFERSIZE];
int m_ResultCount; int m_ResultCount;
int m_ResultDelivered; int m_ResultDelivered;
int m_Synced; int m_Synced;
int m_Skipped; int m_Skipped;
int m_Sync; int m_Sync;
int GetPacketLength(const uchar *Data, int Count, int Offset);
int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType);
virtual void PutTSPacket(int Pid, const uint8_t *Data) = 0; virtual void PutTSPacket(int Pid, const uint8_t *Data) = 0;
@ -24,9 +22,12 @@ public:
cTSRemux(bool Sync = true); cTSRemux(bool Sync = true);
virtual ~cTSRemux(); virtual ~cTSRemux();
virtual uchar *Process(const uchar *Data, int &Count, int &Result); virtual uchar *Process(const uchar *Data, int &Count, int &Result);*/
static void SetBrokenLink(uchar *Data, int Length); static void SetBrokenLink(uchar *Data, int Length);
static int GetPid(const uchar *Data);
static int GetPacketLength(const uchar *Data, int Count, int Offset);
static int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType);
}; };
#endif // VDR_STREAMDEV_TSREMUX_H #endif // VDR_STREAMDEV_TSREMUX_H

View File

@ -1,75 +1,80 @@
/* /*
* $Id: connectionHTTP.c,v 1.6 2005/02/10 22:24:26 lordjaxom Exp $ * $Id: connectionHTTP.c,v 1.7 2005/02/11 16:44:15 lordjaxom Exp $
*/ */
#include "server/connectionHTTP.h" #include "server/connectionHTTP.h"
#include "server/livestreamer.h"
#include "server/setup.h" #include "server/setup.h"
cConnectionHTTP::cConnectionHTTP(void): cServerConnection("HTTP") { cConnectionHTTP::cConnectionHTTP(void):
m_Channel = NULL; cServerConnection("HTTP"),
m_Apid = 0; m_Status(hsRequest),
m_ListChannel = NULL; m_LiveStreamer(NULL),
m_LiveStreamer = NULL; m_Channel(NULL),
m_Status = hsRequest; m_Apid(0),
m_StreamType = (eStreamType)StreamdevServerSetup.HTTPStreamType; m_StreamType((eStreamType)StreamdevServerSetup.HTTPStreamType),
m_Startup = false; m_ListChannel(NULL)
{
Dprintf("constructor hsRequest\n");
} }
cConnectionHTTP::~cConnectionHTTP() { cConnectionHTTP::~cConnectionHTTP()
if (m_LiveStreamer != NULL) delete m_LiveStreamer; {
delete m_LiveStreamer;
} }
void cConnectionHTTP::Detach(void) { bool cConnectionHTTP::Command(char *Cmd)
if (m_LiveStreamer != NULL) m_LiveStreamer->Detach(); {
} Dprintf("command %s\n", Cmd);
void cConnectionHTTP::Attach(void) {
if (m_LiveStreamer != NULL) m_LiveStreamer->Attach();
}
bool cConnectionHTTP::Command(char *Cmd) {
switch (m_Status) { switch (m_Status) {
case hsRequest: case hsRequest:
if (strncmp(Cmd, "GET ", 4) == 0) return CmdGET(Cmd + 4); Dprintf("Request\n");
else { m_Request = Cmd;
DeferClose(); m_Status = hsHeaders;
m_Status = hsTransfer; // Ignore following lines return true;
return Respond("HTTP/1.0 400 Bad Request");
}
break;
case hsHeaders: case hsHeaders:
if (*Cmd == '\0') { if (*Cmd == '\0') {
if (m_ListChannel != NULL) { m_Status = hsBody;
m_Status = hsListing; return ProcessRequest();
return Respond("HTTP/1.0 200 OK") }
&& Respond("Content-Type: text/html") Dprintf("header\n");
&& Respond("") return true;
&& Respond("<html><head><title>VDR Channel Listing</title></head>") }
&& Respond("<body><ul>"); return false; // ??? shouldn't happen
} else if (m_Channel == NULL) { }
bool cConnectionHTTP::ProcessRequest(void) {
Dprintf("process\n");
if (m_Request.substr(0, 4) == "GET " && CmdGET(m_Request.substr(4))) {
switch (m_Job) {
case hjListing:
return Respond("HTTP/1.0 200 OK")
&& Respond("Content-Type: text/html")
&& Respond("")
&& Respond("<html><head><title>VDR Channel Listing</title></head>")
&& Respond("<body><ul>");
case hjTransfer:
if (m_Channel == NULL) {
DeferClose(); DeferClose();
return Respond("HTTP/1.0 404 not found"); return Respond("HTTP/1.0 404 not found");
} }
m_Status = hsTransfer;
m_LiveStreamer = new cStreamdevLiveStreamer(0); m_LiveStreamer = new cStreamdevLiveStreamer(0);
cDevice *device = GetDevice(m_Channel, 0); cDevice *device = GetDevice(m_Channel, 0);
if (device != NULL) { if (device != NULL) {
device->SwitchChannel(m_Channel, false); device->SwitchChannel(m_Channel, false);
if (m_LiveStreamer->SetChannel(m_Channel, m_StreamType, m_Apid)) { if (m_LiveStreamer->SetChannel(m_Channel, m_StreamType, m_Apid)) {
m_LiveStreamer->SetDevice(device); m_LiveStreamer->SetDevice(device);
m_Startup = true; if (m_StreamType == stES && (m_Apid != 0 || ISRADIO(m_Channel))) {
if (m_StreamType == stES && (m_Channel->Vpid() == 0
|| m_Channel->Vpid() == 1 || m_Channel->Vpid() == 0x1FFF)) {
return Respond("HTTP/1.0 200 OK") return Respond("HTTP/1.0 200 OK")
&& Respond("Content-Type: audio/mpeg") && Respond("Content-Type: audio/mpeg")
&& Respond((std::string)"icy-name: " + m_Channel->Name()) && Respond((std::string)"icy-name: " + m_Channel->Name())
&& Respond(""); && Respond("");
} else { } else {
return Respond("HTTP/1.0 200 OK") return Respond("HTTP/1.0 200 OK")
&& Respond("Content-Type: video/mpeg") && Respond("Content-Type: video/mpeg")
&& Respond(""); && Respond("");
} }
} }
} }
@ -77,78 +82,110 @@ bool cConnectionHTTP::Command(char *Cmd) {
DeferClose(); DeferClose();
return Respond("HTTP/1.0 409 Channel not available"); return Respond("HTTP/1.0 409 Channel not available");
} }
break;
default:
break;
} }
return true;
DeferClose();
return Respond("HTTP/1.0 400 Bad Request");
} }
void cConnectionHTTP::Flushed(void) { void cConnectionHTTP::Flushed(void) {
if (m_Status == hsListing) { std::string line;
if (m_Status != hsBody)
return;
switch (m_Job) {
case hjListing:
if (m_ListChannel == NULL) { if (m_ListChannel == NULL) {
Respond("</ul></body></html>"); Respond("</ul></body></html>");
DeferClose(); DeferClose();
m_Status = hsFinished;
return; return;
} }
std::string line;
if (m_ListChannel->GroupSep()) if (m_ListChannel->GroupSep())
line = (std::string)"<li>--- " + m_ListChannel->Name() + "---</li>"; line = (std::string)"<li>--- " + m_ListChannel->Name() + "---</li>";
else else {
int index = 1;
line = (std::string)"<li><a href=\"http://" + LocalIp() + ":" line = (std::string)"<li><a href=\"http://" + LocalIp() + ":"
+ (const char*)itoa(StreamdevServerSetup.HTTPServerPort) + "/" + (const char*)itoa(StreamdevServerSetup.HTTPServerPort) + "/"
+ StreamTypes[m_StreamType] + "/"
+ (const char*)m_ListChannel->GetChannelID().ToString() + "\">" + (const char*)m_ListChannel->GetChannelID().ToString() + "\">"
+ m_ListChannel->Name() + "</a></li>"; + m_ListChannel->Name() + "</a> ";
for (int i = 0; m_ListChannel->Apid(i) != 0; ++i, ++index) {
line += "<a href=\"http://" + LocalIp() + ":"
+ (const char*)itoa(StreamdevServerSetup.HTTPServerPort) + "/"
+ StreamTypes[m_StreamType] + "/"
+ (const char*)m_ListChannel->GetChannelID().ToString() + "+"
+ (const char*)itoa(index) + "\">("
+ m_ListChannel->Alang(i) + ")</a> ";
}
for (int i = 0; m_ListChannel->Dpid(i) != 0; ++i, ++index) {
line += "<a href=\"http://" + LocalIp() + ":"
+ (const char*)itoa(StreamdevServerSetup.HTTPServerPort) + "/"
+ StreamTypes[m_StreamType] + "/"
+ (const char*)m_ListChannel->GetChannelID().ToString() + "+"
+ (const char*)itoa(index) + "\">("
+ m_ListChannel->Dlang(i) + ")</a> ";
}
line += "</li>";
}
if (!Respond(line)) if (!Respond(line))
DeferClose(); DeferClose();
m_ListChannel = Channels.Next(m_ListChannel); m_ListChannel = Channels.Next(m_ListChannel);
} else if (m_Startup) { break;
case hjTransfer:
Dprintf("streamer start\n"); Dprintf("streamer start\n");
m_LiveStreamer->Start(this); m_LiveStreamer->Start(this);
m_Startup = false; m_Status = hsFinished;
break;
} }
} }
bool cConnectionHTTP::CmdGET(char *Opts) { bool cConnectionHTTP::CmdGET(const std::string &Opts) {
const char *sp = Opts.c_str(), *ptr = sp, *ep;
const cChannel *chan; const cChannel *chan;
char *ep; int apid = 0, pos;
int apid = 0;
Opts = skipspace(Opts); ptr = skipspace(ptr);
while (*Opts == '/') while (*ptr == '/')
++Opts; ++ptr;
if (strncasecmp(Opts, "PS/", 3) == 0) { if (strncasecmp(ptr, "PS/", 3) == 0) {
m_StreamType = stPS; m_StreamType = stPS;
Opts+=3; ptr += 3;
} else if (strncasecmp(Opts, "PES/", 4) == 0) { } else if (strncasecmp(ptr, "PES/", 4) == 0) {
m_StreamType = stPES; m_StreamType = stPES;
Opts+=4; ptr += 4;
} else if (strncasecmp(Opts, "TS/", 3) == 0) { } else if (strncasecmp(ptr, "TS/", 3) == 0) {
m_StreamType = stTS; m_StreamType = stTS;
Opts+=3; ptr += 3;
} else if (strncasecmp(Opts, "ES/", 3) == 0) { } else if (strncasecmp(ptr, "ES/", 3) == 0) {
m_StreamType = stES; m_StreamType = stES;
Opts+=3; ptr += 3;
} else if (strncasecmp(ptr, "Extern/", 3) == 0) {
m_StreamType = stExtern;
ptr += 7;
} }
while (*Opts == '/') while (*ptr == '/')
++Opts; ++ptr;
for (ep = Opts + strlen(Opts); ep >= Opts && !isspace(*ep); --ep) for (ep = ptr + strlen(ptr); ep >= ptr && !isspace(*ep); --ep)
; ;
*ep = '\0';
std::string filespec = Opts.substr(ptr - sp, ep - ptr);
Dprintf("substr: %s\n", filespec.c_str());
Dprintf("before channelfromstring\n"); Dprintf("before channelfromstring\n");
if (strncmp(Opts, "channels.htm", 12) == 0) { if (filespec == "" || filespec.substr(0, 12) == "channels.htm") {
m_ListChannel = Channels.First(); m_ListChannel = Channels.First();
m_Status = hsHeaders; m_Job = hjListing;
} else if ((chan = ChannelFromString(Opts, &apid)) != NULL) { } else if ((chan = ChannelFromString(filespec.c_str(), &apid)) != NULL) {
m_Channel = chan; m_Channel = chan;
m_Apid = apid; m_Apid = apid;
Dprintf("Apid is %d\n", apid); Dprintf("Apid is %d\n", apid);
m_Status = hsHeaders; m_Job = hjTransfer;
} }
Dprintf("after channelfromstring\n"); Dprintf("after channelfromstring\n");
return true; return true;

View File

@ -1,11 +1,12 @@
/* /*
* $Id: connectionHTTP.h,v 1.2 2005/02/10 22:24:26 lordjaxom Exp $ * $Id: connectionHTTP.h,v 1.3 2005/02/11 16:44:15 lordjaxom Exp $
*/ */
#ifndef VDR_STREAMDEV_SERVERS_CONNECTIONHTTP_H #ifndef VDR_STREAMDEV_SERVERS_CONNECTIONHTTP_H
#define VDR_STREAMDEV_SERVERS_CONNECTIONHTTP_H #define VDR_STREAMDEV_SERVERS_CONNECTIONHTTP_H
#include "connection.h" #include "connection.h"
#include "server/livestreamer.h"
#include <tools/select.h> #include <tools/select.h>
@ -17,27 +18,39 @@ private:
enum eHTTPStatus { enum eHTTPStatus {
hsRequest, hsRequest,
hsHeaders, hsHeaders,
hsTransfer, hsBody,
hsListing, hsFinished,
}; };
const cChannel *m_Channel; enum eHTTPJob {
int m_Apid; hjTransfer,
const cChannel *m_ListChannel; hjListing,
cStreamdevLiveStreamer *m_LiveStreamer; };
eStreamType m_StreamType;
eHTTPStatus m_Status; std::string m_Request;
bool m_Startup; //std::map<std::string,std::string> m_Headers; TODO: later?
eHTTPStatus m_Status;
eHTTPJob m_Job;
// job: transfer
cStreamdevLiveStreamer *m_LiveStreamer;
const cChannel *m_Channel;
int m_Apid;
eStreamType m_StreamType;
// job: listing
const cChannel *m_ListChannel;
protected:
bool ProcessRequest(void);
public: public:
cConnectionHTTP(void); cConnectionHTTP(void);
virtual ~cConnectionHTTP(); virtual ~cConnectionHTTP();
virtual void Detach(void); virtual void Attach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Attach(); }
virtual void Attach(void); virtual void Detach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Detach(); }
virtual bool Command(char *Cmd); virtual bool Command(char *Cmd);
bool CmdGET(char *Opts); bool CmdGET(const std::string &Opts);
virtual void Flushed(void); virtual void Flushed(void);
}; };

View File

@ -3,6 +3,7 @@
#include "server/livestreamer.h" #include "server/livestreamer.h"
#include "remux/ts2ps.h" #include "remux/ts2ps.h"
#include "remux/ts2es.h" #include "remux/ts2es.h"
#include "remux/extern.h"
#include "common.h" #include "common.h"
// --- cStreamdevLiveReceiver ------------------------------------------------- // --- cStreamdevLiveReceiver -------------------------------------------------
@ -37,15 +38,21 @@ cStreamdevLiveStreamer::cStreamdevLiveStreamer(int Priority):
m_Device(NULL), m_Device(NULL),
m_Receiver(NULL), m_Receiver(NULL),
m_PESRemux(NULL), m_PESRemux(NULL),
m_Remux(NULL) m_ESRemux(NULL),
m_PSRemux(NULL),
m_ExtRemux(NULL)
{ {
} }
cStreamdevLiveStreamer::~cStreamdevLiveStreamer() cStreamdevLiveStreamer::~cStreamdevLiveStreamer()
{ {
Dprintf("Desctructing Live streamer\n"); Dprintf("Desctructing Live streamer\n");
Stop();
delete m_Receiver; delete m_Receiver;
delete m_Remux; delete m_PESRemux;
delete m_ESRemux;
delete m_PSRemux;
delete m_ExtRemux;
#if VDRVERSNUM >= 10300 #if VDRVERSNUM >= 10300
//delete m_Filter; TODO //delete m_Filter; TODO
#endif #endif
@ -104,7 +111,7 @@ bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType Str
int pid = ISRADIO(m_Channel) ? m_Channel->Apid(0) : m_Channel->Vpid(); int pid = ISRADIO(m_Channel) ? m_Channel->Apid(0) : m_Channel->Vpid();
if (Apid != 0) if (Apid != 0)
pid = Apid; pid = Apid;
m_Remux = new cTS2ESRemux(pid); m_ESRemux = new cTS2ESRemux(pid);
return SetPid(pid, true); return SetPid(pid, true);
} }
@ -121,9 +128,15 @@ bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType Str
&& SetPid(m_Channel->Dpid(0), true); && SetPid(m_Channel->Dpid(0), true);
case stPS: case stPS:
m_Remux = new cTS2PSRemux(m_Channel->Vpid(), m_Channel->Apid(0), 0, 0, 0, true); m_PSRemux = new cTS2PSRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
return SetPid(m_Channel->Vpid(), true) m_Channel->Spids());
&& SetPid(m_Channel->Apid(0), true); if (Apid != 0)
return SetPid(m_Channel->Vpid(), true)
&& SetPid(Apid, true);
else
return SetPid(m_Channel->Vpid(), true)
&& SetPid(m_Channel->Apid(0), true)
&& SetPid(m_Channel->Dpid(0), true);
case stTS: case stTS:
if (Apid != 0) if (Apid != 0)
@ -134,6 +147,17 @@ bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType Str
&& SetPid(m_Channel->Apid(0), true) && SetPid(m_Channel->Apid(0), true)
&& SetPid(m_Channel->Dpid(0), true); && SetPid(m_Channel->Dpid(0), true);
case stExtern:
m_ExtRemux = new cExternRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
m_Channel->Spids());
if (Apid != 0)
return SetPid(m_Channel->Vpid(), true)
&& SetPid(Apid, true);
else
return SetPid(m_Channel->Vpid(), true)
&& SetPid(m_Channel->Apid(0), true)
&& SetPid(m_Channel->Dpid(0), true);
case stTSPIDS: case stTSPIDS:
Dprintf("pid streaming mode\n"); Dprintf("pid streaming mode\n");
return true; return true;
@ -170,8 +194,17 @@ int cStreamdevLiveStreamer::Put(const uchar *Data, int Count)
case stPES: case stPES:
return m_PESRemux->Put(Data, Count); return m_PESRemux->Put(Data, Count);
default: case stES:
abort(); return m_ESRemux->Put(Data, Count);
case stPS:
return m_PSRemux->Put(Data, Count);
case stExtern:
return m_ExtRemux->Put(Data, Count);
default: // shouldn't happen???
return 0;
} }
} }
@ -184,9 +217,18 @@ uchar *cStreamdevLiveStreamer::Get(int &Count)
case stPES: case stPES:
return m_PESRemux->Get(Count); return m_PESRemux->Get(Count);
case stES:
return m_ESRemux->Get(Count);
default: case stPS:
abort(); return m_PSRemux->Get(Count);
case stExtern:
return m_ExtRemux->Get(Count);
default: // shouldn't happen???
return 0;
} }
} }
@ -201,9 +243,18 @@ void cStreamdevLiveStreamer::Del(int Count)
case stPES: case stPES:
m_PESRemux->Del(Count); m_PESRemux->Del(Count);
break; break;
case stES:
m_ESRemux->Del(Count);
break;
default: case stPS:
abort(); m_PSRemux->Del(Count);
break;
case stExtern:
m_ExtRemux->Del(Count);
break;
} }
} }

View File

@ -8,7 +8,9 @@
#include "server/livefilter.h" #include "server/livefilter.h"
#include "common.h" #include "common.h"
class cTSRemux; class cTS2PSRemux;
class cTS2ESRemux;
class cExternRemux;
class cRemux; class cRemux;
// --- cStreamdevLiveReceiver ------------------------------------------------- // --- cStreamdevLiveReceiver -------------------------------------------------
@ -40,7 +42,9 @@ private:
cDevice *m_Device; cDevice *m_Device;
cStreamdevLiveReceiver *m_Receiver; cStreamdevLiveReceiver *m_Receiver;
cRemux *m_PESRemux; cRemux *m_PESRemux;
cTSRemux *m_Remux; cTS2ESRemux *m_ESRemux;
cTS2PSRemux *m_PSRemux;
cExternRemux *m_ExtRemux;
public: public:
cStreamdevLiveStreamer(int Priority); cStreamdevLiveStreamer(int Priority);
@ -55,7 +59,7 @@ public:
virtual uchar *Get(int &Count); virtual uchar *Get(int &Count);
virtual void Del(int Count); virtual void Del(int Count);
virtual void Attach(void) { Dprintf("attach %p\n", m_Device);m_Device->AttachReceiver(m_Receiver); } virtual void Attach(void) { m_Device->AttachReceiver(m_Receiver); }
virtual void Detach(void) { m_Device->Detach(m_Receiver); } virtual void Detach(void) { m_Device->Detach(m_Receiver); }
// Statistical purposes: // Statistical purposes:
@ -66,7 +70,7 @@ public:
inline void cStreamdevLiveReceiver::Activate(bool On) inline void cStreamdevLiveReceiver::Activate(bool On)
{ {
Dprintf("LiveReceiver->Activate()\n"); Dprintf("LiveReceiver->Activate(%d)\n", On);
m_Streamer->Activate(On); m_Streamer->Activate(On);
} }

View File

@ -1,5 +1,5 @@
/* /*
* $Id: streamer.c,v 1.6 2005/02/10 22:24:26 lordjaxom Exp $ * $Id: streamer.c,v 1.7 2005/02/11 16:44:15 lordjaxom Exp $
*/ */
#include <vdr/ringbuffer.h> #include <vdr/ringbuffer.h>
@ -68,6 +68,7 @@ cStreamdevStreamer::cStreamdevStreamer(const char *Name):
cStreamdevStreamer::~cStreamdevStreamer() cStreamdevStreamer::~cStreamdevStreamer()
{ {
Dprintf("Desctructing streamer\n");
Stop(); Stop();
delete m_RingBuffer; delete m_RingBuffer;
delete m_Writer; delete m_Writer;
@ -83,8 +84,8 @@ void cStreamdevStreamer::Start(cTBSocket *Socket)
void cStreamdevStreamer::Activate(bool On) void cStreamdevStreamer::Activate(bool On)
{ {
Dprintf("activate streamer\n");
if (On && !m_Active) { if (On && !m_Active) {
Dprintf("activate streamer\n");
m_Writer->Start(); m_Writer->Start();
cThread::Start(); cThread::Start();
} }
@ -93,10 +94,11 @@ void cStreamdevStreamer::Activate(bool On)
void cStreamdevStreamer::Stop(void) void cStreamdevStreamer::Stop(void)
{ {
if (m_Active) { if (m_Active) {
Dprintf("stopping live streamer\n"); Dprintf("stopping streamer\n");
m_Active = false; m_Active = false;
Cancel(3); Cancel(3);
} }
DELETENULL(m_Writer);
} }
void cStreamdevStreamer::Action(void) void cStreamdevStreamer::Action(void)

View File

@ -1,5 +1,5 @@
/* /*
* $Id: streamer.h,v 1.4 2005/02/10 22:24:26 lordjaxom Exp $ * $Id: streamer.h,v 1.5 2005/02/11 16:44:15 lordjaxom Exp $
*/ */
#ifndef VDR_STREAMDEV_STREAMER_H #ifndef VDR_STREAMDEV_STREAMER_H
@ -13,7 +13,7 @@ class cTBSocket;
class cStreamdevStreamer; class cStreamdevStreamer;
#define STREAMERBUFSIZE MEGABYTE(4) #define STREAMERBUFSIZE MEGABYTE(4)
#define WRITERBUFSIZE KILOBYTE(192) #define WRITERBUFSIZE KILOBYTE(256)
// --- cStreamdevWriter ------------------------------------------------------- // --- cStreamdevWriter -------------------------------------------------------