- added namespace to remuxers

- increased WRITERBUFSIZE - buffer was too small for high bandwidth content
- removed cStreamdevStreamer::m_Running
- eliminated potential busy waits in remuxers
- updated cTSRemux static helpers to code of their VDR 1.6.0 counterparts
- re-enabled PES vor VDR 1.7.3+. Streamdev now uses a copy of VDR 1.6.0's
  cRemux for TS to PES remuxing.
- make sure that only complete TS packets are written to ringbuffers
- use signaling instead of sleeps when writing to ringbuffers
- optimized cStreamdevPatFilter PAT packet initialization
- fixed cStreamdevPatFilter not processing PATs with length > TS_SIZE - 5
- use a small ringbuffer for cStreamdevPatFilter instead of writing to
  cStreamdevStreamers SendBuffer as two threads mustn't write to the same
  ringbuffer

Modified Files:
	CONTRIBUTORS HISTORY Makefile common.c common.h
	streamdev-server.c libdvbmpeg/transform.h remux/extern.c
	remux/extern.h remux/ts2es.c remux/ts2es.h remux/ts2ps.c
	remux/ts2ps.h remux/tsremux.c remux/tsremux.h
	server/connectionHTTP.c server/connectionVTP.c
	server/livestreamer.c server/livestreamer.h server/menuHTTP.c
	server/streamer.c server/streamer.h
Added Files:
	remux/ts2pes.c remux/ts2pes.h
This commit is contained in:
schmirl
2009-06-19 06:32:38 +00:00
parent 64ff2c08be
commit 008e7c8510
24 changed files with 2339 additions and 164 deletions

View File

@@ -7,6 +7,8 @@
#include <signal.h>
#include <unistd.h>
namespace Streamdev {
class cTSExt: public cThread {
private:
cRingBufferLinear *m_ResultBuffer;
@@ -24,6 +26,9 @@ public:
void Put(const uchar *Data, int Count);
};
} // namespace Streamdev
using namespace Streamdev;
cTSExt::cTSExt(cRingBufferLinear *ResultBuffer, std::string Parameter):
m_ResultBuffer(ResultBuffer),
m_Active(false),

View File

@@ -5,6 +5,8 @@
#include <vdr/ringbuffer.h>
#include <string>
namespace Streamdev {
class cTSExt;
class cExternRemux: public cTSRemux {
@@ -21,4 +23,6 @@ public:
void Del(int Count) { m_ResultBuffer->Del(Count); }
};
} // namespace Streamdev
#endif // VDR_STREAMDEV_EXTERNREMUX_H

View File

