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 | 
