mirror of
https://projects.vdr-developer.org/git/vdr-plugin-streamdev.git
synced 2023-10-10 17:16:51 +00:00
- 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:
@@ -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),
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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
2035
remux/ts2pes.c
Normal file
File diff suppressed because it is too large
Load Diff
58
remux/ts2pes.h
Normal file
58
remux/ts2pes.h
Normal 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
|
@@ -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++) {
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user