summaryrefslogtreecommitdiff
path: root/remux.h
diff options
context:
space:
mode:
authorKlaus Schmidinger <kls (at) cadsoft (dot) de>2009-01-06 20:31:53 +0100
committerKlaus Schmidinger <kls (at) cadsoft (dot) de>2009-01-06 20:31:53 +0100
commitc2966475942fcb9d4b8d41dbf026ff57630a1ad6 (patch)
tree1b41925820073ddee361c5acb0fd68fbadcd11a8 /remux.h
parent1834751c4510edb66c96d0b741def5922738e74c (diff)
downloadvdr-patch-lnbsharing-c2966475942fcb9d4b8d41dbf026ff57630a1ad6.tar.gz
vdr-patch-lnbsharing-c2966475942fcb9d4b8d41dbf026ff57630a1ad6.tar.bz2
Version 1.7.3vdr-1.7.3
- Updated the Russian OSD texts (thanks to Oleg Roitburd). - Fixed handling the 'pointer field' in generating and parsing PAT/PMT (thanks to Frank Schmirler). - Fixed handling modulation types for DVB-S transponders when processing the NIT. - Changed cDvbDevice::GrabImage() to use V4L2 (thanks to Marco Schlüßler). - Added a poll to cDvbDevice::PlayVideo() and cDvbDevice::PlayAudio() to avoid excessive CPU load (this is just a makeshift solution until the FF DVB cards can play TS directly). - The recording format is now Transport Stream. Existing recordings in PES format can still be replayed and edited, but new recordings are done in TS. All code for recording in PES has been removed. The following changes were made to switch to TS recording format: + The index file format has been changed to support file sizes of up to 1TB (previously 2GB), and up to 65535 separate files per recording (previously 255). + The recording file names are now of the form 00001.ts (previously 001.vdr). + The frame rate is now detected by looking at two subsequent PTS values. The "frame duration" (in multiples of 1/90000) is stored in the info.vdr file using the new tag F (thanks to Artur Skawina for helping to get the IndexToHMSF() calculation right). + Several functions now have an additional parameter FramesPerSecond. + Several functions now have an additional parameter IsPesRecording. + The functionality of cFileWriter was moved into cRecorder, and cRemux is now obsolete. This also avoids one level of data copying while recording. + cRemux, cRingBufferLinearPes, cTS2PES and all c*Repacker classes have been removed. + A PAT/PMT is inserted before every independent frame, so that no extra measures need to be taken when editing a recording. + The directory name for a recording has been changed from YYYY-MM-DD-hh[.:]mm.pr.lt.rec (pr=priority, lt=lifetime) to YYYY-MM-DD-hh.mm.ch-ri.rec (ch=channel, ri=resumeId). Priority and Lifetime are now stored in the info.vdr file with the new tags P and L (if no such file exists, the maximum values are assumed by default, which avoids inadvertently deleting a recording if disk space is low). No longer storing Priority and Lifetime in the directory name avoids starting a new recording if one of these is changed in the timer and the recording is re-started for some reason. Instead of Priority and Lifetime, the directory name now contains the channel number from which the recording was made, and the "resume id" of this instance of VDR. This avoids problems if several VDR instances record the same show on different channels, or even on the same channel. The '-' between channel number and resumeId prevents older versions of VDR from "seeing" these recordings, which makes sure they won't even try to replay them, or remove them in case the disk runs full. + The semantics of PlayTs*() have been changed. These functions are now required to return the given Length (which is TS_SIZE) if they have processed the TS packet. + The files "index", "info", "marks" and "resume" within a TS recording directory are now created without the ".vdr" extension. + The "resume" file is no longer a binary file, but contains tagged lines to be able to store additional information, like the selected audio or subtitle track. + cDevice::StillPicture() will now be called with either TS or PES data. + cDvbPlayer::Goto() no longer appends a "sequence end code" to the data. If the output device needs this, it has to take care of it by itself. - Fixed cPatPmtParser::ParsePmt() to reset vpid and vtype when switching from a video to an audio channel (thanks to Reinhard Nissl). - cDvbDevice now uses the FE_CAN_2G_MODULATION flag to determine whether a device can handle DVB-S2. The #define is still there to allow people with older drivers who don't need DVB-S2 to use this version without pathcing.
Diffstat (limited to 'remux.h')
-rw-r--r--remux.h149
1 files changed, 79 insertions, 70 deletions
diff --git a/remux.h b/remux.h
index f471504..9a0921d 100644
--- a/remux.h
+++ b/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
-
-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