From 084e16c057ab195a76c2117c631a2fe10a904238 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 25 Jan 2009 13:13:00 +0100 Subject: =?UTF-8?q?Version=201.7.4=20-=20Removed=20the=20'#define=20FE=5FC?= =?UTF-8?q?AN=5F2ND=5FGEN=5FMODULATION',=20since=20it=20was=20wrong=20and?= =?UTF-8?q?=20the=20=20=20flag=20is=20now=20in=20the=20driver,=20anyway.?= =?UTF-8?q?=20-=20The=20full-featured=20DVB=20cards=20are=20now=20given=20?= =?UTF-8?q?the=20TS=20data=20directly=20for=20replay=20=20=20(thanks=20to?= =?UTF-8?q?=20Oliver=20Endriss=20for=20enhancing=20the=20av7110=20driver?= =?UTF-8?q?=20to=20make=20it=20replay=20=20=20TS=20data).=20The=20patch=20?= =?UTF-8?q?from=20ftp://ftp.cadsoft.de/vdr/Developer/av7110=5Fts=5Freplay?= =?UTF-8?q?=5F=5F1.diff=20=20=20implements=20this=20change=20in=20the=20dr?= =?UTF-8?q?iver.=20=20=20The=20patch=20av7110=5Fv4ldvb=5Fapi5=5Faudiobuf?= =?UTF-8?q?=5Ftest=5F1.diff=20mentioned=20in=20version=201.7.2=20=20=20is?= =?UTF-8?q?=20still=20necessary=20to=20avoid=20audio=20and=20video=20glitc?= =?UTF-8?q?hes=20on=20some=20channels.=20-=20Added=20a=20typecast=20in=20c?= =?UTF-8?q?UnbufferedFile::Write()=20to=20avoid=20an=20error=20message=20w?= =?UTF-8?q?hen=20=20=20compiling=20on=2064=20bit=20systems.=20-=20Added=20?= =?UTF-8?q?some=20missing=20'const'=20statements=20to=20cBitmap=20(thanks?= =?UTF-8?q?=20to=20Andreas=20Regel).=20-=20Fixed=20returning=20complete=20?= =?UTF-8?q?PES=20packets=20in=20cTsToPes::GetPes()=20(thanks=20to=20Reinha?= =?UTF-8?q?rd=20=20=20Nissl).=20-=20Added=20a=20missing=20Detach()=20in=20?= =?UTF-8?q?cTransfer::Activate()=20(thanks=20to=20Marco=20Schl=FC=DFler).?= =?UTF-8?q?=20-=20Added=20clearing=20the=20TS=20buffers=20in=20cDevice::De?= =?UTF-8?q?tach()=20(thanks=20to=20Marco=20Schl=FC=DFler).=20-=20Fixed=20i?= =?UTF-8?q?ncrementing=20the=20continuity=20counter=20in=20cPatPmtGenerato?= =?UTF-8?q?r::GetPmt()=20(thanks=20=20=20to=20Johann=20Friedrichs).=20-=20?= =?UTF-8?q?Fixed=20removing=20deleted=20recordings=20in=20case=20there=20i?= =?UTF-8?q?s=20a=20problem.=20Once=20a=20recording=20=20=20caused=20a=20pr?= =?UTF-8?q?oblem=20with=20removing,=20no=20others=20were=20removed=20any?= =?UTF-8?q?=20more=20and=20an=20ongoing=20=20=20recording=20could=20fill?= =?UTF-8?q?=20up=20the=20disk=20and=20cause=20other=20recordings=20to=20be?= =?UTF-8?q?=20deleted=20=20=20automatically=20(reported=20by=20Reinhard=20?= =?UTF-8?q?Nissl).=20-=20Added=20"DEFINES=20+=3D=20-D=5FFILE=5FOFFSET=5FBI?= =?UTF-8?q?TS=3D64=20-D=5FLARGEFILE=5FSOURCE=20-D=5FLARGEFILE64=5FSOURCE"?= =?UTF-8?q?=20=20=20to=20Make.config.template=20(thanks=20to=20Johann=20Fr?= =?UTF-8?q?iedrichs=20for=20pointing=20this=20out).=20=20=20Plugin=20autho?= =?UTF-8?q?rs=20should=20add=20this=20line=20to=20their=20Makefile=20or=20?= =?UTF-8?q?Make.config=20if=20they=20use=20=20=20file=20access=20functions?= =?UTF-8?q?=20that=20need=20special=20versions=20for=2064=20bit=20offsets.?= =?UTF-8?q?=20-=20The=20new=20command=20line=20option=20-i=20can=20be=20us?= =?UTF-8?q?ed=20to=20set=20an=20"instance=20id",=20which=20will=20=20=20be?= =?UTF-8?q?=20used=20to=20distinguish=20recordings=20of=20the=20same=20bro?= =?UTF-8?q?adcast=20made=20by=20different=20instances=20=20=20of=20VDR=20(?= =?UTF-8?q?suggested=20by=20Frank=20Schmirler).=20This=20replaces=20the=20?= =?UTF-8?q?use=20of=20the=20"resume=20id"=20=20=20that=20was=20introduced?= =?UTF-8?q?=20in=20version=201.7.3.=20-=20Added=20checking=20mutexCurrentA?= =?UTF-8?q?udioTrack=20to=20cDevice::PlayTs()=20(thanks=20to=20Reinhard=20?= =?UTF-8?q?=20=20Nissl=20for=20pointing=20this=20out).=20-=20Fixed=20handl?= =?UTF-8?q?ing=20the=20pointer=20field=20in=20cPatPmtParser::ParsePmt()=20?= =?UTF-8?q?(thanks=20to=20Frank=20=20=20Schmirler=20-=20sorry=20I=20swappe?= =?UTF-8?q?d=20two=20lines=20when=20adopting=20the=20original=20patch).=20?= =?UTF-8?q?-=20Checking=20the=20remaining=20packet=20length=20after=20proc?= =?UTF-8?q?essing=20the=20pointer=20field=20in=20=20=20cPatPmtParser::Pars?= =?UTF-8?q?ePat()=20and=20cPatPmtParser::ParsePmt()=20(suggested=20by=20Fr?= =?UTF-8?q?ank=20=20=20Schmirler).=20-=20Checking=20the=20pointer=20field?= =?UTF-8?q?=20in=20cPatPmtParser::ParsePmt()=20only=20in=20'payload=20star?= =?UTF-8?q?t'=20=20=20packets=20(suggested=20by=20Frank=20Schmirler).=20-?= =?UTF-8?q?=20Changed=20cPatPmtGenerator=20to=20make=20sure=20the=20PMT=20?= =?UTF-8?q?pid=20doesn't=20collide=20with=20any=20of=20=20=20the=20actual?= =?UTF-8?q?=20pids=20of=20the=20channel.=20-=20Fixed=20cDevice::PlayTsAudi?= =?UTF-8?q?o()=20and=20made=20cDevice::PlayTsVideo()=20return=200=20if=20?= =?UTF-8?q?=20=20PlayVideo()=20didn't=20play=20anything.=20-=20Added=20an?= =?UTF-8?q?=20'int'=20typecast=20to=20calculations=20involving=20FramesPer?= =?UTF-8?q?Second()=20to=20avoid=20=20=20compiler=20warnings=20(reported?= =?UTF-8?q?=20by=20Winfried=20Koehler).=20-=20Fixed=20detecting=20frames?= =?UTF-8?q?=20for=20pure=20audio=20recordings.=20-=20Fixed=20editing=20PES?= =?UTF-8?q?=20recordings.=20The=20frame=20type=20in=20the=20index.vdr=20fi?= =?UTF-8?q?le=20generated=20for=20=20=20the=20edited=20PES=20recording=20i?= =?UTF-8?q?s=20set=20to=201=20for=20I-frames=20and=202=20for=20all=20other?= =?UTF-8?q?s=20(P-=20and=20=20=20B-frames).=20The=20exact=20frame=20type?= =?UTF-8?q?=20doesn't=20matter=20for=20VDR,=20it=20only=20needs=20to=20kno?= =?UTF-8?q?w=20if=20=20=20it's=20an=20I-frame=20or=20not.=20-=20The=20PAT/?= =?UTF-8?q?PMT=20is=20now=20only=20processed=20if=20its=20version=20change?= =?UTF-8?q?s=20(reported=20by=20Reinhard=20=20=20Nissl).=20-=20Fixed=20han?= =?UTF-8?q?dling=20the=20maximum=20video=20file=20size=20(reported=20by=20?= =?UTF-8?q?Udo=20Richter).=20-=20Improved=20fast-forward/-rewind=20for=20a?= =?UTF-8?q?udio=20recordings.=20The=20actual=20data=20is=20now=20sent=20?= =?UTF-8?q?=20=20to=20the=20output=20device,=20so=20that=20it=20can=20be?= =?UTF-8?q?=20replayed=20and=20thus=20cause=20the=20proper=20delay.=20=20?= =?UTF-8?q?=20For=20pure=20audio=20recordings=20the=20audio=20is=20no=20lo?= =?UTF-8?q?nger=20muted=20in=20fast-forward/-rewind=20=20=20mode,=20so=20t?= =?UTF-8?q?hat=20some=20orientation=20regarding=20the=20position=20within?= =?UTF-8?q?=20the=20recording=20is=20=20=20possible.=20There=20may=20still?= =?UTF-8?q?=20be=20some=20offset=20in=20the=20replay=20position=20displaye?= =?UTF-8?q?d=20by=20the=20=20=20progress=20indicator=20when=20switching=20?= =?UTF-8?q?from=20fast-forward/-rewind=20to=20play=20mode,=20as=20well=20?= =?UTF-8?q?=20=20as=20in=20the=20current=20position=20during=20normal=20pl?= =?UTF-8?q?ay=20mode.=20This=20is=20due=20to=20the=20various=20=20=20buffe?= =?UTF-8?q?rs=20between=20the=20player=20and=20the=20output=20device=20and?= =?UTF-8?q?=20will=20be=20addressed=20later.=20=20=20Note=20the=20new=20fu?= =?UTF-8?q?nction=20cDevice::IsPlayingVideo(),=20which=20is=20used=20to=20?= =?UTF-8?q?inform=20the=20=20=20player=20whether=20there=20is=20video=20da?= =?UTF-8?q?ta=20in=20the=20currently=20replayed=20stream.=20If=20a=20deriv?= =?UTF-8?q?ed=20=20=20cDevice=20class=20reimplements=20PlayTs()=20or=20Pla?= =?UTF-8?q?yPes(),=20it=20also=20needs=20to=20make=20sure=20this=20=20=20n?= =?UTF-8?q?ew=20function=20works=20as=20expected.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTORS | 21 +++++++++++ HISTORY | 77 +++++++++++++++++++++++++++++++++++--- Make.config.template | 3 +- PLUGINS.html | 15 ++++++-- config.c | 4 +- config.h | 10 ++--- cutter.c | 8 +++- device.c | 46 ++++++++++++----------- device.h | 15 +++++--- dvbdevice.c | 34 +++-------------- dvbplayer.c | 23 ++++++++---- menu.c | 9 +++-- osd.c | 4 +- osd.h | 6 +-- player.h | 3 +- recorder.c | 4 +- recording.c | 37 ++++++++++++++----- recording.h | 21 ++++++----- remux.c | 102 ++++++++++++++++++++++++++++++++++++++------------- remux.h | 33 +++++++++++------ tools.c | 4 +- transfer.c | 6 ++- vdr.1 | 11 +++++- vdr.c | 12 +++++- 24 files changed, 351 insertions(+), 157 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 7bc1b74..848c367 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -660,6 +660,8 @@ Oliver Endriss the call to cStatus::MsgSetVolume() for providing a driver patch that allows replaying TS->PES converted video in Transfer Mode + for providing a driver patch that allows direct replaying of TS video on full-featured + DVB cards Reinhard Walter Buchner for adding some satellites to 'sources.conf' @@ -1189,6 +1191,12 @@ Reinhard Nissl for reporting the missing description of the 'S' channel parameter in vdr.5 for fixing cPatPmtParser::ParsePmt() to reset vpid and vtype when switching from a video to an audio channel + for fixing returning complete PES packets in cTsToPes::GetPes() + for reporting a possible problem with removing deleted recordings + for pointing out that a check of mutexCurrentAudioTrack needs to be done in + to cDevice::PlayTs() + for reporting that the PAT/PMT is processed too often, even if its version + hasn't changed Richard Robson for reporting freezing replay if a timer starts while in Transfer Mode from the @@ -1313,6 +1321,7 @@ Andreas Regel for implementing palette replace mode in the OSD bitmaps for fixing handling numeric keys in the channel display after switching channel groups + for adding some missing 'const' statements to cBitmap Thomas Bergwinkl for fixing the validity check for channel IDs, because some providers use TIDs @@ -1483,6 +1492,8 @@ Marco Schl for fixing setting the date in the channel display of the classic and sttng skins, to avoid unnecessary OSD access for changing cDvbDevice::GrabImage() to use V4L2 + for adding a missing Detach() in cTransfer::Activate() + for adding clearing the TS buffers in cDevice::Detach() Jürgen Schmitz for reporting a bug in displaying the current channel when switching via the SVDRP @@ -1594,6 +1605,7 @@ Udo Richter for fixing error handling in cCuttingThread::Action() for suppressing the automatic shutdown if the remote control is currently disabled for fixing a problem with calling isyslog() from within the SignalHandler() + for reporting a problem with handling the maximum video file size Sven Kreiensen for his help in keeping 'channels.conf.terr' up to date @@ -2207,6 +2219,8 @@ Frank Schmirler allowed characters for fixing handling address masks in SVDRP host settings for fixing handling the 'pointer field' in generating and parsing PAT/PMT + for suggesting to use an "instance id" instead of the "resume id" to distinguish + recordings of the same broadcast made by different instances of VDR Jörn Reder for reporting that a recording may unnecessarily block a device with a CAM, while @@ -2331,6 +2345,7 @@ Benjamin Hess Winfried Koehler for fixing finding new transponders + for reporting a compiler warning in calculations involving FramesPerSecond() Hans-Werner Hilse for adding the command line option --userdump to enable core dumps in case VDR @@ -2392,3 +2407,9 @@ Niels Wagenaar Edgar Hucek for a patch that was used to convert VDR to the S2API driver API + +Johann Friedrichs + for fixing incrementing the continuity counter in cPatPmtGenerator::GetPmt() + for pointing out that "DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE + -D_LARGEFILE64_SOURCE" should be added to Make.config. + to Make.config.template (thanks to Johann Friedrichs for pointing this out). diff --git a/HISTORY b/HISTORY index 68bdc33..1cbc1bd 100644 --- a/HISTORY +++ b/HISTORY @@ -5868,9 +5868,9 @@ Video Disk Recorder Revision History 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). + The "frames per second" is stored in the "info" 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 @@ -5882,7 +5882,7 @@ Video Disk Recorder Revision History + 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 + Priority and Lifetime are now stored in the "info" 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 @@ -5910,4 +5910,71 @@ Video Disk Recorder Revision History 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. + who don't need DVB-S2 to use this version without patching. + +2009-01-25: Version 1.7.4 + +- Removed the '#define FE_CAN_2ND_GEN_MODULATION', since it was wrong and the + flag is now in the driver, anyway. +- The full-featured DVB cards are now given the TS data directly for replay + (thanks to Oliver Endriss for enhancing the av7110 driver to make it replay + TS data). The patch from ftp://ftp.cadsoft.de/vdr/Developer/av7110_ts_replay__1.diff + implements this change in the driver. + The patch av7110_v4ldvb_api5_audiobuf_test_1.diff mentioned in version 1.7.2 + is still necessary to avoid audio and video glitches on some channels. +- Added a typecast in cUnbufferedFile::Write() to avoid an error message when + compiling on 64 bit systems. +- Added some missing 'const' statements to cBitmap (thanks to Andreas Regel). +- Fixed returning complete PES packets in cTsToPes::GetPes() (thanks to Reinhard + Nissl). +- Added a missing Detach() in cTransfer::Activate() (thanks to Marco Schlüßler). +- Added clearing the TS buffers in cDevice::Detach() (thanks to Marco Schlüßler). +- Fixed incrementing the continuity counter in cPatPmtGenerator::GetPmt() (thanks + to Johann Friedrichs). +- Fixed removing deleted recordings in case there is a problem. Once a recording + caused a problem with removing, no others were removed any more and an ongoing + recording could fill up the disk and cause other recordings to be deleted + automatically (reported by Reinhard Nissl). +- Added "DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE" + to Make.config.template (thanks to Johann Friedrichs for pointing this out). + Plugin authors should add this line to their Makefile or Make.config if they use + file access functions that need special versions for 64 bit offsets. +- The new command line option -i can be used to set an "instance id", which will + be used to distinguish recordings of the same broadcast made by different instances + of VDR (suggested by Frank Schmirler). This replaces the use of the "resume id" + that was introduced in version 1.7.3. +- Added checking mutexCurrentAudioTrack to cDevice::PlayTs() (thanks to Reinhard + Nissl for pointing this out). +- Fixed handling the pointer field in cPatPmtParser::ParsePmt() (thanks to Frank + Schmirler - sorry I swapped two lines when adopting the original patch). +- Checking the remaining packet length after processing the pointer field in + cPatPmtParser::ParsePat() and cPatPmtParser::ParsePmt() (suggested by Frank + Schmirler). +- Checking the pointer field in cPatPmtParser::ParsePmt() only in 'payload start' + packets (suggested by Frank Schmirler). +- Changed cPatPmtGenerator to make sure the PMT pid doesn't collide with any of + the actual pids of the channel. +- Fixed cDevice::PlayTsAudio() and made cDevice::PlayTsVideo() return 0 if + PlayVideo() didn't play anything. +- Added an 'int' typecast to calculations involving FramesPerSecond() to avoid + compiler warnings (reported by Winfried Koehler). +- Fixed detecting frames for pure audio recordings. +- Fixed editing PES recordings. The frame type in the index.vdr file generated for + the edited PES recording is set to 1 for I-frames and 2 for all others (P- and + B-frames). The exact frame type doesn't matter for VDR, it only needs to know if + it's an I-frame or not. +- The PAT/PMT is now only processed if its version changes (reported by Reinhard + Nissl). +- Fixed handling the maximum video file size (reported by Udo Richter). +- Improved fast-forward/-rewind for audio recordings. The actual data is now sent + to the output device, so that it can be replayed and thus cause the proper delay. + For pure audio recordings the audio is no longer muted in fast-forward/-rewind + mode, so that some orientation regarding the position within the recording is + possible. There may still be some offset in the replay position displayed by the + progress indicator when switching from fast-forward/-rewind to play mode, as well + as in the current position during normal play mode. This is due to the various + buffers between the player and the output device and will be addressed later. + Note the new function cDevice::IsPlayingVideo(), which is used to inform the + player whether there is video data in the currently replayed stream. If a derived + cDevice class reimplements PlayTs() or PlayPes(), it also needs to make sure this + new function works as expected. diff --git a/Make.config.template b/Make.config.template index 03e7813..758fc14 100644 --- a/Make.config.template +++ b/Make.config.template @@ -6,7 +6,7 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Make.config.template 2.0 2008/01/13 12:54:09 kls Exp $ +# $Id: Make.config.template 2.1 2009/01/18 10:46:13 kls Exp $ ### The C compiler and options: @@ -19,6 +19,7 @@ CXXFLAGS = -g -O2 -Wall -Woverloaded-virtual -Wno-parentheses ifdef PLUGIN CFLAGS += -fPIC CXXFLAGS += -fPIC +DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE endif ### The directory environment: diff --git a/PLUGINS.html b/PLUGINS.html index 9dc48e7..dfee739 100644 --- a/PLUGINS.html +++ b/PLUGINS.html @@ -16,7 +16,10 @@ html, body { text-align: center; } .code { - background-color: #f0f0f0; + background-color: #F0F0F0; +} +.modified { + background-color: #FFDDDD; } @@ -25,12 +28,15 @@ html, body {

