summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTORS21
-rw-r--r--HISTORY77
-rw-r--r--Make.config.template3
-rw-r--r--PLUGINS.html15
-rw-r--r--config.c4
-rw-r--r--config.h10
-rw-r--r--cutter.c8
-rw-r--r--device.c46
-rw-r--r--device.h15
-rw-r--r--dvbdevice.c34
-rw-r--r--dvbplayer.c23
-rw-r--r--menu.c9
-rw-r--r--osd.c4
-rw-r--r--osd.h6
-rw-r--r--player.h3
-rw-r--r--recorder.c4
-rw-r--r--recording.c37
-rw-r--r--recording.h21
-rw-r--r--remux.c102
-rw-r--r--remux.h33
-rw-r--r--tools.c4
-rw-r--r--transfer.c6
-rw-r--r--vdr.111
-rw-r--r--vdr.c12
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 <o.endriss@gmx.de>
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 <rw.buchner@freenet.de>
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 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 <richard_robson@beeb.net>
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 fixing handling numeric keys in the channel display after switching channel
groups
+ for adding some missing 'const' statements to cBitmap
Thomas Bergwinkl <Thomas.Bergwinkl@vr-web.de>
for fixing the validity check for channel IDs, because some providers use TIDs
@@ -1483,6 +1492,8 @@ Marco Schlüßler <marco@lordzodiac.de>
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 <j.schmitz@web.de>
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 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 <svenk@kammer.uni-hannover.de>
for his help in keeping 'channels.conf.terr' up to date
@@ -2207,6 +2219,8 @@ Frank Schmirler <vdr@schmirler.de>
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 <joern@zyn.de>
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>
for fixing finding new transponders
+ for reporting a compiler warning in calculations involving FramesPerSecond()
Hans-Werner Hilse <hilse@web.de>
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>
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).
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;
}
</style>
</head>
@@ -25,12 +28,15 @@ html, body {
<div class="center">
<h1>The VDR Plugin System</h1>
-<b>Version 1.6</b>
+<b>Version 1.7</b>
<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="http://www.cadsoft.de/vdr">www.cadsoft.de/vdr</a>
</div>
+<div class="modified">
+Important modifications introduced since version 1.6 are marked like this.
+</div modified>
<p>
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);
+<div class="modified">
+virtual bool IsPlayingVideo(void) const;
+</div modified>
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 <math.h>
#include <stdlib.h>
#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 <ctype.h>
#include <limits.h>
+#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -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;
@@ -330,18 +352,32 @@ uchar *cPatPmtGenerator::GetPmt(int &Index)
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 <getopt.h>
@@ -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)