diff options
Diffstat (limited to 'remux.h')
-rw-r--r-- | remux.h | 149 |
1 files changed, 79 insertions, 70 deletions
@@ -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 - -inline int TsHasPayload(const uchar *p) +#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 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 |