The VDR Plugin System

-Version 1.6 +Version 1.7

-Copyright © 2008 Klaus Schmidinger
+Copyright © 2009 Klaus Schmidinger
kls@cadsoft.de
www.cadsoft.de/vdr

+
+Important modifications introduced since version 1.6 are marked like this. +

VDR provides an easy to use plugin interface that allows additional functionality to be added to the program by implementing a dynamically loadable library file. @@ -1844,6 +1850,9 @@ virtual bool HasDecoder(void) const; virtual bool CanReplay(void) const; virtual bool SetPlayMode(ePlayMode PlayMode); virtual int64_t GetSTC(void); +

+virtual bool IsPlayingVideo(void) const; +
virtual bool HasIBPTrickSpeed(void); virtual void TrickSpeed(int Speed); virtual void Clear(void); diff --git a/config.c b/config.c index d3e1dee..1132b12 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 2.0 2008/02/17 13:39:00 kls Exp $ + * $Id: config.c 2.1 2009/01/24 15:05:32 kls Exp $ */ #include "config.h" @@ -275,7 +275,7 @@ cSetup::cSetup(void) FontOsdSize = 22; FontSmlSize = 18; FontFixSize = 20; - MaxVideoFileSize = MAXVIDEOFILESIZE; + MaxVideoFileSize = MAXVIDEOFILESIZEDEFAULT; SplitEditedFiles = 0; MinEventTimeout = 30; MinUserInactivity = 300; diff --git a/config.h b/config.h index 76c8566..0041f83 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 2.5 2008/12/24 14:29:56 kls Exp $ + * $Id: config.h 2.6 2009/01/06 16:56:27 kls Exp $ */ #ifndef __CONFIG_H @@ -22,13 +22,13 @@ // VDR's own version number: -#define VDRVERSION "1.7.3" -#define VDRVERSNUM 10703 // Version * 10000 + Major * 100 + Minor +#define VDRVERSION "1.7.4" +#define VDRVERSNUM 10704 // Version * 10000 + Major * 100 + Minor // The plugin API's version number: -#define APIVERSION "1.7.3" -#define APIVERSNUM 10703 // Version * 10000 + Major * 100 + Minor +#define APIVERSION "1.7.4" +#define APIVERSNUM 10704 // Version * 10000 + Major * 100 + Minor // When loading plugins, VDR searches them by their APIVERSION, which // may be smaller than VDRVERSION in case there have been no changes to diff --git a/cutter.c b/cutter.c index 20a9e67..73ac873 100644 --- a/cutter.c +++ b/cutter.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: cutter.c 2.1 2009/01/06 14:40:48 kls Exp $ + * $Id: cutter.c 2.2 2009/01/24 15:19:26 kls Exp $ */ #include "cutter.h" @@ -22,6 +22,7 @@ private: cFileName *fromFileName, *toFileName; cIndexFile *fromIndex, *toIndex; cMarks fromMarks, toMarks; + off_t maxVideoFileSize; protected: virtual void Action(void); public: @@ -45,6 +46,9 @@ cCuttingThread::cCuttingThread(const char *FromFileName, const char *ToFileName) fromIndex = new cIndexFile(FromFileName, false, isPesRecording); toIndex = new cIndexFile(ToFileName, true, isPesRecording); toMarks.Load(ToFileName, Recording.FramesPerSecond(), isPesRecording); // doesn't actually load marks, just sets the file name + maxVideoFileSize = MEGABYTE(Setup.MaxVideoFileSize); + if (isPesRecording && maxVideoFileSize > MEGABYTE(MAXVIDEOFILESIZEPES)) + maxVideoFileSize = MEGABYTE(MAXVIDEOFILESIZEPES); Start(); } else @@ -125,7 +129,7 @@ void cCuttingThread::Action(void) if (Independent) { // every file shall start with an independent frame if (LastMark) // edited version shall end before next I-frame break; - if (FileSize > MEGABYTE(Setup.MaxVideoFileSize)) { + if (FileSize > maxVideoFileSize) { toFile = toFileName->NextFile(); if (!toFile) { error = "toFile 1"; diff --git a/device.c b/device.c index 8cd0b1e..1f806e0 100644 --- a/device.c +++ b/device.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: device.c 2.5 2009/01/06 09:55:13 kls Exp $ + * $Id: device.c 2.11 2009/01/25 11:10:56 kls Exp $ */ #include "device.h" @@ -81,6 +81,7 @@ cDevice::cDevice(void) startScrambleDetection = 0; player = NULL; + isPlayingVideo = false; ClrAvailableTracks(); currentAudioTrack = ttNone; currentAudioTrackMissingCount = 0; @@ -1020,12 +1021,11 @@ void cDevice::StillPicture(const uchar *Data, int Length) uchar *buf = NULL; int Size = 0; while (Length >= TS_SIZE) { - int PayloadOffset = TsPayloadOffset(Data); int Pid = TsPid(Data); if (Pid == 0) - patPmtParser.ParsePat(Data + PayloadOffset, TS_SIZE - PayloadOffset); + patPmtParser.ParsePat(Data, TS_SIZE); else if (Pid == patPmtParser.PmtPid()) - patPmtParser.ParsePmt(Data + PayloadOffset, TS_SIZE - PayloadOffset); + patPmtParser.ParsePmt(Data, TS_SIZE); else if (Pid == patPmtParser.Vpid()) { if (TsPayloadStart(Data)) { int l; @@ -1098,7 +1098,9 @@ void cDevice::Detach(cPlayer *Player) dvbSubtitleConverter = NULL; SetPlayMode(pmNone); SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat)); + PlayTs(NULL, 0); Audios.ClearAudio(); + isPlayingVideo = false; } } @@ -1151,6 +1153,7 @@ int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly) switch (c) { case 0xBE: // padding stream, needed for MPEG1 case 0xE0 ... 0xEF: // video + isPlayingVideo = true; w = PlayVideo(Start, d); break; case 0xC0 ... 0xDF: // audio @@ -1273,7 +1276,7 @@ int cDevice::PlayTsVideo(const uchar *Data, int Length) int l; while (const uchar *p = tsToPesVideo.GetPes(l)) { int w = PlayVideo(p, l); - if (w < 0) + if (w <= 0) return w; } tsToPesVideo.Reset(); @@ -1284,20 +1287,15 @@ int cDevice::PlayTsVideo(const uchar *Data, int Length) int cDevice::PlayTsAudio(const uchar *Data, int Length) { - bool PayloadStart = TsPayloadStart(Data); - for (int Pass = 0; Pass < 2; Pass++) { - if (Pass == 0 && !PayloadStart) // if no new payload is started, we can always put the packet into the converter - tsToPesAudio.PutTs(Data, Length); - if (const uchar *p = tsToPesAudio.GetPes(Length)) { - int w = PlayAudio(p, Length, 0); - if (w > 0) - tsToPesAudio.Reset(); - else if (PayloadStart) - return w; // must get out the old packet before starting a new one - } - if (Pass == 0 && PayloadStart) - tsToPesAudio.PutTs(Data, Length); - } + // Audio PES always has an explicit length and consists of single packets: + int l; + if (const uchar *p = tsToPesAudio.GetPes(l)) { + int w = PlayAudio(p, l, 0); + if (w <= 0) + return w; + tsToPesAudio.Reset(); + } + tsToPesAudio.PutTs(Data, Length); return Length; } @@ -1321,13 +1319,16 @@ int cDevice::PlayTs(const uchar *Data, int Length, bool VideoOnly) return Length; // silently ignore TS packets w/o payload int PayloadOffset = TsPayloadOffset(Data); if (PayloadOffset < Length) { + cMutexLock MutexLock(&mutexCurrentAudioTrack); int Pid = TsPid(Data); if (Pid == 0) - patPmtParser.ParsePat(Data + PayloadOffset, Length - PayloadOffset); + patPmtParser.ParsePat(Data, Length); else if (Pid == patPmtParser.PmtPid()) - patPmtParser.ParsePmt(Data + PayloadOffset, Length - PayloadOffset); - else if (Pid == patPmtParser.Vpid()) + patPmtParser.ParsePmt(Data, Length); + else if (Pid == patPmtParser.Vpid()) { + isPlayingVideo = true; return PlayTsVideo(Data, Length); + } else if (Pid == availableTracks[currentAudioTrack].id) { if (!VideoOnly || HasIBPTrickSpeed()) { int w = PlayTsAudio(Data, Length); @@ -1344,6 +1345,7 @@ int cDevice::PlayTs(const uchar *Data, int Length, bool VideoOnly) } } else if (Data == NULL) { + patPmtParser.Reset(); tsToPesVideo.Reset(); tsToPesAudio.Reset(); tsToPesSubtitle.Reset(); diff --git a/device.h b/device.h index 7c4a709..67c9be4 100644 --- a/device.h +++ b/device.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: device.h 2.4 2009/01/05 16:28:06 kls Exp $ + * $Id: device.h 2.6 2009/01/25 11:04:39 kls Exp $ */ #ifndef __DEVICE_H @@ -477,6 +477,7 @@ private: cTsToPes tsToPesVideo; cTsToPes tsToPesAudio; cTsToPes tsToPesSubtitle; + bool isPlayingVideo; protected: virtual bool CanReplay(void) const; ///< Returns true if this device can currently start a replay session. @@ -487,7 +488,7 @@ protected: ///< Plays the given data block as video. ///< Data points to exactly one complete PES packet of the given Length. ///< PlayVideo() shall process the packet either as a whole (returning - ///< Length) or not at all (returning 0 or -1 and setting 'errno' to EAGAIN). + ///< Length) or not at all (returning 0 or -1 and setting 'errno' accordingly). ///< \return Returns the number of bytes actually taken from Data, or -1 ///< in case of an error. virtual int PlayAudio(const uchar *Data, int Length, uchar Id); @@ -498,14 +499,14 @@ protected: ///< TS replay). Plugins that need to know this Id shall read it from the ///< actual PES data (it's the 4th byte). ///< PlayAudio() shall process the packet either as a whole (returning - ///< Length) or not at all (returning 0 or -1 and setting 'errno' to EAGAIN). + ///< Length) or not at all (returning 0 or -1 and setting 'errno' accordingly). ///< \return Returns the number of bytes actually taken from Data, or -1 ///< in case of an error. virtual int PlaySubtitle(const uchar *Data, int Length); ///< Plays the given data block as a subtitle. ///< Data points to exactly one complete PES packet of the given Length. ///< PlaySubtitle() shall process the packet either as a whole (returning - ///< Length) or not at all (returning 0 or -1 and setting 'errno' to EAGAIN). + ///< Length) or not at all (returning 0 or -1 and setting 'errno' accordingly). ///< \return Returns the number of bytes actually taken from Data, or -1 ///< in case of an error. virtual int PlayPesPacket(const uchar *Data, int Length, bool VideoOnly = false); @@ -542,6 +543,9 @@ public: ///< Gets the current System Time Counter, which can be used to ///< synchronize audio and video. If this device is unable to ///< provide the STC, -1 will be returned. + virtual bool IsPlayingVideo(void) const { return isPlayingVideo; } + ///< \return Returns true if the currently attached player has delivered + ///< any video packets. virtual bool HasIBPTrickSpeed(void) { return false; } ///< Returns true if this device can handle all frames in 'fast forward' ///< trick speeds. @@ -610,8 +614,7 @@ public: ///< Returns -1 in case of error, otherwise the number of actually ///< processed bytes is returned, which must be Length. ///< PlayTs() shall process the packet either as a whole (returning - ///< a positive number, which needs not necessarily be Length) or not at all - ///< (returning 0 or -1 and setting 'errno' to EAGAIN). + ///< Length) or not at all returning 0 or -1 and setting 'errno' accordingly). bool Replaying(void) const; ///< Returns true if we are currently replaying. bool Transferring(void) const; diff --git a/dvbdevice.c b/dvbdevice.c index 6aa0056..5600191 100644 --- a/dvbdevice.c +++ b/dvbdevice.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbdevice.c 2.10 2009/01/06 14:52:54 kls Exp $ + * $Id: dvbdevice.c 2.12 2009/01/10 10:07:33 kls Exp $ */ #include "dvbdevice.h" @@ -27,13 +27,6 @@ #include "status.h" #include "transfer.h" -// FIXME: temporary workaround until the S2API driver supports detecting -// S2 capability in a clean way. This macro allows compiling VDR with an -// unpatched driver. However, with an unpatched driver it will not support -// DVB-S2 hardware. If you have DVB-S2 hardware you need to either patch -// the driver or modify the line that uses this macro in cDvbDevice::cDvbDevice(). -#define FE_CAN_2ND_GEN_MODULATION 0x10000000 - #define DO_REC_AND_PLAY_ON_PRIMARY_DEVICE 1 #define DO_MULTIPLE_RECORDINGS 1 @@ -1304,39 +1297,22 @@ bool cDvbDevice::Flush(int TimeoutMs) int cDvbDevice::PlayVideo(const uchar *Data, int Length) { - int w; - do { - w = WriteAllOrNothing(fd_video, Data, Length, 1000, 10); - if (w < 0 && errno == EAGAIN) { - cPoller Poller(fd_video, true); - Poller.Poll(200); - } - } while (w != Length); - return w; + return WriteAllOrNothing(fd_video, Data, Length, 1000, 10); } int cDvbDevice::PlayAudio(const uchar *Data, int Length, uchar Id) { - int w; - do { - w = WriteAllOrNothing(fd_audio, Data, Length, 1000, 10); - if (w < 0 && errno == EAGAIN) { - cPoller Poller(fd_audio, true); - Poller.Poll(200); - } - } while (w != Length); - return w; + return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10); } int cDvbDevice::PlayTsVideo(const uchar *Data, int Length) { - return cDevice::PlayTsVideo(Data, Length); + return WriteAllOrNothing(fd_video, Data, Length, 1000, 10); } int cDvbDevice::PlayTsAudio(const uchar *Data, int Length) { - int w = PlayAudio(Data, TsGetPayload(&Data), 0); - return w >= 0 ? Length : w; + return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10); } bool cDvbDevice::OpenDvr(void) diff --git a/dvbplayer.c b/dvbplayer.c index 9de7e48..6e00440 100644 --- a/dvbplayer.c +++ b/dvbplayer.c @@ -4,10 +4,11 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbplayer.c 2.1 2009/01/05 16:52:40 kls Exp $ + * $Id: dvbplayer.c 2.3 2009/01/25 11:11:39 kls Exp $ */ #include "dvbplayer.h" +#include #include #include "recording.h" #include "remux.h" @@ -347,7 +348,7 @@ bool cDvbPlayer::Save(void) if (index) { int Index = writeIndex; if (Index >= 0) { - Index -= RESUMEBACKUP * framesPerSecond; + Index -= int(round(RESUMEBACKUP * framesPerSecond)); if (Index > 0) Index = index->GetNextIFrame(Index, false); else @@ -411,8 +412,12 @@ void cDvbPlayer::Action(void) if (index->Get(readIndex + 1, &FileNumber, &FileOffset, NULL, &Length)) Index = readIndex + 1; } - else - Index = index->GetNextIFrame(readIndex, playDir == pdForward, &FileNumber, &FileOffset, &Length, TimeShiftMode); + else { + int d = int(round(0.4 * framesPerSecond)); + if (playDir != pdForward) + d = -d; + Index = index->GetNextIFrame(readIndex + d, playDir == pdForward, &FileNumber, &FileOffset, &Length, TimeShiftMode); + } if (Index >= 0) { if (!NextFile(FileNumber, FileOffset)) { readIndex = Index; @@ -515,9 +520,9 @@ void cDvbPlayer::Action(void) if (p) { int w; if (isPesRecording) - w = PlayPes(p, pc, playMode != pmPlay); + w = PlayPes(p, pc, playMode != pmPlay && DeviceIsPlayingVideo()); else - w = PlayTs(p, TS_SIZE, playMode != pmPlay); + w = PlayTs(p, TS_SIZE, playMode != pmPlay && DeviceIsPlayingVideo()); if (w > 0) { p += w; pc -= w; @@ -592,7 +597,8 @@ void cDvbPlayer::Forward(void) LOCK_THREAD; if (!(DeviceHasIBPTrickSpeed() && playDir == pdForward)) Empty(); - DeviceMute(); + if (DeviceIsPlayingVideo()) + DeviceMute(); playMode = pmFast; playDir = pdForward; trickSpeed = NORMAL_SPEED; @@ -638,7 +644,8 @@ void cDvbPlayer::Backward(void) case pmPlay: { LOCK_THREAD; Empty(); - DeviceMute(); + if (DeviceIsPlayingVideo()) + DeviceMute(); playMode = pmFast; playDir = pdBackward; trickSpeed = NORMAL_SPEED; diff --git a/menu.c b/menu.c index beb7fb8..fa60065 100644 --- a/menu.c +++ b/menu.c @@ -4,12 +4,13 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 2.4 2009/01/06 14:34:17 kls Exp $ + * $Id: menu.c 2.6 2009/01/24 15:05:43 kls Exp $ */ #include "menu.h" #include #include +#include #include #include #include @@ -2697,7 +2698,7 @@ cMenuSetupRecord::cMenuSetupRecord(void) Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord)); Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord))); Add(new cMenuEditIntItem( tr("Setup.Recording$Instant rec. time (min)"), &data.InstantRecordTime, 1, MAXINSTANTRECTIME)); - Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size (MB)"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZE)); + Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size (MB)"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZETS)); Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles)); } @@ -4170,8 +4171,8 @@ void cReplayControl::TimeSearchProcess(eKeys Key) { #define STAY_SECONDS_OFF_END 10 int Seconds = (timeSearchTime >> 24) * 36000 + ((timeSearchTime & 0x00FF0000) >> 16) * 3600 + ((timeSearchTime & 0x0000FF00) >> 8) * 600 + (timeSearchTime & 0x000000FF) * 60; - int Current = (lastCurrent / FramesPerSecond()); - int Total = (lastTotal / FramesPerSecond()); + int Current = int(round(lastCurrent / FramesPerSecond())); + int Total = int(round(lastTotal / FramesPerSecond())); switch (Key) { case k0 ... k9: if (timeSearchPos < 4) { diff --git a/osd.c b/osd.c index 925d605..32614d8 100644 --- a/osd.c +++ b/osd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.c 2.0 2007/10/12 12:38:36 kls Exp $ + * $Id: osd.c 2.1 2009/01/16 14:34:32 kls Exp $ */ #include "osd.h" @@ -635,7 +635,7 @@ void cBitmap::DrawSlope(int x1, int y1, int x2, int y2, tColor Color, int Type) } } -const tIndex *cBitmap::Data(int x, int y) +const tIndex *cBitmap::Data(int x, int y) const { return &bitmap[y * width + x]; } diff --git a/osd.h b/osd.h index 9950a2d..addbf0e 100644 --- a/osd.h +++ b/osd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 2.0 2007/10/12 14:28:44 kls Exp $ + * $Id: osd.h 2.1 2009/01/16 14:37:03 kls Exp $ */ #ifndef __OSD_H @@ -231,9 +231,9 @@ public: ///< 5: vertical, rising, upper ///< 6: vertical, falling, lower ///< 7: vertical, falling, upper - const tIndex *Data(int x, int y); + const tIndex *Data(int x, int y) const; ///< Returns the address of the index byte at the given coordinates. - tColor GetColor(int x, int y) { return Color(*Data(x, y)); } + tColor GetColor(int x, int y) const { return Color(*Data(x, y)); } ///< Returns the color at the given coordinates. void ReduceBpp(const cPalette &Palette); ///< Reduces the color depth of the bitmap to that of the given Palette. diff --git a/player.h b/player.h index 9bd5a36..d252c57 100644 --- a/player.h +++ b/player.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: player.h 2.2 2009/01/05 13:04:10 kls Exp $ + * $Id: player.h 2.3 2009/01/25 11:03:44 kls Exp $ */ #ifndef __PLAYER_H @@ -26,6 +26,7 @@ protected: bool DevicePoll(cPoller &Poller, int TimeoutMs = 0) { return device ? device->Poll(Poller, TimeoutMs) : false; } bool DeviceFlush(int TimeoutMs = 0) { return device ? device->Flush(TimeoutMs) : true; } bool DeviceHasIBPTrickSpeed(void) { return device ? device->HasIBPTrickSpeed() : false; } + bool DeviceIsPlayingVideo(void) { return device ? device->IsPlayingVideo() : false; } void DeviceTrickSpeed(int Speed) { if (device) device->TrickSpeed(Speed); } void DeviceClear(void) { if (device) device->Clear(); } void DevicePlay(void) { if (device) device->Play(); } diff --git a/recorder.c b/recorder.c index 83024ac..7e41c8d 100644 --- a/recorder.c +++ b/recorder.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recorder.c 2.1 2009/01/06 12:38:01 kls Exp $ + * $Id: recorder.c 2.2 2009/01/23 15:33:37 kls Exp $ */ #include "recorder.h" @@ -44,7 +44,7 @@ cRecorder::cRecorder(const char *FileName, tChannelID ChannelID, int Priority, i Type = 0x06; } frameDetector = new cFrameDetector(Pid, Type); - patPmtGenerator.GeneratePmt(ChannelID); + patPmtGenerator.SetChannel(Channel); fileName = NULL; index = NULL; fileSize = 0; diff --git a/recording.c b/recording.c index 2948343..9c7db99 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 2.4 2009/01/06 14:41:11 kls Exp $ + * $Id: recording.c 2.8 2009/01/24 13:11:04 kls Exp $ */ #include "recording.h" @@ -64,6 +64,7 @@ #define MAX_LINK_LEVEL 6 bool VfatFileSystem = false; +int InstanceId = 0; cRecordings DeletedRecordings(true); @@ -154,9 +155,10 @@ void AssertFreeDiskSpace(int Priority, bool Force) } r = DeletedRecordings.Next(r); } - if (r0 && r0->Remove()) { + if (r0) { + if (r0->Remove()) + LastFreeDiskCheck += REMOVELATENCY / Factor; DeletedRecordings.Del(r0); - LastFreeDiskCheck += REMOVELATENCY / Factor; return; } } @@ -601,7 +603,7 @@ cRecording::cRecording(cTimer *Timer, const cEvent *Event) name = NULL; fileSizeMB = -1; // unknown channel = Timer->Channel()->Number(); - resumeId = Setup.ResumeID; + instanceId = InstanceId; isPesRecording = false; framesPerSecond = DEFAULTFRAMESPERSECOND; deleted = 0; @@ -658,7 +660,7 @@ cRecording::cRecording(const char *FileName) resume = RESUME_NOT_INITIALIZED; fileSizeMB = -1; // unknown channel = -1; - resumeId = -1; + instanceId = -1; priority = MAXPRIORITY; // assume maximum in case there is no info file lifetime = MAXLIFETIME; isPesRecording = false; @@ -677,7 +679,7 @@ cRecording::cRecording(const char *FileName) struct tm tm_r; struct tm t = *localtime_r(&now, &tm_r); // this initializes the time zone in 't' t.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting - if (7 == sscanf(p + 1, DATAFORMATTS, &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &channel, &resumeId) + if (7 == sscanf(p + 1, DATAFORMATTS, &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &channel, &instanceId) || 7 == sscanf(p + 1, DATAFORMATPES, &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &priority, &lifetime)) { t.tm_year -= 1900; t.tm_mon--; @@ -687,7 +689,7 @@ cRecording::cRecording(const char *FileName) strncpy(name, FileName, p - FileName); name[p - FileName] = 0; name = ExchangeChars(name, false); - isPesRecording = resumeId < 0; + isPesRecording = instanceId < 0; } else return; @@ -826,7 +828,7 @@ const char *cRecording::FileName(void) const struct tm *t = localtime_r(&start, &tm_r); const char *fmt = isPesRecording ? NAMEFORMATPES : NAMEFORMATTS; int ch = isPesRecording ? priority : channel; - int ri = isPesRecording ? lifetime : resumeId; + int ri = isPesRecording ? lifetime : instanceId; name = ExchangeChars(name, true); fileName = strdup(cString::sprintf(fmt, VideoDirectory, name, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, ch, ri)); name = ExchangeChars(name, false); @@ -1430,6 +1432,19 @@ void cIndexFile::ConvertFromPes(tIndexTs *IndexTs, int Count) } } +void cIndexFile::ConvertToPes(tIndexTs *IndexTs, int Count) +{ + tIndexPes IndexPes; + while (Count-- > 0) { + IndexPes.offset = uint32_t(IndexTs->offset); + IndexPes.type = IndexTs->independent ? 1 : 2; // I_FRAME : "not I_FRAME" (exact frame type doesn't matter) + IndexPes.number = IndexTs->number; + IndexPes.reserved = 0; + memcpy(IndexTs, &IndexPes, sizeof(*IndexTs)); + IndexTs++; + } +} + bool cIndexFile::CatchUp(int Index) { // returns true unless something really goes wrong, so that 'index' becomes NULL @@ -1489,6 +1504,8 @@ bool cIndexFile::Write(bool Independent, uint16_t FileNumber, off_t FileOffset) { if (f >= 0) { tIndexTs i(FileOffset, Independent, FileNumber); + if (isPesRecording) + ConvertToPes(&i, 1); if (safe_write(f, &i, sizeof(i)) < 0) { LOG_ERROR_STR(fileName); close(f); @@ -1696,7 +1713,7 @@ cString IndexToHMSF(int Index, bool WithFrame, double FramesPerSecond) { char buffer[16]; double Seconds; - int f = modf((Index + 0.5) / FramesPerSecond, &Seconds) * FramesPerSecond + 1; + int f = int(modf((Index + 0.5) / FramesPerSecond, &Seconds) * FramesPerSecond + 1); int s = int(Seconds); int m = s / 60 % 60; int h = s / 3600; @@ -1718,7 +1735,7 @@ int HMSFToIndex(const char *HMSF, double FramesPerSecond) int SecondsToFrames(int Seconds, double FramesPerSecond) { - return round(Seconds * FramesPerSecond); + return int(round(Seconds * FramesPerSecond)); } // --- ReadFrame ------------------------------------------------------------- diff --git a/recording.h b/recording.h index a1d497d..5256a8e 100644 --- a/recording.h +++ b/recording.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 2.1 2009/01/06 10:49:59 kls Exp $ + * $Id: recording.h 2.4 2009/01/24 15:24:19 kls Exp $ */ #ifndef __RECORDING_H @@ -19,6 +19,7 @@ #include "tools.h" extern bool VfatFileSystem; +extern int InstanceId; void RemoveDeletedRecordings(void); void AssertFreeDiskSpace(int Priority = 0, bool Force = false); @@ -82,7 +83,7 @@ private: mutable char *name; mutable int fileSizeMB; int channel; - int resumeId; + int instanceId; bool isPesRecording; double framesPerSecond; cRecordingInfo *info; @@ -208,13 +209,14 @@ public: #define MAXFRAMESIZE KILOBYTE(512) // The maximum file size is limited by the range that can be covered -// with 'int'. 4GB might be possible (if the range is considered -// 'unsigned'), 2GB should be possible (even if the range is considered -// 'signed'), so let's use 2000MB for absolute safety (the actual file size -// may be slightly higher because we stop recording only before the next -// 'I' frame, to have a complete Group Of Pictures): -#define MAXVIDEOFILESIZE 2000 // MB -#define MINVIDEOFILESIZE 100 // MB +// with a 40 bit 'unsigned int', which is 1TB. The actual maximum value +// used is 6MB below the theoretical maximum, to have some safety (the +// actual file size may be slightly higher because we stop recording only +// before the next independent frame, to have a complete Group Of Pictures): +#define MAXVIDEOFILESIZETS 1048570 // MB +#define MAXVIDEOFILESIZEPES 2000 // MB +#define MINVIDEOFILESIZE 100 // MB +#define MAXVIDEOFILESIZEDEFAULT MAXVIDEOFILESIZEPES struct tIndexTs; @@ -228,6 +230,7 @@ private: cResumeFile resumeFile; cMutex mutex; void ConvertFromPes(tIndexTs *IndexTs, int Count); + void ConvertToPes(tIndexTs *IndexTs, int Count); bool CatchUp(int Index = -1); public: cIndexFile(const char *FileName, bool Record, bool IsPesRecording = false); diff --git a/remux.c b/remux.c index 840f5df..b008621 100644 --- a/remux.c +++ b/remux.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remux.c 2.5 2009/01/06 14:46:21 kls Exp $ + * $Id: remux.c 2.13 2009/01/24 13:44:45 kls Exp $ */ #include "remux.h" @@ -111,13 +111,14 @@ void cRemux::SetBrokenLink(uchar *Data, int Length) // --- cPatPmtGenerator ------------------------------------------------------ -cPatPmtGenerator::cPatPmtGenerator(void) +cPatPmtGenerator::cPatPmtGenerator(cChannel *Channel) { numPmtPackets = 0; patCounter = pmtCounter = 0; patVersion = pmtVersion = 0; + pmtPid = 0; esInfoLength = NULL; - GeneratePat(); + SetChannel(Channel); } void cPatPmtGenerator::IncCounter(int &Counter, uchar *TsPacket) @@ -206,16 +207,31 @@ int cPatPmtGenerator::MakeCRC(uchar *Target, const uchar *Data, int Length) } #define P_TSID 0x8008 // pseudo TS ID -#define P_PNR 0x0084 // pseudo Program Number #define P_PMT_PID 0x0084 // pseudo PMT pid +#define MAXPID 0x2000 // the maximum possible number of pids + +void cPatPmtGenerator::GeneratePmtPid(cChannel *Channel) +{ + bool Used[MAXPID] = { false }; +#define SETPID(p) { if ((p) >= 0 && (p) < MAXPID) Used[p] = true; } +#define SETPIDS(l) { const int *p = l; while (*p) { SETPID(*p); p++; } } + SETPID(Channel->Vpid()); + SETPID(Channel->Ppid()); + SETPID(Channel->Tpid()); + SETPIDS(Channel->Apids()); + SETPIDS(Channel->Dpids()); + SETPIDS(Channel->Spids()); + for (pmtPid = P_PMT_PID; Used[pmtPid]; pmtPid++) + ; +} void cPatPmtGenerator::GeneratePat(void) { memset(pat, 0xFF, sizeof(pat)); uchar *p = pat; int i = 0; - p[i++] = 0x47; // TS indicator - p[i++] = 0x40; // flags (3), pid hi (5) + p[i++] = TS_SYNC_BYTE; // TS indicator + p[i++] = TS_PAYLOAD_START; // flags (3), pid hi (5) p[i++] = 0x00; // pid lo p[i++] = 0x10; // flags (4), continuity counter (4) p[i++] = 0x00; // pointer field (payload unit start indicator is set) @@ -229,22 +245,21 @@ void cPatPmtGenerator::GeneratePat(void) p[i++] = 0xC1 | (patVersion << 1); // dummy (2), version number (5), current/next indicator (1) p[i++] = 0x00; // section number p[i++] = 0x00; // last section number - p[i++] = P_PNR >> 8; // program number hi - p[i++] = P_PNR & 0xFF; // program number lo - p[i++] = 0xE0 | (P_PMT_PID >> 8); // dummy (3), PMT pid hi (5) - p[i++] = P_PMT_PID & 0xFF; // PMT pid lo + p[i++] = pmtPid >> 8; // program number hi + p[i++] = pmtPid & 0xFF; // program number lo + p[i++] = 0xE0 | (pmtPid >> 8); // dummy (3), PMT pid hi (5) + p[i++] = pmtPid & 0xFF; // PMT pid lo pat[SectionLength] = i - SectionLength - 1 + 4; // -2 = SectionLength storage, +4 = length of CRC MakeCRC(pat + i, pat + PayloadStart, i - PayloadStart); IncVersion(patVersion); } -void cPatPmtGenerator::GeneratePmt(tChannelID ChannelID) +void cPatPmtGenerator::GeneratePmt(cChannel *Channel) { // generate the complete PMT section: uchar buf[MAX_SECTION_SIZE]; memset(buf, 0xFF, sizeof(buf)); numPmtPackets = 0; - cChannel *Channel = Channels.GetByChannelID(ChannelID); if (Channel) { int Vpid = Channel->Vpid(); uchar *p = buf; @@ -253,8 +268,8 @@ void cPatPmtGenerator::GeneratePmt(tChannelID ChannelID) int SectionLength = i; p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4) p[i++] = 0x00; // section length lo (filled in later) - p[i++] = P_PNR >> 8; // program number hi - p[i++] = P_PNR & 0xFF; // program number lo + p[i++] = pmtPid >> 8; // program number hi + p[i++] = pmtPid & 0xFF; // program number lo p[i++] = 0xC1 | (pmtVersion << 1); // dummy (2), version number (5), current/next indicator (1) p[i++] = 0x00; // section number p[i++] = 0x00; // last section number @@ -292,9 +307,9 @@ void cPatPmtGenerator::GeneratePmt(tChannelID ChannelID) while (i > 0) { uchar *p = pmt[numPmtPackets++]; int j = 0; - p[j++] = 0x47; // TS indicator - p[j++] = (pusi ? 0x40 : 0x00) | (P_PNR >> 8); // flags (3), pid hi (5) - p[j++] = P_PNR & 0xFF; // pid lo + p[j++] = TS_SYNC_BYTE; // TS indicator + p[j++] = (pusi ? TS_PAYLOAD_START : 0x00) | (pmtPid >> 8); // flags (3), pid hi (5) + p[j++] = pmtPid & 0xFF; // pid lo p[j++] = 0x10; // flags (4), continuity counter (4) if (pusi) { p[j++] = 0x00; // pointer field (payload unit start indicator is set) @@ -307,8 +322,15 @@ void cPatPmtGenerator::GeneratePmt(tChannelID ChannelID) } IncVersion(pmtVersion); } - else - esyslog("ERROR: can't find channel %s", *ChannelID.ToString()); +} + +void cPatPmtGenerator::SetChannel(cChannel *Channel) +{ + if (Channel) { + GeneratePmtPid(Channel); + GeneratePat(); + GeneratePmt(Channel); + } } uchar *cPatPmtGenerator::GetPat(void) @@ -320,7 +342,7 @@ uchar *cPatPmtGenerator::GetPat(void) uchar *cPatPmtGenerator::GetPmt(int &Index) { if (Index < numPmtPackets) { - IncCounter(patCounter, pmt[Index]); + IncCounter(pmtCounter, pmt[Index]); return pmt[Index++]; } return NULL; @@ -329,19 +351,33 @@ uchar *cPatPmtGenerator::GetPmt(int &Index) // --- cPatPmtParser --------------------------------------------------------- cPatPmtParser::cPatPmtParser(void) +{ + Reset(); +} + +void cPatPmtParser::Reset(void) { pmtSize = 0; + patVersion = pmtVersion = -1; pmtPid = -1; vpid = vtype = 0; } void cPatPmtParser::ParsePat(const uchar *Data, int Length) { + // Unpack the TS packet: + int PayloadOffset = TsPayloadOffset(Data); + Data += PayloadOffset; + Length -= PayloadOffset; // The PAT is always assumed to fit into a single TS packet + if ((Length -= Data[0] + 1) <= 0) + return; Data += Data[0] + 1; // process pointer_field SI::PAT Pat(Data, false); if (Pat.CheckCRCAndParse()) { dbgpatpmt("PAT: TSid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pat.getTransportStreamId(), Pat.getCurrentNextIndicator(), Pat.getVersionNumber(), Pat.getSectionNumber(), Pat.getLastSectionNumber()); + if (patVersion == Pat.getVersionNumber()) + return; SI::PAT::Association assoc; for (SI::Loop::Iterator it; Pat.associationLoop.getNext(assoc, it); ) { dbgpatpmt(" isNITPid = %d\n", assoc.isNITPid()); @@ -350,6 +386,7 @@ void cPatPmtParser::ParsePat(const uchar *Data, int Length) dbgpatpmt(" service id = %d, pid = %d\n", assoc.getServiceId(), assoc.getPid()); } } + patVersion = Pat.getVersionNumber(); } else esyslog("ERROR: can't parse PAT"); @@ -357,10 +394,17 @@ void cPatPmtParser::ParsePat(const uchar *Data, int Length) void cPatPmtParser::ParsePmt(const uchar *Data, int Length) { + // Unpack the TS packet: + bool PayloadStart = TsPayloadStart(Data); + int PayloadOffset = TsPayloadOffset(Data); + Data += PayloadOffset; + Length -= PayloadOffset; // The PMT may extend over several TS packets, so we need to assemble them - if (pmtSize == 0) { + if (PayloadStart) { + pmtSize = 0; + if ((Length -= Data[0] + 1) <= 0) + return; Data += Data[0] + 1; // this is the first packet - Length -= Data[0] + 1; if (SectionLength(Data, Length) > Length) { if (Length <= int(sizeof(pmt))) { memcpy(pmt, Data, Length); @@ -372,7 +416,7 @@ void cPatPmtParser::ParsePmt(const uchar *Data, int Length) } // the packet contains the entire PMT section, so we run into the actual parsing } - else { + else if (pmtSize > 0) { // this is a following packet, so we add it to the pmt storage if (Length <= int(sizeof(pmt)) - pmtSize) { memcpy(pmt + pmtSize, Data, Length); @@ -387,10 +431,14 @@ void cPatPmtParser::ParsePmt(const uchar *Data, int Length) // the PMT section is now complete, so we run into the actual parsing Data = pmt; } + else + return; // fragment of broken packet - ignore SI::PMT Pmt(Data, false); if (Pmt.CheckCRCAndParse()) { dbgpatpmt("PMT: sid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pmt.getServiceId(), Pmt.getCurrentNextIndicator(), Pmt.getVersionNumber(), Pmt.getSectionNumber(), Pmt.getLastSectionNumber()); dbgpatpmt(" pcr = %d\n", Pmt.getPCRPid()); + if (pmtVersion == Pmt.getVersionNumber()) + return; cDevice::PrimaryDevice()->ClrAvailableTracks(false, true); int NumApids = 0; int NumDpids = 0; @@ -496,6 +544,7 @@ void cPatPmtParser::ParsePmt(const uchar *Data, int Length) cDevice::PrimaryDevice()->EnsureAudioTrack(true); cDevice::PrimaryDevice()->EnsureSubtitleTrack(); } + pmtVersion = Pmt.getVersionNumber(); } else esyslog("ERROR: can't parse PMT"); @@ -559,8 +608,10 @@ const uchar *cTsToPes::GetPes(int &Length) } else { Length = PesLength(data); - offset = Length; // to make sure we break out in case of garbage data - return data; + if (Length <= length) { + offset = Length; // to make sure we break out in case of garbage data + return data; + } } } return NULL; @@ -703,6 +754,7 @@ int cFrameDetector::Analyze(const uchar *Data, int Length) if (frameDuration) { newFrame = true; independentFrame = true; + scanning = false; } else framesPerPayloadUnit = 1; diff --git a/remux.h b/remux.h index 9a0921d..8cb1223 100644 --- a/remux.h +++ b/remux.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remux.h 2.4 2009/01/06 12:40:43 kls Exp $ + * $Id: remux.h 2.7 2009/01/24 13:38:10 kls Exp $ */ #ifndef __REMUX_H @@ -153,6 +153,7 @@ private: int pmtCounter; int patVersion; int pmtVersion; + int pmtPid; uchar *esInfoLength; void IncCounter(int &Counter, uchar *TsPacket); void IncVersion(int &Version); @@ -163,16 +164,20 @@ protected: int MakeSubtitlingDescriptor(uchar *Target, const char *Language); int MakeLanguageDescriptor(uchar *Target, const char *Language); int MakeCRC(uchar *Target, const uchar *Data, int Length); -public: - cPatPmtGenerator(void); + void GeneratePmtPid(cChannel *Channel); + ///< Generates a PMT pid that doesn't collide with any of the actual + ///< pids of the Channel. void GeneratePat(void); ///< Generates a PAT section for later use with GetPat(). - ///< This function is called by default from the constructor. - void GeneratePmt(tChannelID ChannelID); - ///< Generates a PMT section for the given ChannelId, for later use + void GeneratePmt(cChannel *Channel); + ///< Generates a PMT section for the given Channel, for later use ///< with GetPmt(). +public: + cPatPmtGenerator(cChannel *Channel = NULL); + void SetChannel(cChannel *Channel); + ///< Sets the Channel for which the PAT/PMT shall be generated. uchar *GetPat(void); - ///< Returns a pointer to the PAT section, which consist of exactly + ///< Returns a pointer to the PAT section, which consists of exactly ///< one TS packet. uchar *GetPmt(int &Index); ///< Returns a pointer to the Index'th TS packet of the PMT section. @@ -187,6 +192,8 @@ class cPatPmtParser { private: uchar pmt[MAX_SECTION_SIZE]; int pmtSize; + int patVersion; + int pmtVersion; int pmtPid; int vpid; int vtype; @@ -194,12 +201,16 @@ protected: int SectionLength(const uchar *Data, int Length) { return (Length >= 3) ? ((int(Data[1]) & 0x0F) << 8)| Data[2] : 0; } public: cPatPmtParser(void); + void Reset(void); + ///< Resets the parser. This function must be called whenever a new + ///< stream is parsed. void ParsePat(const uchar *Data, int Length); - ///< Parses the given PAT Data, which is the payload of a single TS packet - ///< from the PAT stream. The PAT may consist only of a single TS packet. + ///< Parses the PAT data from the single TS packet in Data. + ///< Length is always TS_SIZE. void ParsePmt(const uchar *Data, int Length); - ///< Parses the given PMT Data, which is the payload of a single TS packet - ///< from the PMT stream. The PMT may consist of several TS packets, which + ///< Parses the PMT data from the single TS packet in Data. + ///< Length is always TS_SIZE. + ///< The PMT may consist of several TS packets, which ///< are delivered to the parser through several subsequent calls to ///< ParsePmt(). The whole PMT data will be processed once the last packet ///< has been received. diff --git a/tools.c b/tools.c index 627bcf8..f49206f 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 2.1 2008/12/24 15:25:15 kls Exp $ + * $Id: tools.c 2.2 2009/01/16 14:29:08 kls Exp $ */ #include "tools.h" @@ -1608,7 +1608,7 @@ ssize_t cUnbufferedFile::Write(const void *Data, size_t Size) // kind of write gathering enabled), but the syncs cause (io) load.. // Uncomment the next line if you think you need them. //fdatasync(fd); - off_t headdrop = min(curpos - totwritten, off_t(totwritten * 2)); + off_t headdrop = min(off_t(curpos - totwritten), off_t(totwritten * 2)); posix_fadvise(fd, curpos - totwritten - headdrop, totwritten + headdrop, POSIX_FADV_DONTNEED); totwritten = 0; } diff --git a/transfer.c b/transfer.c index 9a6aee3..a2ec9b4 100644 --- a/transfer.c +++ b/transfer.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: transfer.c 2.1 2008/08/15 14:32:12 kls Exp $ + * $Id: transfer.c 2.3 2009/01/23 15:34:26 kls Exp $ */ #include "transfer.h" @@ -14,7 +14,7 @@ cTransfer::cTransfer(tChannelID ChannelID, int VPid, const int *APids, const int *DPids, const int *SPids) :cReceiver(ChannelID, -1, VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids) { - patPmtGenerator.GeneratePmt(ChannelID); + patPmtGenerator.SetChannel(Channels.GetByChannelID(ChannelID)); } cTransfer::~cTransfer() @@ -31,6 +31,8 @@ void cTransfer::Activate(bool On) while (uchar *pmt = patPmtGenerator.GetPmt(Index)) PlayTs(pmt, TS_SIZE); } + else + cPlayer::Detach(); } void cTransfer::Receive(uchar *Data, int Length) diff --git a/vdr.1 b/vdr.1 index f5ffb9d..3df1684 100644 --- a/vdr.1 +++ b/vdr.1 @@ -8,7 +8,7 @@ .\" License as specified in the file COPYING that comes with the .\" vdr distribution. .\" -.\" $Id: vdr.1 2.0 2008/03/09 16:07:06 kls Exp $ +.\" $Id: vdr.1 2.1 2009/01/18 11:05:56 kls Exp $ .\" .TH vdr 1 "10 Feb 2008" "1.6" "Video Disk Recorder" .SH NAME @@ -71,6 +71,15 @@ grabbing images to disk is disabled. .B \-h, \-\-help Print a help message and exit. .TP +.BI \-i\ instance ,\ \-\-instance= instance +Use \fIinstance\fR as the id of this VDR instance (default is 0). +In an environment where several instances of VDR use the same video +directory, this parameter can be set to a positive integer value +that's unique for each instance, so that they won't interfere with +each other in case they record exactly the same broadcast. +The number given here will be part of the directory name in which +the recordings will be stored. +.TP .BI \-l\ level ,\ \-\-log= level Set logging to \fIlevel\fR. \fB0\fR\ =\ no logging, \fB1\fR\ =\ errors only, diff --git a/vdr.c b/vdr.c index fa36b88..34ad856 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/vdr * - * $Id: vdr.c 2.3 2008/09/06 14:08:44 kls Exp $ + * $Id: vdr.c 2.4 2009/01/18 11:02:37 kls Exp $ */ #include @@ -223,6 +223,7 @@ int main(int argc, char *argv[]) { "epgfile", required_argument, NULL, 'E' }, { "grab", required_argument, NULL, 'g' }, { "help", no_argument, NULL, 'h' }, + { "instance", required_argument, NULL, 'i' }, { "lib", required_argument, NULL, 'L' }, { "lirc", optional_argument, NULL, 'l' | 0x100 }, { "localedir",required_argument, NULL, 'l' | 0x200 }, @@ -245,7 +246,7 @@ int main(int argc, char *argv[]) }; int c; - while ((c = getopt_long(argc, argv, "a:c:dD:E:g:hl:L:mp:P:r:s:t:u:v:Vw:", long_options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "a:c:dD:E:g:hi:l:L:mp:P:r:s:t:u:v:Vw:", long_options, NULL)) != -1) { switch (c) { case 'a': AudioCommand = optarg; break; @@ -268,6 +269,13 @@ int main(int argc, char *argv[]) break; case 'h': DisplayHelp = true; break; + case 'i': if (isnumber(optarg)) { + InstanceId = atoi(optarg); + if (InstanceId >= 0) + break; + } + fprintf(stderr, "vdr: invalid instance id: %s\n", optarg); + return 2; case 'l': { char *p = strchr(optarg, '.'); if (p) -- cgit v1.2.3