summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <kls (at) cadsoft (dot) de>2009-01-25 13:13:00 +0100
committerKlaus Schmidinger <kls (at) cadsoft (dot) de>2009-01-25 13:13:00 +0100
commit084e16c057ab195a76c2117c631a2fe10a904238 (patch)
tree5506d63dbe1fca2f785017aefd6c9ee03e79c291
parentc2966475942fcb9d4b8d41dbf026ff57630a1ad6 (diff)
downloadvdr-patch-lnbsharing-084e16c057ab195a76c2117c631a2fe10a904238.tar.gz
vdr-patch-lnbsharing-084e16c057ab195a76c2117c631a2fe10a904238.tar.bz2
Version 1.7.4vdr-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.
-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)