From c2966475942fcb9d4b8d41dbf026ff57630a1ad6 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Tue, 6 Jan 2009 20:31:53 +0100 Subject: =?UTF-8?q?Version=201.7.3=20-=20Updated=20the=20Russian=20OSD=20t?= =?UTF-8?q?exts=20(thanks=20to=20Oleg=20Roitburd).=20-=20Fixed=20handling?= =?UTF-8?q?=20the=20'pointer=20field'=20in=20generating=20and=20parsing=20?= =?UTF-8?q?PAT/PMT=20(thanks=20to=20=20=20Frank=20Schmirler).=20-=20Fixed?= =?UTF-8?q?=20handling=20modulation=20types=20for=20DVB-S=20transponders?= =?UTF-8?q?=20when=20processing=20the=20NIT.=20-=20Changed=20cDvbDevice::G?= =?UTF-8?q?rabImage()=20to=20use=20V4L2=20(thanks=20to=20Marco=20Schl=FC?= =?UTF-8?q?=DFler).=20-=20Added=20a=20poll=20to=20cDvbDevice::PlayVideo()?= =?UTF-8?q?=20and=20cDvbDevice::PlayAudio()=20to=20avoid=20=20=20excessive?= =?UTF-8?q?=20CPU=20load=20(this=20is=20just=20a=20makeshift=20solution=20?= =?UTF-8?q?until=20the=20FF=20DVB=20cards=20=20=20can=20play=20TS=20direct?= =?UTF-8?q?ly).=20-=20The=20recording=20format=20is=20now=20Transport=20St?= =?UTF-8?q?ream.=20Existing=20recordings=20in=20PES=20format=20=20=20can?= =?UTF-8?q?=20still=20be=20replayed=20and=20edited,=20but=20new=20recordin?= =?UTF-8?q?gs=20are=20done=20in=20TS.=20=20=20All=20code=20for=20recording?= =?UTF-8?q?=20in=20PES=20has=20been=20removed.=20=20=20The=20following=20c?= =?UTF-8?q?hanges=20were=20made=20to=20switch=20to=20TS=20recording=20form?= =?UTF-8?q?at:=20=20=20+=20The=20index=20file=20format=20has=20been=20chan?= =?UTF-8?q?ged=20to=20support=20file=20sizes=20of=20up=20to=201TB=20=20=20?= =?UTF-8?q?=20=20(previously=202GB),=20and=20up=20to=2065535=20separate=20?= =?UTF-8?q?files=20per=20recording=20(previously=20=20=20=20=20255).=20=20?= =?UTF-8?q?=20+=20The=20recording=20file=20names=20are=20now=20of=20the=20?= =?UTF-8?q?form=2000001.ts=20(previously=20001.vdr).=20=20=20+=20The=20fra?= =?UTF-8?q?me=20rate=20is=20now=20detected=20by=20looking=20at=20two=20sub?= =?UTF-8?q?sequent=20PTS=20values.=20=20=20=20=20The=20"frame=20duration"?= =?UTF-8?q?=20(in=20multiples=20of=201/90000)=20is=20stored=20in=20the=20i?= =?UTF-8?q?nfo.vdr=20=20=20=20=20file=20using=20the=20new=20tag=20F=20(tha?= =?UTF-8?q?nks=20to=20Artur=20Skawina=20for=20helping=20to=20get=20the=20?= =?UTF-8?q?=20=20=20=20IndexToHMSF()=20calculation=20right).=20=20=20+=20S?= =?UTF-8?q?everal=20functions=20now=20have=20an=20additional=20parameter?= =?UTF-8?q?=20FramesPerSecond.=20=20=20+=20Several=20functions=20now=20hav?= =?UTF-8?q?e=20an=20additional=20parameter=20IsPesRecording.=20=20=20+=20T?= =?UTF-8?q?he=20functionality=20of=20cFileWriter=20was=20moved=20into=20cR?= =?UTF-8?q?ecorder,=20and=20cRemux=20is=20=20=20=20=20now=20obsolete.=20Th?= =?UTF-8?q?is=20also=20avoids=20one=20level=20of=20data=20copying=20while?= =?UTF-8?q?=20recording.=20=20=20+=20cRemux,=20cRingBufferLinearPes,=20cTS?= =?UTF-8?q?2PES=20and=20all=20c*Repacker=20classes=20have=20been=20=20=20?= =?UTF-8?q?=20=20removed.=20=20=20+=20A=20PAT/PMT=20is=20inserted=20before?= =?UTF-8?q?=20every=20independent=20frame,=20so=20that=20no=20extra=20=20?= =?UTF-8?q?=20=20=20measures=20need=20to=20be=20taken=20when=20editing=20a?= =?UTF-8?q?=20recording.=20=20=20+=20The=20directory=20name=20for=20a=20re?= =?UTF-8?q?cording=20has=20been=20changed=20from=20=20=20=20=20YYYY-MM-DD-?= =?UTF-8?q?hh[.:]mm.pr.lt.rec=20(pr=3Dpriority,=20lt=3Dlifetime)=20to=20?= =?UTF-8?q?=20=20=20=20YYYY-MM-DD-hh.mm.ch-ri.rec=20(ch=3Dchannel,=20ri=3D?= =?UTF-8?q?resumeId).=20=20=20=20=20Priority=20and=20Lifetime=20are=20now?= =?UTF-8?q?=20stored=20in=20the=20info.vdr=20file=20with=20the=20new=20=20?= =?UTF-8?q?=20=20=20tags=20P=20and=20L=20(if=20no=20such=20file=20exists,?= =?UTF-8?q?=20the=20maximum=20values=20are=20assumed=20by=20=20=20=20=20de?= =?UTF-8?q?fault,=20which=20avoids=20inadvertently=20deleting=20a=20record?= =?UTF-8?q?ing=20if=20disk=20space=20=20=20=20=20is=20low).=20No=20longer?= =?UTF-8?q?=20storing=20Priority=20and=20Lifetime=20in=20the=20directory?= =?UTF-8?q?=20name=20=20=20=20=20avoids=20starting=20a=20new=20recording?= =?UTF-8?q?=20if=20one=20of=20these=20is=20changed=20in=20the=20timer=20?= =?UTF-8?q?=20=20=20=20and=20the=20recording=20is=20re-started=20for=20som?= =?UTF-8?q?e=20reason.=20=20=20=20=20Instead=20of=20Priority=20and=20Lifet?= =?UTF-8?q?ime,=20the=20directory=20name=20now=20contains=20the=20=20=20?= =?UTF-8?q?=20=20channel=20number=20from=20which=20the=20recording=20was?= =?UTF-8?q?=20made,=20and=20the=20"resume=20id"=20of=20=20=20=20=20this=20?= =?UTF-8?q?instance=20of=20VDR.=20This=20avoids=20problems=20if=20several?= =?UTF-8?q?=20VDR=20instances=20record=20=20=20=20=20the=20same=20show=20o?= =?UTF-8?q?n=20different=20channels,=20or=20even=20on=20the=20same=20chann?= =?UTF-8?q?el.=20=20=20=20=20The=20'-'=20between=20channel=20number=20and?= =?UTF-8?q?=20resumeId=20prevents=20older=20versions=20of=20=20=20=20=20VD?= =?UTF-8?q?R=20from=20"seeing"=20these=20recordings,=20which=20makes=20sur?= =?UTF-8?q?e=20they=20won't=20even=20try=20=20=20=20=20to=20replay=20them,?= =?UTF-8?q?=20or=20remove=20them=20in=20case=20the=20disk=20runs=20full.?= =?UTF-8?q?=20=20=20+=20The=20semantics=20of=20PlayTs*()=20have=20been=20c?= =?UTF-8?q?hanged.=20These=20functions=20are=20now=20=20=20=20=20required?= =?UTF-8?q?=20to=20return=20the=20given=20Length=20(which=20is=20TS=5FSIZE?= =?UTF-8?q?)=20if=20they=20have=20=20=20=20=20processed=20the=20TS=20packe?= =?UTF-8?q?t.=20=20=20+=20The=20files=20"index",=20"info",=20"marks"=20and?= =?UTF-8?q?=20"resume"=20within=20a=20TS=20recording=20=20=20=20=20directo?= =?UTF-8?q?ry=20are=20now=20created=20without=20the=20".vdr"=20extension.?= =?UTF-8?q?=20=20=20+=20The=20"resume"=20file=20is=20no=20longer=20a=20bin?= =?UTF-8?q?ary=20file,=20but=20contains=20tagged=20lines=20=20=20=20=20to?= =?UTF-8?q?=20be=20able=20to=20store=20additional=20information,=20like=20?= =?UTF-8?q?the=20selected=20audio=20or=20=20=20=20=20subtitle=20track.=20?= =?UTF-8?q?=20=20+=20cDevice::StillPicture()=20will=20now=20be=20called=20?= =?UTF-8?q?with=20either=20TS=20or=20PES=20data.=20=20=20+=20cDvbPlayer::G?= =?UTF-8?q?oto()=20no=20longer=20appends=20a=20"sequence=20end=20code"=20t?= =?UTF-8?q?o=20the=20data.=20=20=20=20=20If=20the=20output=20device=20need?= =?UTF-8?q?s=20this,=20it=20has=20to=20take=20care=20of=20it=20by=20itself?= =?UTF-8?q?.=20-=20Fixed=20cPatPmtParser::ParsePmt()=20to=20reset=20vpid?= =?UTF-8?q?=20and=20vtype=20when=20switching=20from=20=20=20a=20video=20to?= =?UTF-8?q?=20an=20audio=20channel=20(thanks=20to=20Reinhard=20Nissl).=20-?= =?UTF-8?q?=20cDvbDevice=20now=20uses=20the=20FE=5FCAN=5F2G=5FMODULATION?= =?UTF-8?q?=20flag=20to=20determine=20whether=20a=20device=20=20=20can=20h?= =?UTF-8?q?andle=20DVB-S2.=20The=20#define=20is=20still=20there=20to=20all?= =?UTF-8?q?ow=20people=20with=20older=20drivers=20=20=20who=20don't=20need?= =?UTF-8?q?=20DVB-S2=20to=20use=20this=20version=20without=20pathcing.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- remux.h | 149 ++++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 79 insertions(+), 70 deletions(-) (limited to 'remux.h') 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 -- cgit v1.2.3