@@ -1,12 +1,13 @@
#include "remux/ts2es.h"
#include "server/streamer.h"
#include "libdvbmpeg/transform.h"
#include "common.h"
#include <vdr/device.h>
// from VDR's remux.c
#define MAXNONUSEFULDATA (10*1024*1024)
namespace Streamdev {
class cTS2ES: public ipack {
friend void PutES(uint8_t *Buffer, int Size, void *Data);
@@ -32,6 +33,9 @@ void PutES(uint8_t *Buffer, int Size, void *Data)
This->start = 1;
}
} // namespace Streamdev
using namespace Streamdev;
cTS2ES::cTS2ES(cRingBufferLinear *ResultBuffer)
{
m_ResultBuffer = ResultBuffer;
@@ -75,10 +79,10 @@ void cTS2ES::PutTSPacket(const uint8_t *Buffer) {
cTS2ESRemux::cTS2ESRemux(int Pid):
m_Pid(Pid),
m_ResultBuffer(new cRingBufferLinear(WRITERBUFSIZE, IPACKS)),
m_ResultBuffer(new cStreamdevBuffer(WRITERBUFSIZE, IPACKS)),
m_Remux(new cTS2ES(m_ResultBuffer))
{
m_ResultBuffer->SetTimeouts(0, 100);
m_ResultBuffer->SetTimeouts(100, 100);
}
cTS2ESRemux::~cTS2ESRemux()
@@ -111,8 +115,10 @@ int cTS2ESRemux::Put(const uchar *Data, int Count)
break;
if (Data[i] != TS_SYNC_BYTE)
break;
if (m_ResultBuffer->Free() < 2 * IPACKS)
if (m_ResultBuffer->Free() < 2 * IPACKS) {
m_ResultBuffer->WaitForPut();
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)

View File

@@ -2,15 +2,16 @@
#define VDR_STREAMDEV_TS2ESREMUX_H
#include "remux/tsremux.h"
#include <vdr/ringbuffer.h>
#include "server/streamer.h"
namespace Streamdev {
class cTS2ES;
class cRingBufferLinear;
class cTS2ESRemux: public cTSRemux {
private:
int m_Pid;
cRingBufferLinear *m_ResultBuffer;
cStreamdevBuffer *m_ResultBuffer;
cTS2ES *m_Remux;
public:
@@ -22,4 +23,6 @@ public:
void Del(int Count) { m_ResultBuffer->Del(Count); }
};
} // namespace Streamdev
#endif // VDR_STREAMDEV_TS2ESREMUX_H

2035
remux/ts2pes.c Normal file

File diff suppressed because it is too large Load Diff

58
remux/ts2pes.h Normal file
View File

@@ -0,0 +1,58 @@
/*
* ts2pes.h: A streaming MPEG2 remultiplexer
*
* This file is based on a copy of remux.h from Klaus Schmidinger's
* VDR, version 1.6.0.
*
* $Id: ts2pes.h,v 1.1 2009/06/19 06:32:40 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_TS2PES_H
#define VDR_STREAMDEV_TS2PES_H
#include "remux/tsremux.h"
#include "server/streamer.h"
#define MAXTRACKS 64
namespace Streamdev {
class cTS2PES;
class cTS2PESRemux: public cTSRemux {
private:
bool noVideo;
bool synced;
int skipped;
Streamdev::cTS2PES *ts2pes[MAXTRACKS];
int numTracks;
cStreamdevBuffer *resultBuffer;
int resultSkipped;
public:
cTS2PESRemux(int VPid, const int *APids, const int *DPids, const int *SPids);
///< Creates a new remuxer for the given PIDs. VPid is the video PID, while
///< APids, DPids and SPids are pointers to zero terminated lists of audio,
///< dolby and subtitle PIDs (the pointers may be NULL if there is no such
///< PID).
~cTS2PESRemux();
int Put(const uchar *Data, int Count);
///< Puts at most Count bytes of Data into the remuxer.
///< \return Returns the number of bytes actually consumed from Data.
uchar *Get(int &Count, uchar *PictureType = NULL);
///< Gets all currently available data from the remuxer.
///< \return Count contains the number of bytes the result points to, and
///< PictureType (if not NULL) will contain one of NO_PICTURE, I_FRAME, P_FRAME
///< or B_FRAME.
void Del(int Count);
///< Deletes Count bytes from the remuxer. Count must be the number returned
///< from a previous call to Get(). Several calls to Del() with fractions of
///< a previously returned Count may be made, but the total sum of all Count
///< values must be exactly what the previous Get() has returned.
void Clear(void);
///< Clears the remuxer of all data it might still contain, keeping the PID
///< settings as they are.
};
} // namespace Streamdev
#endif // VDR_STREAMDEV_TS2PES_H

View File

@@ -3,6 +3,8 @@
#include <vdr/channels.h>
#include <vdr/device.h>
namespace Streamdev {
class cTS2PS {
friend void PutPES(uint8_t *Buffer, int Size, void *Data);
@@ -28,6 +30,9 @@ void PutPES(uint8_t *Buffer, int Size, void *Data)
esyslog("ERROR: result buffer overflow, dropped %d out of %d byte", Size - n, Size);
}
} // namespace Streamdev
using namespace Streamdev;
cTS2PS::cTS2PS(cRingBufferLinear *ResultBuffer, int Pid, uint8_t AudioCid)
{
m_ResultBuffer = ResultBuffer;
@@ -74,13 +79,13 @@ void cTS2PS::PutTSPacket(const uint8_t *Buffer)
cTS2PSRemux::cTS2PSRemux(int VPid, const int *APids, const int *DPids, const int *SPids):
m_NumTracks(0),
m_ResultBuffer(new cRingBufferLinear(WRITERBUFSIZE, IPACKS)),
m_ResultBuffer(new cStreamdevBuffer(WRITERBUFSIZE, IPACKS)),
m_ResultSkipped(0),
m_Skipped(0),
m_Synced(false),
m_IsRadio(VPid == 0 || VPid == 1 || VPid == 0x1FFF)
{
m_ResultBuffer->SetTimeouts(0, 100);
m_ResultBuffer->SetTimeouts(100, 100);
if (VPid)
m_Remux[m_NumTracks++] = new cTS2PS(m_ResultBuffer, VPid);
@@ -124,8 +129,10 @@ int cTS2PSRemux::Put(const uchar *Data, int Count)
break;
if (Data[i] != TS_SYNC_BYTE)
break;
if (m_ResultBuffer->Free() < 2 * IPACKS)
if (m_ResultBuffer->Free() < 2 * IPACKS) {
m_ResultBuffer->WaitForPut();
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++) {

View File

@@ -2,20 +2,21 @@
#define VDR_STREAMDEV_TS2PESREMUX_H
#include "remux/tsremux.h"
#include <vdr/remux.h>
#include <vdr/ringbuffer.h>
#include "server/streamer.h"
#ifndef MAXTRACKS
#define MAXTRACKS 64
#endif
namespace Streamdev {
class cTS2PS;
class cTS2PSRemux: public cTSRemux {
private:
int m_NumTracks;
cTS2PS *m_Remux[MAXTRACKS];
cRingBufferLinear *m_ResultBuffer;
cStreamdevBuffer *m_ResultBuffer;
int m_ResultSkipped;
int m_Skipped;
bool m_Synced;
@@ -30,4 +31,6 @@ public:
void Del(int Count) { m_ResultBuffer->Del(Count); }
};
} // namespace Streamdev
#endif // VDR_STREAMDEV_TS2PESREMUX_H

View File

@@ -2,11 +2,15 @@
#define SC_PICTURE 0x00 // "picture header"
#define PID_MASK_HI 0x1F
#define VIDEO_STREAM_S 0xE0
using namespace Streamdev;
void cTSRemux::SetBrokenLink(uchar *Data, int Length)
{
if (Length > 9 && Data[0] == 0 && Data[1] == 0 && Data[2] == 1 && (Data[3] & 0xF0) == VIDEO_STREAM_S) {
for (int i = Data[8] + 9; i < Length - 7; i++) { // +9 to skip video packet header
int PesPayloadOffset = 0;
if (AnalyzePesHeader(Data, Length, PesPayloadOffset) >= phMPEG1 && (Data[3] & 0xF0) == VIDEO_STREAM_S) {
for (int i = PesPayloadOffset; i < Length - 7; i++) {
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
Data[i + 7] |= 0x20;
@@ -40,17 +44,40 @@ int cTSRemux::ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &P
// 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;
int PesPayloadOffset = 0;
if (AnalyzePesHeader(Data + Offset, Length, PesPayloadOffset) >= phMPEG1) {
const uchar *p = Data + Offset + PesPayloadOffset + 2;
const uchar *pLimit = Data + Offset + Length - 3;
#ifdef TEST_cVideoRepacker
// cVideoRepacker ensures that a new PES packet is started for a new sequence,
// group or picture which allows us to easily skip scanning through a huge
// amount of video data.
if (p < pLimit) {
if (p[-2] || p[-1] || p[0] != 0x01)
pLimit = 0; // skip scanning: packet doesn't start with 0x000001
else {
switch (p[1]) {
case SC_SEQUENCE:
case SC_GROUP:
case SC_PICTURE:
break;
default: // skip scanning: packet doesn't start a new sequence, group or picture
pLimit = 0;
}
}
}
#endif
while (p < pLimit && (p = (const uchar *)memchr(p, 0x01, pLimit - p))) {
if (!p[-2] && !p[-1]) { // found 0x000001
switch (p[1]) {
case SC_PICTURE: PictureType = (p[3] >> 3) & 0x07;
return Length;
}
p += 4; // continue scanning after 0x01ssxxyy
}
}
}
else
p += 3; // continue scanning after 0x01xxyy
}
}
PictureType = NO_PICTURE;
return Length;

View File

@@ -4,34 +4,22 @@
#include "libdvbmpeg/transform.h"
#include <vdr/remux.h>
#ifndef NO_PICTURE
// Picture types:
#define NO_PICTURE 0
#endif
#define I_FRAME 1
#define P_FRAME 2
#define B_FRAME 3
#define RESULTBUFFERSIZE KILOBYTE(256)
namespace Streamdev {
class cTSRemux {
protected:
/*uchar m_ResultBuffer[RESULTBUFFERSIZE];
int m_ResultCount;
int m_ResultDelivered;
int m_Synced;
int m_Skipped;
int m_Sync;
virtual void PutTSPacket(int Pid, const uint8_t *Data) = 0;
public:
cTSRemux(bool Sync = true);
virtual ~cTSRemux();
virtual uchar *Process(const uchar *Data, int &Count, int &Result);*/
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 GetPacketLength(const uchar *Data, int Count, int Offset);
static int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType);
};
} // namespace Streamdev
#endif // VDR_STREAMDEV_TSREMUX_H