mirror of
https://github.com/vdr-projects/vdr.git
synced 2025-03-01 10:50:46 +00:00
The recording format is now Transport Stream
This commit is contained in:
147
remux.h
147
remux.h
@@ -1,17 +1,16 @@
|
||||
/*
|
||||
* remux.h: A streaming MPEG2 remultiplexer
|
||||
* remux.h: Tools for detecting frames and handling PAT/PMT
|
||||
*
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: remux.h 2.3 2008/12/13 13:55:07 kls Exp $
|
||||
* $Id: remux.h 2.4 2009/01/06 12:40:43 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __REMUX_H
|
||||
#define __REMUX_H
|
||||
|
||||
#include "channels.h"
|
||||
#include "ringbuffer.h"
|
||||
#include "tools.h"
|
||||
|
||||
enum ePesHeader {
|
||||
@@ -23,61 +22,9 @@ enum ePesHeader {
|
||||
|
||||
ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader = NULL);
|
||||
|
||||
// Picture types:
|
||||
#define NO_PICTURE 0
|
||||
#define I_FRAME 1
|
||||
#define P_FRAME 2
|
||||
#define B_FRAME 3
|
||||
|
||||
#define MAXTRACKS 64
|
||||
|
||||
class cTS2PES;
|
||||
|
||||
class cRemux {
|
||||
private:
|
||||
bool exitOnFailure;
|
||||
bool noVideo;
|
||||
int numUPTerrors;
|
||||
bool synced;
|
||||
int skipped;
|
||||
cTS2PES *ts2pes[MAXTRACKS];
|
||||
int numTracks;
|
||||
cRingBufferLinear *resultBuffer;
|
||||
int resultSkipped;
|
||||
int GetPid(const uchar *Data);
|
||||
public:
|
||||
cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false);
|
||||
///< 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). If ExitOnFailure is true, the remuxer will initiate an "emergency
|
||||
///< exit" in case of problems with the data stream.
|
||||
~cRemux();
|
||||
void SetTimeouts(int PutTimeout, int GetTimeout) { resultBuffer->SetTimeouts(PutTimeout, GetTimeout); }
|
||||
///< By default cRemux assumes that Put() and Get() are called from different
|
||||
///< threads, and uses a timeout in the Get() function in case there is no
|
||||
///< data available. SetTimeouts() can be used to modify these timeouts.
|
||||
///< Especially if Put() and Get() are called from the same thread, setting
|
||||
///< both timeouts to 0 is recommended.
|
||||
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.
|
||||
static void SetBrokenLink(uchar *Data, int Length);
|
||||
static int GetPacketLength(const uchar *Data, int Count, int Offset);
|
||||
static int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType);
|
||||
};
|
||||
|
||||
// Some TS handling tools.
|
||||
@@ -85,24 +32,39 @@ public:
|
||||
|
||||
#define TS_SYNC_BYTE 0x47
|
||||
#define TS_SIZE 188
|
||||
#define TS_ERROR 0x80
|
||||
#define TS_PAYLOAD_START 0x40
|
||||
#define TS_TRANSPORT_PRIORITY 0x20
|
||||
#define TS_PID_MASK_HI 0x1F
|
||||
#define TS_SCRAMBLING_CONTROL 0xC0
|
||||
#define TS_ADAPT_FIELD_EXISTS 0x20
|
||||
#define TS_PAYLOAD_EXISTS 0x10
|
||||
#define TS_CONT_CNT_MASK 0x0F
|
||||
#define TS_PAYLOAD_START 0x40
|
||||
#define TS_ERROR 0x80
|
||||
#define TS_PID_MASK_HI 0x1F
|
||||
#define TS_ADAPT_DISCONT 0x80
|
||||
#define TS_ADAPT_RANDOM_ACC 0x40 // would be perfect for detecting independent frames, but unfortunately not used by all broadcasters
|
||||
#define TS_ADAPT_ELEM_PRIO 0x20
|
||||
#define TS_ADAPT_PCR 0x10
|
||||
#define TS_ADAPT_OPCR 0x08
|
||||
#define TS_ADAPT_SPLICING 0x04
|
||||
#define TS_ADAPT_TP_PRIVATE 0x02
|
||||
#define TS_ADAPT_EXTENSION 0x01
|
||||
|
||||
inline int TsHasPayload(const uchar *p)
|
||||
inline bool TsHasPayload(const uchar *p)
|
||||
{
|
||||
return p[3] & TS_PAYLOAD_EXISTS;
|
||||
}
|
||||
|
||||
inline int TsPayloadStart(const uchar *p)
|
||||
inline bool TsHasAdaptationField(const uchar *p)
|
||||
{
|
||||
return p[3] & TS_ADAPT_FIELD_EXISTS;
|
||||
}
|
||||
|
||||
inline bool TsPayloadStart(const uchar *p)
|
||||
{
|
||||
return p[1] & TS_PAYLOAD_START;
|
||||
}
|
||||
|
||||
inline int TsError(const uchar *p)
|
||||
inline bool TsError(const uchar *p)
|
||||
{
|
||||
return p[1] & TS_ERROR;
|
||||
}
|
||||
@@ -112,6 +74,11 @@ inline int TsPid(const uchar *p)
|
||||
return (p[1] & TS_PID_MASK_HI) * 256 + p[2];
|
||||
}
|
||||
|
||||
inline bool TsIsScrambled(const uchar *p)
|
||||
{
|
||||
return p[3] & TS_SCRAMBLING_CONTROL;
|
||||
}
|
||||
|
||||
inline int TsPayloadOffset(const uchar *p)
|
||||
{
|
||||
return (p[3] & TS_ADAPT_FIELD_EXISTS) ? p[4] + 5 : 4;
|
||||
@@ -129,6 +96,11 @@ inline int TsContinuityCounter(const uchar *p)
|
||||
return p[3] & TS_CONT_CNT_MASK;
|
||||
}
|
||||
|
||||
inline int TsGetAdaptationField(const uchar *p)
|
||||
{
|
||||
return TsHasAdaptationField(p) ? p[5] : 0x00;
|
||||
}
|
||||
|
||||
// Some PES handling tools:
|
||||
// The following functions that take a pointer to PES data all assume that
|
||||
// there is enough data so that PesLongEnough() returns true.
|
||||
@@ -153,16 +125,18 @@ inline int PesPayloadOffset(const uchar *p)
|
||||
return 9 + p[8];
|
||||
}
|
||||
|
||||
inline bool PesHasPts(const uchar *p)
|
||||
{
|
||||
return (p[7] & 0x80) && p[8] >= 5;
|
||||
}
|
||||
|
||||
inline int64_t PesGetPts(const uchar *p)
|
||||
{
|
||||
if ((p[7] & 0x80) && p[8] >= 5) {
|
||||
return ((((int64_t)p[ 9]) & 0x0E) << 29) |
|
||||
(( (int64_t)p[10]) << 22) |
|
||||
((((int64_t)p[11]) & 0xFE) << 14) |
|
||||
(( (int64_t)p[12]) << 7) |
|
||||
((((int64_t)p[13]) & 0xFE) >> 1);
|
||||
}
|
||||
return 0;
|
||||
return ((((int64_t)p[ 9]) & 0x0E) << 29) |
|
||||
(( (int64_t)p[10]) << 22) |
|
||||
((((int64_t)p[11]) & 0xFE) << 14) |
|
||||
(( (int64_t)p[12]) << 7) |
|
||||
((((int64_t)p[13]) & 0xFE) >> 1);
|
||||
}
|
||||
|
||||
// PAT/PMT Generator:
|
||||
@@ -274,4 +248,39 @@ void BlockDump(const char *Name, const u_char *Data, int Length);
|
||||
void TsDump(const char *Name, const u_char *Data, int Length);
|
||||
void PesDump(const char *Name, const u_char *Data, int Length);
|
||||
|
||||
// Frame detector:
|
||||
|
||||
class cFrameDetector {
|
||||
private:
|
||||
int pid;
|
||||
int type;
|
||||
bool newFrame;
|
||||
bool independentFrame;
|
||||
int64_t lastPts;
|
||||
bool isVideo;
|
||||
int frameDuration;
|
||||
int framesPerPayloadUnit;
|
||||
bool scanning;
|
||||
uint32_t scanner;
|
||||
public:
|
||||
cFrameDetector(int Pid, int Type);
|
||||
int Analyze(const uchar *Data, int Length);
|
||||
///< Analyzes the TS packets pointed to by Data. Length is the number of
|
||||
///< bytes Data points to, and must be a multiple of 188.
|
||||
///< Returns the number of bytes that have been analyzed and may be written
|
||||
///< to the recording file. If the return value is 0, the data was not
|
||||
///< sufficient for analyzing and Analyze() needs to be called again with
|
||||
///< more actual data.
|
||||
bool NewFrame(void) { return newFrame; }
|
||||
///< Returns true if the data given to the last call to Analyze() started a
|
||||
///< new frame.
|
||||
bool IndependentFrame(void) { return independentFrame; }
|
||||
///< Returns true if a new frame was detected and this is an independent frame
|
||||
///< (i.e. one that can be displayed by itself, without using data from any
|
||||
///< other frames).
|
||||
double FramesPerSecond(void) { return frameDuration ? 90000.0 / frameDuration : 0; }
|
||||
///< Returns the number of frames per second, or 0 if this information is not
|
||||
///< available.
|
||||
};
|
||||
|
||||
#endif // __REMUX_H
|
||||
|
||||
Reference in New Issue
Block a user