mirror of
https://github.com/vdr-projects/vdr.git
synced 2025-03-01 10:50:46 +00:00
Version 1.7.5
- Fixed a hangup when replaying a TS recording with subtitles activated (reported by Timo Helkio). - Fixed handling the 'new' indicator in the recordings menu for TS recordings (thanks to Derek Kelly). - Added cap_sys_nice to the capabilities that are not dropped (thanks to Rolf Ahrenberg). - Updated the Italian OSD texts (thanks to Diego Pierotto). - Added cRecordingInfo::GetEvent() (thanks to Marcel Unbehaun). - Improved synchronizing the progress display, trick modes and subtitle display to the actual audio/video. This now works independent of any buffer sizes the output device might use. + The cBackTrace class has been replaced with cPtsIndex, which keeps track of the PTS timestamps of recently played frames. + cDevice::GetSTC() is now required to deliver the STC even in trick modes. It is sufficient if it returns the PTS of the most recently presented audio/video frame. + The full-featured DVB cards need an improved firmware in order to return proper STC values in trick modes (thanks to Oliver Endriss for enhancing the av7110 firmware). - Adapted cFrameDetector::Analyze() to HD NTSC broadcasts that split frames over several payload units (thanks to Derek Kelly for reporting this and helping in testing). - Modified cFrameDetector::Analyze() to make it process whole frames at once, so that file I/O overhead is minimized during recording (reported by Günter Niedermeier). - Added command line help for the '-i' option. - Fixed cDvbPlayer::NextFile() to handle files larger than 2GB (thanks to Jose Alberto Reguero). - Improved replay at the begin and end of a recording. The very first and very last frame is now sent to the output device repeatedly until GetSTC() reports that it has been played. cDvbPlayer::Action() no longer calls DeviceFlush() (thanks to Reinhard Nissl for making sure vdr-xine no longer needs this). - Added missing '[]' to the delete operator in cMenuEditStrItem::~cMenuEditStrItem(). - Added missing virtual destructor to cPalette. - Now freeing configDirectory before setting it to a new value in cPlugin::SetConfigDirectory(). - Fixed a crash when jumping to an editing mark in an audio recording. - Fixed the 'VideoOnly' condition in the PlayPes() and PlayTs() calls in cDvbPlayer::Action() (thanks to Reinhard Nissl). - cDevice::PlayTs() now plays as many TS packets as possible in one call. - Making sure any floating point numbers written use a decimal point (thanks to Oliver Endriss for pointing out a problem with the F record in the info file of a recording). - Fixed detecting the frame rate for radio recordings. - Added missing AUDIO_PAUSE/AUDIO_CONTINUE calls to cDvbDevice (thanks to Oliver Endriss). - No longer writing the video type into channels.conf if VPID is 0 (thanks to Oliver Endriss for reporting this). - Improved efficiency of cEIT::cEIT() (thanks to Tobias Bratfisch).
This commit is contained in:
parent
084e16c057
commit
1aadb31fb3
28
CONTRIBUTORS
28
CONTRIBUTORS
@ -662,6 +662,13 @@ Oliver Endriss <o.endriss@gmx.de>
|
|||||||
Transfer Mode
|
Transfer Mode
|
||||||
for providing a driver patch that allows direct replaying of TS video on full-featured
|
for providing a driver patch that allows direct replaying of TS video on full-featured
|
||||||
DVB cards
|
DVB cards
|
||||||
|
for improving the firmware of FF DVB cards to allow getting the current STC value
|
||||||
|
even in trick modes
|
||||||
|
for pointing out a problem with the decimal point of the F record in the info file of
|
||||||
|
a recording
|
||||||
|
for adding missing AUDIO_PAUSE/AUDIO_CONTINUE calls to cDvbDevice
|
||||||
|
for reporting that the video type is unnecessarily written into channels.conf if
|
||||||
|
VPID is 0
|
||||||
|
|
||||||
Reinhard Walter Buchner <rw.buchner@freenet.de>
|
Reinhard Walter Buchner <rw.buchner@freenet.de>
|
||||||
for adding some satellites to 'sources.conf'
|
for adding some satellites to 'sources.conf'
|
||||||
@ -1061,6 +1068,7 @@ Rolf Ahrenberg <rahrenbe@cc.hut.fi>
|
|||||||
the last replayed recording was in a subdirectory, and pressing Back
|
the last replayed recording was in a subdirectory, and pressing Back
|
||||||
for setting the thread name, so that it can be seen in 'top -H'
|
for setting the thread name, so that it can be seen in 'top -H'
|
||||||
for replacing the Finnish language code "smi" with "suo"
|
for replacing the Finnish language code "smi" with "suo"
|
||||||
|
for adding cap_sys_nice to the capabilities that are not dropped
|
||||||
|
|
||||||
Ralf Klueber <ralf.klueber@vodafone.com>
|
Ralf Klueber <ralf.klueber@vodafone.com>
|
||||||
for reporting a bug in cutting a recording if there is only a single editing mark
|
for reporting a bug in cutting a recording if there is only a single editing mark
|
||||||
@ -1197,6 +1205,9 @@ Reinhard Nissl <rnissl@gmx.de>
|
|||||||
to cDevice::PlayTs()
|
to cDevice::PlayTs()
|
||||||
for reporting that the PAT/PMT is processed too often, even if its version
|
for reporting that the PAT/PMT is processed too often, even if its version
|
||||||
hasn't changed
|
hasn't changed
|
||||||
|
for making sure vdr-xine no longer needs cDvbPlayer::Action() to call DeviceFlush()
|
||||||
|
for fixing the 'VideoOnly' condition in the PlayPes() and PlayTs() calls in
|
||||||
|
cDvbPlayer::Action()
|
||||||
|
|
||||||
Richard Robson <richard_robson@beeb.net>
|
Richard Robson <richard_robson@beeb.net>
|
||||||
for reporting freezing replay if a timer starts while in Transfer Mode from the
|
for reporting freezing replay if a timer starts while in Transfer Mode from the
|
||||||
@ -2279,6 +2290,7 @@ Alexander Riedel <alexander-riedel@t-online.de>
|
|||||||
|
|
||||||
Jose Alberto Reguero <jareguero@telefonica.net>
|
Jose Alberto Reguero <jareguero@telefonica.net>
|
||||||
for a patch that fixed part of a crash in i18n character set conversion
|
for a patch that fixed part of a crash in i18n character set conversion
|
||||||
|
for fixing cDvbPlayer::NextFile() to handle files larger than 2GB
|
||||||
|
|
||||||
Patrice Staudt <staudt@engsystem.net>
|
Patrice Staudt <staudt@engsystem.net>
|
||||||
for adding full weekday names to i18n.c for plugins to use
|
for adding full weekday names to i18n.c for plugins to use
|
||||||
@ -2290,6 +2302,7 @@ Tobias Bratfisch <tobias@reel-multimedia.com>
|
|||||||
for optimizing cMenuEditChrItem::Set()
|
for optimizing cMenuEditChrItem::Set()
|
||||||
for optimizing cNitFilter::Process()
|
for optimizing cNitFilter::Process()
|
||||||
for reducing the number of time(NULL) calls in vdr.c's main loop to a single call
|
for reducing the number of time(NULL) calls in vdr.c's main loop to a single call
|
||||||
|
for improving efficiency of cEIT::cEIT()
|
||||||
|
|
||||||
Bruno Roussel <bruno.roussel@free.fr>
|
Bruno Roussel <bruno.roussel@free.fr>
|
||||||
for translating OSD texts to the French language
|
for translating OSD texts to the French language
|
||||||
@ -2412,4 +2425,17 @@ Johann Friedrichs <johann.friedrichs@web.de>
|
|||||||
for fixing incrementing the continuity counter in cPatPmtGenerator::GetPmt()
|
for fixing incrementing the continuity counter in cPatPmtGenerator::GetPmt()
|
||||||
for pointing out that "DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
for pointing out that "DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||||
-D_LARGEFILE64_SOURCE" should be added to Make.config.
|
-D_LARGEFILE64_SOURCE" should be added to Make.config.
|
||||||
to Make.config.template (thanks to Johann Friedrichs for pointing this out).
|
|
||||||
|
Timo Helkio <timolavi@mbnet.fi>
|
||||||
|
for reporting a hangup when replaying a TS recording with subtitles activated
|
||||||
|
|
||||||
|
Derek Kelly (user.vdr@gmail.com)
|
||||||
|
for fixing handling the 'new' indicator in the recordings menu for TS recordings
|
||||||
|
for reporting a problem with HD NTSC broadcasts that split frames over several payload
|
||||||
|
units
|
||||||
|
|
||||||
|
Marcel Unbehaun <frostworks@gmx.de>
|
||||||
|
for adding cRecordingInfo::GetEvent()
|
||||||
|
|
||||||
|
Günter Niedermeier <linuxtv@ncs-online.de>
|
||||||
|
for reporting a problem with file I/O overhead during recording in TS format
|
||||||
|
52
HISTORY
52
HISTORY
@ -5978,3 +5978,55 @@ Video Disk Recorder Revision History
|
|||||||
player whether there is video data in the currently replayed stream. If a derived
|
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
|
cDevice class reimplements PlayTs() or PlayPes(), it also needs to make sure this
|
||||||
new function works as expected.
|
new function works as expected.
|
||||||
|
|
||||||
|
2009-04-12: Version 1.7.5
|
||||||
|
|
||||||
|
- Fixed a hangup when replaying a TS recording with subtitles activated (reported
|
||||||
|
by Timo Helkio).
|
||||||
|
- Fixed handling the 'new' indicator in the recordings menu for TS recordings
|
||||||
|
(thanks to Derek Kelly).
|
||||||
|
- Added cap_sys_nice to the capabilities that are not dropped (thanks to Rolf
|
||||||
|
Ahrenberg).
|
||||||
|
- Updated the Italian OSD texts (thanks to Diego Pierotto).
|
||||||
|
- Added cRecordingInfo::GetEvent() (thanks to Marcel Unbehaun).
|
||||||
|
- Improved synchronizing the progress display, trick modes and subtitle display
|
||||||
|
to the actual audio/video. This now works independent of any buffer sizes the
|
||||||
|
output device might use.
|
||||||
|
+ The cBackTrace class has been replaced with cPtsIndex, which keeps track
|
||||||
|
of the PTS timestamps of recently played frames.
|
||||||
|
+ cDevice::GetSTC() is now required to deliver the STC even in trick modes.
|
||||||
|
It is sufficient if it returns the PTS of the most recently presented
|
||||||
|
audio/video frame.
|
||||||
|
+ The full-featured DVB cards need an improved firmware in order to return
|
||||||
|
proper STC values in trick modes (thanks to Oliver Endriss for enhancing the
|
||||||
|
av7110 firmware).
|
||||||
|
- Adapted cFrameDetector::Analyze() to HD NTSC broadcasts that split frames over
|
||||||
|
several payload units (thanks to Derek Kelly for reporting this and helping in
|
||||||
|
testing).
|
||||||
|
- Modified cFrameDetector::Analyze() to make it process whole frames at once, so
|
||||||
|
that file I/O overhead is minimized during recording (reported by Günter
|
||||||
|
Niedermeier).
|
||||||
|
- Added command line help for the '-i' option.
|
||||||
|
- Fixed cDvbPlayer::NextFile() to handle files larger than 2GB (thanks to Jose
|
||||||
|
Alberto Reguero).
|
||||||
|
- Improved replay at the begin and end of a recording. The very first and very last
|
||||||
|
frame is now sent to the output device repeatedly until GetSTC() reports that it
|
||||||
|
has been played. cDvbPlayer::Action() no longer calls DeviceFlush() (thanks to
|
||||||
|
Reinhard Nissl for making sure vdr-xine no longer needs this).
|
||||||
|
- Added missing '[]' to the delete operator in cMenuEditStrItem::~cMenuEditStrItem().
|
||||||
|
- Added missing virtual destructor to cPalette.
|
||||||
|
- Now freeing configDirectory before setting it to a new value in
|
||||||
|
cPlugin::SetConfigDirectory().
|
||||||
|
- Fixed a crash when jumping to an editing mark in an audio recording.
|
||||||
|
- Fixed the 'VideoOnly' condition in the PlayPes() and PlayTs() calls in
|
||||||
|
cDvbPlayer::Action() (thanks to Reinhard Nissl).
|
||||||
|
- cDevice::PlayTs() now plays as many TS packets as possible in one call.
|
||||||
|
- Making sure any floating point numbers written use a decimal point (thanks to
|
||||||
|
Oliver Endriss for pointing out a problem with the F record in the info file of
|
||||||
|
a recording).
|
||||||
|
- Fixed detecting the frame rate for radio recordings.
|
||||||
|
- Added missing AUDIO_PAUSE/AUDIO_CONTINUE calls to cDvbDevice (thanks to Oliver
|
||||||
|
Endriss).
|
||||||
|
- No longer writing the video type into channels.conf if VPID is 0 (thanks to
|
||||||
|
Oliver Endriss for reporting this).
|
||||||
|
- Improved efficiency of cEIT::cEIT() (thanks to Tobias Bratfisch).
|
||||||
|
3
INSTALL
3
INSTALL
@ -16,8 +16,7 @@ to Make.config and adjust the definition of DVBDIR in that file.
|
|||||||
|
|
||||||
Refer to http://linuxtv.org for more information about the Linux-DVB driver.
|
Refer to http://linuxtv.org for more information about the Linux-DVB driver.
|
||||||
|
|
||||||
VDR requires the Linux-DVB driver version dated 2003-08-23 or higher
|
VDR requires the Linux-DVB driver version that supports the S2API interface.
|
||||||
to work properly.
|
|
||||||
|
|
||||||
You will also need to install the following libraries, as well as their
|
You will also need to install the following libraries, as well as their
|
||||||
"devel" packages to get the necessary header files for compiling VDR:
|
"devel" packages to get the necessary header files for compiling VDR:
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: channels.c 2.4 2008/12/13 11:42:15 kls Exp $
|
* $Id: channels.c 2.5 2009/04/10 11:29:55 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "channels.h"
|
#include "channels.h"
|
||||||
@ -724,7 +724,7 @@ cString cChannel::ToText(const cChannel *Channel)
|
|||||||
q += snprintf(q, sizeof(vpidbuf), "%d", Channel->vpid);
|
q += snprintf(q, sizeof(vpidbuf), "%d", Channel->vpid);
|
||||||
if (Channel->ppid && Channel->ppid != Channel->vpid)
|
if (Channel->ppid && Channel->ppid != Channel->vpid)
|
||||||
q += snprintf(q, sizeof(vpidbuf) - (q - vpidbuf), "+%d", Channel->ppid);
|
q += snprintf(q, sizeof(vpidbuf) - (q - vpidbuf), "+%d", Channel->ppid);
|
||||||
if (Channel->vtype)
|
if (Channel->vpid && Channel->vtype)
|
||||||
q += snprintf(q, sizeof(vpidbuf) - (q - vpidbuf), "=%d", Channel->vtype);
|
q += snprintf(q, sizeof(vpidbuf) - (q - vpidbuf), "=%d", Channel->vtype);
|
||||||
*q = 0;
|
*q = 0;
|
||||||
const int BufferSize = (MAXAPIDS + MAXDPIDS) * (5 + 1 + MAXLANGCODE2) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod+cod', +10: paranoia
|
const int BufferSize = (MAXAPIDS + MAXDPIDS) * (5 + 1 + MAXLANGCODE2) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod+cod', +10: paranoia
|
||||||
|
10
config.h
10
config.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: config.h 2.6 2009/01/06 16:56:27 kls Exp $
|
* $Id: config.h 2.7 2009/01/30 16:05:34 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __CONFIG_H
|
#ifndef __CONFIG_H
|
||||||
@ -22,13 +22,13 @@
|
|||||||
|
|
||||||
// VDR's own version number:
|
// VDR's own version number:
|
||||||
|
|
||||||
#define VDRVERSION "1.7.4"
|
#define VDRVERSION "1.7.5"
|
||||||
#define VDRVERSNUM 10704 // Version * 10000 + Major * 100 + Minor
|
#define VDRVERSNUM 10705 // Version * 10000 + Major * 100 + Minor
|
||||||
|
|
||||||
// The plugin API's version number:
|
// The plugin API's version number:
|
||||||
|
|
||||||
#define APIVERSION "1.7.4"
|
#define APIVERSION "1.7.5"
|
||||||
#define APIVERSNUM 10704 // Version * 10000 + Major * 100 + Minor
|
#define APIVERSNUM 10705 // Version * 10000 + Major * 100 + Minor
|
||||||
|
|
||||||
// When loading plugins, VDR searches them by their APIVERSION, which
|
// When loading plugins, VDR searches them by their APIVERSION, which
|
||||||
// may be smaller than VDRVERSION in case there have been no changes to
|
// may be smaller than VDRVERSION in case there have been no changes to
|
||||||
|
82
device.c
82
device.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: device.c 2.11 2009/01/25 11:10:56 kls Exp $
|
* $Id: device.c 2.13 2009/04/05 12:15:41 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
@ -1304,8 +1304,9 @@ int cDevice::PlayTsSubtitle(const uchar *Data, int Length)
|
|||||||
if (!dvbSubtitleConverter)
|
if (!dvbSubtitleConverter)
|
||||||
dvbSubtitleConverter = new cDvbSubtitleConverter;
|
dvbSubtitleConverter = new cDvbSubtitleConverter;
|
||||||
tsToPesSubtitle.PutTs(Data, Length);
|
tsToPesSubtitle.PutTs(Data, Length);
|
||||||
if (const uchar *p = tsToPesSubtitle.GetPes(Length)) {
|
int l;
|
||||||
dvbSubtitleConverter->Convert(p, Length);
|
if (const uchar *p = tsToPesSubtitle.GetPes(l)) {
|
||||||
|
dvbSubtitleConverter->Convert(p, l);
|
||||||
tsToPesSubtitle.Reset();
|
tsToPesSubtitle.Reset();
|
||||||
}
|
}
|
||||||
return Length;
|
return Length;
|
||||||
@ -1314,43 +1315,54 @@ int cDevice::PlayTsSubtitle(const uchar *Data, int Length)
|
|||||||
//TODO detect and report continuity errors?
|
//TODO detect and report continuity errors?
|
||||||
int cDevice::PlayTs(const uchar *Data, int Length, bool VideoOnly)
|
int cDevice::PlayTs(const uchar *Data, int Length, bool VideoOnly)
|
||||||
{
|
{
|
||||||
if (Length == TS_SIZE) {
|
int Played = 0;
|
||||||
if (!TsHasPayload(Data))
|
if (Data == NULL) {
|
||||||
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, Length);
|
|
||||||
else if (Pid == patPmtParser.PmtPid())
|
|
||||||
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);
|
|
||||||
if (w > 0)
|
|
||||||
Audios.PlayTsAudio(Data, Length);
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Pid == availableTracks[currentSubtitleTrack].id) {
|
|
||||||
if (!VideoOnly || HasIBPTrickSpeed())
|
|
||||||
return PlayTsSubtitle(Data, Length);
|
|
||||||
}
|
|
||||||
return Length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Data == NULL) {
|
|
||||||
patPmtParser.Reset();
|
patPmtParser.Reset();
|
||||||
tsToPesVideo.Reset();
|
tsToPesVideo.Reset();
|
||||||
tsToPesAudio.Reset();
|
tsToPesAudio.Reset();
|
||||||
tsToPesSubtitle.Reset();
|
tsToPesSubtitle.Reset();
|
||||||
}
|
}
|
||||||
return -1;
|
else {
|
||||||
|
cMutexLock MutexLock(&mutexCurrentAudioTrack);
|
||||||
|
while (Length >= TS_SIZE) {
|
||||||
|
if (TsHasPayload(Data)) { // silently ignore TS packets w/o payload
|
||||||
|
int PayloadOffset = TsPayloadOffset(Data);
|
||||||
|
if (PayloadOffset < TS_SIZE) {
|
||||||
|
int Pid = TsPid(Data);
|
||||||
|
if (Pid == 0)
|
||||||
|
patPmtParser.ParsePat(Data, TS_SIZE);
|
||||||
|
else if (Pid == patPmtParser.PmtPid())
|
||||||
|
patPmtParser.ParsePmt(Data, TS_SIZE);
|
||||||
|
else if (Pid == patPmtParser.Vpid()) {
|
||||||
|
isPlayingVideo = true;
|
||||||
|
int w = PlayTsVideo(Data, TS_SIZE);
|
||||||
|
if (w < 0)
|
||||||
|
return Played ? Played : w;
|
||||||
|
if (w == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (Pid == availableTracks[currentAudioTrack].id) {
|
||||||
|
if (!VideoOnly || HasIBPTrickSpeed()) {
|
||||||
|
int w = PlayTsAudio(Data, TS_SIZE);
|
||||||
|
if (w < 0)
|
||||||
|
return Played ? Played : w;
|
||||||
|
if (w == 0)
|
||||||
|
break;
|
||||||
|
Audios.PlayTsAudio(Data, TS_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Pid == availableTracks[currentSubtitleTrack].id) {
|
||||||
|
if (!VideoOnly || HasIBPTrickSpeed())
|
||||||
|
PlayTsSubtitle(Data, TS_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Played += TS_SIZE;
|
||||||
|
Length -= TS_SIZE;
|
||||||
|
Data += TS_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Played;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cDevice::Priority(void) const
|
int cDevice::Priority(void) const
|
||||||
|
17
device.h
17
device.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: device.h 2.6 2009/01/25 11:04:39 kls Exp $
|
* $Id: device.h 2.9 2009/04/05 12:12:44 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __DEVICE_H
|
#ifndef __DEVICE_H
|
||||||
@ -543,6 +543,13 @@ public:
|
|||||||
///< Gets the current System Time Counter, which can be used to
|
///< Gets the current System Time Counter, which can be used to
|
||||||
///< synchronize audio and video. If this device is unable to
|
///< synchronize audio and video. If this device is unable to
|
||||||
///< provide the STC, -1 will be returned.
|
///< provide the STC, -1 will be returned.
|
||||||
|
///< The value returned doesn't need to be an actual "clock" value,
|
||||||
|
///< it is sufficient if it holds the PTS (Presentation Time Stamp) of
|
||||||
|
///< the most recently presented frame. A proper value must be returned
|
||||||
|
///< in normal replay mode as well as in any trick modes (like slow motion,
|
||||||
|
///< fast forward/rewind).
|
||||||
|
///< Only the lower 32 bit of this value are actually used, since some
|
||||||
|
///< devices can't handle the msb correctly.
|
||||||
virtual bool IsPlayingVideo(void) const { return isPlayingVideo; }
|
virtual bool IsPlayingVideo(void) const { return isPlayingVideo; }
|
||||||
///< \return Returns true if the currently attached player has delivered
|
///< \return Returns true if the currently attached player has delivered
|
||||||
///< any video packets.
|
///< any video packets.
|
||||||
@ -588,7 +595,7 @@ public:
|
|||||||
///< data which was bufferd so far has been processed.
|
///< data which was bufferd so far has been processed.
|
||||||
///< If TimeoutMs is not zero, the device will wait up to the given
|
///< If TimeoutMs is not zero, the device will wait up to the given
|
||||||
///< number of milliseconds before returning in case there is still
|
///< number of milliseconds before returning in case there is still
|
||||||
///< data in the buffers..
|
///< data in the buffers.
|
||||||
virtual int PlayPes(const uchar *Data, int Length, bool VideoOnly = false);
|
virtual int PlayPes(const uchar *Data, int Length, bool VideoOnly = false);
|
||||||
///< Plays all valid PES packets in Data with the given Length.
|
///< Plays all valid PES packets in Data with the given Length.
|
||||||
///< If Data is NULL any leftover data from a previous call will be
|
///< If Data is NULL any leftover data from a previous call will be
|
||||||
@ -612,9 +619,9 @@ public:
|
|||||||
///< must be sent to the base class function. This applies especially
|
///< must be sent to the base class function. This applies especially
|
||||||
///< to the PAT/PMT packets.
|
///< to the PAT/PMT packets.
|
||||||
///< Returns -1 in case of error, otherwise the number of actually
|
///< Returns -1 in case of error, otherwise the number of actually
|
||||||
///< processed bytes is returned, which must be Length.
|
///< processed bytes is returned.
|
||||||
///< PlayTs() shall process the packet either as a whole (returning
|
///< PlayTs() shall process the TS packets either as a whole (returning
|
||||||
///< Length) or not at all returning 0 or -1 and setting 'errno' accordingly).
|
///< n*TS_SIZE) or not at all, returning 0 or -1 and setting 'errno' accordingly).
|
||||||
bool Replaying(void) const;
|
bool Replaying(void) const;
|
||||||
///< Returns true if we are currently replaying.
|
///< Returns true if we are currently replaying.
|
||||||
bool Transferring(void) const;
|
bool Transferring(void) const;
|
||||||
|
12
dvbdevice.c
12
dvbdevice.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: dvbdevice.c 2.12 2009/01/10 10:07:33 kls Exp $
|
* $Id: dvbdevice.c 2.14 2009/04/10 09:54:24 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dvbdevice.h"
|
#include "dvbdevice.h"
|
||||||
@ -1172,8 +1172,10 @@ void cDvbDevice::Play(void)
|
|||||||
CHECK(ioctl(fd_audio, AUDIO_CONTINUE));
|
CHECK(ioctl(fd_audio, AUDIO_CONTINUE));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (fd_audio >= 0)
|
if (fd_audio >= 0) {
|
||||||
CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
|
CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
|
||||||
|
CHECK(ioctl(fd_audio, AUDIO_CONTINUE));
|
||||||
|
}
|
||||||
if (fd_video >= 0)
|
if (fd_video >= 0)
|
||||||
CHECK(ioctl(fd_video, VIDEO_CONTINUE));
|
CHECK(ioctl(fd_video, VIDEO_CONTINUE));
|
||||||
}
|
}
|
||||||
@ -1187,8 +1189,10 @@ void cDvbDevice::Freeze(void)
|
|||||||
CHECK(ioctl(fd_audio, AUDIO_PAUSE));
|
CHECK(ioctl(fd_audio, AUDIO_PAUSE));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (fd_audio >= 0)
|
if (fd_audio >= 0) {
|
||||||
CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
|
CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
|
||||||
|
CHECK(ioctl(fd_audio, AUDIO_PAUSE));
|
||||||
|
}
|
||||||
if (fd_video >= 0)
|
if (fd_video >= 0)
|
||||||
CHECK(ioctl(fd_video, VIDEO_FREEZE));
|
CHECK(ioctl(fd_video, VIDEO_FREEZE));
|
||||||
}
|
}
|
||||||
@ -1206,6 +1210,8 @@ void cDvbDevice::Mute(void)
|
|||||||
|
|
||||||
void cDvbDevice::StillPicture(const uchar *Data, int Length)
|
void cDvbDevice::StillPicture(const uchar *Data, int Length)
|
||||||
{
|
{
|
||||||
|
if (!Data || Length < TS_SIZE)
|
||||||
|
return;
|
||||||
if (Data[0] == 0x47) {
|
if (Data[0] == 0x47) {
|
||||||
// TS data
|
// TS data
|
||||||
cDevice::StillPicture(Data, Length);
|
cDevice::StillPicture(Data, Length);
|
||||||
|
231
dvbplayer.c
231
dvbplayer.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: dvbplayer.c 2.3 2009/01/25 11:11:39 kls Exp $
|
* $Id: dvbplayer.c 2.11 2009/04/05 13:04:33 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dvbplayer.h"
|
#include "dvbplayer.h"
|
||||||
@ -16,59 +16,69 @@
|
|||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
// --- cBackTrace ------------------------------------------------------------
|
// --- cPtsIndex -------------------------------------------------------------
|
||||||
|
|
||||||
#define AVG_FRAME_SIZE 15000 // an assumption about the average frame size
|
#define PTSINDEX_ENTRIES 500
|
||||||
#define DVB_BUF_SIZE (256 * 1024) // an assumption about the dvb firmware buffer size
|
|
||||||
#define BACKTRACE_ENTRIES (DVB_BUF_SIZE / AVG_FRAME_SIZE + 20) // how many entries are needed to backtrace buffer contents
|
|
||||||
|
|
||||||
class cBackTrace {
|
class cPtsIndex {
|
||||||
private:
|
private:
|
||||||
int index[BACKTRACE_ENTRIES];
|
struct tPtsIndex {
|
||||||
int length[BACKTRACE_ENTRIES];
|
uint32_t pts; // no need for 33 bit - some devices don't even supply the msb
|
||||||
int pos, num;
|
int index;
|
||||||
|
};
|
||||||
|
tPtsIndex pi[PTSINDEX_ENTRIES];
|
||||||
|
int w, r;
|
||||||
|
int lastFound;
|
||||||
|
cMutex mutex;
|
||||||
public:
|
public:
|
||||||
cBackTrace(void);
|
cPtsIndex(void);
|
||||||
void Clear(void);
|
void Clear(void);
|
||||||
void Add(int Index, int Length);
|
void Put(uint32_t Pts, int Index);
|
||||||
int Get(bool Forward);
|
int FindIndex(uint32_t Pts);
|
||||||
};
|
};
|
||||||
|
|
||||||
cBackTrace::cBackTrace(void)
|
cPtsIndex::cPtsIndex(void)
|
||||||
{
|
{
|
||||||
|
lastFound = 0;
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cBackTrace::Clear(void)
|
void cPtsIndex::Clear(void)
|
||||||
{
|
{
|
||||||
pos = num = 0;
|
cMutexLock MutexLock(&mutex);
|
||||||
|
w = r = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cBackTrace::Add(int Index, int Length)
|
void cPtsIndex::Put(uint32_t Pts, int Index)
|
||||||
{
|
{
|
||||||
index[pos] = Index;
|
cMutexLock MutexLock(&mutex);
|
||||||
length[pos] = Length;
|
pi[w].pts = Pts;
|
||||||
if (++pos >= BACKTRACE_ENTRIES)
|
pi[w].index = Index;
|
||||||
pos = 0;
|
w = (w + 1) % PTSINDEX_ENTRIES;
|
||||||
if (num < BACKTRACE_ENTRIES)
|
if (w == r)
|
||||||
num++;
|
r = (r + 1) % PTSINDEX_ENTRIES;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cBackTrace::Get(bool Forward)
|
int cPtsIndex::FindIndex(uint32_t Pts)
|
||||||
{
|
{
|
||||||
int p = pos;
|
cMutexLock MutexLock(&mutex);
|
||||||
int n = num;
|
if (w == r)
|
||||||
int l = DVB_BUF_SIZE + (Forward ? 0 : 256 * 1024); //XXX (256 * 1024) == DVB_BUF_SIZE ???
|
return lastFound; // list is empty, let's not jump way off the last known position
|
||||||
int i = -1;
|
uint32_t Delta = 0xFFFFFFFF;
|
||||||
|
int Index = -1;
|
||||||
while (n && l > 0) {
|
for (int i = w; i != r; ) {
|
||||||
if (--p < 0)
|
if (--i < 0)
|
||||||
p = BACKTRACE_ENTRIES - 1;
|
i = PTSINDEX_ENTRIES - 1;
|
||||||
i = index[p] - 1;
|
uint32_t d = pi[i].pts < Pts ? Pts - pi[i].pts : pi[i].pts - Pts;
|
||||||
l -= length[p];
|
if (d > 0x7FFFFFFF)
|
||||||
n--;
|
d = 0xFFFFFFFF - d; // handle rollover
|
||||||
|
if (d < Delta) {
|
||||||
|
Delta = d;
|
||||||
|
Index = pi[i].index;
|
||||||
}
|
}
|
||||||
return i;
|
}
|
||||||
|
lastFound = Index;
|
||||||
|
return Index;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- cNonBlockingFileReader ------------------------------------------------
|
// --- cNonBlockingFileReader ------------------------------------------------
|
||||||
@ -183,8 +193,8 @@ bool cNonBlockingFileReader::WaitForDataMs(int msToWait)
|
|||||||
|
|
||||||
#define PLAYERBUFSIZE MEGABYTE(1)
|
#define PLAYERBUFSIZE MEGABYTE(1)
|
||||||
|
|
||||||
// The number of seconds to back up when resuming an interrupted replay session:
|
#define RESUMEBACKUP 10 // number of seconds to back up when resuming an interrupted replay session
|
||||||
#define RESUMEBACKUP 10
|
#define MAXSTUCKATEOF 3 // max. number of seconds to wait in case the device doesn't play the last frame
|
||||||
|
|
||||||
class cDvbPlayer : public cPlayer, cThread {
|
class cDvbPlayer : public cPlayer, cThread {
|
||||||
private:
|
private:
|
||||||
@ -193,7 +203,7 @@ private:
|
|||||||
static int Speeds[];
|
static int Speeds[];
|
||||||
cNonBlockingFileReader *nonBlockingFileReader;
|
cNonBlockingFileReader *nonBlockingFileReader;
|
||||||
cRingBufferFrame *ringBuffer;
|
cRingBufferFrame *ringBuffer;
|
||||||
cBackTrace *backTrace;
|
cPtsIndex ptsIndex;
|
||||||
cFileName *fileName;
|
cFileName *fileName;
|
||||||
cIndexFile *index;
|
cIndexFile *index;
|
||||||
cUnbufferedFile *replayFile;
|
cUnbufferedFile *replayFile;
|
||||||
@ -204,12 +214,13 @@ private:
|
|||||||
ePlayModes playMode;
|
ePlayModes playMode;
|
||||||
ePlayDirs playDir;
|
ePlayDirs playDir;
|
||||||
int trickSpeed;
|
int trickSpeed;
|
||||||
int readIndex, writeIndex;
|
int readIndex;
|
||||||
|
bool readIndependent;
|
||||||
cFrame *readFrame;
|
cFrame *readFrame;
|
||||||
cFrame *playFrame;
|
cFrame *playFrame;
|
||||||
void TrickSpeed(int Increment);
|
void TrickSpeed(int Increment);
|
||||||
void Empty(void);
|
void Empty(void);
|
||||||
bool NextFile(uchar FileNumber = 0, int FileOffset = -1);
|
bool NextFile(uint16_t FileNumber = 0, off_t FileOffset = -1);
|
||||||
int Resume(void);
|
int Resume(void);
|
||||||
bool Save(void);
|
bool Save(void);
|
||||||
protected:
|
protected:
|
||||||
@ -242,7 +253,6 @@ cDvbPlayer::cDvbPlayer(const char *FileName)
|
|||||||
{
|
{
|
||||||
nonBlockingFileReader = NULL;
|
nonBlockingFileReader = NULL;
|
||||||
ringBuffer = NULL;
|
ringBuffer = NULL;
|
||||||
backTrace = NULL;
|
|
||||||
index = NULL;
|
index = NULL;
|
||||||
cRecording Recording(FileName);
|
cRecording Recording(FileName);
|
||||||
framesPerSecond = Recording.FramesPerSecond();
|
framesPerSecond = Recording.FramesPerSecond();
|
||||||
@ -252,7 +262,8 @@ cDvbPlayer::cDvbPlayer(const char *FileName)
|
|||||||
playMode = pmPlay;
|
playMode = pmPlay;
|
||||||
playDir = pdForward;
|
playDir = pdForward;
|
||||||
trickSpeed = NORMAL_SPEED;
|
trickSpeed = NORMAL_SPEED;
|
||||||
readIndex = writeIndex = -1;
|
readIndex = -1;
|
||||||
|
readIndependent = false;
|
||||||
readFrame = NULL;
|
readFrame = NULL;
|
||||||
playFrame = NULL;
|
playFrame = NULL;
|
||||||
isyslog("replay %s", FileName);
|
isyslog("replay %s", FileName);
|
||||||
@ -269,17 +280,15 @@ cDvbPlayer::cDvbPlayer(const char *FileName)
|
|||||||
delete index;
|
delete index;
|
||||||
index = NULL;
|
index = NULL;
|
||||||
}
|
}
|
||||||
backTrace = new cBackTrace;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cDvbPlayer::~cDvbPlayer()
|
cDvbPlayer::~cDvbPlayer()
|
||||||
{
|
{
|
||||||
Detach();
|
|
||||||
Save();
|
Save();
|
||||||
|
Detach();
|
||||||
delete readFrame; // might not have been stored in the buffer in Action()
|
delete readFrame; // might not have been stored in the buffer in Action()
|
||||||
delete index;
|
delete index;
|
||||||
delete fileName;
|
delete fileName;
|
||||||
delete backTrace;
|
|
||||||
delete ringBuffer;
|
delete ringBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,18 +317,18 @@ void cDvbPlayer::Empty(void)
|
|||||||
LOCK_THREAD;
|
LOCK_THREAD;
|
||||||
if (nonBlockingFileReader)
|
if (nonBlockingFileReader)
|
||||||
nonBlockingFileReader->Clear();
|
nonBlockingFileReader->Clear();
|
||||||
if ((readIndex = backTrace->Get(playDir == pdForward)) < 0)
|
if (!firstPacket) // don't set the readIndex twice if Empty() is called more than once
|
||||||
readIndex = writeIndex;
|
readIndex = ptsIndex.FindIndex(DeviceGetSTC());
|
||||||
delete readFrame; // might not have been stored in the buffer in Action()
|
delete readFrame; // might not have been stored in the buffer in Action()
|
||||||
readFrame = NULL;
|
readFrame = NULL;
|
||||||
playFrame = NULL;
|
playFrame = NULL;
|
||||||
ringBuffer->Clear();
|
ringBuffer->Clear();
|
||||||
backTrace->Clear();
|
ptsIndex.Clear();
|
||||||
DeviceClear();
|
DeviceClear();
|
||||||
firstPacket = true;
|
firstPacket = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cDvbPlayer::NextFile(uchar FileNumber, int FileOffset)
|
bool cDvbPlayer::NextFile(uint16_t FileNumber, off_t FileOffset)
|
||||||
{
|
{
|
||||||
if (FileNumber > 0)
|
if (FileNumber > 0)
|
||||||
replayFile = fileName->SetOffset(FileNumber, FileOffset);
|
replayFile = fileName->SetOffset(FileNumber, FileOffset);
|
||||||
@ -346,7 +355,7 @@ int cDvbPlayer::Resume(void)
|
|||||||
bool cDvbPlayer::Save(void)
|
bool cDvbPlayer::Save(void)
|
||||||
{
|
{
|
||||||
if (index) {
|
if (index) {
|
||||||
int Index = writeIndex;
|
int Index = ptsIndex.FindIndex(DeviceGetSTC());
|
||||||
if (Index >= 0) {
|
if (Index >= 0) {
|
||||||
Index -= int(round(RESUMEBACKUP * framesPerSecond));
|
Index -= int(round(RESUMEBACKUP * framesPerSecond));
|
||||||
if (Index > 0)
|
if (Index > 0)
|
||||||
@ -384,8 +393,12 @@ void cDvbPlayer::Action(void)
|
|||||||
int Length = 0;
|
int Length = 0;
|
||||||
bool Sleep = false;
|
bool Sleep = false;
|
||||||
bool WaitingForData = false;
|
bool WaitingForData = false;
|
||||||
|
time_t StuckAtEof = 0;
|
||||||
|
uint32_t LastStc = 0;
|
||||||
|
int LastReadIFrame = -1;
|
||||||
|
int SwitchToPlayFrame = 0;
|
||||||
|
|
||||||
while (Running() && (NextFile() || readIndex >= 0 || ringBuffer->Available() || !DeviceFlush(100))) {
|
while (Running() && (NextFile() || readIndex >= 0 || ringBuffer->Available())) {
|
||||||
if (Sleep) {
|
if (Sleep) {
|
||||||
if (WaitingForData)
|
if (WaitingForData)
|
||||||
nonBlockingFileReader->WaitForDataMs(3); // this keeps the CPU load low, but reacts immediately on new data
|
nonBlockingFileReader->WaitForDataMs(3); // this keeps the CPU load low, but reacts immediately on new data
|
||||||
@ -403,60 +416,47 @@ void cDvbPlayer::Action(void)
|
|||||||
if (playMode != pmStill && playMode != pmPause) {
|
if (playMode != pmStill && playMode != pmPause) {
|
||||||
if (!readFrame && (replayFile || readIndex >= 0)) {
|
if (!readFrame && (replayFile || readIndex >= 0)) {
|
||||||
if (!nonBlockingFileReader->Reading()) {
|
if (!nonBlockingFileReader->Reading()) {
|
||||||
if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) {
|
if (!SwitchToPlayFrame && (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward))) {
|
||||||
uint16_t FileNumber;
|
uint16_t FileNumber;
|
||||||
off_t FileOffset;
|
off_t FileOffset;
|
||||||
bool TimeShiftMode = index->IsStillRecording();
|
bool TimeShiftMode = index->IsStillRecording();
|
||||||
int Index = -1;
|
int Index = -1;
|
||||||
|
readIndependent = false;
|
||||||
if (DeviceHasIBPTrickSpeed() && playDir == pdForward) {
|
if (DeviceHasIBPTrickSpeed() && playDir == pdForward) {
|
||||||
if (index->Get(readIndex + 1, &FileNumber, &FileOffset, NULL, &Length))
|
if (index->Get(readIndex + 1, &FileNumber, &FileOffset, &readIndependent, &Length))
|
||||||
Index = readIndex + 1;
|
Index = readIndex + 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int d = int(round(0.4 * framesPerSecond));
|
int d = int(round(0.4 * framesPerSecond));
|
||||||
if (playDir != pdForward)
|
if (playDir != pdForward)
|
||||||
d = -d;
|
d = -d;
|
||||||
Index = index->GetNextIFrame(readIndex + d, playDir == pdForward, &FileNumber, &FileOffset, &Length, TimeShiftMode);
|
int NewIndex = readIndex + d;
|
||||||
|
if (NewIndex <= 0 && readIndex > 0)
|
||||||
|
NewIndex = 1; // make sure the very first frame is delivered
|
||||||
|
NewIndex = index->GetNextIFrame(NewIndex, playDir == pdForward, &FileNumber, &FileOffset, &Length, TimeShiftMode);
|
||||||
|
if (NewIndex < 0 && TimeShiftMode && playDir == pdForward)
|
||||||
|
SwitchToPlayFrame = Index;
|
||||||
|
Index = NewIndex;
|
||||||
|
readIndependent = true;
|
||||||
}
|
}
|
||||||
if (Index >= 0) {
|
if (Index >= 0) {
|
||||||
if (!NextFile(FileNumber, FileOffset)) {
|
|
||||||
readIndex = Index;
|
readIndex = Index;
|
||||||
|
if (!NextFile(FileNumber, FileOffset))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
if (!TimeShiftMode && playDir == pdForward) {
|
|
||||||
// hit end of recording: signal end of file but don't change playMode
|
|
||||||
readIndex = -1;
|
|
||||||
eof = true;
|
eof = true;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// hit begin of recording: wait for device buffers to drain
|
|
||||||
// before changing play mode:
|
|
||||||
if (!DeviceFlush(100))
|
|
||||||
continue;
|
|
||||||
// can't call Play() here, because those functions may only be
|
|
||||||
// called from the foreground thread - and we also don't need
|
|
||||||
// to empty the buffer here
|
|
||||||
DevicePlay();
|
|
||||||
playMode = pmPlay;
|
|
||||||
playDir = pdForward;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
readIndex = Index;
|
|
||||||
}
|
}
|
||||||
else if (index) {
|
else if (index) {
|
||||||
uint16_t FileNumber;
|
uint16_t FileNumber;
|
||||||
off_t FileOffset;
|
off_t FileOffset;
|
||||||
|
if (index->Get(readIndex + 1, &FileNumber, &FileOffset, &readIndependent, &Length) && NextFile(FileNumber, FileOffset))
|
||||||
readIndex++;
|
readIndex++;
|
||||||
if (!(index->Get(readIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset))) {
|
else
|
||||||
readIndex = -1;
|
|
||||||
eof = true;
|
eof = true;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else // allows replay even if the index file is missing
|
else // allows replay even if the index file is missing
|
||||||
Length = MAXFRAMESIZE;
|
Length = MAXFRAMESIZE / TS_SIZE * TS_SIZE;// FIXME: use a linear ringbuffer in this case, and fix cDevice::PlayPes()
|
||||||
if (Length == -1)
|
if (Length == -1)
|
||||||
Length = MAXFRAMESIZE; // this means we read up to EOF (see cIndex)
|
Length = MAXFRAMESIZE; // this means we read up to EOF (see cIndex)
|
||||||
else if (Length > MAXFRAMESIZE) {
|
else if (Length > MAXFRAMESIZE) {
|
||||||
@ -465,10 +465,16 @@ void cDvbPlayer::Action(void)
|
|||||||
}
|
}
|
||||||
b = MALLOC(uchar, Length);
|
b = MALLOC(uchar, Length);
|
||||||
}
|
}
|
||||||
|
if (!eof) {
|
||||||
int r = nonBlockingFileReader->Read(replayFile, b, Length);
|
int r = nonBlockingFileReader->Read(replayFile, b, Length);
|
||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
WaitingForData = false;
|
WaitingForData = false;
|
||||||
readFrame = new cFrame(b, -r, ftUnknown, readIndex); // hands over b to the ringBuffer
|
uint32_t Pts = 0;
|
||||||
|
if (readIndependent) {
|
||||||
|
Pts = isPesRecording ? PesGetPts(b) : TsGetPts(b, r);
|
||||||
|
LastReadIFrame = readIndex;
|
||||||
|
}
|
||||||
|
readFrame = new cFrame(b, -r, ftUnknown, readIndex, Pts); // hands over b to the ringBuffer
|
||||||
b = NULL;
|
b = NULL;
|
||||||
}
|
}
|
||||||
else if (r == 0)
|
else if (r == 0)
|
||||||
@ -480,6 +486,7 @@ void cDvbPlayer::Action(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Store the frame in the buffer:
|
// Store the frame in the buffer:
|
||||||
|
|
||||||
@ -506,6 +513,8 @@ void cDvbPlayer::Action(void)
|
|||||||
p = playFrame->Data();
|
p = playFrame->Data();
|
||||||
pc = playFrame->Count();
|
pc = playFrame->Count();
|
||||||
if (p) {
|
if (p) {
|
||||||
|
if (playFrame->Index() >= 0)
|
||||||
|
ptsIndex.Put(playFrame->Pts(), playFrame->Index());
|
||||||
if (firstPacket) {
|
if (firstPacket) {
|
||||||
if (isPesRecording) {
|
if (isPesRecording) {
|
||||||
PlayPes(NULL, 0);
|
PlayPes(NULL, 0);
|
||||||
@ -520,28 +529,57 @@ void cDvbPlayer::Action(void)
|
|||||||
if (p) {
|
if (p) {
|
||||||
int w;
|
int w;
|
||||||
if (isPesRecording)
|
if (isPesRecording)
|
||||||
w = PlayPes(p, pc, playMode != pmPlay && DeviceIsPlayingVideo());
|
w = PlayPes(p, pc, playMode != pmPlay && !(playMode == pmSlow && playDir == pdForward) && DeviceIsPlayingVideo());
|
||||||
else
|
else
|
||||||
w = PlayTs(p, TS_SIZE, playMode != pmPlay && DeviceIsPlayingVideo());
|
w = PlayTs(p, pc, playMode != pmPlay && !(playMode == pmSlow && playDir == pdForward) && DeviceIsPlayingVideo());
|
||||||
if (w > 0) {
|
if (w > 0) {
|
||||||
p += w;
|
p += w;
|
||||||
pc -= w;
|
pc -= w;
|
||||||
}
|
}
|
||||||
else if (w < 0 && FATALERRNO) {
|
else if (w < 0 && FATALERRNO)
|
||||||
LOG_ERROR;
|
LOG_ERROR;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (pc <= 0) {
|
if (pc <= 0) {
|
||||||
writeIndex = playFrame->Index();
|
if (!eof || (playDir != pdForward && playFrame->Index() > 0) || (playDir == pdForward && playFrame->Index() < readIndex))
|
||||||
backTrace->Add(playFrame->Index(), playFrame->Count());
|
ringBuffer->Drop(playFrame); // the very first and last frame are continously repeated to flush data through the device
|
||||||
ringBuffer->Drop(playFrame);
|
|
||||||
playFrame = NULL;
|
playFrame = NULL;
|
||||||
p = NULL;
|
p = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Sleep = true;
|
Sleep = true;
|
||||||
|
|
||||||
|
// Handle hitting begin/end of recording:
|
||||||
|
|
||||||
|
if (eof || SwitchToPlayFrame) {
|
||||||
|
bool SwitchToPlay = false;
|
||||||
|
uint32_t Stc = DeviceGetSTC();
|
||||||
|
if (Stc != LastStc)
|
||||||
|
StuckAtEof = 0;
|
||||||
|
else if (!StuckAtEof)
|
||||||
|
StuckAtEof = time(NULL);
|
||||||
|
else if (time(NULL) - StuckAtEof > MAXSTUCKATEOF) {
|
||||||
|
if (playDir == pdForward)
|
||||||
|
break; // automatically stop at end of recording
|
||||||
|
SwitchToPlay = true;
|
||||||
|
}
|
||||||
|
LastStc = Stc;
|
||||||
|
int Index = ptsIndex.FindIndex(Stc);
|
||||||
|
if (playDir == pdForward && !SwitchToPlayFrame) {
|
||||||
|
if (Index >= LastReadIFrame)
|
||||||
|
break; // automatically stop at end of recording
|
||||||
|
}
|
||||||
|
else if (Index <= 0 || SwitchToPlayFrame && Index >= SwitchToPlayFrame)
|
||||||
|
SwitchToPlay = true;
|
||||||
|
if (SwitchToPlay) {
|
||||||
|
if (!SwitchToPlayFrame)
|
||||||
|
Empty();
|
||||||
|
DevicePlay();
|
||||||
|
playMode = pmPlay;
|
||||||
|
playDir = pdForward;
|
||||||
|
SwitchToPlayFrame = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -614,6 +652,7 @@ void cDvbPlayer::Forward(void)
|
|||||||
Pause();
|
Pause();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Empty();
|
||||||
// run into pmPause
|
// run into pmPause
|
||||||
case pmStill:
|
case pmStill:
|
||||||
case pmPause:
|
case pmPause:
|
||||||
@ -661,6 +700,7 @@ void cDvbPlayer::Backward(void)
|
|||||||
Pause();
|
Pause();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Empty();
|
||||||
// run into pmPause
|
// run into pmPause
|
||||||
case pmStill:
|
case pmStill:
|
||||||
case pmPause: {
|
case pmPause: {
|
||||||
@ -696,14 +736,14 @@ void cDvbPlayer::SkipSeconds(int Seconds)
|
|||||||
{
|
{
|
||||||
if (index && Seconds) {
|
if (index && Seconds) {
|
||||||
LOCK_THREAD;
|
LOCK_THREAD;
|
||||||
|
int Index = ptsIndex.FindIndex(DeviceGetSTC());
|
||||||
Empty();
|
Empty();
|
||||||
int Index = writeIndex;
|
|
||||||
if (Index >= 0) {
|
if (Index >= 0) {
|
||||||
Index = max(Index + SecondsToFrames(Seconds, framesPerSecond), 0);
|
Index = max(Index + SecondsToFrames(Seconds, framesPerSecond), 0);
|
||||||
if (Index > 0)
|
if (Index > 0)
|
||||||
Index = index->GetNextIFrame(Index, false, NULL, NULL, NULL, true);
|
Index = index->GetNextIFrame(Index, false, NULL, NULL, NULL, true);
|
||||||
if (Index >= 0)
|
if (Index >= 0)
|
||||||
readIndex = writeIndex = Index - 1; // Action() will first increment it!
|
readIndex = Index - 1; // Action() will first increment it!
|
||||||
}
|
}
|
||||||
Play();
|
Play();
|
||||||
}
|
}
|
||||||
@ -727,26 +767,23 @@ void cDvbPlayer::Goto(int Index, bool Still)
|
|||||||
if (playMode == pmPause)
|
if (playMode == pmPause)
|
||||||
DevicePlay();
|
DevicePlay();
|
||||||
DeviceStillPicture(b, r);
|
DeviceStillPicture(b, r);
|
||||||
|
ptsIndex.Put(isPesRecording ? PesGetPts(b) : TsGetPts(b, r), Index);
|
||||||
}
|
}
|
||||||
playMode = pmStill;
|
playMode = pmStill;
|
||||||
}
|
}
|
||||||
readIndex = writeIndex = Index;
|
readIndex = Index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cDvbPlayer::GetIndex(int &Current, int &Total, bool SnapToIFrame)
|
bool cDvbPlayer::GetIndex(int &Current, int &Total, bool SnapToIFrame)
|
||||||
{
|
{
|
||||||
if (index) {
|
if (index) {
|
||||||
if (playMode == pmStill)
|
Current = ptsIndex.FindIndex(DeviceGetSTC());
|
||||||
Current = max(readIndex, 0);
|
|
||||||
else {
|
|
||||||
Current = max(writeIndex, 0);
|
|
||||||
if (SnapToIFrame) {
|
if (SnapToIFrame) {
|
||||||
int i1 = index->GetNextIFrame(Current + 1, false);
|
int i1 = index->GetNextIFrame(Current + 1, false);
|
||||||
int i2 = index->GetNextIFrame(Current, true);
|
int i2 = index->GetNextIFrame(Current, true);
|
||||||
Current = (abs(Current - i1) <= abs(Current - i2)) ? i1 : i2;
|
Current = (abs(Current - i1) <= abs(Current - i2)) ? i1 : i2;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Total = index->Last();
|
Total = index->Last();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
37
eit.c
37
eit.c
@ -8,7 +8,7 @@
|
|||||||
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
|
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
|
||||||
* Adapted to 'libsi' for VDR 1.3.0 by Marcel Wiesweg <marcel.wiesweg@gmx.de>.
|
* Adapted to 'libsi' for VDR 1.3.0 by Marcel Wiesweg <marcel.wiesweg@gmx.de>.
|
||||||
*
|
*
|
||||||
* $Id: eit.c 2.2 2008/05/01 15:33:27 kls Exp $
|
* $Id: eit.c 2.3 2009/04/11 10:03:24 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "eit.h"
|
#include "eit.h"
|
||||||
@ -42,20 +42,25 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bo
|
|||||||
bool HasExternalData = false;
|
bool HasExternalData = false;
|
||||||
time_t SegmentStart = 0;
|
time_t SegmentStart = 0;
|
||||||
time_t SegmentEnd = 0;
|
time_t SegmentEnd = 0;
|
||||||
|
time_t Now = time(NULL);
|
||||||
|
struct tm tm_r;
|
||||||
|
struct tm t = *localtime_r(&Now, &tm_r); // this initializes the time zone in 't'
|
||||||
|
|
||||||
SI::EIT::Event SiEitEvent;
|
SI::EIT::Event SiEitEvent;
|
||||||
for (SI::Loop::Iterator it; eventLoop.getNext(SiEitEvent, it); ) {
|
for (SI::Loop::Iterator it; eventLoop.getNext(SiEitEvent, it); ) {
|
||||||
bool ExternalData = false;
|
bool ExternalData = false;
|
||||||
|
int StartTime = SiEitEvent.getStartTime();
|
||||||
|
int Duration = SiEitEvent.getDuration();
|
||||||
// Drop bogus events - but keep NVOD reference events, where all bits of the start time field are set to 1, resulting in a negative number.
|
// Drop bogus events - but keep NVOD reference events, where all bits of the start time field are set to 1, resulting in a negative number.
|
||||||
if (SiEitEvent.getStartTime() == 0 || SiEitEvent.getStartTime() > 0 && SiEitEvent.getDuration() == 0)
|
if (StartTime == 0 || StartTime > 0 && Duration == 0)
|
||||||
continue;
|
continue;
|
||||||
Empty = false;
|
Empty = false;
|
||||||
if (!SegmentStart)
|
if (!SegmentStart)
|
||||||
SegmentStart = SiEitEvent.getStartTime();
|
SegmentStart = StartTime;
|
||||||
SegmentEnd = SiEitEvent.getStartTime() + SiEitEvent.getDuration();
|
SegmentEnd = StartTime + Duration;
|
||||||
cEvent *newEvent = NULL;
|
cEvent *newEvent = NULL;
|
||||||
cEvent *rEvent = NULL;
|
cEvent *rEvent = NULL;
|
||||||
cEvent *pEvent = (cEvent *)pSchedule->GetEvent(SiEitEvent.getEventId(), SiEitEvent.getStartTime());
|
cEvent *pEvent = (cEvent *)pSchedule->GetEvent(SiEitEvent.getEventId(), StartTime);
|
||||||
if (!pEvent) {
|
if (!pEvent) {
|
||||||
if (OnlyRunningStatus)
|
if (OnlyRunningStatus)
|
||||||
continue;
|
continue;
|
||||||
@ -70,14 +75,15 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bo
|
|||||||
pEvent->SetSeen();
|
pEvent->SetSeen();
|
||||||
// If the existing event has a zero table ID it was defined externally and shall
|
// If the existing event has a zero table ID it was defined externally and shall
|
||||||
// not be overwritten.
|
// not be overwritten.
|
||||||
if (pEvent->TableID() == 0x00) {
|
uchar TableID = pEvent->TableID();
|
||||||
|
if (TableID == 0x00) {
|
||||||
if (pEvent->Version() == getVersionNumber())
|
if (pEvent->Version() == getVersionNumber())
|
||||||
continue;
|
continue;
|
||||||
HasExternalData = ExternalData = true;
|
HasExternalData = ExternalData = true;
|
||||||
}
|
}
|
||||||
// If the new event has a higher table ID, let's skip it.
|
// If the new event has a higher table ID, let's skip it.
|
||||||
// The lower the table ID, the more "current" the information.
|
// The lower the table ID, the more "current" the information.
|
||||||
else if (Tid > pEvent->TableID())
|
else if (Tid > TableID)
|
||||||
continue;
|
continue;
|
||||||
// If the new event comes from the same table and has the same version number
|
// If the new event comes from the same table and has the same version number
|
||||||
// as the existing one, let's skip it to avoid unnecessary work.
|
// as the existing one, let's skip it to avoid unnecessary work.
|
||||||
@ -85,14 +91,14 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bo
|
|||||||
// the actual Premiere transponder and the Sat.1/Pro7 transponder), but use different version numbers on
|
// the actual Premiere transponder and the Sat.1/Pro7 transponder), but use different version numbers on
|
||||||
// each of them :-( So if one DVB card is tuned to the Premiere transponder, while an other one is tuned
|
// each of them :-( So if one DVB card is tuned to the Premiere transponder, while an other one is tuned
|
||||||
// to the Sat.1/Pro7 transponder, events will keep toggling because of the bogus version numbers.
|
// to the Sat.1/Pro7 transponder, events will keep toggling because of the bogus version numbers.
|
||||||
else if (Tid == pEvent->TableID() && pEvent->Version() == getVersionNumber())
|
else if (Tid == TableID && pEvent->Version() == getVersionNumber())
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!ExternalData) {
|
if (!ExternalData) {
|
||||||
pEvent->SetEventID(SiEitEvent.getEventId()); // unfortunately some stations use different event ids for the same event in different tables :-(
|
pEvent->SetEventID(SiEitEvent.getEventId()); // unfortunately some stations use different event ids for the same event in different tables :-(
|
||||||
pEvent->SetTableID(Tid);
|
pEvent->SetTableID(Tid);
|
||||||
pEvent->SetStartTime(SiEitEvent.getStartTime());
|
pEvent->SetStartTime(StartTime);
|
||||||
pEvent->SetDuration(SiEitEvent.getDuration());
|
pEvent->SetDuration(Duration);
|
||||||
}
|
}
|
||||||
if (newEvent)
|
if (newEvent)
|
||||||
pSchedule->AddEvent(newEvent);
|
pSchedule->AddEvent(newEvent);
|
||||||
@ -148,9 +154,6 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bo
|
|||||||
break;
|
break;
|
||||||
case SI::PDCDescriptorTag: {
|
case SI::PDCDescriptorTag: {
|
||||||
SI::PDCDescriptor *pd = (SI::PDCDescriptor *)d;
|
SI::PDCDescriptor *pd = (SI::PDCDescriptor *)d;
|
||||||
time_t now = time(NULL);
|
|
||||||
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
|
t.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
|
||||||
int month = t.tm_mon;
|
int month = t.tm_mon;
|
||||||
t.tm_mon = pd->getMonth() - 1;
|
t.tm_mon = pd->getMonth() - 1;
|
||||||
@ -183,8 +186,7 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bo
|
|||||||
SI::LinkageDescriptor *ld = (SI::LinkageDescriptor *)d;
|
SI::LinkageDescriptor *ld = (SI::LinkageDescriptor *)d;
|
||||||
tChannelID linkID(Source, ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId());
|
tChannelID linkID(Source, ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId());
|
||||||
if (ld->getLinkageType() == 0xB0) { // Premiere World
|
if (ld->getLinkageType() == 0xB0) { // Premiere World
|
||||||
time_t now = time(NULL);
|
bool hit = StartTime <= Now && Now < StartTime + Duration;
|
||||||
bool hit = SiEitEvent.getStartTime() <= now && now < SiEitEvent.getStartTime() + SiEitEvent.getDuration();
|
|
||||||
if (hit) {
|
if (hit) {
|
||||||
char linkName[ld->privateData.getLength() + 1];
|
char linkName[ld->privateData.getLength() + 1];
|
||||||
strn0cpy(linkName, (const char *)ld->privateData.getData(), sizeof(linkName));
|
strn0cpy(linkName, (const char *)ld->privateData.getData(), sizeof(linkName));
|
||||||
@ -260,11 +262,12 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bo
|
|||||||
channel->SetLinkChannels(LinkChannels);
|
channel->SetLinkChannels(LinkChannels);
|
||||||
Modified = true;
|
Modified = true;
|
||||||
}
|
}
|
||||||
if (Empty && Tid == 0x4E && getSectionNumber() == 0)
|
if (Tid == 0x4E) {
|
||||||
|
if (Empty && getSectionNumber() == 0)
|
||||||
// ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running
|
// ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running
|
||||||
pSchedule->ClrRunningStatus(channel);
|
pSchedule->ClrRunningStatus(channel);
|
||||||
if (Tid == 0x4E)
|
|
||||||
pSchedule->SetPresentSeen();
|
pSchedule->SetPresentSeen();
|
||||||
|
}
|
||||||
if (OnlyRunningStatus)
|
if (OnlyRunningStatus)
|
||||||
return;
|
return;
|
||||||
if (Modified) {
|
if (Modified) {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: menuitems.c 2.2 2008/12/13 11:35:31 kls Exp $
|
* $Id: menuitems.c 2.3 2009/04/05 10:15:12 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "menuitems.h"
|
#include "menuitems.h"
|
||||||
@ -271,9 +271,9 @@ cMenuEditStrItem::cMenuEditStrItem(const char *Name, char *Value, int Length, co
|
|||||||
|
|
||||||
cMenuEditStrItem::~cMenuEditStrItem()
|
cMenuEditStrItem::~cMenuEditStrItem()
|
||||||
{
|
{
|
||||||
delete valueUtf8;
|
delete[] valueUtf8;
|
||||||
delete allowedUtf8;
|
delete[] allowedUtf8;
|
||||||
delete charMapUtf8;
|
delete[] charMapUtf8;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cMenuEditStrItem::EnterEditMode(void)
|
void cMenuEditStrItem::EnterEditMode(void)
|
||||||
|
6
osd.c
6
osd.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: osd.c 2.1 2009/01/16 14:34:32 kls Exp $
|
* $Id: osd.c 2.2 2009/04/05 10:17:25 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "osd.h"
|
#include "osd.h"
|
||||||
@ -24,6 +24,10 @@ cPalette::cPalette(int Bpp)
|
|||||||
SetAntiAliasGranularity(10, 10);
|
SetAntiAliasGranularity(10, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cPalette::~cPalette()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void cPalette::SetAntiAliasGranularity(uint FixedColors, uint BlendColors)
|
void cPalette::SetAntiAliasGranularity(uint FixedColors, uint BlendColors)
|
||||||
{
|
{
|
||||||
if (FixedColors >= MAXNUMCOLORS || BlendColors == 0)
|
if (FixedColors >= MAXNUMCOLORS || BlendColors == 0)
|
||||||
|
3
osd.h
3
osd.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: osd.h 2.1 2009/01/16 14:37:03 kls Exp $
|
* $Id: osd.h 2.2 2009/04/05 10:16:05 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __OSD_H
|
#ifndef __OSD_H
|
||||||
@ -62,6 +62,7 @@ protected:
|
|||||||
public:
|
public:
|
||||||
cPalette(int Bpp = 8);
|
cPalette(int Bpp = 8);
|
||||||
///< Initializes the palette with the given color depth.
|
///< Initializes the palette with the given color depth.
|
||||||
|
virtual ~cPalette();
|
||||||
void SetAntiAliasGranularity(uint FixedColors, uint BlendColors);
|
void SetAntiAliasGranularity(uint FixedColors, uint BlendColors);
|
||||||
///< Allows the system to optimize utilization of the limited color
|
///< Allows the system to optimize utilization of the limited color
|
||||||
///< palette entries when generating blended colors for anti-aliasing.
|
///< palette entries when generating blended colors for anti-aliasing.
|
||||||
|
3
player.h
3
player.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: player.h 2.3 2009/01/25 11:03:44 kls Exp $
|
* $Id: player.h 2.4 2009/03/08 12:29:10 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __PLAYER_H
|
#ifndef __PLAYER_H
|
||||||
@ -34,6 +34,7 @@ protected:
|
|||||||
void DeviceMute(void) { if (device) device->Mute(); }
|
void DeviceMute(void) { if (device) device->Mute(); }
|
||||||
void DeviceSetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat) { if (device) device->SetVideoDisplayFormat(VideoDisplayFormat); }
|
void DeviceSetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat) { if (device) device->SetVideoDisplayFormat(VideoDisplayFormat); }
|
||||||
void DeviceStillPicture(const uchar *Data, int Length) { if (device) device->StillPicture(Data, Length); }
|
void DeviceStillPicture(const uchar *Data, int Length) { if (device) device->StillPicture(Data, Length); }
|
||||||
|
uint64_t DeviceGetSTC(void) { return device ? device->GetSTC() : -1; }
|
||||||
void Detach(void);
|
void Detach(void);
|
||||||
virtual void Activate(bool On) {}
|
virtual void Activate(bool On) {}
|
||||||
// This function is called right after the cPlayer has been attached to
|
// This function is called right after the cPlayer has been attached to
|
||||||
|
3
plugin.c
3
plugin.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: plugin.c 2.0 2008/02/17 13:32:12 kls Exp $
|
* $Id: plugin.c 2.1 2009/04/05 10:16:48 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
@ -137,6 +137,7 @@ void cPlugin::RegisterI18n(const void *)
|
|||||||
|
|
||||||
void cPlugin::SetConfigDirectory(const char *Dir)
|
void cPlugin::SetConfigDirectory(const char *Dir)
|
||||||
{
|
{
|
||||||
|
free(configDirectory);
|
||||||
configDirectory = strdup(Dir);
|
configDirectory = strdup(Dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
67
po/it_IT.po
67
po/it_IT.po
@ -12,18 +12,21 @@ msgstr ""
|
|||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n"
|
"Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n"
|
||||||
"POT-Creation-Date: 2008-12-14 16:10+0100\n"
|
"POT-Creation-Date: 2008-12-14 16:10+0100\n"
|
||||||
"PO-Revision-Date: 2008-08-25 02:36+0100\n"
|
"PO-Revision-Date: 2009-02-08 18:58+0100\n"
|
||||||
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
|
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
|
||||||
"Language-Team: Italian\n"
|
"Language-Team: Italian\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=ISO-8859-15\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"X-Poedit-Language: Italian\n"
|
||||||
|
"X-Poedit-Country: ITALY\n"
|
||||||
|
"X-Poedit-SourceCharset: utf-8\n"
|
||||||
|
|
||||||
msgid "off"
|
msgid "off"
|
||||||
msgstr "off"
|
msgstr "off"
|
||||||
|
|
||||||
msgid "on"
|
msgid "on"
|
||||||
msgstr ""
|
msgstr "on"
|
||||||
|
|
||||||
msgid "auto"
|
msgid "auto"
|
||||||
msgstr "automatico"
|
msgstr "automatico"
|
||||||
@ -58,7 +61,7 @@ msgid "Phase 1: Detecting RC code type"
|
|||||||
msgstr "Fase 1: Rilevamento tipo codice RC"
|
msgstr "Fase 1: Rilevamento tipo codice RC"
|
||||||
|
|
||||||
msgid "Press any key on the RC unit"
|
msgid "Press any key on the RC unit"
|
||||||
msgstr "Premi un tasto dell'unità RC"
|
msgstr "Premi un tasto dell'unità RC"
|
||||||
|
|
||||||
msgid "RC code detected!"
|
msgid "RC code detected!"
|
||||||
msgstr "Codice RC rilevato!"
|
msgstr "Codice RC rilevato!"
|
||||||
@ -77,13 +80,13 @@ msgid "Press 'Up' to confirm"
|
|||||||
msgstr "Premi 'Su' per confermare"
|
msgstr "Premi 'Su' per confermare"
|
||||||
|
|
||||||
msgid "Press 'Down' to continue"
|
msgid "Press 'Down' to continue"
|
||||||
msgstr "Premi 'Giù' per continuare"
|
msgstr "Premi 'Giù' per continuare"
|
||||||
|
|
||||||
msgid "(press 'Up' to go back)"
|
msgid "(press 'Up' to go back)"
|
||||||
msgstr "(premi 'Su' per tornare indietro)"
|
msgstr "(premi 'Su' per tornare indietro)"
|
||||||
|
|
||||||
msgid "(press 'Down' to end key definition)"
|
msgid "(press 'Down' to end key definition)"
|
||||||
msgstr "(premi 'Giù' per concludere definizione tasti)"
|
msgstr "(premi 'Giù' per concludere definizione tasti)"
|
||||||
|
|
||||||
msgid "(press 'Menu' to skip this key)"
|
msgid "(press 'Menu' to skip this key)"
|
||||||
msgstr "(premi 'Menu' per saltare questo tasto)"
|
msgstr "(premi 'Menu' per saltare questo tasto)"
|
||||||
@ -95,13 +98,13 @@ msgid "Phase 3: Saving key codes"
|
|||||||
msgstr "Fase 3: Salvataggio codici tasti"
|
msgstr "Fase 3: Salvataggio codici tasti"
|
||||||
|
|
||||||
msgid "Press 'Up' to save, 'Down' to cancel"
|
msgid "Press 'Up' to save, 'Down' to cancel"
|
||||||
msgstr "Premi 'Su' per salvare, 'Giù' per annullare"
|
msgstr "Premi 'Su' per salvare, 'Giù' per annullare"
|
||||||
|
|
||||||
msgid "Key$Up"
|
msgid "Key$Up"
|
||||||
msgstr "Su"
|
msgstr "Su"
|
||||||
|
|
||||||
msgid "Key$Down"
|
msgid "Key$Down"
|
||||||
msgstr "Giù"
|
msgstr "Giù"
|
||||||
|
|
||||||
msgid "Key$Menu"
|
msgid "Key$Menu"
|
||||||
msgstr "Menu"
|
msgstr "Menu"
|
||||||
@ -290,7 +293,7 @@ msgid "Polarization"
|
|||||||
msgstr "Polarizzazione"
|
msgstr "Polarizzazione"
|
||||||
|
|
||||||
msgid "System"
|
msgid "System"
|
||||||
msgstr ""
|
msgstr "Sistema"
|
||||||
|
|
||||||
msgid "Srate"
|
msgid "Srate"
|
||||||
msgstr "SymbolRate"
|
msgstr "SymbolRate"
|
||||||
@ -320,7 +323,7 @@ msgid "Hierarchy"
|
|||||||
msgstr "Gerarchia"
|
msgstr "Gerarchia"
|
||||||
|
|
||||||
msgid "Rolloff"
|
msgid "Rolloff"
|
||||||
msgstr ""
|
msgstr "Rolloff"
|
||||||
|
|
||||||
msgid "Channel settings are not unique!"
|
msgid "Channel settings are not unique!"
|
||||||
msgstr "Parametri canale non univoci!"
|
msgstr "Parametri canale non univoci!"
|
||||||
@ -368,7 +371,7 @@ msgid "VPS"
|
|||||||
msgstr "VPS"
|
msgstr "VPS"
|
||||||
|
|
||||||
msgid "Priority"
|
msgid "Priority"
|
||||||
msgstr "Priorità"
|
msgstr "Priorità"
|
||||||
|
|
||||||
msgid "Lifetime"
|
msgid "Lifetime"
|
||||||
msgstr "Scadenza"
|
msgstr "Scadenza"
|
||||||
@ -377,7 +380,7 @@ msgid "File"
|
|||||||
msgstr "Nome"
|
msgstr "Nome"
|
||||||
|
|
||||||
msgid "First day"
|
msgid "First day"
|
||||||
msgstr "1° giorno"
|
msgstr "1° giorno"
|
||||||
|
|
||||||
msgid "Timers"
|
msgid "Timers"
|
||||||
msgstr "Timer"
|
msgstr "Timer"
|
||||||
@ -682,10 +685,10 @@ msgid "CAM reset"
|
|||||||
msgstr "Reimposta la CAM"
|
msgstr "Reimposta la CAM"
|
||||||
|
|
||||||
msgid "CAM present"
|
msgid "CAM present"
|
||||||
msgstr "La CAM è presente"
|
msgstr "La CAM è presente"
|
||||||
|
|
||||||
msgid "CAM ready"
|
msgid "CAM ready"
|
||||||
msgstr "La CAM è pronta"
|
msgstr "La CAM è pronta"
|
||||||
|
|
||||||
msgid "CAM"
|
msgid "CAM"
|
||||||
msgstr "Accesso condizionato CAM"
|
msgstr "Accesso condizionato CAM"
|
||||||
@ -703,7 +706,7 @@ msgid "Can't open CAM menu!"
|
|||||||
msgstr "Impossibile aprire il menu CAM!"
|
msgstr "Impossibile aprire il menu CAM!"
|
||||||
|
|
||||||
msgid "CAM is in use - really reset?"
|
msgid "CAM is in use - really reset?"
|
||||||
msgstr "La CAM è in uso - vuoi reimpostarla?"
|
msgstr "La CAM è in uso - vuoi reimpostarla?"
|
||||||
|
|
||||||
msgid "Can't reset CAM!"
|
msgid "Can't reset CAM!"
|
||||||
msgstr "Impossibile reimpostare il modulo CAM!"
|
msgstr "Impossibile reimpostare il modulo CAM!"
|
||||||
@ -721,13 +724,13 @@ msgid "Setup.Recording$Primary limit"
|
|||||||
msgstr "Limite primario"
|
msgstr "Limite primario"
|
||||||
|
|
||||||
msgid "Setup.Recording$Default priority"
|
msgid "Setup.Recording$Default priority"
|
||||||
msgstr "Priorità predefinita"
|
msgstr "Priorità predefinita"
|
||||||
|
|
||||||
msgid "Setup.Recording$Default lifetime (d)"
|
msgid "Setup.Recording$Default lifetime (d)"
|
||||||
msgstr "Scadenza predefinita (gg)"
|
msgstr "Scadenza predefinita (gg)"
|
||||||
|
|
||||||
msgid "Setup.Recording$Pause priority"
|
msgid "Setup.Recording$Pause priority"
|
||||||
msgstr "Priorità di pausa"
|
msgstr "Priorità di pausa"
|
||||||
|
|
||||||
msgid "Setup.Recording$Pause lifetime (d)"
|
msgid "Setup.Recording$Pause lifetime (d)"
|
||||||
msgstr "Scadenza pausa (gg)"
|
msgstr "Scadenza pausa (gg)"
|
||||||
@ -760,10 +763,10 @@ msgid "Replay"
|
|||||||
msgstr "Riproduzione"
|
msgstr "Riproduzione"
|
||||||
|
|
||||||
msgid "Setup.Replay$Multi speed mode"
|
msgid "Setup.Replay$Multi speed mode"
|
||||||
msgstr "Modalità multispeed"
|
msgstr "Modalità multispeed"
|
||||||
|
|
||||||
msgid "Setup.Replay$Show replay mode"
|
msgid "Setup.Replay$Show replay mode"
|
||||||
msgstr "Mostra modalità riproduzione"
|
msgstr "Mostra modalità riproduzione"
|
||||||
|
|
||||||
msgid "Setup.Replay$Resume ID"
|
msgid "Setup.Replay$Resume ID"
|
||||||
msgstr "ID di ripristino"
|
msgstr "ID di ripristino"
|
||||||
@ -775,7 +778,7 @@ msgid "Setup.Miscellaneous$Min. event timeout (min)"
|
|||||||
msgstr "Scadenza min. evento (min)"
|
msgstr "Scadenza min. evento (min)"
|
||||||
|
|
||||||
msgid "Setup.Miscellaneous$Min. user inactivity (min)"
|
msgid "Setup.Miscellaneous$Min. user inactivity (min)"
|
||||||
msgstr "Periodo min. inattività (min)"
|
msgstr "Periodo min. inattività (min)"
|
||||||
|
|
||||||
msgid "Setup.Miscellaneous$SVDRP timeout (s)"
|
msgid "Setup.Miscellaneous$SVDRP timeout (s)"
|
||||||
msgstr "Scadenza SVDRP (s)"
|
msgstr "Scadenza SVDRP (s)"
|
||||||
@ -884,16 +887,16 @@ msgid "Editing process started"
|
|||||||
msgstr "Processo di modifica avviato"
|
msgstr "Processo di modifica avviato"
|
||||||
|
|
||||||
msgid "Editing process already active!"
|
msgid "Editing process already active!"
|
||||||
msgstr "Processo di modifica già attivo!"
|
msgstr "Processo di modifica già attivo!"
|
||||||
|
|
||||||
msgid "FileNameChars$ abcdefghijklmnopqrstuvwxyz0123456789-.,#~\\^$[]|()*+?{}/:%@&"
|
msgid "FileNameChars$ abcdefghijklmnopqrstuvwxyz0123456789-.,#~\\^$[]|()*+?{}/:%@&"
|
||||||
msgstr " aáàbcdeéèfghiìîjklmnoòpqrstuùvwxyz0123456789-.,#~\\^$[]|()*+?{}/:%@&°"
|
msgstr " aáàbcdeéèfghiìîjklmnoòpqrstuùvwxyz0123456789-.,#~\\^$[]|()*+?{}/:%@&°"
|
||||||
|
|
||||||
msgid "yes"
|
msgid "yes"
|
||||||
msgstr "sì"
|
msgstr "sì"
|
||||||
|
|
||||||
msgid "CharMap$ 0\t-.,1#~\\^$[]|()*+?{}/:%@&\tabc2\tdef3\tghi4\tjkl5\tmno6\tpqrs7\ttuv8\twxyz9"
|
msgid "CharMap$ 0\t-.,1#~\\^$[]|()*+?{}/:%@&\tabc2\tdef3\tghi4\tjkl5\tmno6\tpqrs7\ttuv8\twxyz9"
|
||||||
msgstr " 0\t-.,1#~\\^$[]|()*+°?{}/:%@&\taàbc2\tdeèf3\tghiì4\tjkl5\tmnoò6\tpqrs7\ttuùv8\twxyz9"
|
msgstr " 0\t-.,1#~\\^$[]|()*+°?{}/:%@&\taàbc2\tdeèf3\tghiì4\tjkl5\tmnoò6\tpqrs7\ttuùv8\twxyz9"
|
||||||
|
|
||||||
msgid "Button$ABC/abc"
|
msgid "Button$ABC/abc"
|
||||||
msgstr "ABC/abc"
|
msgstr "ABC/abc"
|
||||||
@ -908,7 +911,7 @@ msgid "Plugin"
|
|||||||
msgstr "Plugin"
|
msgstr "Plugin"
|
||||||
|
|
||||||
msgid "Up/Dn for new location - OK to move"
|
msgid "Up/Dn for new location - OK to move"
|
||||||
msgstr "Su/Giù per nuova posizione - OK per spostare"
|
msgstr "Su/Giù per nuova posizione - OK per spostare"
|
||||||
|
|
||||||
msgid "Channel locked (recording)!"
|
msgid "Channel locked (recording)!"
|
||||||
msgstr "Canale bloccato (in registrazione)!"
|
msgstr "Canale bloccato (in registrazione)!"
|
||||||
@ -964,19 +967,19 @@ msgid "MonTueWedThuFriSatSun"
|
|||||||
msgstr "LunMarMerGioVenSabDom"
|
msgstr "LunMarMerGioVenSabDom"
|
||||||
|
|
||||||
msgid "Monday"
|
msgid "Monday"
|
||||||
msgstr "Lunedì"
|
msgstr "Lunedì"
|
||||||
|
|
||||||
msgid "Tuesday"
|
msgid "Tuesday"
|
||||||
msgstr "Martedì"
|
msgstr "Martedì"
|
||||||
|
|
||||||
msgid "Wednesday"
|
msgid "Wednesday"
|
||||||
msgstr "Mercoledì"
|
msgstr "Mercoledì"
|
||||||
|
|
||||||
msgid "Thursday"
|
msgid "Thursday"
|
||||||
msgstr "Giovedì"
|
msgstr "Giovedì"
|
||||||
|
|
||||||
msgid "Friday"
|
msgid "Friday"
|
||||||
msgstr "Venerdì"
|
msgstr "Venerdì"
|
||||||
|
|
||||||
msgid "Saturday"
|
msgid "Saturday"
|
||||||
msgstr "Sabato"
|
msgstr "Sabato"
|
||||||
@ -991,7 +994,7 @@ msgid "Recording started"
|
|||||||
msgstr "Registrazione avviata"
|
msgstr "Registrazione avviata"
|
||||||
|
|
||||||
msgid "VDR will shut down later - press Power to force"
|
msgid "VDR will shut down later - press Power to force"
|
||||||
msgstr "VDR si spegnerà più tardi - premi Power per forzare"
|
msgstr "VDR si spegnerà più tardi - premi Power per forzare"
|
||||||
|
|
||||||
msgid "Press any key to cancel shutdown"
|
msgid "Press any key to cancel shutdown"
|
||||||
msgstr "Premi un tasto per annullare lo spegnimento"
|
msgstr "Premi un tasto per annullare lo spegnimento"
|
||||||
@ -1010,4 +1013,4 @@ msgstr "Premi un tasto per annullare il riavvio"
|
|||||||
|
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "VDR will shut down in %s minutes"
|
msgid "VDR will shut down in %s minutes"
|
||||||
msgstr "VDR si spegnerà tra %s minuti"
|
msgstr "VDR si spegnerà tra %s minuti"
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: recorder.c 2.2 2009/01/23 15:33:37 kls Exp $
|
* $Id: recorder.c 2.3 2009/03/20 15:49:02 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "recorder.h"
|
#include "recorder.h"
|
||||||
@ -113,7 +113,6 @@ void cRecorder::Receive(uchar *Data, int Length)
|
|||||||
void cRecorder::Action(void)
|
void cRecorder::Action(void)
|
||||||
{
|
{
|
||||||
time_t t = time(NULL);
|
time_t t = time(NULL);
|
||||||
bool Synced = false;
|
|
||||||
bool InfoWritten = false;
|
bool InfoWritten = false;
|
||||||
while (Running()) {
|
while (Running()) {
|
||||||
int r;
|
int r;
|
||||||
@ -123,7 +122,7 @@ void cRecorder::Action(void)
|
|||||||
if (Count) {
|
if (Count) {
|
||||||
if (!Running() && frameDetector->IndependentFrame()) // finish the recording before the next independent frame
|
if (!Running() && frameDetector->IndependentFrame()) // finish the recording before the next independent frame
|
||||||
break;
|
break;
|
||||||
if (Synced |= frameDetector->IndependentFrame()) { // start with first independent frame
|
if (frameDetector->Synced()) {
|
||||||
if (!InfoWritten) {
|
if (!InfoWritten) {
|
||||||
if (recordingInfo.Read()) {
|
if (recordingInfo.Read()) {
|
||||||
if (frameDetector->FramesPerSecond() > 0 && recordingInfo.FramesPerSecond() != frameDetector->FramesPerSecond()) {
|
if (frameDetector->FramesPerSecond() > 0 && recordingInfo.FramesPerSecond() != frameDetector->FramesPerSecond()) {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: recording.c 2.8 2009/01/24 13:11:04 kls Exp $
|
* $Id: recording.c 2.9 2009/01/30 16:27:19 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "recording.h"
|
#include "recording.h"
|
||||||
@ -286,6 +286,7 @@ bool cResumeFile::Save(int Index)
|
|||||||
if (f) {
|
if (f) {
|
||||||
fprintf(f, "I %d\n", Index);
|
fprintf(f, "I %d\n", Index);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
Recordings.ResetResume(fileName);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LOG_ERROR_STR(fileName);
|
LOG_ERROR_STR(fileName);
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: recording.h 2.4 2009/01/24 15:24:19 kls Exp $
|
* $Id: recording.h 2.5 2009/02/28 10:50:12 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __RECORDING_H
|
#ifndef __RECORDING_H
|
||||||
@ -60,6 +60,7 @@ public:
|
|||||||
~cRecordingInfo();
|
~cRecordingInfo();
|
||||||
tChannelID ChannelID(void) const { return channelID; }
|
tChannelID ChannelID(void) const { return channelID; }
|
||||||
const char *ChannelName(void) const { return channelName; }
|
const char *ChannelName(void) const { return channelName; }
|
||||||
|
const cEvent *GetEvent(void) const { return event; }
|
||||||
const char *Title(void) const { return event->Title(); }
|
const char *Title(void) const { return event->Title(); }
|
||||||
const char *ShortText(void) const { return event->ShortText(); }
|
const char *ShortText(void) const { return event->ShortText(); }
|
||||||
const char *Description(void) const { return event->Description(); }
|
const char *Description(void) const { return event->Description(); }
|
||||||
|
131
remux.c
131
remux.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: remux.c 2.13 2009/01/24 13:44:45 kls Exp $
|
* $Id: remux.c 2.17 2009/04/05 14:07:48 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "remux.h"
|
#include "remux.h"
|
||||||
@ -109,6 +109,21 @@ void cRemux::SetBrokenLink(uchar *Data, int Length)
|
|||||||
dsyslog("SetBrokenLink: no video packet in frame");
|
dsyslog("SetBrokenLink: no video packet in frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Some TS handling tools ------------------------------------------------
|
||||||
|
|
||||||
|
int64_t TsGetPts(const uchar *p, int l)
|
||||||
|
{
|
||||||
|
// Find the first packet with a PTS and use it:
|
||||||
|
while (l > 0) {
|
||||||
|
const uchar *d = p;
|
||||||
|
if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasPts(d))
|
||||||
|
return PesGetPts(d);
|
||||||
|
p += TS_SIZE;
|
||||||
|
l -= TS_SIZE;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// --- cPatPmtGenerator ------------------------------------------------------
|
// --- cPatPmtGenerator ------------------------------------------------------
|
||||||
|
|
||||||
cPatPmtGenerator::cPatPmtGenerator(cChannel *Channel)
|
cPatPmtGenerator::cPatPmtGenerator(cChannel *Channel)
|
||||||
@ -661,47 +676,74 @@ cFrameDetector::cFrameDetector(int Pid, int Type)
|
|||||||
{
|
{
|
||||||
pid = Pid;
|
pid = Pid;
|
||||||
type = Type;
|
type = Type;
|
||||||
|
synced = false;
|
||||||
newFrame = independentFrame = false;
|
newFrame = independentFrame = false;
|
||||||
lastPts = 0;
|
numPtsValues = 0;
|
||||||
|
numIFrames = 0;
|
||||||
isVideo = type == 0x02 || type == 0x1B; // MPEG 2 or MPEG 4
|
isVideo = type == 0x02 || type == 0x1B; // MPEG 2 or MPEG 4
|
||||||
frameDuration = 0;
|
frameDuration = 0;
|
||||||
framesPerPayloadUnit = 0;
|
framesInPayloadUnit = framesPerPayloadUnit = 0;
|
||||||
|
payloadUnitOfFrame = 0;
|
||||||
scanning = false;
|
scanning = false;
|
||||||
scanner = 0;
|
scanner = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int CmpUint32(const void *p1, const void *p2)
|
||||||
|
{
|
||||||
|
if (*(uint32_t *)p1 < *(uint32_t *)p2) return -1;
|
||||||
|
if (*(uint32_t *)p1 > *(uint32_t *)p2) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int cFrameDetector::Analyze(const uchar *Data, int Length)
|
int cFrameDetector::Analyze(const uchar *Data, int Length)
|
||||||
{
|
{
|
||||||
|
int Processed = 0;
|
||||||
newFrame = independentFrame = false;
|
newFrame = independentFrame = false;
|
||||||
if (Length >= TS_SIZE) {
|
while (Length >= TS_SIZE) {
|
||||||
if (TsHasPayload(Data) && !TsIsScrambled(Data) && TsPid(Data) == pid) {
|
if (TsHasPayload(Data) && !TsIsScrambled(Data) && TsPid(Data) == pid) {
|
||||||
if (TsPayloadStart(Data)) {
|
if (TsPayloadStart(Data)) {
|
||||||
if (!frameDuration) {
|
if (!frameDuration) {
|
||||||
|
// frame duration unknown, so collect a sequenece of PTS values:
|
||||||
|
if (numPtsValues < MaxPtsValues && numIFrames < 2) { // collect a sequence containing at least two I-frames
|
||||||
const uchar *Pes = Data + TsPayloadOffset(Data);
|
const uchar *Pes = Data + TsPayloadOffset(Data);
|
||||||
if (PesHasPts(Pes)) {
|
if (PesHasPts(Pes)) {
|
||||||
int64_t Pts = PesGetPts(Pes);
|
ptsValues[numPtsValues] = PesGetPts(Pes);
|
||||||
if (Pts < lastPts) { // avoid wrapping
|
// check for rollover:
|
||||||
lastPts = 0;
|
if (numPtsValues && ptsValues[numPtsValues - 1] > 0xF0000000 && ptsValues[numPtsValues] < 0x10000000) {
|
||||||
framesPerPayloadUnit = 0;
|
dbgframes("#");
|
||||||
|
numPtsValues = 0;
|
||||||
|
numIFrames = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
numPtsValues++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ((!lastPts || !framesPerPayloadUnit) && Pts != lastPts)
|
|
||||||
lastPts = Pts;
|
|
||||||
else {
|
else {
|
||||||
int64_t Delta = Pts - lastPts;
|
// find the smallest PTS delta:
|
||||||
|
qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
|
||||||
|
numPtsValues--;
|
||||||
|
for (int i = 0; i < numPtsValues; i++)
|
||||||
|
ptsValues[i] = ptsValues[i + 1] - ptsValues[i];
|
||||||
|
qsort(ptsValues, numPtsValues, sizeof(uint32_t), CmpUint32);
|
||||||
|
uint32_t Delta = ptsValues[0];
|
||||||
|
// determine frame info:
|
||||||
if (isVideo) {
|
if (isVideo) {
|
||||||
if (Delta % 3600 == 0)
|
if (Delta % 3600 == 0)
|
||||||
frameDuration = 3600; // PAL, 25 fps
|
frameDuration = 3600; // PAL, 25 fps
|
||||||
else if (Delta % 3003 == 0)
|
else if (Delta % 3003 == 0)
|
||||||
frameDuration = 3003; // NTSC, 29.97 fps
|
frameDuration = 3003; // NTSC, 29.97 fps
|
||||||
|
else if (Delta == 1501) {
|
||||||
|
frameDuration = 3003; // NTSC, 29.97 fps
|
||||||
|
framesPerPayloadUnit = -2;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
frameDuration = 3600; // unknown, assuming 25 fps
|
frameDuration = 3600; // unknown, assuming 25 fps
|
||||||
dsyslog("unknown frame duration, assuming 25 fps (PTS: %lld - %lld = %lld FPPU = %d)\n", Pts, lastPts, Delta, framesPerPayloadUnit);
|
dsyslog("unknown frame duration (%d), assuming 25 fps", Delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // audio
|
else // audio
|
||||||
frameDuration = Delta; // PTS of audio frames is always increasing
|
frameDuration = Delta; // PTS of audio frames is always increasing
|
||||||
dbgframes("PTS: %lld - %lld = %lld -> FD = %d FPS = %5.2f FPPU = %d\n", Pts, lastPts, Delta, frameDuration, 90000.0 / frameDuration, framesPerPayloadUnit);
|
dbgframes("\nframe duration = %d FPS = %5.2f FPPU = %d\n", frameDuration, 90000.0 / frameDuration, framesPerPayloadUnit);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scanner = 0;
|
scanner = 0;
|
||||||
@ -709,24 +751,31 @@ int cFrameDetector::Analyze(const uchar *Data, int Length)
|
|||||||
}
|
}
|
||||||
if (scanning) {
|
if (scanning) {
|
||||||
int PayloadOffset = TsPayloadOffset(Data);
|
int PayloadOffset = TsPayloadOffset(Data);
|
||||||
if (TsPayloadStart(Data))
|
if (TsPayloadStart(Data)) {
|
||||||
PayloadOffset += PesPayloadOffset(Data + PayloadOffset);
|
PayloadOffset += PesPayloadOffset(Data + PayloadOffset);
|
||||||
for (int i = PayloadOffset; i < TS_SIZE; i++) {
|
if (!framesPerPayloadUnit)
|
||||||
|
framesPerPayloadUnit = framesInPayloadUnit;
|
||||||
|
if (DebugFrames && !synced)
|
||||||
|
dbgframes("/");
|
||||||
|
}
|
||||||
|
for (int i = PayloadOffset; scanning && i < TS_SIZE; i++) {
|
||||||
scanner <<= 8;
|
scanner <<= 8;
|
||||||
scanner |= Data[i];
|
scanner |= Data[i];
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 0x02: // MPEG 2 video
|
case 0x02: // MPEG 2 video
|
||||||
if (scanner == 0x00000100) { // Picture Start Code
|
if (scanner == 0x00000100) { // Picture Start Code
|
||||||
if (frameDuration) {
|
if (synced && Processed)
|
||||||
|
return Processed;
|
||||||
newFrame = true;
|
newFrame = true;
|
||||||
independentFrame = ((Data[i + 2] >> 3) & 0x07) == 1; // I-Frame
|
independentFrame = ((Data[i + 2] >> 3) & 0x07) == 1; // I-Frame
|
||||||
if (framesPerPayloadUnit == 1) {
|
if (synced) {
|
||||||
|
if (framesPerPayloadUnit <= 1)
|
||||||
scanning = false;
|
scanning = false;
|
||||||
return TS_SIZE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
framesPerPayloadUnit++;
|
framesInPayloadUnit++;
|
||||||
|
if (independentFrame)
|
||||||
|
numIFrames++;
|
||||||
dbgframes("%d ", (Data[i + 2] >> 3) & 0x07);
|
dbgframes("%d ", (Data[i + 2] >> 3) & 0x07);
|
||||||
}
|
}
|
||||||
scanner = 0;
|
scanner = 0;
|
||||||
@ -734,16 +783,25 @@ int cFrameDetector::Analyze(const uchar *Data, int Length)
|
|||||||
break;
|
break;
|
||||||
case 0x1B: // MPEG 4 video
|
case 0x1B: // MPEG 4 video
|
||||||
if (scanner == 0x00000109) { // Access Unit Delimiter
|
if (scanner == 0x00000109) { // Access Unit Delimiter
|
||||||
if (frameDuration) {
|
if (synced && Processed)
|
||||||
|
return Processed;
|
||||||
newFrame = true;
|
newFrame = true;
|
||||||
independentFrame = Data[i + 1] == 0x10;
|
independentFrame = Data[i + 1] == 0x10;
|
||||||
if (framesPerPayloadUnit == 1) {
|
if (synced) {
|
||||||
scanning = false;
|
if (framesPerPayloadUnit < 0) {
|
||||||
return TS_SIZE;
|
payloadUnitOfFrame = (payloadUnitOfFrame + 1) % -framesPerPayloadUnit;
|
||||||
|
if (payloadUnitOfFrame != 0 && independentFrame)
|
||||||
|
payloadUnitOfFrame = 0;
|
||||||
|
if (payloadUnitOfFrame)
|
||||||
|
newFrame = false;
|
||||||
}
|
}
|
||||||
|
if (framesPerPayloadUnit <= 1)
|
||||||
|
scanning = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
framesPerPayloadUnit++;
|
framesInPayloadUnit++;
|
||||||
|
if (independentFrame)
|
||||||
|
numIFrames++;
|
||||||
dbgframes("%02X ", Data[i + 1]);
|
dbgframes("%02X ", Data[i + 1]);
|
||||||
}
|
}
|
||||||
scanner = 0;
|
scanner = 0;
|
||||||
@ -751,21 +809,30 @@ int cFrameDetector::Analyze(const uchar *Data, int Length)
|
|||||||
break;
|
break;
|
||||||
case 0x04: // MPEG audio
|
case 0x04: // MPEG audio
|
||||||
case 0x06: // AC3 audio
|
case 0x06: // AC3 audio
|
||||||
if (frameDuration) {
|
if (synced && Processed)
|
||||||
|
return Processed;
|
||||||
newFrame = true;
|
newFrame = true;
|
||||||
independentFrame = true;
|
independentFrame = true;
|
||||||
scanning = false;
|
if (!synced) {
|
||||||
|
framesInPayloadUnit = 1;
|
||||||
|
if (TsPayloadStart(Data))
|
||||||
|
numIFrames++;
|
||||||
}
|
}
|
||||||
else
|
scanning = false;
|
||||||
framesPerPayloadUnit = 1;
|
|
||||||
break;
|
break;
|
||||||
default: esyslog("ERROR: unknown stream type %d (PID %d) in frame detector", type, pid);
|
default: esyslog("ERROR: unknown stream type %d (PID %d) in frame detector", type, pid);
|
||||||
pid = 0; // let's just ignore any further data
|
pid = 0; // let's just ignore any further data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!synced && frameDuration && independentFrame) {
|
||||||
|
synced = true;
|
||||||
|
dbgframes("*");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return TS_SIZE;
|
|
||||||
}
|
}
|
||||||
return 0;
|
Data += TS_SIZE;
|
||||||
|
Length -= TS_SIZE;
|
||||||
|
Processed += TS_SIZE;
|
||||||
|
}
|
||||||
|
return Processed;
|
||||||
}
|
}
|
||||||
|
27
remux.h
27
remux.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: remux.h 2.7 2009/01/24 13:38:10 kls Exp $
|
* $Id: remux.h 2.9 2009/03/27 13:38:59 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __REMUX_H
|
#ifndef __REMUX_H
|
||||||
@ -101,6 +101,10 @@ inline int TsGetAdaptationField(const uchar *p)
|
|||||||
return TsHasAdaptationField(p) ? p[5] : 0x00;
|
return TsHasAdaptationField(p) ? p[5] : 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The following functions all take a pointer to a sequence of complete TS packets.
|
||||||
|
|
||||||
|
int64_t TsGetPts(const uchar *p, int l);
|
||||||
|
|
||||||
// Some PES handling tools:
|
// Some PES handling tools:
|
||||||
// The following functions that take a pointer to PES data all assume that
|
// The following functions that take a pointer to PES data all assume that
|
||||||
// there is enough data so that PesLongEnough() returns true.
|
// there is enough data so that PesLongEnough() returns true.
|
||||||
@ -263,14 +267,22 @@ void PesDump(const char *Name, const u_char *Data, int Length);
|
|||||||
|
|
||||||
class cFrameDetector {
|
class cFrameDetector {
|
||||||
private:
|
private:
|
||||||
|
enum { MaxPtsValues = 150 };
|
||||||
int pid;
|
int pid;
|
||||||
int type;
|
int type;
|
||||||
|
bool synced;
|
||||||
bool newFrame;
|
bool newFrame;
|
||||||
bool independentFrame;
|
bool independentFrame;
|
||||||
int64_t lastPts;
|
uint32_t ptsValues[MaxPtsValues]; // 32 bit is enough - we only need the delta
|
||||||
|
int numPtsValues;
|
||||||
|
int numIFrames;
|
||||||
bool isVideo;
|
bool isVideo;
|
||||||
int frameDuration;
|
int frameDuration;
|
||||||
int framesPerPayloadUnit;
|
int framesInPayloadUnit;
|
||||||
|
int framesPerPayloadUnit; // Some broadcasters send one frame per payload unit (== 1),
|
||||||
|
// some put an entire GOP into one payload unit (> 1), and
|
||||||
|
// some spread a single frame over several payload units (< 0).
|
||||||
|
int payloadUnitOfFrame;
|
||||||
bool scanning;
|
bool scanning;
|
||||||
uint32_t scanner;
|
uint32_t scanner;
|
||||||
public:
|
public:
|
||||||
@ -278,10 +290,11 @@ public:
|
|||||||
int Analyze(const uchar *Data, int Length);
|
int Analyze(const uchar *Data, int Length);
|
||||||
///< Analyzes the TS packets pointed to by Data. Length is the number of
|
///< Analyzes the TS packets pointed to by Data. Length is the number of
|
||||||
///< bytes Data points to, and must be a multiple of 188.
|
///< bytes Data points to, and must be a multiple of 188.
|
||||||
///< Returns the number of bytes that have been analyzed and may be written
|
///< Returns the number of bytes that have been analyzed.
|
||||||
///< to the recording file. If the return value is 0, the data was not
|
///< If the return value is 0, the data was not sufficient for analyzing and
|
||||||
///< sufficient for analyzing and Analyze() needs to be called again with
|
///< Analyze() needs to be called again with more actual data.
|
||||||
///< more actual data.
|
bool Synced(void) { return synced; }
|
||||||
|
///< Returns true if the frame detector has synced on the data stream.
|
||||||
bool NewFrame(void) { return newFrame; }
|
bool NewFrame(void) { return newFrame; }
|
||||||
///< Returns true if the data given to the last call to Analyze() started a
|
///< Returns true if the data given to the last call to Analyze() started a
|
||||||
///< new frame.
|
///< new frame.
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Parts of this file were inspired by the 'ringbuffy.c' from the
|
* Parts of this file were inspired by the 'ringbuffy.c' from the
|
||||||
* LinuxDVB driver (see linuxtv.org).
|
* LinuxDVB driver (see linuxtv.org).
|
||||||
*
|
*
|
||||||
* $Id: ringbuffer.c 2.0 2007/11/17 13:49:34 kls Exp $
|
* $Id: ringbuffer.c 2.1 2009/02/24 11:32:14 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
@ -335,11 +335,12 @@ void cRingBufferLinear::Del(int Count)
|
|||||||
|
|
||||||
// --- cFrame ----------------------------------------------------------------
|
// --- cFrame ----------------------------------------------------------------
|
||||||
|
|
||||||
cFrame::cFrame(const uchar *Data, int Count, eFrameType Type, int Index)
|
cFrame::cFrame(const uchar *Data, int Count, eFrameType Type, int Index, uint32_t Pts)
|
||||||
{
|
{
|
||||||
count = abs(Count);
|
count = abs(Count);
|
||||||
type = Type;
|
type = Type;
|
||||||
index = Index;
|
index = Index;
|
||||||
|
pts = Pts;
|
||||||
if (Count < 0)
|
if (Count < 0)
|
||||||
data = (uchar *)Data;
|
data = (uchar *)Data;
|
||||||
else {
|
else {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: ringbuffer.h 2.0 2007/11/17 13:49:34 kls Exp $
|
* $Id: ringbuffer.h 2.1 2009/02/24 11:31:32 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __RINGBUFFER_H
|
#ifndef __RINGBUFFER_H
|
||||||
@ -108,8 +108,9 @@ private:
|
|||||||
int count;
|
int count;
|
||||||
eFrameType type;
|
eFrameType type;
|
||||||
int index;
|
int index;
|
||||||
|
uint32_t pts;
|
||||||
public:
|
public:
|
||||||
cFrame(const uchar *Data, int Count, eFrameType = ftUnknown, int Index = -1);
|
cFrame(const uchar *Data, int Count, eFrameType = ftUnknown, int Index = -1, uint32_t Pts = 0);
|
||||||
///< Creates a new cFrame object.
|
///< Creates a new cFrame object.
|
||||||
///< If Count is negative, the cFrame object will take ownership of the given
|
///< If Count is negative, the cFrame object will take ownership of the given
|
||||||
///< Data. Otherwise it will allocate Count bytes of memory and copy Data.
|
///< Data. Otherwise it will allocate Count bytes of memory and copy Data.
|
||||||
@ -118,6 +119,7 @@ public:
|
|||||||
int Count(void) const { return count; }
|
int Count(void) const { return count; }
|
||||||
eFrameType Type(void) const { return type; }
|
eFrameType Type(void) const { return type; }
|
||||||
int Index(void) const { return index; }
|
int Index(void) const { return index; }
|
||||||
|
uint32_t Pts(void) const { return pts; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class cRingBufferFrame : public cRingBuffer {
|
class cRingBufferFrame : public cRingBuffer {
|
||||||
|
12
vdr.c
12
vdr.c
@ -22,7 +22,7 @@
|
|||||||
*
|
*
|
||||||
* The project's page is at http://www.cadsoft.de/vdr
|
* The project's page is at http://www.cadsoft.de/vdr
|
||||||
*
|
*
|
||||||
* $Id: vdr.c 2.4 2009/01/18 11:02:37 kls Exp $
|
* $Id: vdr.c 2.7 2009/04/05 13:21:46 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
@ -112,10 +112,10 @@ static bool SetUser(const char *UserName, bool UserDump)//XXX name?
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool SetCapSysTime(void)
|
static bool DropCaps(void)
|
||||||
{
|
{
|
||||||
// drop all capabilities except cap_sys_time
|
// drop all capabilities except selected ones
|
||||||
cap_t caps = cap_from_text("= cap_sys_time=ep");
|
cap_t caps = cap_from_text("= cap_sys_nice,cap_sys_time=ep");
|
||||||
if (!caps) {
|
if (!caps) {
|
||||||
fprintf(stderr, "vdr: cap_from_text failed: %s\n", strerror(errno));
|
fprintf(stderr, "vdr: cap_from_text failed: %s\n", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
@ -387,7 +387,7 @@ int main(int argc, char *argv[])
|
|||||||
return 2;
|
return 2;
|
||||||
if (!SetKeepCaps(false))
|
if (!SetKeepCaps(false))
|
||||||
return 2;
|
return 2;
|
||||||
if (!SetCapSysTime())
|
if (!DropCaps())
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -416,6 +416,7 @@ int main(int argc, char *argv[])
|
|||||||
" existing directory, without any \"..\", double '/'\n"
|
" existing directory, without any \"..\", double '/'\n"
|
||||||
" or symlinks (default: none, same as -g-)\n"
|
" or symlinks (default: none, same as -g-)\n"
|
||||||
" -h, --help print this help and exit\n"
|
" -h, --help print this help and exit\n"
|
||||||
|
" -i ID, --instance=ID use ID as the id of this VDR instance (default: 0)\n"
|
||||||
" -l LEVEL, --log=LEVEL set log level (default: 3)\n"
|
" -l LEVEL, --log=LEVEL set log level (default: 3)\n"
|
||||||
" 0 = no logging, 1 = errors only,\n"
|
" 0 = no logging, 1 = errors only,\n"
|
||||||
" 2 = errors and info, 3 = errors, info and debug\n"
|
" 2 = errors and info, 3 = errors, info and debug\n"
|
||||||
@ -533,6 +534,7 @@ int main(int argc, char *argv[])
|
|||||||
isyslog("codeset is '%s' - %s", CodeSet, known ? "known" : "unknown");
|
isyslog("codeset is '%s' - %s", CodeSet, known ? "known" : "unknown");
|
||||||
cCharSetConv::SetSystemCharacterTable(CodeSet);
|
cCharSetConv::SetSystemCharacterTable(CodeSet);
|
||||||
}
|
}
|
||||||
|
setlocale(LC_NUMERIC, "C"); // makes sure any floating point numbers written use a decimal point
|
||||||
|
|
||||||
// Initialize internationalization:
|
// Initialize internationalization:
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user