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 Schller).
- Added clearing the TS buffers in cDevice::Detach() (thanks to Marco Schller).
- 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.
This commit is contained in:
Klaus Schmidinger 2009-01-25 13:13:00 +01:00
parent c296647594
commit 084e16c057
24 changed files with 351 additions and 157 deletions

View File

@ -660,6 +660,8 @@ Oliver Endriss <o.endriss@gmx.de>
the call to cStatus::MsgSetVolume() the call to cStatus::MsgSetVolume()
for providing a driver patch that allows replaying TS->PES converted video in for providing a driver patch that allows replaying TS->PES converted video in
Transfer Mode Transfer Mode
for providing a driver patch that allows direct replaying of TS video on full-featured
DVB cards
Reinhard Walter Buchner <rw.buchner@freenet.de> Reinhard Walter Buchner <rw.buchner@freenet.de>
for adding some satellites to 'sources.conf' for adding some satellites to 'sources.conf'
@ -1189,6 +1191,12 @@ Reinhard Nissl <rnissl@gmx.de>
for reporting the missing description of the 'S' channel parameter in vdr.5 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 for fixing cPatPmtParser::ParsePmt() to reset vpid and vtype when switching from
a video to an audio channel 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 <richard_robson@beeb.net> Richard Robson <richard_robson@beeb.net>
for reporting freezing replay if a timer starts while in Transfer Mode from the for reporting freezing replay if a timer starts while in Transfer Mode from the
@ -1313,6 +1321,7 @@ Andreas Regel <andreas.regel@gmx.de>
for implementing palette replace mode in the OSD bitmaps for implementing palette replace mode in the OSD bitmaps
for fixing handling numeric keys in the channel display after switching channel for fixing handling numeric keys in the channel display after switching channel
groups groups
for adding some missing 'const' statements to cBitmap
Thomas Bergwinkl <Thomas.Bergwinkl@vr-web.de> Thomas Bergwinkl <Thomas.Bergwinkl@vr-web.de>
for fixing the validity check for channel IDs, because some providers use TIDs 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, for fixing setting the date in the channel display of the classic and sttng skins,
to avoid unnecessary OSD access to avoid unnecessary OSD access
for changing cDvbDevice::GrabImage() to use V4L2 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 <j.schmitz@web.de> Jürgen Schmitz <j.schmitz@web.de>
for reporting a bug in displaying the current channel when switching via the SVDRP for reporting a bug in displaying the current channel when switching via the SVDRP
@ -1594,6 +1605,7 @@ Udo Richter <udo_richter@gmx.de>
for fixing error handling in cCuttingThread::Action() for fixing error handling in cCuttingThread::Action()
for suppressing the automatic shutdown if the remote control is currently disabled for suppressing the automatic shutdown if the remote control is currently disabled
for fixing a problem with calling isyslog() from within the SignalHandler() for fixing a problem with calling isyslog() from within the SignalHandler()
for reporting a problem with handling the maximum video file size
Sven Kreiensen <svenk@kammer.uni-hannover.de> Sven Kreiensen <svenk@kammer.uni-hannover.de>
for his help in keeping 'channels.conf.terr' up to date for his help in keeping 'channels.conf.terr' up to date
@ -2207,6 +2219,8 @@ Frank Schmirler <vdr@schmirler.de>
allowed characters allowed characters
for fixing handling address masks in SVDRP host settings for fixing handling address masks in SVDRP host settings
for fixing handling the 'pointer field' in generating and parsing PAT/PMT 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 <joern@zyn.de> Jörn Reder <joern@zyn.de>
for reporting that a recording may unnecessarily block a device with a CAM, while for reporting that a recording may unnecessarily block a device with a CAM, while
@ -2331,6 +2345,7 @@ Benjamin Hess <benjamin.h@gmx.ch>
Winfried Koehler <w_koehl@gmx.de> Winfried Koehler <w_koehl@gmx.de>
for fixing finding new transponders for fixing finding new transponders
for reporting a compiler warning in calculations involving FramesPerSecond()
Hans-Werner Hilse <hilse@web.de> Hans-Werner Hilse <hilse@web.de>
for adding the command line option --userdump to enable core dumps in case VDR for adding the command line option --userdump to enable core dumps in case VDR
@ -2392,3 +2407,9 @@ Niels Wagenaar <n.wagenaar@xs4all.nl>
Edgar Hucek <gimli@dark-green.com> Edgar Hucek <gimli@dark-green.com>
for a patch that was used to convert VDR to the S2API driver API for a patch that was used to convert VDR to the S2API driver API
Johann Friedrichs <johann.friedrichs@web.de>
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).

77
HISTORY
View File

@ -5868,9 +5868,9 @@ Video Disk Recorder Revision History
255). 255).
+ The recording file names are now of the form 00001.ts (previously 001.vdr). + 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 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 The "frames per second" is stored in the "info" file using the new tag F
file using the new tag F (thanks to Artur Skawina for helping to get the (thanks to Artur Skawina for helping to get the IndexToHMSF() calculation
IndexToHMSF() calculation right). right).
+ Several functions now have an additional parameter FramesPerSecond. + Several functions now have an additional parameter FramesPerSecond.
+ Several functions now have an additional parameter IsPesRecording. + Several functions now have an additional parameter IsPesRecording.
+ The functionality of cFileWriter was moved into cRecorder, and cRemux is + 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 + 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.pr.lt.rec (pr=priority, lt=lifetime) to
YYYY-MM-DD-hh.mm.ch-ri.rec (ch=channel, ri=resumeId). 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 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 default, which avoids inadvertently deleting a recording if disk space
is low). No longer storing Priority and Lifetime in the directory name 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). a video to an audio channel (thanks to Reinhard Nissl).
- cDvbDevice now uses the FE_CAN_2G_MODULATION flag to determine whether a device - 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 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.

View File

@ -6,7 +6,7 @@
# See the main source file 'vdr.c' for copyright information and # See the main source file 'vdr.c' for copyright information and
# how to reach the author. # 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: ### The C compiler and options:
@ -19,6 +19,7 @@ CXXFLAGS = -g -O2 -Wall -Woverloaded-virtual -Wno-parentheses
ifdef PLUGIN ifdef PLUGIN
CFLAGS += -fPIC CFLAGS += -fPIC
CXXFLAGS += -fPIC CXXFLAGS += -fPIC
DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE
endif endif
### The directory environment: ### The directory environment:

View File

@ -16,7 +16,10 @@ html, body {
text-align: center; text-align: center;
} }
.code { .code {
background-color: #f0f0f0; background-color: #F0F0F0;
}
.modified {
background-color: #FFDDDD;
} }
</style> </style>
</head> </head>
@ -25,12 +28,15 @@ html, body {
<div class="center"> <div class="center">
<h1>The VDR Plugin System</h1> <h1>The VDR Plugin System</h1>
<b>Version 1.6</b> <b>Version 1.7</b>
<p> <p>
Copyright &copy; 2008 Klaus Schmidinger<br> Copyright &copy; 2009 Klaus Schmidinger<br>
<a href="mailto:kls@cadsoft.de">kls@cadsoft.de</a><br> <a href="mailto:kls@cadsoft.de">kls@cadsoft.de</a><br>
<a href="http://www.cadsoft.de/vdr">www.cadsoft.de/vdr</a> <a href="http://www.cadsoft.de/vdr">www.cadsoft.de/vdr</a>
</div> </div>
<div class="modified">
Important modifications introduced since version 1.6 are marked like this.
</div modified>
<p> <p>
VDR provides an easy to use plugin interface that allows additional functionality 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. 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 CanReplay(void) const;
virtual bool SetPlayMode(ePlayMode PlayMode); virtual bool SetPlayMode(ePlayMode PlayMode);
virtual int64_t GetSTC(void); virtual int64_t GetSTC(void);
<div class="modified">
virtual bool IsPlayingVideo(void) const;
</div modified>
virtual bool HasIBPTrickSpeed(void); virtual bool HasIBPTrickSpeed(void);
virtual void TrickSpeed(int Speed); virtual void TrickSpeed(int Speed);
virtual void Clear(void); virtual void Clear(void);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "config.h"
@ -275,7 +275,7 @@ cSetup::cSetup(void)
FontOsdSize = 22; FontOsdSize = 22;
FontSmlSize = 18; FontSmlSize = 18;
FontFixSize = 20; FontFixSize = 20;
MaxVideoFileSize = MAXVIDEOFILESIZE; MaxVideoFileSize = MAXVIDEOFILESIZEDEFAULT;
SplitEditedFiles = 0; SplitEditedFiles = 0;
MinEventTimeout = 30; MinEventTimeout = 30;
MinUserInactivity = 300; MinUserInactivity = 300;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef __CONFIG_H
@ -22,13 +22,13 @@
// VDR's own version number: // VDR's own version number:
#define VDRVERSION "1.7.3" #define VDRVERSION "1.7.4"
#define VDRVERSNUM 10703 // Version * 10000 + Major * 100 + Minor #define VDRVERSNUM 10704 // Version * 10000 + Major * 100 + Minor
// The plugin API's version number: // The plugin API's version number:
#define APIVERSION "1.7.3" #define APIVERSION "1.7.4"
#define APIVERSNUM 10703 // Version * 10000 + Major * 100 + Minor #define APIVERSNUM 10704 // Version * 10000 + Major * 100 + Minor
// When loading plugins, VDR searches them by their APIVERSION, which // When loading plugins, VDR searches them by their APIVERSION, which
// may be smaller than VDRVERSION in case there have been no changes to // may be smaller than VDRVERSION in case there have been no changes to

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "cutter.h"
@ -22,6 +22,7 @@ private:
cFileName *fromFileName, *toFileName; cFileName *fromFileName, *toFileName;
cIndexFile *fromIndex, *toIndex; cIndexFile *fromIndex, *toIndex;
cMarks fromMarks, toMarks; cMarks fromMarks, toMarks;
off_t maxVideoFileSize;
protected: protected:
virtual void Action(void); virtual void Action(void);
public: public:
@ -45,6 +46,9 @@ cCuttingThread::cCuttingThread(const char *FromFileName, const char *ToFileName)
fromIndex = new cIndexFile(FromFileName, false, isPesRecording); fromIndex = new cIndexFile(FromFileName, false, isPesRecording);
toIndex = new cIndexFile(ToFileName, true, isPesRecording); toIndex = new cIndexFile(ToFileName, true, isPesRecording);
toMarks.Load(ToFileName, Recording.FramesPerSecond(), isPesRecording); // doesn't actually load marks, just sets the file name 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(); Start();
} }
else else
@ -125,7 +129,7 @@ void cCuttingThread::Action(void)
if (Independent) { // every file shall start with an independent frame if (Independent) { // every file shall start with an independent frame
if (LastMark) // edited version shall end before next I-frame if (LastMark) // edited version shall end before next I-frame
break; break;
if (FileSize > MEGABYTE(Setup.MaxVideoFileSize)) { if (FileSize > maxVideoFileSize) {
toFile = toFileName->NextFile(); toFile = toFileName->NextFile();
if (!toFile) { if (!toFile) {
error = "toFile 1"; error = "toFile 1";

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "device.h"
@ -81,6 +81,7 @@ cDevice::cDevice(void)
startScrambleDetection = 0; startScrambleDetection = 0;
player = NULL; player = NULL;
isPlayingVideo = false;
ClrAvailableTracks(); ClrAvailableTracks();
currentAudioTrack = ttNone; currentAudioTrack = ttNone;
currentAudioTrackMissingCount = 0; currentAudioTrackMissingCount = 0;
@ -1020,12 +1021,11 @@ void cDevice::StillPicture(const uchar *Data, int Length)
uchar *buf = NULL; uchar *buf = NULL;
int Size = 0; int Size = 0;
while (Length >= TS_SIZE) { while (Length >= TS_SIZE) {
int PayloadOffset = TsPayloadOffset(Data);
int Pid = TsPid(Data); int Pid = TsPid(Data);
if (Pid == 0) if (Pid == 0)
patPmtParser.ParsePat(Data + PayloadOffset, TS_SIZE - PayloadOffset); patPmtParser.ParsePat(Data, TS_SIZE);
else if (Pid == patPmtParser.PmtPid()) else if (Pid == patPmtParser.PmtPid())
patPmtParser.ParsePmt(Data + PayloadOffset, TS_SIZE - PayloadOffset); patPmtParser.ParsePmt(Data, TS_SIZE);
else if (Pid == patPmtParser.Vpid()) { else if (Pid == patPmtParser.Vpid()) {
if (TsPayloadStart(Data)) { if (TsPayloadStart(Data)) {
int l; int l;
@ -1098,7 +1098,9 @@ void cDevice::Detach(cPlayer *Player)
dvbSubtitleConverter = NULL; dvbSubtitleConverter = NULL;
SetPlayMode(pmNone); SetPlayMode(pmNone);
SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat)); SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat));
PlayTs(NULL, 0);
Audios.ClearAudio(); Audios.ClearAudio();
isPlayingVideo = false;
} }
} }
@ -1151,6 +1153,7 @@ int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly)
switch (c) { switch (c) {
case 0xBE: // padding stream, needed for MPEG1 case 0xBE: // padding stream, needed for MPEG1
case 0xE0 ... 0xEF: // video case 0xE0 ... 0xEF: // video
isPlayingVideo = true;
w = PlayVideo(Start, d); w = PlayVideo(Start, d);
break; break;
case 0xC0 ... 0xDF: // audio case 0xC0 ... 0xDF: // audio
@ -1273,7 +1276,7 @@ int cDevice::PlayTsVideo(const uchar *Data, int Length)
int l; int l;
while (const uchar *p = tsToPesVideo.GetPes(l)) { while (const uchar *p = tsToPesVideo.GetPes(l)) {
int w = PlayVideo(p, l); int w = PlayVideo(p, l);
if (w < 0) if (w <= 0)
return w; return w;
} }
tsToPesVideo.Reset(); tsToPesVideo.Reset();
@ -1284,20 +1287,15 @@ int cDevice::PlayTsVideo(const uchar *Data, int Length)
int cDevice::PlayTsAudio(const uchar *Data, int Length) int cDevice::PlayTsAudio(const uchar *Data, int Length)
{ {
bool PayloadStart = TsPayloadStart(Data); // Audio PES always has an explicit length and consists of single packets:
for (int Pass = 0; Pass < 2; Pass++) { int l;
if (Pass == 0 && !PayloadStart) // if no new payload is started, we can always put the packet into the converter if (const uchar *p = tsToPesAudio.GetPes(l)) {
tsToPesAudio.PutTs(Data, Length); int w = PlayAudio(p, l, 0);
if (const uchar *p = tsToPesAudio.GetPes(Length)) { if (w <= 0)
int w = PlayAudio(p, Length, 0); return w;
if (w > 0) tsToPesAudio.Reset();
tsToPesAudio.Reset(); }
else if (PayloadStart) tsToPesAudio.PutTs(Data, Length);
return w; // must get out the old packet before starting a new one
}
if (Pass == 0 && PayloadStart)
tsToPesAudio.PutTs(Data, Length);
}
return 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 return Length; // silently ignore TS packets w/o payload
int PayloadOffset = TsPayloadOffset(Data); int PayloadOffset = TsPayloadOffset(Data);
if (PayloadOffset < Length) { if (PayloadOffset < Length) {
cMutexLock MutexLock(&mutexCurrentAudioTrack);
int Pid = TsPid(Data); int Pid = TsPid(Data);
if (Pid == 0) if (Pid == 0)
patPmtParser.ParsePat(Data + PayloadOffset, Length - PayloadOffset); patPmtParser.ParsePat(Data, Length);
else if (Pid == patPmtParser.PmtPid()) else if (Pid == patPmtParser.PmtPid())
patPmtParser.ParsePmt(Data + PayloadOffset, Length - PayloadOffset); patPmtParser.ParsePmt(Data, Length);
else if (Pid == patPmtParser.Vpid()) else if (Pid == patPmtParser.Vpid()) {
isPlayingVideo = true;
return PlayTsVideo(Data, Length); return PlayTsVideo(Data, Length);
}
else if (Pid == availableTracks[currentAudioTrack].id) { else if (Pid == availableTracks[currentAudioTrack].id) {
if (!VideoOnly || HasIBPTrickSpeed()) { if (!VideoOnly || HasIBPTrickSpeed()) {
int w = PlayTsAudio(Data, Length); int w = PlayTsAudio(Data, Length);
@ -1344,6 +1345,7 @@ int cDevice::PlayTs(const uchar *Data, int Length, bool VideoOnly)
} }
} }
else if (Data == NULL) { else if (Data == NULL) {
patPmtParser.Reset();
tsToPesVideo.Reset(); tsToPesVideo.Reset();
tsToPesAudio.Reset(); tsToPesAudio.Reset();
tsToPesSubtitle.Reset(); tsToPesSubtitle.Reset();

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef __DEVICE_H
@ -477,6 +477,7 @@ private:
cTsToPes tsToPesVideo; cTsToPes tsToPesVideo;
cTsToPes tsToPesAudio; cTsToPes tsToPesAudio;
cTsToPes tsToPesSubtitle; cTsToPes tsToPesSubtitle;
bool isPlayingVideo;
protected: protected:
virtual bool CanReplay(void) const; virtual bool CanReplay(void) const;
///< Returns true if this device can currently start a replay session. ///< Returns true if this device can currently start a replay session.
@ -487,7 +488,7 @@ protected:
///< Plays the given data block as video. ///< Plays the given data block as video.
///< Data points to exactly one complete PES packet of the given Length. ///< Data points to exactly one complete PES packet of the given Length.
///< PlayVideo() shall process the packet either as a whole (returning ///< 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 ///< \return Returns the number of bytes actually taken from Data, or -1
///< in case of an error. ///< in case of an error.
virtual int PlayAudio(const uchar *Data, int Length, uchar Id); 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 ///< TS replay). Plugins that need to know this Id shall read it from the
///< actual PES data (it's the 4th byte). ///< actual PES data (it's the 4th byte).
///< PlayAudio() shall process the packet either as a whole (returning ///< 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 ///< \return Returns the number of bytes actually taken from Data, or -1
///< in case of an error. ///< in case of an error.
virtual int PlaySubtitle(const uchar *Data, int Length); virtual int PlaySubtitle(const uchar *Data, int Length);
///< Plays the given data block as a subtitle. ///< Plays the given data block as a subtitle.
///< Data points to exactly one complete PES packet of the given Length. ///< Data points to exactly one complete PES packet of the given Length.
///< PlaySubtitle() shall process the packet either as a whole (returning ///< 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 ///< \return Returns the number of bytes actually taken from Data, or -1
///< in case of an error. ///< in case of an error.
virtual int PlayPesPacket(const uchar *Data, int Length, bool VideoOnly = false); 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 ///< Gets the current System Time Counter, which can be used to
///< synchronize audio and video. If this device is unable to ///< synchronize audio and video. If this device is unable to
///< provide the STC, -1 will be returned. ///< 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; } virtual bool HasIBPTrickSpeed(void) { return false; }
///< Returns true if this device can handle all frames in 'fast forward' ///< Returns true if this device can handle all frames in 'fast forward'
///< trick speeds. ///< trick speeds.
@ -610,8 +614,7 @@ public:
///< Returns -1 in case of error, otherwise the number of actually ///< Returns -1 in case of error, otherwise the number of actually
///< processed bytes is returned, which must be Length. ///< processed bytes is returned, which must be Length.
///< PlayTs() shall process the packet either as a whole (returning ///< PlayTs() shall process the packet either as a whole (returning
///< a positive number, which needs not necessarily be Length) or not at all ///< Length) or not at all returning 0 or -1 and setting 'errno' accordingly).
///< (returning 0 or -1 and setting 'errno' to EAGAIN).
bool Replaying(void) const; bool Replaying(void) const;
///< Returns true if we are currently replaying. ///< Returns true if we are currently replaying.
bool Transferring(void) const; bool Transferring(void) const;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "dvbdevice.h"
@ -27,13 +27,6 @@
#include "status.h" #include "status.h"
#include "transfer.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_REC_AND_PLAY_ON_PRIMARY_DEVICE 1
#define DO_MULTIPLE_RECORDINGS 1 #define DO_MULTIPLE_RECORDINGS 1
@ -1304,39 +1297,22 @@ bool cDvbDevice::Flush(int TimeoutMs)
int cDvbDevice::PlayVideo(const uchar *Data, int Length) int cDvbDevice::PlayVideo(const uchar *Data, int Length)
{ {
int w; return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
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;
} }
int cDvbDevice::PlayAudio(const uchar *Data, int Length, uchar Id) int cDvbDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
{ {
int w; return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10);
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;
} }
int cDvbDevice::PlayTsVideo(const uchar *Data, int Length) 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 cDvbDevice::PlayTsAudio(const uchar *Data, int Length)
{ {
int w = PlayAudio(Data, TsGetPayload(&Data), 0); return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10);
return w >= 0 ? Length : w;
} }
bool cDvbDevice::OpenDvr(void) bool cDvbDevice::OpenDvr(void)

View File

@ -4,10 +4,11 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 "dvbplayer.h"
#include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include "recording.h" #include "recording.h"
#include "remux.h" #include "remux.h"
@ -347,7 +348,7 @@ bool cDvbPlayer::Save(void)
if (index) { if (index) {
int Index = writeIndex; int Index = writeIndex;
if (Index >= 0) { if (Index >= 0) {
Index -= RESUMEBACKUP * framesPerSecond; Index -= int(round(RESUMEBACKUP * framesPerSecond));
if (Index > 0) if (Index > 0)
Index = index->GetNextIFrame(Index, false); Index = index->GetNextIFrame(Index, false);
else else
@ -411,8 +412,12 @@ void cDvbPlayer::Action(void)
if (index->Get(readIndex + 1, &FileNumber, &FileOffset, NULL, &Length)) if (index->Get(readIndex + 1, &FileNumber, &FileOffset, NULL, &Length))
Index = readIndex + 1; Index = readIndex + 1;
} }
else else {
Index = index->GetNextIFrame(readIndex, playDir == pdForward, &FileNumber, &FileOffset, &Length, TimeShiftMode); 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 (Index >= 0) {
if (!NextFile(FileNumber, FileOffset)) { if (!NextFile(FileNumber, FileOffset)) {
readIndex = Index; readIndex = Index;
@ -515,9 +520,9 @@ void cDvbPlayer::Action(void)
if (p) { if (p) {
int w; int w;
if (isPesRecording) if (isPesRecording)
w = PlayPes(p, pc, playMode != pmPlay); w = PlayPes(p, pc, playMode != pmPlay && DeviceIsPlayingVideo());
else else
w = PlayTs(p, TS_SIZE, playMode != pmPlay); w = PlayTs(p, TS_SIZE, playMode != pmPlay && DeviceIsPlayingVideo());
if (w > 0) { if (w > 0) {
p += w; p += w;
pc -= w; pc -= w;
@ -592,7 +597,8 @@ void cDvbPlayer::Forward(void)
LOCK_THREAD; LOCK_THREAD;
if (!(DeviceHasIBPTrickSpeed() && playDir == pdForward)) if (!(DeviceHasIBPTrickSpeed() && playDir == pdForward))
Empty(); Empty();
DeviceMute(); if (DeviceIsPlayingVideo())
DeviceMute();
playMode = pmFast; playMode = pmFast;
playDir = pdForward; playDir = pdForward;
trickSpeed = NORMAL_SPEED; trickSpeed = NORMAL_SPEED;
@ -638,7 +644,8 @@ void cDvbPlayer::Backward(void)
case pmPlay: { case pmPlay: {
LOCK_THREAD; LOCK_THREAD;
Empty(); Empty();
DeviceMute(); if (DeviceIsPlayingVideo())
DeviceMute();
playMode = pmFast; playMode = pmFast;
playDir = pdBackward; playDir = pdBackward;
trickSpeed = NORMAL_SPEED; trickSpeed = NORMAL_SPEED;

9
menu.c
View File

@ -4,12 +4,13 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 "menu.h"
#include <ctype.h> #include <ctype.h>
#include <limits.h> #include <limits.h>
#include <math.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -2697,7 +2698,7 @@ cMenuSetupRecord::cMenuSetupRecord(void)
Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord)); 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 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$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)); 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 #define STAY_SECONDS_OFF_END 10
int Seconds = (timeSearchTime >> 24) * 36000 + ((timeSearchTime & 0x00FF0000) >> 16) * 3600 + ((timeSearchTime & 0x0000FF00) >> 8) * 600 + (timeSearchTime & 0x000000FF) * 60; int Seconds = (timeSearchTime >> 24) * 36000 + ((timeSearchTime & 0x00FF0000) >> 16) * 3600 + ((timeSearchTime & 0x0000FF00) >> 8) * 600 + (timeSearchTime & 0x000000FF) * 60;
int Current = (lastCurrent / FramesPerSecond()); int Current = int(round(lastCurrent / FramesPerSecond()));
int Total = (lastTotal / FramesPerSecond()); int Total = int(round(lastTotal / FramesPerSecond()));
switch (Key) { switch (Key) {
case k0 ... k9: case k0 ... k9:
if (timeSearchPos < 4) { if (timeSearchPos < 4) {

4
osd.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #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]; return &bitmap[y * width + x];
} }

6
osd.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef __OSD_H
@ -231,9 +231,9 @@ public:
///< 5: vertical, rising, upper ///< 5: vertical, rising, upper
///< 6: vertical, falling, lower ///< 6: vertical, falling, lower
///< 7: vertical, falling, upper ///< 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. ///< 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. ///< Returns the color at the given coordinates.
void ReduceBpp(const cPalette &Palette); void ReduceBpp(const cPalette &Palette);
///< Reduces the color depth of the bitmap to that of the given Palette. ///< Reduces the color depth of the bitmap to that of the given Palette.

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef __PLAYER_H
@ -26,6 +26,7 @@ protected:
bool DevicePoll(cPoller &Poller, int TimeoutMs = 0) { return device ? device->Poll(Poller, TimeoutMs) : false; } 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 DeviceFlush(int TimeoutMs = 0) { return device ? device->Flush(TimeoutMs) : true; }
bool DeviceHasIBPTrickSpeed(void) { return device ? device->HasIBPTrickSpeed() : false; } 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 DeviceTrickSpeed(int Speed) { if (device) device->TrickSpeed(Speed); }
void DeviceClear(void) { if (device) device->Clear(); } void DeviceClear(void) { if (device) device->Clear(); }
void DevicePlay(void) { if (device) device->Play(); } void DevicePlay(void) { if (device) device->Play(); }

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "recorder.h"
@ -44,7 +44,7 @@ cRecorder::cRecorder(const char *FileName, tChannelID ChannelID, int Priority, i
Type = 0x06; Type = 0x06;
} }
frameDetector = new cFrameDetector(Pid, Type); frameDetector = new cFrameDetector(Pid, Type);
patPmtGenerator.GeneratePmt(ChannelID); patPmtGenerator.SetChannel(Channel);
fileName = NULL; fileName = NULL;
index = NULL; index = NULL;
fileSize = 0; fileSize = 0;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "recording.h"
@ -64,6 +64,7 @@
#define MAX_LINK_LEVEL 6 #define MAX_LINK_LEVEL 6
bool VfatFileSystem = false; bool VfatFileSystem = false;
int InstanceId = 0;
cRecordings DeletedRecordings(true); cRecordings DeletedRecordings(true);
@ -154,9 +155,10 @@ void AssertFreeDiskSpace(int Priority, bool Force)
} }
r = DeletedRecordings.Next(r); r = DeletedRecordings.Next(r);
} }
if (r0 && r0->Remove()) { if (r0) {
if (r0->Remove())
LastFreeDiskCheck += REMOVELATENCY / Factor;
DeletedRecordings.Del(r0); DeletedRecordings.Del(r0);
LastFreeDiskCheck += REMOVELATENCY / Factor;
return; return;
} }
} }
@ -601,7 +603,7 @@ cRecording::cRecording(cTimer *Timer, const cEvent *Event)
name = NULL; name = NULL;
fileSizeMB = -1; // unknown fileSizeMB = -1; // unknown
channel = Timer->Channel()->Number(); channel = Timer->Channel()->Number();
resumeId = Setup.ResumeID; instanceId = InstanceId;
isPesRecording = false; isPesRecording = false;
framesPerSecond = DEFAULTFRAMESPERSECOND; framesPerSecond = DEFAULTFRAMESPERSECOND;
deleted = 0; deleted = 0;
@ -658,7 +660,7 @@ cRecording::cRecording(const char *FileName)
resume = RESUME_NOT_INITIALIZED; resume = RESUME_NOT_INITIALIZED;
fileSizeMB = -1; // unknown fileSizeMB = -1; // unknown
channel = -1; channel = -1;
resumeId = -1; instanceId = -1;
priority = MAXPRIORITY; // assume maximum in case there is no info file priority = MAXPRIORITY; // assume maximum in case there is no info file
lifetime = MAXLIFETIME; lifetime = MAXLIFETIME;
isPesRecording = false; isPesRecording = false;
@ -677,7 +679,7 @@ cRecording::cRecording(const char *FileName)
struct tm tm_r; struct tm tm_r;
struct tm t = *localtime_r(&now, &tm_r); // this initializes the time zone in 't' 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 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)) { || 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_year -= 1900;
t.tm_mon--; t.tm_mon--;
@ -687,7 +689,7 @@ cRecording::cRecording(const char *FileName)
strncpy(name, FileName, p - FileName); strncpy(name, FileName, p - FileName);
name[p - FileName] = 0; name[p - FileName] = 0;
name = ExchangeChars(name, false); name = ExchangeChars(name, false);
isPesRecording = resumeId < 0; isPesRecording = instanceId < 0;
} }
else else
return; return;
@ -826,7 +828,7 @@ const char *cRecording::FileName(void) const
struct tm *t = localtime_r(&start, &tm_r); struct tm *t = localtime_r(&start, &tm_r);
const char *fmt = isPesRecording ? NAMEFORMATPES : NAMEFORMATTS; const char *fmt = isPesRecording ? NAMEFORMATPES : NAMEFORMATTS;
int ch = isPesRecording ? priority : channel; int ch = isPesRecording ? priority : channel;
int ri = isPesRecording ? lifetime : resumeId; int ri = isPesRecording ? lifetime : instanceId;
name = ExchangeChars(name, true); 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)); 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); 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) bool cIndexFile::CatchUp(int Index)
{ {
// returns true unless something really goes wrong, so that 'index' becomes NULL // 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) { if (f >= 0) {
tIndexTs i(FileOffset, Independent, FileNumber); tIndexTs i(FileOffset, Independent, FileNumber);
if (isPesRecording)
ConvertToPes(&i, 1);
if (safe_write(f, &i, sizeof(i)) < 0) { if (safe_write(f, &i, sizeof(i)) < 0) {
LOG_ERROR_STR(fileName); LOG_ERROR_STR(fileName);
close(f); close(f);
@ -1696,7 +1713,7 @@ cString IndexToHMSF(int Index, bool WithFrame, double FramesPerSecond)
{ {
char buffer[16]; char buffer[16];
double Seconds; 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 s = int(Seconds);
int m = s / 60 % 60; int m = s / 60 % 60;
int h = s / 3600; int h = s / 3600;
@ -1718,7 +1735,7 @@ int HMSFToIndex(const char *HMSF, double FramesPerSecond)
int SecondsToFrames(int Seconds, double FramesPerSecond) int SecondsToFrames(int Seconds, double FramesPerSecond)
{ {
return round(Seconds * FramesPerSecond); return int(round(Seconds * FramesPerSecond));
} }
// --- ReadFrame ------------------------------------------------------------- // --- ReadFrame -------------------------------------------------------------

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef __RECORDING_H
@ -19,6 +19,7 @@
#include "tools.h" #include "tools.h"
extern bool VfatFileSystem; extern bool VfatFileSystem;
extern int InstanceId;
void RemoveDeletedRecordings(void); void RemoveDeletedRecordings(void);
void AssertFreeDiskSpace(int Priority = 0, bool Force = false); void AssertFreeDiskSpace(int Priority = 0, bool Force = false);
@ -82,7 +83,7 @@ private:
mutable char *name; mutable char *name;
mutable int fileSizeMB; mutable int fileSizeMB;
int channel; int channel;
int resumeId; int instanceId;
bool isPesRecording; bool isPesRecording;
double framesPerSecond; double framesPerSecond;
cRecordingInfo *info; cRecordingInfo *info;
@ -208,13 +209,14 @@ public:
#define MAXFRAMESIZE KILOBYTE(512) #define MAXFRAMESIZE KILOBYTE(512)
// The maximum file size is limited by the range that can be covered // The maximum file size is limited by the range that can be covered
// with 'int'. 4GB might be possible (if the range is considered // with a 40 bit 'unsigned int', which is 1TB. The actual maximum value
// 'unsigned'), 2GB should be possible (even if the range is considered // used is 6MB below the theoretical maximum, to have some safety (the
// 'signed'), so let's use 2000MB for absolute safety (the actual file size // actual file size may be slightly higher because we stop recording only
// may be slightly higher because we stop recording only before the next // before the next independent frame, to have a complete Group Of Pictures):
// 'I' frame, to have a complete Group Of Pictures): #define MAXVIDEOFILESIZETS 1048570 // MB
#define MAXVIDEOFILESIZE 2000 // MB #define MAXVIDEOFILESIZEPES 2000 // MB
#define MINVIDEOFILESIZE 100 // MB #define MINVIDEOFILESIZE 100 // MB
#define MAXVIDEOFILESIZEDEFAULT MAXVIDEOFILESIZEPES
struct tIndexTs; struct tIndexTs;
@ -228,6 +230,7 @@ private:
cResumeFile resumeFile; cResumeFile resumeFile;
cMutex mutex; cMutex mutex;
void ConvertFromPes(tIndexTs *IndexTs, int Count); void ConvertFromPes(tIndexTs *IndexTs, int Count);
void ConvertToPes(tIndexTs *IndexTs, int Count);
bool CatchUp(int Index = -1); bool CatchUp(int Index = -1);
public: public:
cIndexFile(const char *FileName, bool Record, bool IsPesRecording = false); cIndexFile(const char *FileName, bool Record, bool IsPesRecording = false);

102
remux.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "remux.h"
@ -111,13 +111,14 @@ void cRemux::SetBrokenLink(uchar *Data, int Length)
// --- cPatPmtGenerator ------------------------------------------------------ // --- cPatPmtGenerator ------------------------------------------------------
cPatPmtGenerator::cPatPmtGenerator(void) cPatPmtGenerator::cPatPmtGenerator(cChannel *Channel)
{ {
numPmtPackets = 0; numPmtPackets = 0;
patCounter = pmtCounter = 0; patCounter = pmtCounter = 0;
patVersion = pmtVersion = 0; patVersion = pmtVersion = 0;
pmtPid = 0;
esInfoLength = NULL; esInfoLength = NULL;
GeneratePat(); SetChannel(Channel);
} }
void cPatPmtGenerator::IncCounter(int &Counter, uchar *TsPacket) 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_TSID 0x8008 // pseudo TS ID
#define P_PNR 0x0084 // pseudo Program Number
#define P_PMT_PID 0x0084 // pseudo PMT pid #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) void cPatPmtGenerator::GeneratePat(void)
{ {
memset(pat, 0xFF, sizeof(pat)); memset(pat, 0xFF, sizeof(pat));
uchar *p = pat; uchar *p = pat;
int i = 0; int i = 0;
p[i++] = 0x47; // TS indicator p[i++] = TS_SYNC_BYTE; // TS indicator
p[i++] = 0x40; // flags (3), pid hi (5) p[i++] = TS_PAYLOAD_START; // flags (3), pid hi (5)
p[i++] = 0x00; // pid lo p[i++] = 0x00; // pid lo
p[i++] = 0x10; // flags (4), continuity counter (4) p[i++] = 0x10; // flags (4), continuity counter (4)
p[i++] = 0x00; // pointer field (payload unit start indicator is set) 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++] = 0xC1 | (patVersion << 1); // dummy (2), version number (5), current/next indicator (1)
p[i++] = 0x00; // section number p[i++] = 0x00; // section number
p[i++] = 0x00; // last section number p[i++] = 0x00; // last section number
p[i++] = P_PNR >> 8; // program number hi p[i++] = pmtPid >> 8; // program number hi
p[i++] = P_PNR & 0xFF; // program number lo p[i++] = pmtPid & 0xFF; // program number lo
p[i++] = 0xE0 | (P_PMT_PID >> 8); // dummy (3), PMT pid hi (5) p[i++] = 0xE0 | (pmtPid >> 8); // dummy (3), PMT pid hi (5)
p[i++] = P_PMT_PID & 0xFF; // PMT pid lo p[i++] = pmtPid & 0xFF; // PMT pid lo
pat[SectionLength] = i - SectionLength - 1 + 4; // -2 = SectionLength storage, +4 = length of CRC pat[SectionLength] = i - SectionLength - 1 + 4; // -2 = SectionLength storage, +4 = length of CRC
MakeCRC(pat + i, pat + PayloadStart, i - PayloadStart); MakeCRC(pat + i, pat + PayloadStart, i - PayloadStart);
IncVersion(patVersion); IncVersion(patVersion);
} }
void cPatPmtGenerator::GeneratePmt(tChannelID ChannelID) void cPatPmtGenerator::GeneratePmt(cChannel *Channel)
{ {
// generate the complete PMT section: // generate the complete PMT section:
uchar buf[MAX_SECTION_SIZE]; uchar buf[MAX_SECTION_SIZE];
memset(buf, 0xFF, sizeof(buf)); memset(buf, 0xFF, sizeof(buf));
numPmtPackets = 0; numPmtPackets = 0;
cChannel *Channel = Channels.GetByChannelID(ChannelID);
if (Channel) { if (Channel) {
int Vpid = Channel->Vpid(); int Vpid = Channel->Vpid();
uchar *p = buf; uchar *p = buf;
@ -253,8 +268,8 @@ void cPatPmtGenerator::GeneratePmt(tChannelID ChannelID)
int SectionLength = i; int SectionLength = i;
p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4) p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
p[i++] = 0x00; // section length lo (filled in later) p[i++] = 0x00; // section length lo (filled in later)
p[i++] = P_PNR >> 8; // program number hi p[i++] = pmtPid >> 8; // program number hi
p[i++] = P_PNR & 0xFF; // program number lo p[i++] = pmtPid & 0xFF; // program number lo
p[i++] = 0xC1 | (pmtVersion << 1); // dummy (2), version number (5), current/next indicator (1) p[i++] = 0xC1 | (pmtVersion << 1); // dummy (2), version number (5), current/next indicator (1)
p[i++] = 0x00; // section number p[i++] = 0x00; // section number
p[i++] = 0x00; // last section number p[i++] = 0x00; // last section number
@ -292,9 +307,9 @@ void cPatPmtGenerator::GeneratePmt(tChannelID ChannelID)
while (i > 0) { while (i > 0) {
uchar *p = pmt[numPmtPackets++]; uchar *p = pmt[numPmtPackets++];
int j = 0; int j = 0;
p[j++] = 0x47; // TS indicator p[j++] = TS_SYNC_BYTE; // TS indicator
p[j++] = (pusi ? 0x40 : 0x00) | (P_PNR >> 8); // flags (3), pid hi (5) p[j++] = (pusi ? TS_PAYLOAD_START : 0x00) | (pmtPid >> 8); // flags (3), pid hi (5)
p[j++] = P_PNR & 0xFF; // pid lo p[j++] = pmtPid & 0xFF; // pid lo
p[j++] = 0x10; // flags (4), continuity counter (4) p[j++] = 0x10; // flags (4), continuity counter (4)
if (pusi) { if (pusi) {
p[j++] = 0x00; // pointer field (payload unit start indicator is set) p[j++] = 0x00; // pointer field (payload unit start indicator is set)
@ -307,8 +322,15 @@ void cPatPmtGenerator::GeneratePmt(tChannelID ChannelID)
} }
IncVersion(pmtVersion); 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) uchar *cPatPmtGenerator::GetPat(void)
@ -320,7 +342,7 @@ uchar *cPatPmtGenerator::GetPat(void)
uchar *cPatPmtGenerator::GetPmt(int &Index) uchar *cPatPmtGenerator::GetPmt(int &Index)
{ {
if (Index < numPmtPackets) { if (Index < numPmtPackets) {
IncCounter(patCounter, pmt[Index]); IncCounter(pmtCounter, pmt[Index]);
return pmt[Index++]; return pmt[Index++];
} }
return NULL; return NULL;
@ -329,19 +351,33 @@ uchar *cPatPmtGenerator::GetPmt(int &Index)
// --- cPatPmtParser --------------------------------------------------------- // --- cPatPmtParser ---------------------------------------------------------
cPatPmtParser::cPatPmtParser(void) cPatPmtParser::cPatPmtParser(void)
{
Reset();
}
void cPatPmtParser::Reset(void)
{ {
pmtSize = 0; pmtSize = 0;
patVersion = pmtVersion = -1;
pmtPid = -1; pmtPid = -1;
vpid = vtype = 0; vpid = vtype = 0;
} }
void cPatPmtParser::ParsePat(const uchar *Data, int Length) 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 // 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 Data += Data[0] + 1; // process pointer_field
SI::PAT Pat(Data, false); SI::PAT Pat(Data, false);
if (Pat.CheckCRCAndParse()) { 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()); 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; SI::PAT::Association assoc;
for (SI::Loop::Iterator it; Pat.associationLoop.getNext(assoc, it); ) { for (SI::Loop::Iterator it; Pat.associationLoop.getNext(assoc, it); ) {
dbgpatpmt(" isNITPid = %d\n", assoc.isNITPid()); 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()); dbgpatpmt(" service id = %d, pid = %d\n", assoc.getServiceId(), assoc.getPid());
} }
} }
patVersion = Pat.getVersionNumber();
} }
else else
esyslog("ERROR: can't parse PAT"); 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) 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 // 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 Data += Data[0] + 1; // this is the first packet
Length -= Data[0] + 1;
if (SectionLength(Data, Length) > Length) { if (SectionLength(Data, Length) > Length) {
if (Length <= int(sizeof(pmt))) { if (Length <= int(sizeof(pmt))) {
memcpy(pmt, Data, Length); 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 // 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 // this is a following packet, so we add it to the pmt storage
if (Length <= int(sizeof(pmt)) - pmtSize) { if (Length <= int(sizeof(pmt)) - pmtSize) {
memcpy(pmt + pmtSize, Data, Length); 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 // the PMT section is now complete, so we run into the actual parsing
Data = pmt; Data = pmt;
} }
else
return; // fragment of broken packet - ignore
SI::PMT Pmt(Data, false); SI::PMT Pmt(Data, false);
if (Pmt.CheckCRCAndParse()) { 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("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()); dbgpatpmt(" pcr = %d\n", Pmt.getPCRPid());
if (pmtVersion == Pmt.getVersionNumber())
return;
cDevice::PrimaryDevice()->ClrAvailableTracks(false, true); cDevice::PrimaryDevice()->ClrAvailableTracks(false, true);
int NumApids = 0; int NumApids = 0;
int NumDpids = 0; int NumDpids = 0;
@ -496,6 +544,7 @@ void cPatPmtParser::ParsePmt(const uchar *Data, int Length)
cDevice::PrimaryDevice()->EnsureAudioTrack(true); cDevice::PrimaryDevice()->EnsureAudioTrack(true);
cDevice::PrimaryDevice()->EnsureSubtitleTrack(); cDevice::PrimaryDevice()->EnsureSubtitleTrack();
} }
pmtVersion = Pmt.getVersionNumber();
} }
else else
esyslog("ERROR: can't parse PMT"); esyslog("ERROR: can't parse PMT");
@ -559,8 +608,10 @@ const uchar *cTsToPes::GetPes(int &Length)
} }
else { else {
Length = PesLength(data); Length = PesLength(data);
offset = Length; // to make sure we break out in case of garbage data if (Length <= length) {
return data; offset = Length; // to make sure we break out in case of garbage data
return data;
}
} }
} }
return NULL; return NULL;
@ -703,6 +754,7 @@ int cFrameDetector::Analyze(const uchar *Data, int Length)
if (frameDuration) { if (frameDuration) {
newFrame = true; newFrame = true;
independentFrame = true; independentFrame = true;
scanning = false;
} }
else else
framesPerPayloadUnit = 1; framesPerPayloadUnit = 1;

33
remux.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef __REMUX_H
@ -153,6 +153,7 @@ private:
int pmtCounter; int pmtCounter;
int patVersion; int patVersion;
int pmtVersion; int pmtVersion;
int pmtPid;
uchar *esInfoLength; uchar *esInfoLength;
void IncCounter(int &Counter, uchar *TsPacket); void IncCounter(int &Counter, uchar *TsPacket);
void IncVersion(int &Version); void IncVersion(int &Version);
@ -163,16 +164,20 @@ protected:
int MakeSubtitlingDescriptor(uchar *Target, const char *Language); int MakeSubtitlingDescriptor(uchar *Target, const char *Language);
int MakeLanguageDescriptor(uchar *Target, const char *Language); int MakeLanguageDescriptor(uchar *Target, const char *Language);
int MakeCRC(uchar *Target, const uchar *Data, int Length); int MakeCRC(uchar *Target, const uchar *Data, int Length);
public: void GeneratePmtPid(cChannel *Channel);
cPatPmtGenerator(void); ///< Generates a PMT pid that doesn't collide with any of the actual
///< pids of the Channel.
void GeneratePat(void); void GeneratePat(void);
///< Generates a PAT section for later use with GetPat(). ///< Generates a PAT section for later use with GetPat().
///< This function is called by default from the constructor. void GeneratePmt(cChannel *Channel);
void GeneratePmt(tChannelID ChannelID); ///< Generates a PMT section for the given Channel, for later use
///< Generates a PMT section for the given ChannelId, for later use
///< with GetPmt(). ///< 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); 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. ///< one TS packet.
uchar *GetPmt(int &Index); uchar *GetPmt(int &Index);
///< Returns a pointer to the Index'th TS packet of the PMT section. ///< Returns a pointer to the Index'th TS packet of the PMT section.
@ -187,6 +192,8 @@ class cPatPmtParser {
private: private:
uchar pmt[MAX_SECTION_SIZE]; uchar pmt[MAX_SECTION_SIZE];
int pmtSize; int pmtSize;
int patVersion;
int pmtVersion;
int pmtPid; int pmtPid;
int vpid; int vpid;
int vtype; 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; } int SectionLength(const uchar *Data, int Length) { return (Length >= 3) ? ((int(Data[1]) & 0x0F) << 8)| Data[2] : 0; }
public: public:
cPatPmtParser(void); 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); void ParsePat(const uchar *Data, int Length);
///< Parses the given PAT Data, which is the payload of a single TS packet ///< Parses the PAT data from the single TS packet in Data.
///< from the PAT stream. The PAT may consist only of a single TS packet. ///< Length is always TS_SIZE.
void ParsePmt(const uchar *Data, int Length); void ParsePmt(const uchar *Data, int Length);
///< Parses the given PMT Data, which is the payload of a single TS packet ///< Parses the PMT data from the single TS packet in Data.
///< from the PMT stream. The PMT may consist of several TS packets, which ///< Length is always TS_SIZE.
///< The PMT may consist of several TS packets, which
///< are delivered to the parser through several subsequent calls to ///< are delivered to the parser through several subsequent calls to
///< ParsePmt(). The whole PMT data will be processed once the last packet ///< ParsePmt(). The whole PMT data will be processed once the last packet
///< has been received. ///< has been received.

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #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.. // kind of write gathering enabled), but the syncs cause (io) load..
// Uncomment the next line if you think you need them. // Uncomment the next line if you think you need them.
//fdatasync(fd); //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); posix_fadvise(fd, curpos - totwritten - headdrop, totwritten + headdrop, POSIX_FADV_DONTNEED);
totwritten = 0; totwritten = 0;
} }

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "transfer.h"
@ -14,7 +14,7 @@
cTransfer::cTransfer(tChannelID ChannelID, int VPid, const int *APids, const int *DPids, const int *SPids) 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) :cReceiver(ChannelID, -1, VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids)
{ {
patPmtGenerator.GeneratePmt(ChannelID); patPmtGenerator.SetChannel(Channels.GetByChannelID(ChannelID));
} }
cTransfer::~cTransfer() cTransfer::~cTransfer()
@ -31,6 +31,8 @@ void cTransfer::Activate(bool On)
while (uchar *pmt = patPmtGenerator.GetPmt(Index)) while (uchar *pmt = patPmtGenerator.GetPmt(Index))
PlayTs(pmt, TS_SIZE); PlayTs(pmt, TS_SIZE);
} }
else
cPlayer::Detach();
} }
void cTransfer::Receive(uchar *Data, int Length) void cTransfer::Receive(uchar *Data, int Length)

11
vdr.1
View File

@ -8,7 +8,7 @@
.\" License as specified in the file COPYING that comes with the .\" License as specified in the file COPYING that comes with the
.\" vdr distribution. .\" 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" .TH vdr 1 "10 Feb 2008" "1.6" "Video Disk Recorder"
.SH NAME .SH NAME
@ -71,6 +71,15 @@ grabbing images to disk is disabled.
.B \-h, \-\-help .B \-h, \-\-help
Print a help message and exit. Print a help message and exit.
.TP .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 .BI \-l\ level ,\ \-\-log= level
Set logging to \fIlevel\fR. Set logging to \fIlevel\fR.
\fB0\fR\ =\ no logging, \fB1\fR\ =\ errors only, \fB0\fR\ =\ no logging, \fB1\fR\ =\ errors only,

12
vdr.c
View File

@ -22,7 +22,7 @@
* *
* The project's page is at http://www.cadsoft.de/vdr * 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 <getopt.h> #include <getopt.h>
@ -223,6 +223,7 @@ int main(int argc, char *argv[])
{ "epgfile", required_argument, NULL, 'E' }, { "epgfile", required_argument, NULL, 'E' },
{ "grab", required_argument, NULL, 'g' }, { "grab", required_argument, NULL, 'g' },
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ "instance", required_argument, NULL, 'i' },
{ "lib", required_argument, NULL, 'L' }, { "lib", required_argument, NULL, 'L' },
{ "lirc", optional_argument, NULL, 'l' | 0x100 }, { "lirc", optional_argument, NULL, 'l' | 0x100 },
{ "localedir",required_argument, NULL, 'l' | 0x200 }, { "localedir",required_argument, NULL, 'l' | 0x200 },
@ -245,7 +246,7 @@ int main(int argc, char *argv[])
}; };
int c; 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) { switch (c) {
case 'a': AudioCommand = optarg; case 'a': AudioCommand = optarg;
break; break;
@ -268,6 +269,13 @@ int main(int argc, char *argv[])
break; break;
case 'h': DisplayHelp = true; case 'h': DisplayHelp = true;
break; 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': { case 'l': {
char *p = strchr(optarg, '.'); char *p = strchr(optarg, '.');
if (p) if (p)