summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTORS13
-rw-r--r--HISTORY67
-rw-r--r--INSTALL4
-rw-r--r--MANUAL20
-rw-r--r--Make.config.template8
-rw-r--r--Makefile4
-rw-r--r--PLUGINS/src/dvbhddevice/dvbhdffdevice.c169
-rw-r--r--PLUGINS/src/dvbhddevice/dvbhdffdevice.h3
-rw-r--r--PLUGINS/src/dvbhddevice/hdffcmd.c7
-rw-r--r--PLUGINS/src/dvbhddevice/hdffcmd.h3
-rw-r--r--PLUGINS/src/dvbhddevice/hdffmsgdef.h313
-rw-r--r--PLUGINS/src/dvbhddevice/hdffosd.c4
-rw-r--r--PLUGINS/src/dvbhddevice/libhdffcmd/Makefile12
-rw-r--r--PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_av.c19
-rw-r--r--PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_av.h2
-rw-r--r--PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_defs.h1
-rw-r--r--PLUGINS/src/dvbhddevice/po/de_DE.po5
-rw-r--r--PLUGINS/src/dvbhddevice/po/fi_FI.po5
-rw-r--r--PLUGINS/src/dvbhddevice/po/it_IT.po5
-rw-r--r--PLUGINS/src/dvbhddevice/setup.c7
-rw-r--r--PLUGINS/src/dvbhddevice/setup.h3
-rw-r--r--ci.c6
-rw-r--r--config.h10
-rw-r--r--cutter.c654
-rw-r--r--device.c6
-rw-r--r--dvbdevice.c22
-rw-r--r--epg.c6
-rw-r--r--libsi/si.h6
-rw-r--r--menu.c28
-rw-r--r--po/ar.po5
-rw-r--r--po/ca_ES.po5
-rw-r--r--po/cs_CZ.po5
-rw-r--r--po/da_DK.po5
-rw-r--r--po/de_DE.po5
-rw-r--r--po/el_GR.po5
-rw-r--r--po/es_ES.po5
-rw-r--r--po/et_EE.po5
-rw-r--r--po/fi_FI.po5
-rw-r--r--po/fr_FR.po5
-rw-r--r--po/hr_HR.po5
-rw-r--r--po/hu_HU.po5
-rw-r--r--po/it_IT.po5
-rw-r--r--po/lt_LT.po5
-rw-r--r--po/mk_MK.po5
-rw-r--r--po/nl_NL.po5
-rw-r--r--po/nn_NO.po5
-rw-r--r--po/pl_PL.po5
-rw-r--r--po/pt_PT.po5
-rw-r--r--po/ro_RO.po495
-rw-r--r--po/ru_RU.po5
-rw-r--r--po/sk_SK.po5
-rw-r--r--po/sl_SI.po5
-rw-r--r--po/sr_SR.po5
-rw-r--r--po/sv_SE.po5
-rw-r--r--po/tr_TR.po5
-rw-r--r--po/uk_UA.po5
-rw-r--r--po/zh_CN.po5
-rw-r--r--recording.c139
-rw-r--r--recording.h26
-rw-r--r--remux.c812
-rw-r--r--remux.h142
-rw-r--r--sections.c5
-rw-r--r--skinlcars.h2
-rw-r--r--themes.h4
-rw-r--r--thread.c11
-rw-r--r--thread.h7
-rw-r--r--timers.c21
-rw-r--r--vdr.510
-rw-r--r--vdr.c6
69 files changed, 2091 insertions, 1136 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index a275edb..9e2317f 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -1757,6 +1757,9 @@ Udo Richter <udo_richter@gmx.de>
for adding the option --outputonly to the dvbsddevice plugin
for adding a missing template specification to the c'tor of cSortedTimers
for contributing to a patch that implements FHS support
+ for suggesting to check cIoThrottle::Engaged() in cRemoveDeletedRecordingsThread::Action()
+ for suggesting to shift editing marks that don't point to an I-frame towards the next I-frame
+ when a recording is played
Sven Kreiensen <svenk@kammer.uni-hannover.de>
for his help in keeping 'channels.conf.terr' up to date
@@ -2305,6 +2308,8 @@ Christoph Haubrich <christoph1.haubrich@arcor.de>
for fixing cRecording::LengthInSeconds(), which wrongfully rounded the result to full
minutes
for suggesting to check for NULL in cOsd::AddPixmap()
+ for making modified editing marks be written to disk whenever the replay progress
+ display gets hidden
Pekka Mauno <pekka.mauno@iki.fi>
for fixing cSchedule::GetFollowingEvent() in case there is currently no present
@@ -2314,6 +2319,8 @@ Alexander Wenzel <hondansx@gmx.de>
for fixing the shutdown timeout
for making the script given to VDR with the '-r' option be also called whenever a
recording is deleted
+ for making pressing the Play key during normal live viewing mode open the Recordings
+ menu if there is no "last viewed" recording
Jan Lenz <email@JanLenz.de>
for reporting a bug in deleting recordings that have been removed externally when
@@ -2618,6 +2625,7 @@ Sundararaj Reel <sundararaj.reel@googlemail.com>
for reporting a problem with the function cString::sprintf(const char *fmt, va_list &ap),
that might inadvertently be called with a 'char *' as the second argument on some
compilers and cause a crash
+ for reporting a possible memory leak in SI::StructureLoop::getNextAsPointer()
Ales Jurik <ajurik@quick.cz>
for reporting broken SI data on Czech/Slovak channels after changing the default
@@ -2692,6 +2700,7 @@ Derek Kelly (user.vdr@gmail.com)
several payloads
for reporting a problem with getting the maximum short channel name length in case there
are no short names at all
+ for reporting an incompatible change from DTV_DVBT2_PLP_ID to DTV_STREAM_ID in DVB API 5.8
Marcel Unbehaun <frostworks@gmx.de>
for adding cRecordingInfo::GetEvent()
@@ -2895,6 +2904,7 @@ Torsten Lang <info@torstenlang.de>
in case buffers run full
for suggesting to increase the size of the TS buffer to 5MB and that of the Recorder
buffer to 20MB to better handle HD recordings
+ for fixing setting the video format in the dvbhdffdevice
Christian Ruppert <idl0r@gentoo.org>
for some improvements to the Makefiles
@@ -2960,3 +2970,6 @@ Sören Moch <smoch@web.de>
for a patch that was used to move cleaning up the EPG data and writing the epg.data
file into a separate thread to avoid sluggish response to user input on slow systems
for fixing sorting folders before recordings in case of UTF-8
+
+Peter Münster <pmlists@free.fr>
+ for fixing 'make install' to not overwrite existing configuration files
diff --git a/HISTORY b/HISTORY
index a1cb40c..ff1681b 100644
--- a/HISTORY
+++ b/HISTORY
@@ -7271,3 +7271,70 @@ Video Disk Recorder Revision History
whether a directory is empty. This allows users to continue to use files such as
".keep" to prevent a directory from being deleted when it is empty. Currently the
only file name that is ignored is ".sort".
+
+2012-11-18: Version 1.7.32
+
+- Pressing the Play key during normal live viewing mode now opens the Recordings menu
+ if there is no "last viewed" recording (thanks to Alexander Wenzel).
+ The same behavior has been implemented for the Blue key in the main menu.
+- cIoThrottle::Engaged() is now also checked in cRemoveDeletedRecordingsThread::Action(),
+ to suspend removing deleted recordings in case this is necessary to make room for
+ new, ongoing recordings (suggested by Udo Richter).
+- The cThread constructor now has an additional boolean parameter that can be set to
+ true to have this thread run at a lower priority. Plugin authors that use low
+ priority threads may want to use this instead of the calls to SetPriority(19) and
+ SetIOPriority(7). The priority of a thread ("low" or "high") is now logged when the
+ thread starts.
+- Changed DTV_DVBT2_PLP_ID to DTV_STREAM_ID in dvbdevice.c to adapt to an incompatible
+ change in DVB API 5.8 (reported by Derek Kelly).
+ Removed the meanwhile obsolete definition of FE_CAN_TURBO_FEC.
+- Fixed some compiler warnings under gcc version 4.7.1.
+- Fixed setting the video format in the dvbhdffdevice (thanks to Torsten Lang).
+- Fixed 'make install' to not overwrite existing configuration files (thanks to Peter
+ Münster).
+- Added including the Make.global and Make.config files to the dvbdhffdevice's
+ libhdffcmd/Makefile.
+- Added options to build a 32-bit version of VDR on a 64-bit machine to
+ Make.config.template.
+- Fixed handling VPS timers in case the running status of an event goes to '1' (not
+ running) and later goes to '4' (running).
+- If a frame position in the 'marks' file of a recording doesn't point to an I-frame,
+ it will now be shifted towards the next I-frame, either up or down, whichever is
+ closer (suggested by Udo Richter).
+- Fixed a possible memory leak in SI::StructureLoop::getNextAsPointer() (reported by
+ Sundararaj Reel).
+- Fixed handling timers in case an event is modified and "phased out" while the timer
+ is recording.
+- Improved frame detection by parsing just far enough into the MPEG-4 NAL units to get
+ the necessary information about frames and slices.
+- The initial syncing of the frame detector is now done immediately after the first
+ complete GOP has been seen. This makes recordings and especially pausing live video
+ start up to twice as fast as before.
+- Updated the Romanian OSD texts (thanks to Lucian Muresan).
+- Fixed handling the very last entry in a recording index.
+- The return type of cMarks::Add() has been changed to void, since due to the sorting
+ of the list of marks the returned pointer might have pointed to a totally different
+ mark. Besides, the return value was never actually used.
+- Improved editing TS recordings by
+ + stripping dangling TS packets from the beginning of a sequence
+ + including pending TS packets at the end of a sequence
+ + fixing all timestamps and continuity counters
+ + generating editing marks for the edited version in such a way that each cutting
+ point is marked by an "end" and "begin" mark with the same offset
+ + no longer generating an editing mark at the "end" of the edited recording (this
+ was actually generated at the beginning of the last GOP, so that a subsequent
+ edit would have cut off the last GOP)
+ + no longer generating any editing marks if the edited recording results on just
+ one single sequence
+ + ignoring pairs of editing marks that are placed at exactly the same position of
+ a recording when actually cutting the recording
+ + not doing anything if the editing marks in place would result in the edited
+ version being the same as the original recording
+- Editing marks can now be placed directly on top of each other, in which case they
+ simply mark a position, but have no effect on the actual cutting process.
+- When positioned at an offset where two (or more) editing marks are placed on top
+ of each other, the '4' key moves the first one of them to the left, while the '6'
+ key moves the last one of them to the right. The '7' and '9' key handle multiple
+ marks at the same place as if it were one single mark.
+- Modified editing marks are now written to disk whenever the replay progress display
+ gets hidden (thanks to Christoph Haubrich).
diff --git a/INSTALL b/INSTALL
index 07a5079..1767451 100644
--- a/INSTALL
+++ b/INSTALL
@@ -36,6 +36,10 @@ and type 'make'. This should produce an executable file
named 'vdr', which can be run after the DVB driver has been
installed.
+If you want to build a 32-bit version of VDR on a 64-bit machine, you can
+use 'make M32=1' to do so. Note that you also need to have a Make.config file
+(derived from Make.config.template) to make this work.
+
IMPORTANT: See "Configuration files" below for information on how
========= to set up the configuration files at the proper location!
diff --git a/MANUAL b/MANUAL
index fb28462..272659c 100644
--- a/MANUAL
+++ b/MANUAL
@@ -367,13 +367,13 @@ Version 1.6
- 7, 9 Jump back and forward between editing marks. Replay goes into still
mode after jumping to a mark.
- 8 Positions replay at a point 3 seconds before the current or next
- "start" mark and starts replay.
+ "begin" mark and starts replay.
- 2 Start the actual cutting process.
Editing marks are represented by black, vertical lines in the progress display.
- A small black triangle at the top of the mark means that this is a "start"
+ A small black triangle at the top of the mark means that this is a "begin"
mark, and a triangle at the bottom means that this is an "end" mark.
- The cutting process will save all video data between "start" and "end" marks
+ The cutting process will save all video data between "begin" and "end" marks
into a new file (the original recording remains untouched). The new file will
have the same name as the original recording, preceded with a '%' character
(imagine the '%' somehow looking like a pair of scissors ;-). Red bars in the
@@ -382,7 +382,7 @@ Version 1.6
The video sequences to be saved by the cutting process are determined by an
"even/odd" algorithm. This means that every odd numbered editing mark (i.e.
- 1, 3, 5,...) represents a "start" mark, while every even numbered mark (2, 4,
+ 1, 3, 5,...) represents a "begin" mark, while every even numbered mark (2, 4,
6,...) is an "end" mark. Inserting or toggling a mark on or off automatically
adjusts the sequence to the right side of that mark.
@@ -395,11 +395,13 @@ Version 1.6
version of the recording you can use the '8' key to jump to a point just
before the next cut and have a look at the resulting sequence.
- Currently editing marks can only be set at I-frames, which typically is
- every 12th frame. So editing can be done with a resolution of roughly half
- a second. A "start" mark marks the first frame of a resulting video
- sequence, and an "end" mark marks the last frame of that sequence.
-
+ Currently editing marks can only be set at I-frames, which typically appear
+ every half of a second to a second. A "begin" mark marks the first frame of
+ a resulting video sequence, and an "end" mark marks the last frame of that
+ sequence. Note that the actual frame indicated by the an "end" mark will
+ not be included in the edited version of the recording. That's because every
+ recording (and every sequence of an edited recording) begins with an I-frame
+ and ends right before the next I-frame.
An edited recording (indicated by the '%' character) will never be deleted
automatically in case the disk runs full (no matter what "lifetime" it has).
diff --git a/Make.config.template b/Make.config.template
index ef463b1..08f9ece 100644
--- a/Make.config.template
+++ b/Make.config.template
@@ -6,7 +6,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
-# $Id: Make.config.template 2.9 2012/09/01 10:31:33 kls Exp $
+# $Id: Make.config.template 2.10 2012/10/09 10:32:32 kls Exp $
### The C compiler and options:
@@ -21,6 +21,12 @@ CFLAGS += -fPIC
CXXFLAGS += -fPIC
endif
+# Use 'make M32=1 ...' to build a 32-bit version of VDR on a 64-bit machine:
+ifdef M32
+CFLAGS += -m32
+CXXFLAGS += -m32
+endif
+
### The directory environment:
PREFIX = $(DESTDIR)/usr/local
diff --git a/Makefile b/Makefile
index ba5a458..e165ee8 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
-# $Id: Makefile 2.29 2012/09/07 14:11:37 kls Exp $
+# $Id: Makefile 2.30 2012/10/09 08:32:25 kls Exp $
.DELETE_ON_ERROR:
@@ -211,7 +211,7 @@ install-dirs:
@mkdir -p $(DESTDIR)$(RESDIRDEF)
install-conf:
- @cp *.conf $(DESTDIR)$(CONFDIRDEF)
+ @cp -n *.conf $(DESTDIR)$(CONFDIRDEF)
# Documentation:
diff --git a/PLUGINS/src/dvbhddevice/dvbhdffdevice.c b/PLUGINS/src/dvbhddevice/dvbhdffdevice.c
index f8b47bd..845fa6b 100644
--- a/PLUGINS/src/dvbhddevice/dvbhdffdevice.c
+++ b/PLUGINS/src/dvbhddevice/dvbhdffdevice.c
@@ -3,7 +3,7 @@
*
* See the README file for copyright information and how to reach the author.
*
- * $Id: dvbhdffdevice.c 1.43 2012/05/08 11:40:32 kls Exp $
+ * $Id: dvbhdffdevice.c 1.46 2012/11/15 09:19:10 kls Exp $
*/
#include <stdint.h>
@@ -69,6 +69,7 @@ cDvbHdFfDevice::cDvbHdFfDevice(int Adapter, int Frontend)
mHdffCmdIf->CmdAvSetAudioDelay(gHdffSetup.AudioDelay);
mHdffCmdIf->CmdAvSetAudioDownmix((HdffAudioDownmixMode_t) gHdffSetup.AudioDownmix);
+ mHdffCmdIf->CmdAvSetSyncShift(gHdffSetup.AvSyncShift);
mHdffCmdIf->CmdMuxSetVideoOut((HdffVideoOut_t) gHdffSetup.AnalogueVideo);
mHdffCmdIf->CmdHdmiSetVideoMode(gHdffSetup.GetVideoMode());
@@ -136,7 +137,7 @@ void cDvbHdFfDevice::SetVideoFormat(bool VideoFormat16_9)
{
HdffVideoFormat_t videoFormat;
videoFormat.AutomaticEnabled = true;
- videoFormat.AfdEnabled = true;
+ videoFormat.AfdEnabled = false;
videoFormat.TvFormat = (HdffTvFormat_t) gHdffSetup.TvFormat;
videoFormat.VideoConversion = (HdffVideoConversion_t) gHdffSetup.VideoConversion;
mHdffCmdIf->CmdAvSetVideoFormat(0, &videoFormat);
@@ -375,62 +376,86 @@ bool cDvbHdFfDevice::CanReplay(void) const
bool cDvbHdFfDevice::SetPlayMode(ePlayMode PlayMode)
{
- if (PlayMode == pmNone) {
- mHdffCmdIf->CmdAvSetVideoSpeed(0, 100);
- mHdffCmdIf->CmdAvSetAudioSpeed(0, 100);
-
- mHdffCmdIf->CmdAvEnableVideoAfterStop(0, false);
- mHdffCmdIf->CmdAvSetPcrPid(0, 0);
- mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF_VIDEO_STREAM_MPEG1);
- mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1);
+ if (PlayMode == pmNone) {
+ if (fd_video == -1)
+ fd_video = DvbOpen(DEV_DVB_VIDEO, adapter, frontend, O_RDWR | O_NONBLOCK);
+ if (fd_audio == -1)
+ fd_audio = DvbOpen(DEV_DVB_AUDIO, adapter, frontend, O_RDWR | O_NONBLOCK);
- ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX);
- mHdffCmdIf->CmdAvSetDecoderInput(0, 0);
- mHdffCmdIf->CmdAvEnableSync(0, true);
- mHdffCmdIf->CmdAvSetPlayMode(0, true);
- }
- else {
- if (playMode == pmNone)
- TurnOffLiveMode(true);
+ mHdffCmdIf->CmdAvSetVideoSpeed(0, 100);
+ mHdffCmdIf->CmdAvSetAudioSpeed(0, 100);
- mHdffCmdIf->CmdAvSetPlayMode(1, Transferring() || (cTransferControl::ReceiverDevice() == this));
- mHdffCmdIf->CmdAvSetStc(0, 100000);
- mHdffCmdIf->CmdAvEnableSync(0, true);
- mHdffCmdIf->CmdAvEnableVideoAfterStop(0, true);
+ mHdffCmdIf->CmdAvEnableVideoAfterStop(0, false);
+ mHdffCmdIf->CmdAvSetPcrPid(0, 0);
+ mHdffCmdIf->CmdAvSetVideoPid(0, 0, HDFF_VIDEO_STREAM_MPEG1);
+ mHdffCmdIf->CmdAvSetAudioPid(0, 0, HDFF_AUDIO_STREAM_MPEG1);
- playVideoPid = -1;
- playAudioPid = -1;
- audioCounter = 0;
- videoCounter = 0;
- freezed = false;
- trickMode = false;
+ ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX);
+ mHdffCmdIf->CmdAvSetDecoderInput(0, 0);
+ mHdffCmdIf->CmdAvEnableSync(0, true);
+ mHdffCmdIf->CmdAvSetPlayMode(0, true);
+ }
+ else {
+ if (playMode == pmNone)
+ TurnOffLiveMode(true);
- mHdffCmdIf->CmdAvSetDecoderInput(0, 2);
- ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY);
- }
- playMode = PlayMode;
- return true;
+ if (PlayMode == pmExtern_THIS_SHOULD_BE_AVOIDED)
+ {
+ close(fd_video);
+ fd_video = -1;
+ close(fd_audio);
+ fd_audio = -1;
+ }
+ else
+ {
+ mHdffCmdIf->CmdAvSetPlayMode(1, Transferring() || (cTransferControl::ReceiverDevice() == this));
+ mHdffCmdIf->CmdAvSetStc(0, 100000);
+ mHdffCmdIf->CmdAvEnableSync(0, false);
+ mHdffCmdIf->CmdAvEnableVideoAfterStop(0, true);
+
+ playVideoPid = -1;
+ playAudioPid = -1;
+ audioCounter = 0;
+ videoCounter = 0;
+ freezed = false;
+ trickMode = false;
+ isPlayingVideo = false;
+
+ mHdffCmdIf->CmdAvSetDecoderInput(0, 2);
+ ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY);
+ }
+ }
+ playMode = PlayMode;
+ return true;
}
int64_t cDvbHdFfDevice::GetSTC(void)
{
- if (fd_video >= 0) {
- uint64_t pts;
- if (ioctl(fd_video, VIDEO_GET_PTS, &pts) == -1) {
- esyslog("ERROR: pts %d: %m", CardIndex() + 1);
- return -1;
+ if (isPlayingVideo)
+ {
+ if (fd_video >= 0) {
+ uint64_t pts;
+ if (ioctl(fd_video, VIDEO_GET_PTS, &pts) == -1) {
+ esyslog("ERROR: pts %d: %m", CardIndex() + 1);
+ return -1;
+ }
+ //printf("video PTS %lld\n", pts);
+ return pts;
}
- return pts;
- }
- if (fd_audio >= 0) {
- uint64_t pts;
- if (ioctl(fd_audio, AUDIO_GET_PTS, &pts) == -1) {
- esyslog("ERROR: pts %d: %m", CardIndex() + 1);
- return -1;
+ }
+ else
+ {
+ if (fd_audio >= 0) {
+ uint64_t pts;
+ if (ioctl(fd_audio, AUDIO_GET_PTS, &pts) == -1) {
+ esyslog("ERROR: pts %d: %m", CardIndex() + 1);
+ return -1;
+ }
+ //printf("audio PTS %lld\n", pts);
+ return pts;
}
- return pts;
- }
- return -1;
+ }
+ return -1;
}
void cDvbHdFfDevice::TrickSpeed(int Speed)
@@ -456,12 +481,13 @@ void cDvbHdFfDevice::Clear(void)
void cDvbHdFfDevice::Play(void)
{
- freezed = false;
- trickMode = false;
- mHdffCmdIf->CmdAvEnableSync(0, true);
- mHdffCmdIf->CmdAvSetVideoSpeed(0, 100);
- mHdffCmdIf->CmdAvSetAudioSpeed(0, 100);
- cDevice::Play();
+ freezed = false;
+ trickMode = false;
+ if (isPlayingVideo)
+ mHdffCmdIf->CmdAvEnableSync(0, true);
+ mHdffCmdIf->CmdAvSetVideoSpeed(0, 100);
+ mHdffCmdIf->CmdAvSetAudioSpeed(0, 100);
+ cDevice::Play();
}
void cDvbHdFfDevice::Freeze(void)
@@ -631,6 +657,11 @@ int cDvbHdFfDevice::PlayVideo(const uchar *Data, int Length)
{
if (freezed)
return -1;
+ if (!isPlayingVideo)
+ {
+ mHdffCmdIf->CmdAvEnableSync(0, true);
+ isPlayingVideo = true;
+ }
//TODO: support greater Length
uint8_t tsBuffer[188 * 16];
uint32_t tsLength;
@@ -651,8 +682,6 @@ int cDvbHdFfDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
{
if (freezed)
return -1;
- if (trickMode)
- return Length;
uint8_t streamId;
uint8_t tsBuffer[188 * 16];
uint32_t tsLength;
@@ -702,17 +731,23 @@ int cDvbHdFfDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
int cDvbHdFfDevice::PlayTsVideo(const uchar *Data, int Length)
{
- if (freezed)
- return -1;
- int pid = TsPid(Data);
- if (pid != playVideoPid) {
- PatPmtParser();
- if (pid == PatPmtParser()->Vpid()) {
- playVideoPid = pid;
- mHdffCmdIf->CmdAvSetVideoPid(0, playVideoPid, MapVideoStreamTypes(PatPmtParser()->Vtype()), true);
+ if (freezed)
+ return -1;
+ if (!isPlayingVideo)
+ {
+ mHdffCmdIf->CmdAvEnableSync(0, true);
+ isPlayingVideo = true;
+ }
+
+ int pid = TsPid(Data);
+ if (pid != playVideoPid) {
+ PatPmtParser();
+ if (pid == PatPmtParser()->Vpid()) {
+ playVideoPid = pid;
+ mHdffCmdIf->CmdAvSetVideoPid(0, playVideoPid, MapVideoStreamTypes(PatPmtParser()->Vtype()), true);
}
- }
- return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
+ }
+ return WriteAllOrNothing(fd_video, Data, Length, 1000, 10);
}
static HdffAudioStreamType_t MapAudioStreamTypes(int Atype)
@@ -732,8 +767,6 @@ int cDvbHdFfDevice::PlayTsAudio(const uchar *Data, int Length)
{
if (freezed)
return -1;
- if (trickMode)
- return Length;
int pid = TsPid(Data);
if (pid != playAudioPid) {
playAudioPid = pid;
diff --git a/PLUGINS/src/dvbhddevice/dvbhdffdevice.h b/PLUGINS/src/dvbhddevice/dvbhdffdevice.h
index 439ec9b..344f3dc 100644
--- a/PLUGINS/src/dvbhddevice/dvbhdffdevice.h
+++ b/PLUGINS/src/dvbhddevice/dvbhdffdevice.h
@@ -3,7 +3,7 @@
*
* See the README file for copyright information and how to reach the author.
*
- * $Id: dvbhdffdevice.h 1.7 2011/09/10 10:17:32 kls Exp $
+ * $Id: dvbhdffdevice.h 1.8 2012/11/05 08:49:29 kls Exp $
*/
#ifndef __DVBHDFFDEVICE_H
@@ -81,6 +81,7 @@ private:
int playAudioPid;
bool freezed;
bool trickMode;
+ bool isPlayingVideo;
// Pes2Ts conversion stuff
uint8_t videoCounter;
diff --git a/PLUGINS/src/dvbhddevice/hdffcmd.c b/PLUGINS/src/dvbhddevice/hdffcmd.c
index a6a41d9..1532cc2 100644
--- a/PLUGINS/src/dvbhddevice/hdffcmd.c
+++ b/PLUGINS/src/dvbhddevice/hdffcmd.c
@@ -3,7 +3,7 @@
*
* See the README file for copyright information and how to reach the author.
*
- * $Id: hdffcmd.c 1.25 2012/06/16 11:16:38 kls Exp $
+ * $Id: hdffcmd.c 1.26 2012/11/15 09:19:47 kls Exp $
*/
#include <stdint.h>
@@ -170,6 +170,11 @@ void cHdffCmdIf::CmdAvSetAudioChannel(uint8_t AudioChannel)
HdffCmdAvSetAudioChannel(mOsdDev, AudioChannel);
}
+void cHdffCmdIf::CmdAvSetSyncShift(int16_t SyncShift)
+{
+ HdffCmdAvSetSyncShift(mOsdDev, SyncShift);
+}
+
void cHdffCmdIf::CmdOsdConfigure(const HdffOsdConfig_t * pConfig)
{
diff --git a/PLUGINS/src/dvbhddevice/hdffcmd.h b/PLUGINS/src/dvbhddevice/hdffcmd.h
index f33fe08..58ed138 100644
--- a/PLUGINS/src/dvbhddevice/hdffcmd.h
+++ b/PLUGINS/src/dvbhddevice/hdffcmd.h
@@ -3,7 +3,7 @@
*
* See the README file for copyright information and how to reach the author.
*
- * $Id: hdffcmd.h 1.20 2012/06/16 11:16:52 kls Exp $
+ * $Id: hdffcmd.h 1.21 2012/11/15 09:20:05 kls Exp $
*/
#ifndef _HDFF_CMD_H_
@@ -47,6 +47,7 @@ public:
void CmdAvSetAudioDelay(int16_t Delay);
void CmdAvSetAudioDownmix(HdffAudioDownmixMode_t DownmixMode);
void CmdAvSetAudioChannel(uint8_t AudioChannel);
+ void CmdAvSetSyncShift(int16_t SyncShift);
void CmdOsdConfigure(const HdffOsdConfig_t * pConfig);
void CmdOsdReset(void);
diff --git a/PLUGINS/src/dvbhddevice/hdffmsgdef.h b/PLUGINS/src/dvbhddevice/hdffmsgdef.h
deleted file mode 100644
index d63e88a..0000000
--- a/PLUGINS/src/dvbhddevice/hdffmsgdef.h
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * hdffmsgdef.h: TODO(short description)
- *
- * See the README file for copyright information and how to reach the author.
- *
- * $Id: hdffmsgdef.h 1.13 2011/08/27 09:34:43 kls Exp $
- */
-
-#ifndef _HDFF_MSGDEF_H_
-#define _HDFF_MSGDEF_H_
-
-#define MAX_CMD_LEN 1536
-
-namespace HDFF
-{
-
-typedef enum _eMessageType
-{
- msgTypeCommand,
- msgTypeAnswer,
- msgTypeResult,
- msgTypeEvent
-} eMessageType;
-
-typedef enum _eMessageGroup
-{
- msgGroupGeneric,
- msgGroupAvDec,
- msgGroupAvMux,
- msgGroupFrontend,
- msgGroupOsd,
- msgGroupHdmi,
- msgGroupRemoteControl
-} eMessageGroup;
-
-typedef enum _eMessageId
-{
- msgGenGetFirmwareVersion = 0,
- msgGenGetInterfaceVersion,
- msgGenGetCopyrights,
-
- msgAvSetAudioPid = 0,
- msgAvSetVideoPid,
- msgAvSetPcrPid,
- msgAvSetTeletextPid,
- msgAvShowStillImage,
- msgAvSetVideoWindow,
- msgAvSetDecoderInput,
- msgAvSetDemultiplexerInput,
- msgAvSetVideoFormat,
- msgAvSetVideoOutputMode,
- msgAvSetStc,
- msgAvFlushBuffer,
- msgAvEnableSync,
- msgAvSetVideoSpeed,
- msgAvSetAudioSpeed,
- msgAvEnableVideoAfterStop,
- msgAvGetVideoFormatInfo,
- msgAvSetAudioDelay,
- msgAvSetAudioDownmix,
- msgAvSetAudioChannel,
- msgAvSetPlayMode,
-
- msgMuxSetVideoOut = 0,
- msgMuxSetSlowBlank,
- msgMuxSetFastBlank,
- msgMuxSetVolume,
- msgMuxSetAudioMute,
-
- msgOsdConfigure = 0,
- msgOsdReset,
- msgOsdCreateDisplay = 10,
- msgOsdDeleteDisplay,
- msgOsdEnableDisplay,
- msgOsdSetDisplayOutputRectangle,
- msgOsdSetDisplayClippingArea,
- msgOsdRenderDisplay,
- msgOsdSaveRegion,
- msgOsdRestoreRegion,
- msgOsdCreatePalette = 30,
- msgOsdDeletePalette,
- msgOsdSetDisplayPalette,
- msgOsdSetPaletteColors,
- msgOsdCreateFontFace = 50,
- msgOsdDeleteFontFace,
- msgOsdCreateFont,
- msgOsdDeleteFont,
- msgOsdDrawPixel = 70,
- msgOsdDrawRectangle,
- msgOsdDrawCircle,
- msgOsdDrawEllipse,
- msgOsdDrawSlope,
- msgOsdDrawText,
- msgOsdDrawTextW,
- msgOsdDrawBitmap,
-
- msgHdmiEnableOutput = 0,
- msgHdmiSetVideoMode,
- msgHdmiConfigure,
- msgHdmiIsDisplayConnected,
- msgHdmiGetDisplayInfo,
- msgHdmiGetVideoMode,
- msgHdmiSendCecCommand,
-
- msgRemoteSetProtocol = 0,
- msgRemoteSetAddressFilter,
- msgRemoteKeyEvent
-} eMessageId;
-
-
-// AvDec definitions
-
-typedef enum _eAVContainerType
-{
- avContainerPes,
- avContainerPesDvd,
- avContainerMaxValue
-} eAVContainerType;
-
-typedef enum _eAudioStreamType
-{
- audioStreamMpeg1,
- audioStreamMpeg2,
- audioStreamAc3,
- audioStreamAac,
- audioStreamHeAac,
- audioStreamPcm,
- audioStreamEAc3,
- audioStreamDts,
- audioStreamMaxValue
-} eAudioStreamType;
-
-typedef enum _eVideoStreamType
-{
- videoStreamMpeg1,
- videoStreamMpeg2,
- videoStreamH264,
- videoStreamMpeg4Asp,
- videoStreamVc1,
- videoStreamMaxValue
-} eVideoStreamType;
-
-
-typedef enum _eTvFormat
-{
- tvFormat4by3,
- tvFormat16by9,
- tvFormatMaxValue
-} eTvFormat;
-
-typedef enum _eVideoConversion
-{
- videoConversionAutomatic,
- videoConversionLetterbox16by9,
- videoConversionLetterbox14by9,
- videoConversionPillarbox,
- videoConversionCentreCutOut,
- videoConversionAlways16by9,
- videoConversionMaxValue
-} eVideoConversion;
-
-typedef struct _tVideoFormat
-{
- bool AutomaticEnabled;
- bool AfdEnabled;
- eTvFormat TvFormat;
- eVideoConversion VideoConversion;
-} tVideoFormat;
-
-typedef enum _eVideoOutputMode
-{
- videoOutputClone,
- videoOutputDualView,
- videoOutputMaxValue
-} eVideoOutputMode;
-
-typedef enum _eDownmixMode
-{
- downmixOff,
- downmixAnalog,
- downmixAlways,
- downmixAutomatic,
- downmixHdmi
-} eDownmixMode;
-
-// AvMux definitions
-
-typedef enum _eVideoOut
-{
- videoOutDisabled,
- videoOutRgb,
- videoOutCvbsYuv,
- videoOutYc,
- videoOutMaxValue
-} eVideoOut;
-
-typedef enum _eSlowBlank
-{
- slowBlankOff,
- slowBlank16by9,
- slowBlank4by3,
- slowBlankMaxValue
-} eSlowBlank;
-
-typedef enum _eFastBlank
-{
- fastBlankCvbs,
- fastBlankRgb,
- fastBlankMaxValue
-} eFastBlank;
-
-
-// OSD definitions
-
-#define InvalidHandle 0xFFFFFFFF
-#define ScreenDisplayHandle 0xFFFFFFFE
-
-#define PositionScreenCentered 0xFFFF
-
-#define SizeFullScreen 0xFFFF
-#define SizeSameAsSource 0xFFFE
-
-#define FontFaceTiresias 0x00000000
-
-typedef enum _eColorType
-{
- colorTypeClut1,
- colorTypeClut2,
- colorTypeClut4,
- colorTypeClut8,
- colorTypeARGB8888,
- colorTypeARGB8565,
- colorTypeARGB4444,
- colorTypeARGB1555,
-} eColorType;
-
-typedef enum _eColorFormat
-{
- colorFormatARGB,
- colorFormatACbYCr,
-} eColorFormat;
-
-typedef enum _eDrawingFlags
-{
- drawFull,
- drawHalfTop,
- drawHalfLeft,
- drawHalfBottom,
- drawHalfRight,
- drawQuarterTopLeft,
- drawQuarterTopRight,
- drawQuarterBottomLeft,
- drawQuarterBottomRight,
- drawQuarterTopLeftInverted,
- drawQuarterTopRightInverted,
- drawQuarterBottomLeftInverted,
- drawQuarterBottomRightInverted
-} eDrawingFlags;
-
-typedef struct _tOsdConfig
-{
- bool FontAntialiasing;
- bool FontKerning;
-} tOsdConfig;
-
-// HDMI definitions
-
-typedef enum _eHdmiVideoMode
-{
- videoMode576p50 = 18,
- videoMode720p50 = 19,
- videoMode1080i50 = 20,
- videoMode576i50 = 22,
- videoModeMaxValue
-} eHdmiVideoMode;
-
-typedef enum _eVideoModeAdaption
-{
- videoModeAdaptOff,
- videoModeAdaptFrameRate,
- videoModeAdaptOnlyForHd,
- videoModeAdaptAlways
-} eVideoModeAdaption;
-
-typedef enum _eCecCommand
-{
- cecCommandTvOn,
- cecCommandTvOff,
- cecCommandActiveSource,
- cecCommandInactiveSource
-} eCecCommand;
-
-typedef struct _tHdmiConfig
-{
- bool TransmitAudio;
- bool ForceDviMode;
- bool CecEnabled;
- eVideoModeAdaption VideoModeAdaption;
-} tHdmiConfig;
-
-// Remote control definitions
-
-typedef enum _eRemoteProtocol
-{
- remoteProtocolNone,
- remoteProtocolRc5,
- remoteProtocolRc6,
- remoteProtocolMaxValue
-} eRemoteProtocol;
-
-} // end of namespace
-
-#endif
diff --git a/PLUGINS/src/dvbhddevice/hdffosd.c b/PLUGINS/src/dvbhddevice/hdffosd.c
index 427a3fb..5d55c95 100644
--- a/PLUGINS/src/dvbhddevice/hdffosd.c
+++ b/PLUGINS/src/dvbhddevice/hdffosd.c
@@ -3,7 +3,7 @@
*
* See the README file for copyright information and how to reach the author.
*
- * $Id: hdffosd.c 1.17 2012/06/16 11:17:11 kls Exp $
+ * $Id: hdffosd.c 1.18 2012/11/15 09:20:24 kls Exp $
*/
#include "hdffosd.h"
@@ -390,11 +390,13 @@ void cHdffOsd::DrawText(int x, int y, const char *s, tColor ColorFg, tColor Colo
}
}
}
+#if 0
if (mSupportsUtf8Text)
{
mHdffCmdIf->CmdOsdDrawUtf8Text(mDisplay, pFont->Handle, x + mLeft, y + mTop + h, s, ColorFg);
}
else
+#endif
{
uint16_t tmp[1000];
uint16_t len = 0;
diff --git a/PLUGINS/src/dvbhddevice/libhdffcmd/Makefile b/PLUGINS/src/dvbhddevice/libhdffcmd/Makefile
index 8b25f66..babe79b 100644
--- a/PLUGINS/src/dvbhddevice/libhdffcmd/Makefile
+++ b/PLUGINS/src/dvbhddevice/libhdffcmd/Makefile
@@ -24,6 +24,18 @@ CFLAGS ?= -g -O2 -fPIC -Wall
AR ?= ar
ARFLAGS ?= r
+### The directory environment:
+
+VDRDIR ?= ../../../..
+
+### Make sure that necessary options are included:
+
+include $(VDRDIR)/Make.global
+
+### Allow user defined options to overwrite defaults:
+
+-include $(VDRDIR)/Make.config
+
### Implicit rules:
%.o: %.c
diff --git a/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_av.c b/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_av.c
index 413f3e2..3ae1fd7 100644
--- a/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_av.c
+++ b/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_av.c
@@ -449,3 +449,22 @@ int HdffCmdAvSetAudioChannel(int OsdDevice, uint8_t AudioChannel)
osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
}
+
+int HdffCmdAvSetSyncShift(int OsdDevice, int16_t SyncShift)
+{
+ uint8_t cmdData[16];
+ BitBuffer_t cmdBuf;
+ osd_raw_cmd_t osd_cmd;
+
+ BitBuffer_Init(&cmdBuf, cmdData, sizeof(cmdData));
+ memset(&osd_cmd, 0, sizeof(osd_raw_cmd_t));
+ osd_cmd.cmd_data = cmdData;
+ HdffCmdBuildHeader(&cmdBuf, HDFF_MSG_TYPE_COMMAND,
+ HDFF_MSG_GROUP_AV_DECODER,
+ HDFF_MSG_AV_SET_OPTIONS);
+ BitBuffer_SetBits(&cmdBuf, 1, 1);
+ BitBuffer_SetBits(&cmdBuf, 31, 0); // reserved
+ BitBuffer_SetBits(&cmdBuf, 16, SyncShift);
+ osd_cmd.cmd_len = HdffCmdSetLength(&cmdBuf);
+ return ioctl(OsdDevice, OSD_RAW_CMD, &osd_cmd);
+}
diff --git a/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_av.h b/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_av.h
index 0e77c79..bfed59d 100644
--- a/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_av.h
+++ b/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_av.h
@@ -149,4 +149,6 @@ int HdffCmdAvSetAudioDownmix(int OsdDevice,
int HdffCmdAvSetAudioChannel(int OsdDevice, uint8_t AudioChannel);
+int HdffCmdAvSetSyncShift(int OsdDevice, int16_t SyncShift);
+
#endif /* HDFFCMD_AV_H */
diff --git a/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_defs.h b/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_defs.h
index 322c256..5ead270 100644
--- a/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_defs.h
+++ b/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_defs.h
@@ -70,6 +70,7 @@ typedef enum HdffMessageId_t
HDFF_MSG_AV_SET_AUDIO_DOWNMIX,
HDFF_MSG_AV_SET_AUDIO_CHANNEL,
HDFF_MSG_AV_SET_PLAY_MODE,
+ HDFF_MSG_AV_SET_OPTIONS,
HDFF_MSG_MUX_SET_VIDEO_OUT = 0,
HDFF_MSG_MUX_SET_SLOW_BLANK,
diff --git a/PLUGINS/src/dvbhddevice/po/de_DE.po b/PLUGINS/src/dvbhddevice/po/de_DE.po
index ac58c0c..b263f08 100644
--- a/PLUGINS/src/dvbhddevice/po/de_DE.po
+++ b/PLUGINS/src/dvbhddevice/po/de_DE.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR \n"
"Report-Msgid-Bugs-To: <see README>\n"
-"POT-Creation-Date: 2012-02-07 20:13+0100\n"
+"POT-Creation-Date: 2012-11-13 20:08+0100\n"
"PO-Revision-Date: 2011-04-25 21:44+0200\n"
"Last-Translator: Christoph Haubrich\n"
"Language-Team: <see README>\n"
@@ -91,6 +91,9 @@ msgstr "Audio Verzĥgerung (ms)"
msgid "Audio Downmix"
msgstr "Audio Downmix"
+msgid "A/V Sync Shift (ms)"
+msgstr "A/V-Sync Verschiebung (ms)"
+
msgid "OSD Size"
msgstr "OSD GrĥŸe"
diff --git a/PLUGINS/src/dvbhddevice/po/fi_FI.po b/PLUGINS/src/dvbhddevice/po/fi_FI.po
index f8e480b..a971773 100644
--- a/PLUGINS/src/dvbhddevice/po/fi_FI.po
+++ b/PLUGINS/src/dvbhddevice/po/fi_FI.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR \n"
"Report-Msgid-Bugs-To: <see README>\n"
-"POT-Creation-Date: 2012-02-07 20:13+0100\n"
+"POT-Creation-Date: 2012-11-13 20:08+0100\n"
"PO-Revision-Date: 2011-04-25 21:44+0200\n"
"Last-Translator: Rolf Ahrenberg\n"
"Language-Team: Finnish <vdr@linuxtv.org>\n"
@@ -91,6 +91,9 @@ msgstr "„¤nen viive (ms)"
msgid "Audio Downmix"
msgstr "„¤nen alasmiksaus"
+msgid "A/V Sync Shift (ms)"
+msgstr ""
+
msgid "OSD Size"
msgstr "Kuvaruutun¤ytĥn koko"
diff --git a/PLUGINS/src/dvbhddevice/po/it_IT.po b/PLUGINS/src/dvbhddevice/po/it_IT.po
index def0389..56b987a 100644
--- a/PLUGINS/src/dvbhddevice/po/it_IT.po
+++ b/PLUGINS/src/dvbhddevice/po/it_IT.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR\n"
"Report-Msgid-Bugs-To: <see README>\n"
-"POT-Creation-Date: 2012-02-07 20:13+0100\n"
+"POT-Creation-Date: 2012-11-13 20:08+0100\n"
"PO-Revision-Date: 2011-07-10 00:23+0100\n"
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
"Language-Team: <see README>\n"
@@ -94,6 +94,9 @@ msgstr "Ritardo audio (ms)"
msgid "Audio Downmix"
msgstr "Scala Audio"
+msgid "A/V Sync Shift (ms)"
+msgstr ""
+
msgid "OSD Size"
msgstr "Dimensione OSD"
diff --git a/PLUGINS/src/dvbhddevice/setup.c b/PLUGINS/src/dvbhddevice/setup.c
index b6525a0..fcc1648 100644
--- a/PLUGINS/src/dvbhddevice/setup.c
+++ b/PLUGINS/src/dvbhddevice/setup.c
@@ -3,7 +3,7 @@
*
* See the README file for copyright information and how to reach the author.
*
- * $Id: setup.c 1.17 2012/02/08 15:14:01 kls Exp $
+ * $Id: setup.c 1.18 2012/11/15 09:20:50 kls Exp $
*/
#include "setup.h"
@@ -26,6 +26,7 @@ cHdffSetup::cHdffSetup(void)
AnalogueVideo = HDFF_VIDEO_OUT_CVBS_YUV;
AudioDelay = 0;
AudioDownmix = HDFF_AUDIO_DOWNMIX_AUTOMATIC;
+ AvSyncShift = 0;
OsdSize = 0;
CecEnabled = 1;
CecTvOn = 1;
@@ -46,6 +47,7 @@ bool cHdffSetup::SetupParse(const char *Name, const char *Value)
else if (strcmp(Name, "AnalogueVideo") == 0) AnalogueVideo = atoi(Value);
else if (strcmp(Name, "AudioDelay") == 0) AudioDelay = atoi(Value);
else if (strcmp(Name, "AudioDownmix") == 0) AudioDownmix = atoi(Value);
+ else if (strcmp(Name, "AvSyncShift") == 0) AvSyncShift = atoi(Value);
else if (strcmp(Name, "OsdSize") == 0) OsdSize = atoi(Value);
else if (strcmp(Name, "CecEnabled") == 0) CecEnabled = atoi(Value);
else if (strcmp(Name, "CecTvOn") == 0) CecTvOn = atoi(Value);
@@ -256,6 +258,7 @@ cHdffSetupPage::cHdffSetupPage(HDFF::cHdffCmdIf * pHdffCmdIf)
Add(new cMenuEditStraItem(tr("Analogue Video"), &mNewHdffSetup.AnalogueVideo, kAnalogueVideos, AnalogueVideoItems));
Add(new cMenuEditIntItem(tr("Audio Delay (ms)"), &mNewHdffSetup.AudioDelay, 0, 500));
Add(new cMenuEditStraItem(tr("Audio Downmix"), &mNewHdffSetup.AudioDownmix, kAudioDownmixes, AudioDownmixItems));
+ Add(new cMenuEditIntItem(tr("A/V Sync Shift (ms)"), &mNewHdffSetup.AvSyncShift, -500, 500));
Add(new cMenuEditStraItem(tr("OSD Size"), &mNewHdffSetup.OsdSize, kOsdSizes, OsdSizeItems));
Add(new cMenuEditBoolItem(tr("HDMI CEC"), &mNewHdffSetup.CecEnabled));
Add(new cMenuEditBoolItem(tr("CEC: Switch TV on"), &mNewHdffSetup.CecTvOn));
@@ -385,6 +388,7 @@ void cHdffSetupPage::Store(void)
SetupStore("AnalogueVideo", mNewHdffSetup.AnalogueVideo);
SetupStore("AudioDelay", mNewHdffSetup.AudioDelay);
SetupStore("AudioDownmix", mNewHdffSetup.AudioDownmix);
+ SetupStore("AvSyncShift", mNewHdffSetup.AvSyncShift);
SetupStore("OsdSize", mNewHdffSetup.OsdSize);
SetupStore("CecEnabled", mNewHdffSetup.CecEnabled);
SetupStore("CecTvOn", mNewHdffSetup.CecTvOn);
@@ -412,6 +416,7 @@ void cHdffSetupPage::Store(void)
mHdffCmdIf->CmdAvSetAudioDelay(mNewHdffSetup.AudioDelay);
mHdffCmdIf->CmdAvSetAudioDownmix((HdffAudioDownmixMode_t) mNewHdffSetup.AudioDownmix);
+ mHdffCmdIf->CmdAvSetSyncShift(mNewHdffSetup.AvSyncShift);
mHdffCmdIf->CmdMuxSetVideoOut((HdffVideoOut_t) mNewHdffSetup.AnalogueVideo);
diff --git a/PLUGINS/src/dvbhddevice/setup.h b/PLUGINS/src/dvbhddevice/setup.h
index 64033e1..011411d 100644
--- a/PLUGINS/src/dvbhddevice/setup.h
+++ b/PLUGINS/src/dvbhddevice/setup.h
@@ -3,7 +3,7 @@
*
* See the README file for copyright information and how to reach the author.
*
- * $Id: setup.h 1.12 2012/02/08 15:14:56 kls Exp $
+ * $Id: setup.h 1.13 2012/11/15 09:21:07 kls Exp $
*/
#ifndef _HDFF_SETUP_H_
@@ -28,6 +28,7 @@ struct cHdffSetup
int AnalogueVideo;
int AudioDelay;
int AudioDownmix;
+ int AvSyncShift;
int OsdSize;
int CecEnabled;
int CecTvOn;
diff --git a/ci.c b/ci.c
index ebed320..904697e 100644
--- a/ci.c
+++ b/ci.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: ci.c 2.9 2012/05/29 11:13:40 kls Exp $
+ * $Id: ci.c 2.10 2012/10/07 11:11:18 kls Exp $
*/
#include "ci.h"
@@ -845,9 +845,9 @@ void cCiDateTime::SendDateTime(void)
int D = tm_gmt.tm_mday;
int L = (M == 1 || M == 2) ? 1 : 0;
int MJD = 14956 + D + int((Y - L) * 365.25) + int((M + 1 + L * 12) * 30.6001);
-#define DEC2BCD(d) (((d / 10) << 4) + (d % 10))
+#define DEC2BCD(d) uint8_t(((d / 10) << 4) + (d % 10))
struct tTime { uint16_t mjd; uint8_t h, m, s; short offset; };
- tTime T = { mjd : htons(MJD), h : DEC2BCD(tm_gmt.tm_hour), m : DEC2BCD(tm_gmt.tm_min), s : DEC2BCD(tm_gmt.tm_sec), offset : htons(tm_loc.tm_gmtoff / 60) };
+ tTime T = { mjd : htons(MJD), h : DEC2BCD(tm_gmt.tm_hour), m : DEC2BCD(tm_gmt.tm_min), s : DEC2BCD(tm_gmt.tm_sec), offset : short(htons(tm_loc.tm_gmtoff / 60)) };
bool OldDumpTPDUDataTransfer = DumpTPDUDataTransfer;
DumpTPDUDataTransfer &= DumpDateTime;
if (DumpDateTime)
diff --git a/config.h b/config.h
index a07310e..03b6cf0 100644
--- a/config.h
+++ b/config.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: config.h 2.53 2012/09/15 11:51:54 kls Exp $
+ * $Id: config.h 2.54 2012/10/03 09:59:34 kls Exp $
*/
#ifndef __CONFIG_H
@@ -22,13 +22,13 @@
// VDR's own version number:
-#define VDRVERSION "1.7.31"
-#define VDRVERSNUM 10731 // Version * 10000 + Major * 100 + Minor
+#define VDRVERSION "1.7.32"
+#define VDRVERSNUM 10732 // Version * 10000 + Major * 100 + Minor
// The plugin API's version number:
-#define APIVERSION "1.7.31"
-#define APIVERSNUM 10731 // Version * 10000 + Major * 100 + Minor
+#define APIVERSION "1.7.32"
+#define APIVERSNUM 10732 // Version * 10000 + Major * 100 + Minor
// When loading plugins, VDR searches them by their APIVERSION, which
// may be smaller than VDRVERSION in case there have been no changes to
diff --git a/cutter.c b/cutter.c
index bcae2b7..ace1893 100644
--- a/cutter.c
+++ b/cutter.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: cutter.c 2.14 2012/09/20 09:12:47 kls Exp $
+ * $Id: cutter.c 2.16 2012/11/18 12:09:00 kls Exp $
*/
#include "cutter.h"
@@ -13,17 +13,261 @@
#include "remux.h"
#include "videodir.h"
+// --- cPacketBuffer ---------------------------------------------------------
+
+class cPacketBuffer {
+private:
+ uchar *data;
+ int size;
+ int length;
+public:
+ cPacketBuffer(void);
+ ~cPacketBuffer();
+ void Append(uchar *Data, int Length);
+ ///< Appends Length bytes of Data to this packet buffer.
+ void Flush(uchar *Data, int &Length, int MaxLength);
+ ///< Flushes the content of this packet buffer into the given Data, starting
+ ///< at position Length, and clears the buffer afterwards. Length will be
+ ///< incremented accordingly. If Length plus the total length of the stored
+ ///< packets would exceed MaxLength, nothing is copied.
+ };
+
+cPacketBuffer::cPacketBuffer(void)
+{
+ data = NULL;
+ size = length = 0;
+}
+
+cPacketBuffer::~cPacketBuffer()
+{
+ free(data);
+}
+
+void cPacketBuffer::Append(uchar *Data, int Length)
+{
+ if (length + Length >= size) {
+ int NewSize = (length + Length) * 3 / 2;
+ if (uchar *p = (uchar *)realloc(data, NewSize)) {
+ data = p;
+ size = NewSize;
+ }
+ else
+ return; // out of memory
+ }
+ memcpy(data + length, Data, Length);
+ length += Length;
+}
+
+void cPacketBuffer::Flush(uchar *Data, int &Length, int MaxLength)
+{
+ if (Data && length > 0 && Length + length <= MaxLength) {
+ memcpy(Data + Length, data, length);
+ Length += length;
+ }
+ length = 0;
+}
+
+// --- cPacketStorage --------------------------------------------------------
+
+class cPacketStorage {
+private:
+ cPacketBuffer *buffers[MAXPID];
+public:
+ cPacketStorage(void);
+ ~cPacketStorage();
+ void Append(int Pid, uchar *Data, int Length);
+ void Flush(int Pid, uchar *Data, int &Length, int MaxLength);
+ };
+
+cPacketStorage::cPacketStorage(void)
+{
+ for (int i = 0; i < MAXPID; i++)
+ buffers[i] = NULL;
+}
+
+cPacketStorage::~cPacketStorage()
+{
+ for (int i = 0; i < MAXPID; i++)
+ delete buffers[i];
+}
+
+void cPacketStorage::Append(int Pid, uchar *Data, int Length)
+{
+ if (!buffers[Pid])
+ buffers[Pid] = new cPacketBuffer;
+ buffers[Pid]->Append(Data, Length);
+}
+
+void cPacketStorage::Flush(int Pid, uchar *Data, int &Length, int MaxLength)
+{
+ if (buffers[Pid])
+ buffers[Pid]->Flush(Data, Length, MaxLength);
+}
+
+// --- cDanglingPacketStripper -----------------------------------------------
+
+class cDanglingPacketStripper {
+private:
+ bool processed[MAXPID];
+ cPatPmtParser patPmtParser;
+public:
+ cDanglingPacketStripper(void);
+ bool Process(uchar *Data, int Length, int64_t FirstPts);
+ ///< Scans the frame given in Data and hides the payloads of any TS packets
+ ///< that either didn't start within this frame, or have a PTS that is
+ ///< before FirstPts. The TS packets in question are not physically removed
+ ///< from Data in order to keep any frame counts and PCR timestamps intact.
+ ///< Returns true if any dangling packets have been found.
+ };
+
+cDanglingPacketStripper::cDanglingPacketStripper(void)
+{
+ memset(processed, 0x00, sizeof(processed));
+}
+
+bool cDanglingPacketStripper::Process(uchar *Data, int Length, int64_t FirstPts)
+{
+ bool Found = false;
+ while (Length >= TS_SIZE && *Data == TS_SYNC_BYTE) {
+ int Pid = TsPid(Data);
+ if (Pid == PATPID)
+ patPmtParser.ParsePat(Data, TS_SIZE);
+ else if (Pid == patPmtParser.PmtPid())
+ patPmtParser.ParsePmt(Data, TS_SIZE);
+ else {
+ int64_t Pts = TsGetPts(Data, TS_SIZE);
+ if (Pts >= 0)
+ processed[Pid] = PtsDiff(FirstPts, Pts) >= 0; // Pts is at or after FirstPts
+ if (!processed[Pid]) {
+ TsHidePayload(Data);
+ Found = true;
+ }
+ }
+ Length -= TS_SIZE;
+ Data += TS_SIZE;
+ }
+ return Found;
+}
+
+// --- cPtsFixer -------------------------------------------------------------
+
+class cPtsFixer {
+private:
+ int delta; // time between two frames
+ int64_t last; // the last (i.e. highest) video PTS value seen
+ int64_t offset; // offset to add to PTS values
+ bool fixCounters; // controls fixing the TS continuity counters (only from the second CutIn up)
+ uchar counter[MAXPID]; // the TS continuity counter for each PID
+ cPatPmtParser patPmtParser;
+public:
+ cPtsFixer(void);
+ void Setup(double FramesPerSecond);
+ void Fix(uchar *Data, int Length, bool CutIn);
+ };
+
+cPtsFixer::cPtsFixer(void)
+{
+ delta = 0;
+ last = -1;
+ offset = -1;
+ fixCounters = false;
+ memset(counter, 0x00, sizeof(counter));
+}
+
+void cPtsFixer::Setup(double FramesPerSecond)
+{
+ delta = int(round(PTSTICKS / FramesPerSecond));
+}
+
+void cPtsFixer::Fix(uchar *Data, int Length, bool CutIn)
+{
+ if (!patPmtParser.Vpid()) {
+ if (!patPmtParser.ParsePatPmt(Data, Length))
+ return;
+ }
+ // Determine the PTS offset at the beginning of each sequence (except the first one):
+ if (CutIn && last >= 0) {
+ int64_t Pts = TsGetPts(Data, Length);
+ if (Pts >= 0) {
+ // offset is calculated so that Pts + offset results in last + delta:
+ offset = Pts - PtsAdd(last, delta);
+ if (offset <= 0)
+ offset = -offset;
+ else
+ offset = MAX33BIT + 1 - offset;
+ }
+ fixCounters = true;
+ }
+ // Keep track of the highest video PTS:
+ uchar *p = Data;
+ int len = Length;
+ while (len >= TS_SIZE && *p == TS_SYNC_BYTE) {
+ int Pid = TsPid(p);
+ if (Pid == patPmtParser.Vpid()) {
+ int64_t Pts = PtsAdd(TsGetPts(p, TS_SIZE), offset); // offset is taken into account here, to make last have the "new" value already!
+ if (Pts >= 0 && (last < 0 || PtsDiff(last, Pts) > 0))
+ last = Pts;
+ }
+ // Adjust the TS continuity counter:
+ if (fixCounters) {
+ counter[Pid] = (counter[Pid] + 1) & TS_CONT_CNT_MASK;
+ TsSetContinuityCounter(p, counter[Pid]);
+ }
+ else
+ counter[Pid] = TsGetContinuityCounter(p); // collect initial counters
+ p += TS_SIZE;
+ len -= TS_SIZE;
+ }
+ // Apply the PTS offset:
+ if (offset > 0) {
+ uchar *p = Data;
+ int len = Length;
+ while (len >= TS_SIZE && *p == TS_SYNC_BYTE) {
+ // Adjust the various timestamps:
+ int64_t Pts = TsGetPts(p, TS_SIZE);
+ if (Pts >= 0)
+ TsSetPts(p, TS_SIZE, PtsAdd(Pts, offset));
+ int64_t Dts = TsGetDts(p, TS_SIZE);
+ if (Dts >= 0)
+ TsSetDts(p, TS_SIZE, PtsAdd(Dts, offset));
+ int64_t Pcr = TsGetPcr(p);
+ if (Pcr >= 0) {
+ int64_t NewPcr = Pcr + offset * PCRFACTOR;
+ if (NewPcr >= MAX27MHZ)
+ NewPcr -= MAX27MHZ + 1;
+ TsSetPcr(p, NewPcr);
+ }
+ p += TS_SIZE;
+ len -= TS_SIZE;
+ }
+ }
+}
+
// --- cCuttingThread --------------------------------------------------------
class cCuttingThread : public cThread {
private:
const char *error;
bool isPesRecording;
+ double framesPerSecond;
cUnbufferedFile *fromFile, *toFile;
cFileName *fromFileName, *toFileName;
cIndexFile *fromIndex, *toIndex;
cMarks fromMarks, toMarks;
+ int numSequences;
off_t maxVideoFileSize;
+ off_t fileSize;
+ cPtsFixer ptsFixer;
+ bool suspensionLogged;
+ bool Throttled(void);
+ bool SwitchFile(bool Force = false);
+ bool LoadFrame(int Index, uchar *Buffer, bool &Independent, int &Length);
+ bool FramesAreEqual(int Index1, int Index2);
+ void GetPendingPackets(uchar *Buffer, int &Length, int Index, int64_t LastPts);
+ // Gather all non-video TS packets from Index upward that either belong to
+ // payloads that started before Index, or have a PTS that is before LastPts,
+ // and add them to the end of the given Data.
+ bool ProcessSequence(int LastEndIndex, int BeginIndex, int EndIndex, int NextBeginIndex);
protected:
virtual void Action(void);
public:
@@ -33,7 +277,7 @@ public:
};
cCuttingThread::cCuttingThread(const char *FromFileName, const char *ToFileName)
-:cThread("video cutting")
+:cThread("video cutting", true)
{
error = NULL;
fromFile = toFile = NULL;
@@ -41,16 +285,25 @@ cCuttingThread::cCuttingThread(const char *FromFileName, const char *ToFileName)
fromIndex = toIndex = NULL;
cRecording Recording(FromFileName);
isPesRecording = Recording.IsPesRecording();
- if (fromMarks.Load(FromFileName, Recording.FramesPerSecond(), isPesRecording) && fromMarks.Count()) {
- fromFileName = new cFileName(FromFileName, false, true, isPesRecording);
- toFileName = new cFileName(ToFileName, true, true, isPesRecording);
- fromIndex = new cIndexFile(FromFileName, false, isPesRecording);
- toIndex = new cIndexFile(ToFileName, true, isPesRecording);
- toMarks.Load(ToFileName, Recording.FramesPerSecond(), isPesRecording); // doesn't actually load marks, just sets the file name
- maxVideoFileSize = MEGABYTE(Setup.MaxVideoFileSize);
- if (isPesRecording && maxVideoFileSize > MEGABYTE(MAXVIDEOFILESIZEPES))
- maxVideoFileSize = MEGABYTE(MAXVIDEOFILESIZEPES);
- Start();
+ framesPerSecond = Recording.FramesPerSecond();
+ suspensionLogged = false;
+ fileSize = 0;
+ ptsFixer.Setup(framesPerSecond);
+ if (fromMarks.Load(FromFileName, framesPerSecond, isPesRecording) && fromMarks.Count()) {
+ numSequences = fromMarks.GetNumSequences();
+ if (numSequences > 0) {
+ fromFileName = new cFileName(FromFileName, false, true, isPesRecording);
+ toFileName = new cFileName(ToFileName, true, true, isPesRecording);
+ fromIndex = new cIndexFile(FromFileName, false, isPesRecording);
+ toIndex = new cIndexFile(ToFileName, true, isPesRecording);
+ toMarks.Load(ToFileName, framesPerSecond, isPesRecording); // doesn't actually load marks, just sets the file name
+ maxVideoFileSize = MEGABYTE(Setup.MaxVideoFileSize);
+ if (isPesRecording && maxVideoFileSize > MEGABYTE(MAXVIDEOFILESIZEPES))
+ maxVideoFileSize = MEGABYTE(MAXVIDEOFILESIZEPES);
+ Start();
+ }
+ else
+ esyslog("no editing sequences found for %s", FromFileName);
}
else
esyslog("no editing marks found for %s", FromFileName);
@@ -65,171 +318,236 @@ cCuttingThread::~cCuttingThread()
delete toIndex;
}
+bool cCuttingThread::Throttled(void)
+{
+ if (cIoThrottle::Engaged()) {
+ if (!suspensionLogged) {
+ dsyslog("suspending cutter thread");
+ suspensionLogged = true;
+ }
+ return true;
+ }
+ else if (suspensionLogged) {
+ dsyslog("resuming cutter thread");
+ suspensionLogged = false;
+ }
+ return false;
+}
+
+bool cCuttingThread::LoadFrame(int Index, uchar *Buffer, bool &Independent, int &Length)
+{
+ uint16_t FileNumber;
+ off_t FileOffset;
+ if (fromIndex->Get(Index, &FileNumber, &FileOffset, &Independent, &Length)) {
+ fromFile = fromFileName->SetOffset(FileNumber, FileOffset);
+ if (fromFile) {
+ fromFile->SetReadAhead(MEGABYTE(20));
+ int len = ReadFrame(fromFile, Buffer, Length, MAXFRAMESIZE);
+ if (len < 0)
+ error = "ReadFrame";
+ else if (len != Length)
+ Length = len;
+ return error == NULL;
+ }
+ else
+ error = "fromFile";
+ }
+ return false;
+}
+
+bool cCuttingThread::SwitchFile(bool Force)
+{
+ if (fileSize > maxVideoFileSize || Force) {
+ toFile = toFileName->NextFile();
+ if (!toFile) {
+ error = "toFile";
+ return false;
+ }
+ fileSize = 0;
+ }
+ return true;
+}
+
+bool cCuttingThread::FramesAreEqual(int Index1, int Index2)
+{
+ bool Independent;
+ uchar Buffer1[MAXFRAMESIZE];
+ uchar Buffer2[MAXFRAMESIZE];
+ int Length1;
+ int Length2;
+ if (LoadFrame(Index1, Buffer1, Independent, Length1) && LoadFrame(Index2, Buffer2, Independent, Length2)) {
+ if (Length1 == Length2) {
+ int Diffs = 0;
+ for (int i = 0; i < Length1; i++) {
+ if (Buffer1[i] != Buffer2[i]) {
+ if (Diffs++ > 10) // the continuity counters of the PAT/PMT packets may differ
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+void cCuttingThread::GetPendingPackets(uchar *Data, int &Length, int Index, int64_t LastPts)
+{
+ bool Processed[MAXPID] = { false };
+ int NumIndependentFrames = 0;
+ cPatPmtParser PatPmtParser;
+ cPacketStorage PacketStorage;
+ for (; NumIndependentFrames < 2; Index++) {
+ uchar Buffer[MAXFRAMESIZE];
+ bool Independent;
+ int len;
+ if (LoadFrame(Index, Buffer, Independent, len)) {
+ if (Independent)
+ NumIndependentFrames++;
+ uchar *p = Buffer;
+ while (len >= TS_SIZE && *p == TS_SYNC_BYTE) {
+ int Pid = TsPid(p);
+ if (Pid == PATPID)
+ PatPmtParser.ParsePat(p, TS_SIZE);
+ else if (Pid == PatPmtParser.PmtPid())
+ PatPmtParser.ParsePmt(p, TS_SIZE);
+ else if (!Processed[Pid]) {
+ int64_t Pts = TsGetPts(p, TS_SIZE);
+ if (Pts >= 0) {
+ int64_t d = PtsDiff(LastPts, Pts);
+ if (d <= 0) // Pts is before or at LastPts
+ PacketStorage.Flush(Pid, Data, Length, MAXFRAMESIZE);
+ if (d >= 0) { // Pts is at or after LastPts
+ NumIndependentFrames = 0; // we search until we find two consecutive I-frames without any more pending packets
+ Processed[Pid] = true;
+ }
+ }
+ if (!Processed[Pid])
+ PacketStorage.Append(Pid, p, TS_SIZE);
+ }
+ len -= TS_SIZE;
+ p += TS_SIZE;
+ }
+ }
+ else
+ break;
+ }
+}
+
+bool cCuttingThread::ProcessSequence(int LastEndIndex, int BeginIndex, int EndIndex, int NextBeginIndex)
+{
+ // Check for seamless connections:
+ bool SeamlessBegin = LastEndIndex >= 0 && FramesAreEqual(LastEndIndex, BeginIndex);
+ bool SeamlessEnd = NextBeginIndex >= 0 && FramesAreEqual(EndIndex, NextBeginIndex);
+ // Process all frames from BeginIndex (included) to EndIndex (excluded):
+ cDanglingPacketStripper DanglingPacketStripper;
+ int NumIndependentFrames = 0;
+ int64_t FirstPts = -1;
+ int64_t LastPts = -1;
+ for (int Index = BeginIndex; Running() && Index < EndIndex; Index++) {
+ uchar Buffer[MAXFRAMESIZE];
+ bool Independent;
+ int Length;
+ if (LoadFrame(Index, Buffer, Independent, Length)) {
+ if (!isPesRecording) {
+ int64_t Pts = TsGetPts(Buffer, Length);
+ if (FirstPts < 0)
+ FirstPts = Pts; // the PTS of the first frame in the sequence
+ else if (LastPts < 0 || PtsDiff(LastPts, Pts) > 0)
+ LastPts = Pts; // the PTS of the frame that is displayed as the very last one of the sequence
+ }
+ // Fixup data at the beginning of the sequence:
+ if (!SeamlessBegin) {
+ if (isPesRecording) {
+ if (Index == BeginIndex)
+ cRemux::SetBrokenLink(Buffer, Length);
+ }
+ else if (NumIndependentFrames < 2) {
+ if (DanglingPacketStripper.Process(Buffer, Length, FirstPts))
+ NumIndependentFrames = 0; // we search until we find two consecutive I-frames without any more dangling packets
+ }
+ }
+ // Fixup data at the end of the sequence:
+ if (!SeamlessEnd) {
+ if (Index == EndIndex - 1) {
+ if (!isPesRecording)
+ GetPendingPackets(Buffer, Length, EndIndex, LastPts + int(round(PTSTICKS / framesPerSecond))); // adding one frame length to fully cover the very last frame
+ }
+ }
+ // Fixup timestamps and continuity counters:
+ if (!isPesRecording) {
+ if (numSequences > 1)
+ ptsFixer.Fix(Buffer, Length, !SeamlessBegin && Index == BeginIndex);
+ }
+ // Every file shall start with an independent frame:
+ if (Independent) {
+ NumIndependentFrames++;
+ if (!SwitchFile())
+ return false;
+ }
+ // Write index:
+ if (!toIndex->Write(Independent, toFileName->Number(), fileSize)) {
+ error = "toIndex";
+ return false;
+ }
+ // Write data:
+ if (toFile->Write(Buffer, Length) < 0) {
+ error = "safe_write";
+ return false;
+ }
+ fileSize += Length;
+ // Generate marks at the editing points in the edited recording:
+ if (numSequences > 0 && Index == BeginIndex) {
+ if (toMarks.Count() > 0)
+ toMarks.Add(toIndex->Last());
+ toMarks.Add(toIndex->Last());
+ toMarks.Save();
+ }
+ }
+ else
+ return false;
+ }
+ return true;
+}
+
void cCuttingThread::Action(void)
{
- cMark *Mark = fromMarks.First();
- if (Mark) {
- SetPriority(19);
- SetIOPriority(7);
+ if (cMark *BeginMark = fromMarks.GetNextBegin()) {
fromFile = fromFileName->Open();
toFile = toFileName->Open();
if (!fromFile || !toFile)
return;
- fromFile->SetReadAhead(MEGABYTE(20));
- int Index = Mark->Position();
- Mark = fromMarks.Next(Mark);
- off_t FileSize = 0;
- int CurrentFileNumber = 0;
- int LastIFrame = 0;
- toMarks.Add(0);
- toMarks.Save();
- uchar buffer[MAXFRAMESIZE], buffer2[MAXFRAMESIZE];
- int Length2;
- bool CheckForSeamlessStream = false;
- bool LastMark = false;
- bool cutIn = true;
- bool suspensionLogged = false;
- while (Running()) {
- uint16_t FileNumber;
- off_t FileOffset;
- int Length;
- bool Independent;
-
+ int LastEndIndex = -1;
+ while (BeginMark && Running()) {
// Suspend cutting if we have severe throughput problems:
-
- if (cIoThrottle::Engaged()) {
- if (!suspensionLogged) {
- dsyslog("suspending cutter thread");
- suspensionLogged = true;
- }
+ if (Throttled()) {
cCondWait::SleepMs(100);
continue;
}
- else if (suspensionLogged) {
- dsyslog("resuming cutter thread");
- suspensionLogged = false;
- }
-
// Make sure there is enough disk space:
-
AssertFreeDiskSpace(-1);
-
- // Read one frame:
-
- if (fromIndex->Get(Index++, &FileNumber, &FileOffset, &Independent, &Length)) {
- if (FileNumber != CurrentFileNumber) {
- fromFile = fromFileName->SetOffset(FileNumber, FileOffset);
- if (fromFile)
- fromFile->SetReadAhead(MEGABYTE(20));
- CurrentFileNumber = FileNumber;
- }
- if (fromFile) {
- int len = ReadFrame(fromFile, buffer, Length, sizeof(buffer));
- if (len < 0) {
- error = "ReadFrame";
- break;
- }
- if (len != Length) {
- CurrentFileNumber = 0; // this re-syncs in case the frame was larger than the buffer
- Length = len;
- }
- }
- else {
- error = "fromFile";
- break;
- }
+ // Determine the actual begin and end marks, skipping any marks at the same position:
+ cMark *EndMark = fromMarks.GetNextEnd(BeginMark);
+ // Process the current sequence:
+ int EndIndex = EndMark ? EndMark->Position() : fromIndex->Last() + 1;
+ int NextBeginIndex = -1;
+ if (EndMark) {
+ if (cMark *NextBeginMark = fromMarks.GetNextBegin(EndMark))
+ NextBeginIndex = NextBeginMark->Position();
}
- else {
- // Error, unless we're past the last cut-in and there's no cut-out
- if (Mark || LastMark)
- error = "index";
+ if (!ProcessSequence(LastEndIndex, BeginMark->Position(), EndIndex, NextBeginIndex))
break;
- }
-
- // Write one frame:
-
- if (Independent) { // every file shall start with an independent frame
- if (LastMark) // edited version shall end before next I-frame
- break;
- if (FileSize > maxVideoFileSize) {
- toFile = toFileName->NextFile();
- if (!toFile) {
- error = "toFile 1";
+ if (!EndMark)
+ break; // reached EOF
+ LastEndIndex = EndIndex;
+ // Switch to the next sequence:
+ BeginMark = fromMarks.GetNextBegin(EndMark);
+ if (BeginMark) {
+ // Split edited files:
+ if (Setup.SplitEditedFiles) {
+ if (!SwitchFile(true))
break;
- }
- FileSize = 0;
- }
- LastIFrame = 0;
- // Compare the current frame with the previously stored one, to see if this is a seamlessly merged recording of the same stream:
- if (CheckForSeamlessStream) {
- if (Length == Length2) {
- int diffs = 0;
- for (int i = 0; i < Length; i++) {
- if (buffer[i] != buffer2[i]) {
- if (diffs++ > 10)
- break;
- }
- }
- if (diffs < 10) // the continuity counters of the PAT/PMT packets may differ
- cutIn = false; // it's apparently a seamless stream, so no need for "broken" handling
- }
- CheckForSeamlessStream = false;
- }
- if (cutIn) {
- if (isPesRecording)
- cRemux::SetBrokenLink(buffer, Length);
- else
- TsSetTeiOnBrokenPackets(buffer, Length);
- cutIn = false;
}
}
- if (toFile->Write(buffer, Length) < 0) {
- error = "safe_write";
- break;
- }
- if (!toIndex->Write(Independent, toFileName->Number(), FileSize)) {
- error = "toIndex";
- break;
- }
- FileSize += Length;
- if (!LastIFrame)
- LastIFrame = toIndex->Last();
-
- // Check editing marks:
-
- if (Mark && Index >= Mark->Position()) {
- Mark = fromMarks.Next(Mark);
- toMarks.Add(LastIFrame);
- if (Mark)
- toMarks.Add(toIndex->Last() + 1);
- toMarks.Save();
- if (Mark) {
- // Read the next frame, for later comparison with the first frame at this mark:
- if (fromIndex->Get(Index, &FileNumber, &FileOffset, &Independent, &Length2)) {
- if (FileNumber != CurrentFileNumber)
- fromFile = fromFileName->SetOffset(FileNumber, FileOffset);
- if (fromFile) {
- int len = ReadFrame(fromFile, buffer2, Length2, sizeof(buffer2));
- if (len >= 0 && len == Length2)
- CheckForSeamlessStream = true;
- }
- }
- Index = Mark->Position();
- Mark = fromMarks.Next(Mark);
- CurrentFileNumber = 0; // triggers SetOffset before reading next frame
- cutIn = true;
- if (Setup.SplitEditedFiles) {
- toFile = toFileName->NextFile();
- if (!toFile) {
- error = "toFile 2";
- break;
- }
- FileSize = 0;
- }
- }
- else
- LastMark = true;
- }
}
Recordings.TouchUpdate();
}
@@ -257,7 +575,7 @@ bool cCutter::Start(const char *FileName)
cMarks FromMarks;
FromMarks.Load(FileName, Recording.FramesPerSecond(), Recording.IsPesRecording());
- if (cMark *First = FromMarks.First())
+ if (cMark *First = FromMarks.GetNextBegin())
Recording.SetStartTime(Recording.Start() + (int(First->Position() / Recording.FramesPerSecond() + 30) / 60) * 60);
const char *evn = Recording.PrefixFileName('%');
@@ -345,13 +663,17 @@ bool CutRecording(const char *FileName)
if (Recording.Name()) {
cMarks Marks;
if (Marks.Load(FileName, Recording.FramesPerSecond(), Recording.IsPesRecording()) && Marks.Count()) {
- if (cCutter::Start(FileName)) {
- while (cCutter::Active())
- cCondWait::SleepMs(CUTTINGCHECKINTERVAL);
- return true;
+ if (Marks.GetNumSequences()) {
+ if (cCutter::Start(FileName)) {
+ while (cCutter::Active())
+ cCondWait::SleepMs(CUTTINGCHECKINTERVAL);
+ return true;
+ }
+ else
+ fprintf(stderr, "can't start editing process\n");
}
else
- fprintf(stderr, "can't start editing process\n");
+ fprintf(stderr, "'%s' has no editing sequences\n", FileName);
}
else
fprintf(stderr, "'%s' has no editing marks\n", FileName);
diff --git a/device.c b/device.c
index aa93a8e..766253a 100644
--- a/device.c
+++ b/device.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: device.c 2.68 2012/09/20 09:32:26 kls Exp $
+ * $Id: device.c 2.69 2012/11/13 09:11:43 kls Exp $
*/
#include "device.h"
@@ -1147,7 +1147,7 @@ void cDevice::StillPicture(const uchar *Data, int Length)
int Size = 0;
while (Length >= TS_SIZE) {
int Pid = TsPid(Data);
- if (Pid == 0)
+ if (Pid == PATPID)
patPmtParser.ParsePat(Data, TS_SIZE);
else if (Pid == patPmtParser.PmtPid())
patPmtParser.ParsePmt(Data, TS_SIZE);
@@ -1484,7 +1484,7 @@ int cDevice::PlayTs(const uchar *Data, int Length, bool VideoOnly)
if (TsHasPayload(Data)) { // silently ignore TS packets w/o payload
int PayloadOffset = TsPayloadOffset(Data);
if (PayloadOffset < TS_SIZE) {
- if (Pid == 0)
+ if (Pid == PATPID)
patPmtParser.ParsePat(Data, TS_SIZE);
else if (Pid == patPmtParser.PmtPid())
patPmtParser.ParsePmt(Data, TS_SIZE);
diff --git a/dvbdevice.c b/dvbdevice.c
index 9320da6..d3ade75 100644
--- a/dvbdevice.c
+++ b/dvbdevice.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbdevice.c 2.72 2012/09/20 10:07:54 kls Exp $
+ * $Id: dvbdevice.c 2.74 2012/10/07 11:11:30 kls Exp $
*/
#include "dvbdevice.h"
@@ -21,7 +21,9 @@
#include "menuitems.h"
#include "sourceparams.h"
-#define FE_CAN_TURBO_FEC 0x8000000 // TODO: remove this once it is defined in the driver
+#if (DVB_API_VERSION << 8 | DVB_API_VERSION_MINOR) < 0x0508
+#define DTV_STREAM_ID DTV_DVBT2_PLP_ID
+#endif
#define DVBS_TUNE_TIMEOUT 9000 //ms
#define DVBS_LOCK_TIMEOUT 2000 //ms
@@ -408,7 +410,7 @@ cString cDvbTuner::GetBondingParams(const cChannel *Channel) const
return diseqc->Commands();
}
else {
- bool ToneOff = Channel->Frequency() < (unsigned int)Setup.LnbSLOF;
+ bool ToneOff = Channel->Frequency() < Setup.LnbSLOF;
bool VoltOff = dtp.Polarization() == 'V' || dtp.Polarization() == 'R';
return cString::sprintf("%c %c", ToneOff ? 't' : 'T', VoltOff ? 'v' : 'V');
}
@@ -574,40 +576,52 @@ int cDvbTuner::GetSignalQuality(void) const
return 3;
return 4;
}
+#ifdef DEBUG_SIGNALQUALITY
bool HasSnr = true;
+#endif
uint16_t Snr;
while (1) {
if (ioctl(fd_frontend, FE_READ_SNR, &Snr) != -1)
break;
if (errno == EOPNOTSUPP) {
Snr = 0xFFFF;
+#ifdef DEBUG_SIGNALQUALITY
HasSnr = false;
+#endif
break;
}
if (errno != EINTR)
return -1;
}
+#ifdef DEBUG_SIGNALQUALITY
bool HasBer = true;
+#endif
uint32_t Ber;
while (1) {
if (ioctl(fd_frontend, FE_READ_BER, &Ber) != -1)
break;
if (errno == EOPNOTSUPP) {
Ber = 0;
+#ifdef DEBUG_SIGNALQUALITY
HasBer = false;
+#endif
break;
}
if (errno != EINTR)
return -1;
}
+#ifdef DEBUG_SIGNALQUALITY
bool HasUnc = true;
+#endif
uint32_t Unc;
while (1) {
if (ioctl(fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &Unc) != -1)
break;
if (errno == EOPNOTSUPP) {
Unc = 0;
+#ifdef DEBUG_SIGNALQUALITY
HasUnc = false;
+#endif
break;
}
if (errno != EINTR)
@@ -810,7 +824,7 @@ bool cDvbTuner::SetFrontend(void)
SETCMD(DTV_HIERARCHY, dtp.Hierarchy());
if (frontendType == SYS_DVBT2) {
// DVB-T2
- SETCMD(DTV_DVBT2_PLP_ID, dtp.PlpId());
+ SETCMD(DTV_STREAM_ID, dtp.PlpId());
}
tuneTimeout = DVBT_TUNE_TIMEOUT;
diff --git a/epg.c b/epg.c
index 1c1ecdf..3da7dc1 100644
--- a/epg.c
+++ b/epg.c
@@ -7,7 +7,7 @@
* Original version (as used in VDR before 1.3.0) written by
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
*
- * $Id: epg.c 2.21 2012/09/29 14:29:49 kls Exp $
+ * $Id: epg.c 2.22 2012/10/04 12:21:24 kls Exp $
*/
#include "epg.h"
@@ -1148,14 +1148,12 @@ public:
};
cEpgDataWriter::cEpgDataWriter(void)
-:cThread("epg data writer")
+:cThread("epg data writer", true)
{
}
void cEpgDataWriter::Action(void)
{
- SetPriority(19);
- SetIOPriority(7);
Perform();
}
diff --git a/libsi/si.h b/libsi/si.h
index 4dccdd8..8e4255e 100644
--- a/libsi/si.h
+++ b/libsi/si.h
@@ -6,7 +6,7 @@
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
- * $Id: si.h 2.5 2012/01/11 11:35:17 kls Exp $
+ * $Id: si.h 2.6 2012/10/15 11:56:06 kls Exp $
* *
***************************************************************************/
@@ -347,8 +347,10 @@ public:
T *ret=new T();
ret->setData(d);
ret->CheckParse();
- if (!checkSize(ret->getLength()))
+ if (!checkSize(ret->getLength())) {
+ delete ret;
return 0;
+ }
it.i+=ret->getLength();
return ret;
}
diff --git a/menu.c b/menu.c
index cdd9d3a..b5a0d25 100644
--- a/menu.c
+++ b/menu.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.c 2.61 2012/09/15 11:45:28 kls Exp $
+ * $Id: menu.c 2.65 2012/11/18 13:07:53 kls Exp $
*/
#include "menu.h"
@@ -3418,7 +3418,7 @@ bool cMenuMain::Update(bool Force)
stopReplayItem = NULL;
}
// Color buttons:
- SetHelp(!replaying ? tr("Button$Record") : NULL, tr("Button$Audio"), replaying ? NULL : tr("Button$Pause"), replaying ? tr("Button$Stop") : cReplayControl::LastReplayed() ? tr("Button$Resume") : NULL);
+ SetHelp(!replaying ? tr("Button$Record") : NULL, tr("Button$Audio"), replaying ? NULL : tr("Button$Pause"), replaying ? tr("Button$Stop") : cReplayControl::LastReplayed() ? tr("Button$Resume") : tr("Button$Play"));
result = true;
}
@@ -3516,7 +3516,7 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
state = replaying ? osContinue : osPause;
break;
case kBlue: if (!HadSubMenu)
- state = replaying ? osStopReplay : cReplayControl::LastReplayed() ? osReplay : osContinue;
+ state = replaying ? osStopReplay : cReplayControl::LastReplayed() ? osReplay : osRecordings;
break;
default: break;
}
@@ -4482,10 +4482,6 @@ cReplayControl::~cReplayControl()
Hide();
cStatus::MsgReplaying(this, NULL, fileName, false);
Stop();
- if (marksModified) {
- marks.Save();
- marksModified = false;
- }
if (currentReplayControl == this)
currentReplayControl = NULL;
}
@@ -4573,6 +4569,10 @@ void cReplayControl::Hide(void)
timeSearchActive = false;
timeoutShow = 0;
}
+ if (marksModified) {
+ marks.Save();
+ marksModified = false;
+ }
}
void cReplayControl::ShowMode(void)
@@ -4771,12 +4771,12 @@ void cReplayControl::MarkMove(bool Forward)
int p = SkipFrames(Forward ? 1 : -1);
cMark *m2;
if (Forward) {
- if ((m2 = marks.Next(m)) != NULL && m2->Position() <= p)
- return;
+ while ((m2 = marks.Next(m)) != NULL && m2->Position() == m->Position())
+ m = m2;
}
else {
- if ((m2 = marks.Prev(m)) != NULL && m2->Position() >= p)
- return;
+ while ((m2 = marks.Prev(m)) != NULL && m2->Position() == m->Position())
+ m = m2;
}
m->SetPosition(p);
Goto(m->Position(), true);
@@ -4789,13 +4789,11 @@ void cReplayControl::EditCut(void)
{
if (*fileName) {
Hide();
- if (marksModified) {
- marks.Save();
- marksModified = false;
- }
if (!cCutter::Active()) {
if (!marks.Count())
Skins.Message(mtError, tr("No editing marks defined!"));
+ else if (!marks.GetNumSequences())
+ Skins.Message(mtError, tr("No editing sequences defined!"));
else if (!cCutter::Start(fileName))
Skins.Message(mtError, tr("Can't start editing process!"));
else
diff --git a/po/ar.po b/po/ar.po
index 14e8126..c0fb31f 100644
--- a/po/ar.po
+++ b/po/ar.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.7.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-10-16 11:16-0400\n"
"Last-Translator: Osama Alrawab <alrawab@hotmail.com>\n"
"Language-Team: Arabic <ar@li.org>\n"
@@ -1241,6 +1241,9 @@ msgstr "Ĝ§Ù‚فĜ² Ĝ§Ù„Ù‰ "
msgid "No editing marks defined!"
msgstr "لĜ§ĜŞÙˆĜĴĜŻ ĜıلĜ§Ù…Ĝ§ĜŞ ĜŞĜıĜŻÙŠÙ„ مĜıĜħفĜİ"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "لĜ§ يمكن Ĝ§Ù„Ĝ¨ĜŻĜĦ فى ĜıمليĜİ Ĝ§Ù„ĜŞĜıĜŻÙŠÙ„"
diff --git a/po/ca_ES.po b/po/ca_ES.po
index c67265b..f08cd57 100644
--- a/po/ca_ES.po
+++ b/po/ca_ES.po
@@ -10,7 +10,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-03-02 19:02+0100\n"
"Last-Translator: Luca Olivetti <luca@ventoso.org>\n"
"Language-Team: Catalan <vdr@linuxtv.org>\n"
@@ -1216,6 +1216,9 @@ msgstr "Salta a:"
msgid "No editing marks defined!"
msgstr "No hi ha marques d'edició definides"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "No puc iniciar el procés d'edició!"
diff --git a/po/cs_CZ.po b/po/cs_CZ.po
index 55053f9..1a62102 100644
--- a/po/cs_CZ.po
+++ b/po/cs_CZ.po
@@ -9,7 +9,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.7.14\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2010-05-06 11:00+0200\n"
"Last-Translator: Radek Ċ Ċastn½ <dedkus@gmail.com>\n"
"Language-Team: Czech <vdr@linuxtv.org>\n"
@@ -1215,6 +1215,9 @@ msgstr "Skok: "
msgid "No editing marks defined!"
msgstr "Nejsou definovĦny editačn­ značky!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Nelze zač­t editačn­ proces!"
diff --git a/po/da_DK.po b/po/da_DK.po
index fac5800..597539f 100644
--- a/po/da_DK.po
+++ b/po/da_DK.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2007-08-12 14:17+0200\n"
"Last-Translator: Mogens Elneff <mogens@elneff.dk>\n"
"Language-Team: Danish <vdr@linuxtv.org>\n"
@@ -1213,6 +1213,9 @@ msgstr "Hop: "
msgid "No editing marks defined!"
msgstr "Der er ikke sat nogen redigeringsmĉrker!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Kan ikke starte redigeringsprocessen!"
diff --git a/po/de_DE.po b/po/de_DE.po
index a321b50..c958758 100644
--- a/po/de_DE.po
+++ b/po/de_DE.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2010-01-16 16:46+0100\n"
"Last-Translator: Klaus Schmidinger <kls@tvdr.de>\n"
"Language-Team: German <vdr@linuxtv.org>\n"
@@ -1213,6 +1213,9 @@ msgstr "Springen: "
msgid "No editing marks defined!"
msgstr "Keine Schnittmarken gesetzt!"
+msgid "No editing sequences defined!"
+msgstr "Keine Schnittsequenzen definiert!"
+
msgid "Can't start editing process!"
msgstr "Schnitt kann nicht gestartet werden!"
diff --git a/po/el_GR.po b/po/el_GR.po
index 8936408..1347812 100644
--- a/po/el_GR.po
+++ b/po/el_GR.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2007-08-12 14:17+0200\n"
"Last-Translator: Dimitrios Dimitrakos <mail@dimitrios.de>\n"
"Language-Team: Greek <vdr@linuxtv.org>\n"
@@ -1213,6 +1213,9 @@ msgstr "ÔïïèŬôçóç: "
msgid "No editing marks defined!"
msgstr "ÄŬí Ŭ÷ïġí ïñéóôċß óçìċßá ċċîċñáóßáò"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Áäġíáìßá ċêêßíçóçò ôçò ċċîċñáóßáò!"
diff --git a/po/es_ES.po b/po/es_ES.po
index bc80a11..8e76063 100644
--- a/po/es_ES.po
+++ b/po/es_ES.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-03-02 19:02+0100\n"
"Last-Translator: Luca Olivetti <luca@ventoso.org>\n"
"Language-Team: Spanish <vdr@linuxtv.org>\n"
@@ -1214,6 +1214,9 @@ msgstr "Saltar: "
msgid "No editing marks defined!"
msgstr "ĦNo se definieron marcas de edición!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "ĦNo se puede iniciar el proceso de edición!"
diff --git a/po/et_EE.po b/po/et_EE.po
index 0dea999..12c1f25 100644
--- a/po/et_EE.po
+++ b/po/et_EE.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2007-08-12 14:17+0200\n"
"Last-Translator: Arthur Konovalov <artlov@gmail.com>\n"
"Language-Team: Estonian <vdr@linuxtv.org>\n"
@@ -1213,6 +1213,9 @@ msgstr "Hĵpe: "
msgid "No editing marks defined!"
msgstr "Redigeerimise markerid puuduvad!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Redigeerimise start nurjus!"
diff --git a/po/fi_FI.po b/po/fi_FI.po
index daad22a..901328a 100644
--- a/po/fi_FI.po
+++ b/po/fi_FI.po
@@ -10,7 +10,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-13 13:15+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2007-08-15 15:52+0200\n"
"Last-Translator: Rolf Ahrenberg <rahrenbe@cc.hut.fi>\n"
"Language-Team: Finnish <vdr@linuxtv.org>\n"
@@ -1216,6 +1216,9 @@ msgstr "Siirry: "
msgid "No editing marks defined!"
msgstr "Muokkausmerkinn¤t puuttuvat!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Muokkauksen aloitus ep¤onnistui!"
diff --git a/po/fr_FR.po b/po/fr_FR.po
index 3ca3c06..a0995ae 100644
--- a/po/fr_FR.po
+++ b/po/fr_FR.po
@@ -13,7 +13,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-02-27 18:14+0100\n"
"Last-Translator: Jean-Claude Repetto <jc@repetto.org>\n"
"Language-Team: French <vdr@linuxtv.org>\n"
@@ -1219,6 +1219,9 @@ msgstr "Accès direct : "
msgid "No editing marks defined!"
msgstr "Pas de marques d'édition définies !"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Impossible de commencer le montage !"
diff --git a/po/hr_HR.po b/po/hr_HR.po
index dcb1a21..44cfd09 100644
--- a/po/hr_HR.po
+++ b/po/hr_HR.po
@@ -9,7 +9,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-03-17 19:00+0100\n"
"Last-Translator: Adrian Caval <anrxc@sysphere.org>\n"
"Language-Team: Croatian <vdr@linuxtv.org>\n"
@@ -1215,6 +1215,9 @@ msgstr "Skoèi: "
msgid "No editing marks defined!"
msgstr "Nijedna toèka rezanja nije odreena!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Ne mogu zapoèeti ureivanje!"
diff --git a/po/hu_HU.po b/po/hu_HU.po
index c391b67..30ab8ab 100644
--- a/po/hu_HU.po
+++ b/po/hu_HU.po
@@ -10,7 +10,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2012-01-02 11:54+0200\n"
"Last-Translator: István Füley <ifuley@tigercomp.ro>\n"
"Language-Team: Hungarian <vdr@linuxtv.org>\n"
@@ -1217,6 +1217,9 @@ msgstr "Ugrás ide: "
msgid "No editing marks defined!"
msgstr "Nincs vágópont kijelölve"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "A vágás nem indítható!"
diff --git a/po/it_IT.po b/po/it_IT.po
index b63d93d..1258f23 100644
--- a/po/it_IT.po
+++ b/po/it_IT.po
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2012-06-06 22:50+0100\n"
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
"Language-Team: Italian <vdr@linuxtv.org>\n"
@@ -1220,6 +1220,9 @@ msgstr "Vai a: "
msgid "No editing marks defined!"
msgstr "Nessun marcatore di modifica definito!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Impossibile avviare il processo di modifica!"
diff --git a/po/lt_LT.po b/po/lt_LT.po
index 95f8e83..b53c762 100644
--- a/po/lt_LT.po
+++ b/po/lt_LT.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.7.16\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2010-10-30 11:55+0200\n"
"Last-Translator: Valdemaras Pipiras <varas@ambernet.lt>\n"
"Language-Team: Lithuanian <vdr@linuxtv.org>\n"
@@ -1213,6 +1213,9 @@ msgstr "PerĊĦokti: "
msgid "No editing marks defined!"
msgstr "Nenustatytos koregavimo Ċymės!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Negali pradėti koregavimo!"
diff --git a/po/mk_MK.po b/po/mk_MK.po
index fd16ec8..89e8b73 100644
--- a/po/mk_MK.po
+++ b/po/mk_MK.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR-1.7.14\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2010-03-11 00:54+0100\n"
"Last-Translator: Dimitar Petrovski <dimeptr@gmail.com>\n"
"Language-Team: Macedonian <en@li.org>\n"
@@ -1214,6 +1214,9 @@ msgstr "Ħşş½¸:"
msgid "No editing marks defined!"
msgstr "µĵ° ´Ñ€µ´µ½ ·½°ş¸ ·° сµÑ‡µÑšµ!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "µ ĵĥµ ´° żÑ‡½µ урµ´Ñƒ²°Ñšµ!"
diff --git a/po/nl_NL.po b/po/nl_NL.po
index 6c3825d..5e515c3 100644
--- a/po/nl_NL.po
+++ b/po/nl_NL.po
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-02-26 17:20+0100\n"
"Last-Translator: Johan Schuring <johan.schuring@vetteblei.nl>\n"
"Language-Team: Dutch <vdr@linuxtv.org>\n"
@@ -1217,6 +1217,9 @@ msgstr "Springen: "
msgid "No editing marks defined!"
msgstr "Geen bewerkingsmarkeringen gedefinieerd!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Kan niet beginnen met bewerken!"
diff --git a/po/nn_NO.po b/po/nn_NO.po
index 41ce5c3..f366260 100644
--- a/po/nn_NO.po
+++ b/po/nn_NO.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2007-08-12 14:17+0200\n"
"Last-Translator: Truls Slevigen <truls@slevigen.no>\n"
"Language-Team: Norwegian Nynorsk <vdr@linuxtv.org>\n"
@@ -1214,6 +1214,9 @@ msgstr "Hopp: "
msgid "No editing marks defined!"
msgstr ""
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Kan ikke starte redigeringsprosessen!"
diff --git a/po/pl_PL.po b/po/pl_PL.po
index f4c1876..fbe8a86 100644
--- a/po/pl_PL.po
+++ b/po/pl_PL.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-03-09 12:59+0100\n"
"Last-Translator: Michael Rakowski <mrak@gmx.de>\n"
"Language-Team: Polish <vdr@linuxtv.org>\n"
@@ -1214,6 +1214,9 @@ msgstr "Skok: "
msgid "No editing marks defined!"
msgstr "Nie zdefiniowano znaczników montażu!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Nie można uruchomiĉ procesu edycji!"
diff --git a/po/pt_PT.po b/po/pt_PT.po
index 5cfc203..d69e069 100644
--- a/po/pt_PT.po
+++ b/po/pt_PT.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.7.15\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2010-03-28 22:49+0100\n"
"Last-Translator: Cris Silva <hudokkow@gmail.com>\n"
"Language-Team: Portuguese <vdr@linuxtv.org>\n"
@@ -1214,6 +1214,9 @@ msgstr "Saltar: "
msgid "No editing marks defined!"
msgstr "Marcas de ediço no foram definidas!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Impossível iniciar processo de ediço!"
diff --git a/po/ro_RO.po b/po/ro_RO.po
index cd638dc..03ae8f0 100644
--- a/po/ro_RO.po
+++ b/po/ro_RO.po
@@ -2,19 +2,19 @@
# Copyright (C) 2008 Klaus Schmidinger <kls@tvdr.de>
# This file is distributed under the same license as the VDR package.
# Paul Lacatus <paul@campina.iiruc.ro>, 2002
-# Lucian Muresan <lucianm@users.sourceforge.net>, 2004, 2005, 2006, 2008, 2010, 2011
+# Lucian Muresan <lucianm@users.sourceforge.net>, 2004, 2005, 2006, 2008, 2010, 2011, 2012
#
msgid ""
msgstr ""
"Project-Id-Version: VDR 1.7.12\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
-"PO-Revision-Date: 2011-03-10 23:52+0100\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
+"PO-Revision-Date: 2012-11-05 01:28+0100\n"
"Last-Translator: Lucian Muresan <lucianm@users.sourceforge.net>\n"
"Language-Team: Romanian <vdr@linuxtv.org>\n"
"Language: ro\n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=ISO-8859-2\n"
+"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Poedit-Language: Romanian\n"
"X-Poedit-Country: ROMANIA\n"
@@ -47,7 +47,7 @@ msgid "System"
msgstr "Sistem"
msgid "Srate"
-msgstr "Rat simboluri"
+msgstr "Rată simboluri"
msgid "Inversion"
msgstr "Inversiune"
@@ -59,10 +59,10 @@ msgid "CoderateL"
msgstr "CoderateL"
msgid "Modulation"
-msgstr "Modulaŝie"
+msgstr "ModulaĊ£ie"
msgid "Bandwidth"
-msgstr "Lrgime de band"
+msgstr "Lărgime de bandă"
msgid "Transmission"
msgstr "Transmisie"
@@ -77,52 +77,52 @@ msgid "Rolloff"
msgstr "Rolloff"
msgid "PlpId"
-msgstr ""
+msgstr "Identificator PLP"
msgid "Starting EPG scan"
-msgstr "Pornesc achiziŝia EPG"
+msgstr "Pornesc achiziĊ£ia EPG"
msgid "Content$Movie/Drama"
-msgstr "Film/Dram"
+msgstr "Film/Dramă"
msgid "Content$Detective/Thriller"
-msgstr "Poliŝist/Suspense"
+msgstr "PoliĊ£ist/Suspense"
msgid "Content$Adventure/Western/War"
-msgstr "Aventuri/Western/Rzboi"
+msgstr "Aventuri/Western/Război"
msgid "Content$Science Fiction/Fantasy/Horror"
-msgstr "Science-Fiction/Fantastic/Groaz"
+msgstr "Science-Fiction/Fantastic/Groază"
msgid "Content$Comedy"
msgstr "Comedie"
msgid "Content$Soap/Melodrama/Folkloric"
-msgstr "Telenovel/Melodram/Folclor"
+msgstr "Telenovelă/Melodramă/Folclor"
msgid "Content$Romance"
msgstr "Film romantic"
msgid "Content$Serious/Classical/Religious/Historical Movie/Drama"
-msgstr "Film serios/clasic/religios/istoric/Dram"
+msgstr "Film serios/clasic/religios/istoric/Dramă"
msgid "Content$Adult Movie/Drama"
-msgstr "Film pentru adulŝi/Dram"
+msgstr "Film pentru adulĊ£i/Dramă"
msgid "Content$News/Current Affairs"
-msgstr "Ştiri/Actualitŝi"
+msgstr "Ċžtiri/ActualităĊ£i"
msgid "Content$News/Weather Report"
-msgstr "Ştiri/Buletin meteorologic"
+msgstr "Ċžtiri/Buletin meteorologic"
msgid "Content$News Magazine"
-msgstr "Magazin de ştiri"
+msgstr "Magazin de ĊŸtiri"
msgid "Content$Documentary"
msgstr "Documentar"
msgid "Content$Discussion/Inverview/Debate"
-msgstr "Discuŝie/Interviu/Dezbatere"
+msgstr "DiscuĊ£ie/Interviu/Dezbatere"
msgid "Content$Show/Game Show"
msgstr "Show/Jocuri"
@@ -131,7 +131,7 @@ msgid "Content$Game Show/Quiz/Contest"
msgstr "Emisiune jocuri/quiz/concurs"
msgid "Content$Variety Show"
-msgstr "Varietŝi"
+msgstr "VarietăĊ£i"
msgid "Content$Talk Show"
msgstr "Talk Show"
@@ -152,7 +152,7 @@ msgid "Content$Tennis/Squash"
msgstr "Tenis/Squash"
msgid "Content$Team Sports"
-msgstr "Sporturi de echip"
+msgstr "Sporturi de echipă"
msgid "Content$Athletics"
msgstr "Atletism"
@@ -164,19 +164,19 @@ msgid "Content$Water Sport"
msgstr "Sporturi acvatice"
msgid "Content$Winter Sports"
-msgstr "Sporturi de iarn"
+msgstr "Sporturi de iarnă"
msgid "Content$Equestrian"
-msgstr "Echitaŝie"
+msgstr "EchitaĊ£ie"
msgid "Content$Martial Sports"
-msgstr "Arte marŝiale"
+msgstr "Arte marĊ£iale"
msgid "Content$Children's/Youth Programme"
msgstr "Emisiune pentru copii/tineret"
msgid "Content$Pre-school Children's Programme"
-msgstr "Emisiune pentru copii preşcolari"
+msgstr "Emisiune pentru copii preĊŸcolari"
msgid "Content$Entertainment Programme for 6 to 14"
msgstr "Divertisment pentru copii intre 6 - 16 ani"
@@ -185,34 +185,34 @@ msgid "Content$Entertainment Programme for 10 to 16"
msgstr "Divertisment pentru copii intre 10 - 16 ani"
msgid "Content$Informational/Educational/School Programme"
-msgstr "Informaŝional/Educaŝional/Emisiune şcoal"
+msgstr "InformaĊ£ional/EducaĊ£ional/Emisiune ĊŸcoală"
msgid "Content$Cartoons/Puppets"
-msgstr "Desene animate/Teatru de ppuşi"
+msgstr "Desene animate/Teatru de păpuĊŸi"
msgid "Content$Music/Ballet/Dance"
-msgstr "Muzic/Balet/Dans"
+msgstr "Muzică/Balet/Dans"
msgid "Content$Rock/Pop"
msgstr "Rock/Pop"
msgid "Content$Serious/Classical Music"
-msgstr "Muzic clasic/serioas"
+msgstr "Muzică clasică/serioasă"
msgid "Content$Folk/Tradional Music"
-msgstr "Muzic folk/tradiŝional"
+msgstr "Muzică folk/tradiĊ£ională"
msgid "Content$Jazz"
msgstr "Jazz"
msgid "Content$Musical/Opera"
-msgstr "Teatru muzical/Oper/Operet"
+msgstr "Teatru muzical/Operă/Operetă"
msgid "Content$Ballet"
msgstr "Balet"
msgid "Content$Arts/Culture"
-msgstr "Art/Cultur"
+msgstr "Artă/Cultură"
msgid "Content$Performing Arts"
msgstr "Spectacole"
@@ -224,10 +224,10 @@ msgid "Content$Religion"
msgstr "Religie"
msgid "Content$Popular Culture/Traditional Arts"
-msgstr "Cultur Pop/Arte tradiŝionale"
+msgstr "Cultură Pop/Arte tradiĊ£ionale"
msgid "Content$Literature"
-msgstr "Literatur"
+msgstr "Literatură"
msgid "Content$Film/Cinema"
msgstr "Film/Cinema"
@@ -236,16 +236,16 @@ msgid "Content$Experimental Film/Video"
msgstr "Film experimental/Video"
msgid "Content$Broadcasting/Press"
-msgstr "Radiodifuziune/Pres"
+msgstr "Radiodifuziune/Presă"
msgid "Content$New Media"
msgstr "Medii noi"
msgid "Content$Arts/Culture Magazine"
-msgstr "Art/Magazin cultural"
+msgstr "Artă/Magazin cultural"
msgid "Content$Fashion"
-msgstr "Mod"
+msgstr "Modă"
msgid "Content$Social/Political/Economics"
msgstr "Social/Politic/Economie"
@@ -254,28 +254,28 @@ msgid "Content$Magazine/Report/Documentary"
msgstr "Magazin/Reportaj/Documentar"
msgid "Content$Economics/Social Advisory"
-msgstr "Economie/Consiliere social"
+msgstr "Economie/Consiliere socială"
msgid "Content$Remarkable People"
msgstr "Oameni remarcabili"
msgid "Content$Education/Science/Factual"
-msgstr "Educaŝie/Ştiinŝ/Practic"
+msgstr "EducaĊ£ie/ĊžtiinĊ£Äƒ/Practic"
msgid "Content$Nature/Animals/Environment"
-msgstr "Natur/Animale/Mediu"
+msgstr "Natură/Animale/Mediu"
msgid "Content$Technology/Natural Sciences"
-msgstr "Tehnologie/Ştiinŝe naturale"
+msgstr "Tehnologie/ĊžtiinĊ£e naturale"
msgid "Content$Medicine/Physiology/Psychology"
-msgstr "Medicin/Fiziologie/Psihologie"
+msgstr "Medicină/Fiziologie/Psihologie"
msgid "Content$Foreign Countries/Expeditions"
-msgstr "Ŝri strine/Expediŝii"
+msgstr "Ċ˘Äƒri străine/ExpediĊ£ii"
msgid "Content$Social/Spiritual Sciences"
-msgstr "Social/Ştiinŝe spirituale"
+msgstr "Social/ĊžtiinĊ£e spirituale"
msgid "Content$Further Education"
msgstr "Cursuri de aprofundare"
@@ -287,28 +287,28 @@ msgid "Content$Leisure/Hobbies"
msgstr "Timp liber/Hobby"
msgid "Content$Tourism/Travel"
-msgstr "Turism/Cltorie"
+msgstr "Turism/Călătorie"
msgid "Content$Handicraft"
-msgstr "Meşteşug"
+msgstr "MeĊŸteĊŸug"
msgid "Content$Motoring"
msgstr "Motoare"
msgid "Content$Fitness & Health"
-msgstr "Mişcare & Sntate"
+msgstr "MiĊŸcare & Sănătate"
msgid "Content$Cooking"
-msgstr "Gtit"
+msgstr "Gătit"
msgid "Content$Advertisement/Shopping"
-msgstr "Publicitate/Cumprturi"
+msgstr "Publicitate/Cumpărături"
msgid "Content$Gardening"
-msgstr "Grdinrit"
+msgstr "Grădinărit"
msgid "Content$Original Language"
-msgstr "Limba original"
+msgstr "Limba originală"
msgid "Content$Black & White"
msgstr "Alb-Negru"
@@ -317,65 +317,65 @@ msgid "Content$Unpublished"
msgstr "Nepublicat"
msgid "Content$Live Broadcast"
-msgstr "Transmisie în direct"
+msgstr "Transmisie n direct"
#, c-format
msgid "ParentalRating$from %d"
msgstr "de la %d ani"
msgid "No title"
-msgstr "Fr titlu"
+msgstr "Fără titlu"
#. TRANSLATORS: The name of the language, as written natively
msgid "LanguageName$English"
-msgstr "Român"
+msgstr "Rom˘nă"
#. TRANSLATORS: The 3-letter code of the language
msgid "LanguageCode$eng"
msgstr "rom"
msgid "Phase 1: Detecting RC code type"
-msgstr "Faza 1: Detecŝia tipului telecomenzii"
+msgstr "Faza 1: DetecĊ£ia tipului telecomenzii"
msgid "Press any key on the RC unit"
-msgstr "Apsaŝi o tast pe telecomand"
+msgstr "ApăsaĊ£i o tastă pe telecomandă"
msgid "RC code detected!"
msgstr "S-a detectat tipul telecomenzii!"
msgid "Do not press any key..."
-msgstr "Nu apsaŝi nici o tast..."
+msgstr "Nu apăsaĊ£i nici o tastă..."
msgid "Phase 2: Learning specific key codes"
-msgstr "Faza 2: Învŝarea codurilor anumitor taste"
+msgstr "Faza 2: ŽnvăĊ£area codurilor anumitor taste"
#, c-format
msgid "Press key for '%s'"
-msgstr "Apsaŝi tasta pentru '%s'"
+msgstr "ApăsaĊ£i tasta pentru '%s'"
msgid "Press 'Up' to confirm"
-msgstr "Apsaŝi 'Sus' pentru confirmare"
+msgstr "ApăsaĊ£i 'Sus' pentru confirmare"
msgid "Press 'Down' to continue"
-msgstr "Apsaŝi 'Jos' pentru continuare"
+msgstr "ApăsaĊ£i 'Jos' pentru continuare"
msgid "(press 'Up' to go back)"
-msgstr "(Apsaŝi 'Sus' pentru revenire)"
+msgstr "(ApăsaĊ£i 'Sus' pentru revenire)"
msgid "(press 'Down' to end key definition)"
-msgstr "(Apsaŝi 'Jos' pentru terminare)"
+msgstr "(ApăsaĊ£i 'Jos' pentru terminare)"
msgid "(press 'Menu' to skip this key)"
-msgstr "Apsaŝi 'Meniu' pentru a sri peste aceast tast"
+msgstr "ApăsaĊ£i 'Meniu' pentru a sări peste această tastă"
msgid "Learning Remote Control Keys"
-msgstr "Învŝare taste telecomand"
+msgstr "ŽnvăĊ£are taste telecomandă"
msgid "Phase 3: Saving key codes"
msgstr "Faza 3: Salvarea codurilor de taste"
msgid "Press 'Up' to save, 'Down' to cancel"
-msgstr "Apsaŝi 'Sus' pentru salvare, 'Jos' pentru anulare"
+msgstr "ApăsaĊ£i 'Sus' pentru salvare, 'Jos' pentru anulare"
msgid "Key$Up"
msgstr "Sus"
@@ -390,16 +390,16 @@ msgid "Key$Ok"
msgstr "OK"
msgid "Key$Back"
-msgstr "Înapoi"
+msgstr "Žnapoi"
msgid "Key$Left"
-msgstr "Stânga"
+msgstr "St˘nga"
msgid "Key$Right"
msgstr "Dreapta"
msgid "Key$Red"
-msgstr "Roşu"
+msgstr "RoĊŸu"
msgid "Key$Green"
msgstr "Verde"
@@ -417,28 +417,28 @@ msgid "Key$Play"
msgstr "Redare"
msgid "Key$Pause"
-msgstr "Pauz"
+msgstr "Pauză"
msgid "Key$Stop"
msgstr "Stop"
msgid "Key$Record"
-msgstr "Înregistrare"
+msgstr "Žnregistrare"
msgid "Key$FastFwd"
-msgstr "Derulare înainte"
+msgstr "Derulare nainte"
msgid "Key$FastRew"
-msgstr "Derulare înapoi"
+msgstr "Derulare napoi"
msgid "Key$Next"
-msgstr "Urmtor"
+msgstr "Următor"
msgid "Key$Prev"
msgstr "Anterior"
msgid "Key$Power"
-msgstr "Închidere"
+msgstr "Žnchidere"
msgid "Key$Channel+"
msgstr "Canal+"
@@ -456,7 +456,7 @@ msgid "Key$Volume-"
msgstr "Volum-"
msgid "Key$Mute"
-msgstr "Fr sunet"
+msgstr "Fără sunet"
msgid "Key$Audio"
msgstr "Sunet"
@@ -474,10 +474,10 @@ msgid "Key$Timers"
msgstr "Timer-e"
msgid "Key$Recordings"
-msgstr "Înregistrri"
+msgstr "Žnregistrări"
msgid "Key$Setup"
-msgstr "Configuraŝie"
+msgstr "ConfiguraĊ£ie"
msgid "Key$Commands"
msgstr "Comenzi"
@@ -525,10 +525,10 @@ msgid "Name"
msgstr "Nume"
msgid "Source"
-msgstr "Surs"
+msgstr "Sursă"
msgid "Frequency"
-msgstr "Frecvenŝ"
+msgstr "FrecvenĊ£Äƒ"
msgid "Vpid"
msgstr "PID Video"
@@ -558,7 +558,7 @@ msgid "Tpid"
msgstr "PID Teletext"
msgid "CA"
-msgstr "CA (Acces Condiŝional)"
+msgstr "CA (Acces CondiĊ£ional)"
msgid "Sid"
msgstr "Sid"
@@ -570,25 +570,25 @@ msgid "Channels"
msgstr "Canale"
msgid "Button$Edit"
-msgstr "Modific"
+msgstr "Modifică"
msgid "Button$New"
msgstr "Nou"
msgid "Button$Delete"
-msgstr "Şterge"
+msgstr "Ċžterge"
msgid "Button$Mark"
-msgstr "Marcheaz"
+msgstr "Marchează"
msgid "Channel is being used by a timer!"
msgstr "Canalul este utilizat de un timer!"
msgid "Delete channel?"
-msgstr "Şterg canalul?"
+msgstr "Ċžterg canalul?"
msgid "Edit folder"
-msgstr "Editeaz directorul"
+msgstr "Editează directorul"
msgid "New folder"
msgstr "Director nou"
@@ -597,20 +597,20 @@ msgid "Sub folder"
msgstr "Sub-director"
msgid "Folder name already exists!"
-msgstr "Un director cu acelaşi nume exist!"
+msgstr "Un director cu acelaĊŸi nume există!"
#, c-format
msgid "Folder name must not contain '%c'!"
-msgstr "Numele directorului nu poate s conŝin '%c'!"
+msgstr "Numele directorului nu poate să conĊ£ină '%c'!"
msgid "Button$Select"
-msgstr "Selecteaz"
+msgstr "Selectează"
msgid "Delete folder and all sub folders?"
-msgstr "Şterg directorul şi toate sub-directoarele?"
+msgstr "Ċžterg directorul ĊŸi toate sub-directoarele?"
msgid "Delete folder?"
-msgstr "Şterg directorul?"
+msgstr "Ċžterg directorul?"
msgid "Edit timer"
msgstr "Modificare timer"
@@ -625,10 +625,10 @@ msgid "Day"
msgstr "Ziua"
msgid "Start"
-msgstr "Început"
+msgstr "Žnceput"
msgid "Stop"
-msgstr "Sfârşit"
+msgstr "Sf˘rĊŸit"
msgid "VPS"
msgstr "VPS"
@@ -637,25 +637,25 @@ msgid "Priority"
msgstr "Prioritate"
msgid "Lifetime"
-msgstr "Timp de pstrare"
+msgstr "Timp de păstrare"
msgid "File"
-msgstr "Fişier"
+msgstr "FiĊŸier"
msgid "Button$Folder"
msgstr "Director"
msgid "Button$Single"
-msgstr ""
+msgstr "Odată"
msgid "Button$Repeating"
-msgstr ""
+msgstr "Repetitiv"
msgid "First day"
msgstr "Prima zi"
msgid "Select folder"
-msgstr "Selecteaz directorul"
+msgstr "Selectează directorul"
msgid "Timers"
msgstr "Timer-e"
@@ -667,10 +667,10 @@ msgid "Button$Info"
msgstr "Info"
msgid "Delete timer?"
-msgstr "Şterg timer-ul?"
+msgstr "Ċžterg timer-ul?"
msgid "Timer still recording - really delete?"
-msgstr "Timer-ul tocmai înregistreaz - şterg, totuşi?"
+msgstr "Timer-ul tocmai nregistrează - ĊŸterg, totuĊŸi?"
msgid "Event"
msgstr "Emisiune"
@@ -679,19 +679,19 @@ msgid "Button$Timer"
msgstr "Timer"
msgid "Button$Record"
-msgstr "Înregistr."
+msgstr "Žnregistr."
msgid "Button$Switch"
-msgstr "Comut"
+msgstr "Comută"
msgid "What's on now?"
msgstr "Ce emisiuni sunt acum?"
msgid "What's on next?"
-msgstr "Ce emisiuni urmeaz?"
+msgstr "Ce emisiuni urmează?"
msgid "Button$Next"
-msgstr "Urmtor"
+msgstr "Următor"
msgid "Button$Now"
msgstr "Acum"
@@ -708,32 +708,32 @@ msgstr "Programul canalului %s"
#, c-format
msgid "This event - %s"
-msgstr "Aceast emisiune - %s"
+msgstr "Această emisiune - %s"
msgid "This event - all channels"
-msgstr "Aceast emisiune - toate canalele"
+msgstr "Această emisiune - toate canalele"
msgid "All events - all channels"
msgstr "Toate emisiunile - toate canalele"
#, c-format
msgid "Please enter %d digits!"
-msgstr "V rog introduceŝi %d cifre!"
+msgstr "Vă rog introduceĊ£i %d cifre!"
msgid "CAM not responding!"
-msgstr "CAM-ul nu reacŝioneaz!"
+msgstr "CAM-ul nu reacĊ£ionează!"
msgid "Recording info"
-msgstr "Detaliile înregistrrii"
+msgstr "Detaliile nregistrării"
msgid "Button$Play"
msgstr "Redare"
msgid "Button$Rewind"
-msgstr "Înapoi"
+msgstr "Žnapoi"
msgid "Recordings"
-msgstr "Înregistrri"
+msgstr "Žnregistrări"
msgid "Button$Open"
msgstr "Deschide"
@@ -742,28 +742,28 @@ msgid "Commands"
msgstr "Comenzi"
msgid "Error while accessing recording!"
-msgstr "Eroare la accesarea înregistrrii"
+msgstr "Eroare la accesarea nregistrării"
msgid "Delete recording?"
-msgstr "Şterg înregistrarea?"
+msgstr "Ċžterg nregistrarea?"
msgid "Recording is being edited - really delete?"
-msgstr ""
+msgstr "Montajul nregistrării e n curs de desfășurare - șterg totuși?"
msgid "Error while deleting recording!"
-msgstr "Eroare la ştergerea înregistrrii!"
+msgstr "Eroare la ĊŸtergerea nregistrării!"
msgid "Recording commands"
-msgstr "Comenzi pentru înregistrri"
+msgstr "Comenzi pentru nregistrări"
msgid "never"
-msgstr "niciodat"
+msgstr "niciodată"
msgid "skin dependent"
msgstr "dep. de skin"
msgid "always"
-msgstr "întotdeauna"
+msgstr "ntotdeauna"
msgid "OSD"
msgstr "OSD"
@@ -775,22 +775,22 @@ msgid "Setup.OSD$Skin"
msgstr "Skin"
msgid "Setup.OSD$Theme"
-msgstr "Tem"
+msgstr "Temă"
msgid "Setup.OSD$Left (%)"
-msgstr "Stânga (%)"
+msgstr "St˘nga (%)"
msgid "Setup.OSD$Top (%)"
msgstr "Sus (%)"
msgid "Setup.OSD$Width (%)"
-msgstr "Lŝime OSD (%)"
+msgstr "LăĊ£ime OSD (%)"
msgid "Setup.OSD$Height (%)"
-msgstr "Înlŝime OSD (%)"
+msgstr "ŽnălĊ£ime OSD (%)"
msgid "Setup.OSD$Message time (s)"
-msgstr "Timp afişare mesaje (sec)"
+msgstr "Timp afiĊŸare mesaje (sec)"
msgid "Setup.OSD$Use small font"
msgstr "Utilizare fonturi mici"
@@ -805,19 +805,19 @@ msgid "Setup.OSD$Small font"
msgstr "Font mic"
msgid "Setup.OSD$Fixed font"
-msgstr "Font cu lŝime fix"
+msgstr "Font cu lăĊ£ime fixă"
msgid "Setup.OSD$Default font size (%)"
-msgstr "Mrimea implicit a fontului (%)"
+msgstr "Mărimea implicită a fontului (%)"
msgid "Setup.OSD$Small font size (%)"
-msgstr "Mrimea 'mic' a fontului (%)"
+msgstr "Mărimea 'mică' a fontului (%)"
msgid "Setup.OSD$Fixed font size (%)"
-msgstr "Mrimea 'fix' a fontului (%)"
+msgstr "Mărimea 'fixă' a fontului (%)"
msgid "Setup.OSD$Channel info position"
-msgstr "Poziŝia informaŝiilor despre canal"
+msgstr "PoziĊ£ia informaĊ£iilor despre canal"
msgid "bottom"
msgstr "jos"
@@ -826,61 +826,61 @@ msgid "top"
msgstr "sus"
msgid "Setup.OSD$Channel info time (s)"
-msgstr "Durata afişrii info-canal (s)"
+msgstr "Durata afiĊŸÄƒrii info-canal (s)"
msgid "Setup.OSD$Info on channel switch"
-msgstr "Informaŝii la comutarea canalului"
+msgstr "InformaĊ£ii la comutarea canalului"
msgid "Setup.OSD$Timeout requested channel info"
-msgstr "Durata afişrii informaŝii canal"
+msgstr "Durata afiĊŸÄƒrii informaĊ£ii canal"
msgid "Setup.OSD$Scroll pages"
-msgstr "Deruleaz pagini"
+msgstr "Derulează pagini"
msgid "Setup.OSD$Scroll wraps"
-msgstr "Derulare circular"
+msgstr "Derulare circulară"
msgid "Setup.OSD$Menu key closes"
-msgstr "Tasta 'Meniu' închide"
+msgstr "Tasta 'Meniu' nchide"
msgid "Setup.OSD$Recording directories"
-msgstr "Directoare înregistrri"
+msgstr "Directoare nregistrări"
msgid "Setup.OSD$Folders in timer menu"
-msgstr "Directoare în meniul de timer-e"
+msgstr "Directoare n meniul de timer-e"
msgid "Setup.OSD$Number keys for characters"
msgstr "Caractere pe tastele numerice"
msgid "Setup.OSD$Color key 0"
-msgstr ""
+msgstr "Primul buton colorat"
msgid "Setup.OSD$Color key 1"
-msgstr ""
+msgstr "Al 2-lea buton colorat"
msgid "Setup.OSD$Color key 2"
-msgstr ""
+msgstr "Al 3-lea buton colorat"
msgid "Setup.OSD$Color key 3"
-msgstr ""
+msgstr "Al 4-lea buton colorat"
msgid "EPG"
msgstr "EPG"
msgid "Button$Scan"
-msgstr "Cutare canale"
+msgstr "Căutare canale"
msgid "Setup.EPG$EPG scan timeout (h)"
-msgstr "Interval achiziŝie EPG (h)"
+msgstr "Interval achiziĊ£ie EPG (h)"
msgid "Setup.EPG$EPG bugfix level"
-msgstr "Nivel corecŝie EPG"
+msgstr "Nivel corecĊ£ie EPG"
msgid "Setup.EPG$EPG linger time (min)"
msgstr "Date EPG expirate cel mult (min)"
msgid "Setup.EPG$Set system time"
-msgstr "Potriveşte ceasul sistem"
+msgstr "PotriveĊŸte ceasul sistem"
msgid "Setup.EPG$Use time from transponder"
msgstr "Preia ora din transponder"
@@ -891,7 +891,7 @@ msgstr "Limbi preferate"
#. TRANSLATORS: note the singular!
msgid "Setup.EPG$Preferred language"
-msgstr "Limba preferat"
+msgstr "Limba preferată"
msgid "pan&scan"
msgstr "pan&scan"
@@ -915,10 +915,10 @@ msgid "names and PIDs"
msgstr "nume si PID-uri"
msgid "add new channels"
-msgstr "adugare canale noi"
+msgstr "adăugare canale noi"
msgid "add new transponders"
-msgstr "adugare transpondere noi"
+msgstr "adăugare transpondere noi"
msgid "DVB"
msgstr "Dispozitiv DVB"
@@ -930,16 +930,16 @@ msgid "Button$Subtitles"
msgstr "Subtitrare"
msgid "Setup.DVB$Primary DVB interface"
-msgstr "Dispozitiv DVB primar"
+msgstr "Interfață DVB primară"
msgid "Setup.DVB$Standard compliance"
-msgstr ""
+msgstr "Standard de recepție"
msgid "Setup.DVB$Video format"
msgstr "Format video"
msgid "Setup.DVB$Video display format"
-msgstr "Formatul redrii video"
+msgstr "Formatul redării video"
msgid "Setup.DVB$Use Dolby Digital"
msgstr "Sunet Dolby Digital"
@@ -954,22 +954,22 @@ msgid "Setup.DVB$Audio language"
msgstr "Limba sunetului"
msgid "Setup.DVB$Display subtitles"
-msgstr "Afişeaz subtitrare"
+msgstr "AfiĊŸează subtitrare"
msgid "Setup.DVB$Subtitle languages"
msgstr "Limbi subtitrare"
msgid "Setup.DVB$Subtitle language"
-msgstr "Limb subtitrare"
+msgstr "Limbă subtitrare"
msgid "Setup.DVB$Subtitle offset"
msgstr "Offset subtitrare"
msgid "Setup.DVB$Subtitle foreground transparency"
-msgstr "Transparenŝa prim-planului subtitrrii"
+msgstr "TransparenĊ£a prim-planului subtitrării"
msgid "Setup.DVB$Subtitle background transparency"
-msgstr "Transparenŝa fundalului subtitrrii"
+msgstr "TransparenĊ£a fundalului subtitrării"
msgid "LNB"
msgstr "LNB"
@@ -978,20 +978,20 @@ msgid "Setup.LNB$Use DiSEqC"
msgstr "Utilizare DiSEqC"
msgid "Setup.LNB$SLOF (MHz)"
-msgstr "Frecvenŝ comutare band, SLOF (MHz)"
+msgstr "FrecvenĊ£Äƒ comutare bandă, SLOF (MHz)"
msgid "Setup.LNB$Low LNB frequency (MHz)"
-msgstr "Frecvnŝ LNB inferioar (Mhz)"
+msgstr "FrecvnĊ£Äƒ LNB inferioară (Mhz)"
msgid "Setup.LNB$High LNB frequency (MHz)"
-msgstr "Frecvnŝ LNB superioar (MHz)"
+msgstr "FrecvnĊ£Äƒ LNB superioară (MHz)"
#, c-format
msgid "Setup.LNB$Device %d connected to sat cable"
-msgstr ""
+msgstr "Receptorul %d conectat la cablul de satelit"
msgid "Setup.LNB$own"
-msgstr ""
+msgstr "propriu"
msgid "CAM reset"
msgstr "Resetare CAM"
@@ -1000,7 +1000,7 @@ msgid "CAM present"
msgstr "CAM prezent"
msgid "CAM ready"
-msgstr "CAM pregtit"
+msgstr "CAM pregătit"
msgid "CAM"
msgstr "CAM"
@@ -1018,19 +1018,19 @@ msgid "Can't open CAM menu!"
msgstr "Nu pot deschide meniul CAM"
msgid "CAM is in use - really reset?"
-msgstr "CAM-ul este in folosinŝ - totuşi resetez?"
+msgstr "CAM-ul este in folosinĊ£Äƒ - totuĊŸi resetez?"
msgid "Can't reset CAM!"
msgstr "Nu pot reseta CAM"
msgid "do not pause live video"
-msgstr "nu înregistra emisiunea"
+msgstr "nu nregistra emisiunea"
msgid "confirm pause live video"
-msgstr "confirm înregistrarea emisiunii"
+msgstr "confirmă nregistrarea emisiunii"
msgid "pause live video"
-msgstr "înregistreaz emisiunea"
+msgstr "nregistrează emisiunea"
msgid "confirm"
msgstr "confirmare"
@@ -1039,70 +1039,70 @@ msgid "yes"
msgstr "da"
msgid "Recording"
-msgstr "Înregistrare"
+msgstr "Žnregistrare"
msgid "Setup.Recording$Margin at start (min)"
-msgstr "Marj la pornire (min)"
+msgstr "Marjă la pornire (min)"
msgid "Setup.Recording$Margin at stop (min)"
-msgstr "Marj la oprire (min)"
+msgstr "Marjă la oprire (min)"
msgid "Setup.Recording$Default priority"
-msgstr "Prioritate implicit"
+msgstr "Prioritate implicită"
msgid "Setup.Recording$Default lifetime (d)"
-msgstr "Timp de pstrare predefinit (zile)"
+msgstr "Timp de păstrare predefinit (zile)"
msgid "Setup.Recording$Pause key handling"
-msgstr "Funcŝia tastei 'pauz'"
+msgstr "FuncĊ£ia tastei 'pauză'"
msgid "Setup.Recording$Pause priority"
-msgstr "Prioritate pauz"
+msgstr "Prioritate pauză"
msgid "Setup.Recording$Pause lifetime (d)"
-msgstr "Pstrarea emisiunilor 'pauzate' (zile)"
+msgstr "Păstrarea emisiunilor 'pauzate' (zile)"
msgid "Setup.Recording$Use episode name"
-msgstr "Utilizeaz numele episodului"
+msgstr "Utilizează numele episodului"
msgid "Setup.Recording$Use VPS"
-msgstr "Utilizeaz VPS"
+msgstr "Utilizează VPS"
msgid "Setup.Recording$VPS margin (s)"
-msgstr "Marj de timp la utilizare VPS (s)"
+msgstr "Marjă de timp la utilizare VPS (s)"
msgid "Setup.Recording$Mark instant recording"
-msgstr "Marcheaz înregistrare imediat"
+msgstr "Marchează nregistrare imediată"
msgid "Setup.Recording$Name instant recording"
-msgstr "Nume înregistrare imediat"
+msgstr "Nume nregistrare imediată"
msgid "Setup.Recording$Instant rec. time (min)"
-msgstr "Timpul de înregistare imediat (min)"
+msgstr "Timpul de nregistare imediată (min)"
msgid "Setup.Recording$present event"
-msgstr ""
+msgstr "eveniment curent"
msgid "Setup.Recording$Max. video file size (MB)"
-msgstr "Dimensiune maxim a fişierului video (MB)"
+msgstr "Dimensiune maximă a fiĊŸierului video (MB)"
msgid "Setup.Recording$Split edited files"
-msgstr "Separare fişiere montate"
+msgstr "Separare fiĊŸiere montate"
msgid "Setup.Recording$Delete timeshift recording"
-msgstr "Şterge înregistrarea pentru vizionare decalat"
+msgstr "Ċžterge nregistrarea pentru vizionare decalată"
msgid "Replay"
msgstr "Redare"
msgid "Setup.Replay$Multi speed mode"
-msgstr "Mod multi-vitez"
+msgstr "Mod multi-viteză"
msgid "Setup.Replay$Show replay mode"
-msgstr "Afişeaz redarea"
+msgstr "AfiĊŸează redarea"
msgid "Setup.Replay$Show remaining time"
-msgstr ""
+msgstr "Arată timpul rămas"
msgid "Setup.Replay$Resume ID"
msgstr "Identificator continuare"
@@ -1111,10 +1111,10 @@ msgid "Miscellaneous"
msgstr "Diverse"
msgid "Setup.Miscellaneous$Min. event timeout (min)"
-msgstr "Durat minim emisiuni (min)"
+msgstr "Durată minimă emisiuni (min)"
msgid "Setup.Miscellaneous$Min. user inactivity (min)"
-msgstr "Durata minim de inactivitate (min)"
+msgstr "Durata minimă de inactivitate (min)"
msgid "Setup.Miscellaneous$SVDRP timeout (s)"
msgstr "Timeout SVDRP (sec)"
@@ -1129,28 +1129,28 @@ msgid "Setup.Miscellaneous$Initial channel"
msgstr "Canalul de pornire"
msgid "Setup.Miscellaneous$as before"
-msgstr "ca mai înainte"
+msgstr "ca mai nainte"
msgid "Setup.Miscellaneous$Initial volume"
msgstr "Volumul la pornire"
msgid "Setup.Miscellaneous$Channels wrap"
-msgstr "Lista de canale în bucl"
+msgstr "Lista de canale n buclă"
msgid "Setup.Miscellaneous$Show channel names with source"
-msgstr ""
+msgstr "Arată numele canalelor cu sursa"
msgid "Setup.Miscellaneous$Emergency exit"
-msgstr "Oprire de urgenŝ"
+msgstr "Oprire de urgenĊ£Äƒ"
msgid "Plugins"
msgstr "Plugin-uri"
msgid "This plugin has no setup parameters!"
-msgstr "Acest plugin nu se configureaz!"
+msgstr "Acest plugin nu se configurează!"
msgid "Setup"
-msgstr "Configuraŝie"
+msgstr "ConfiguraĊ£ie"
msgid "Restart"
msgstr "Repornire"
@@ -1160,17 +1160,17 @@ msgstr "Sigur repornesc?"
#. TRANSLATORS: note the leading and trailing blanks!
msgid " Stop recording "
-msgstr " Opreşte înregistrarea "
+msgstr " OpreĊŸte nregistrarea "
msgid "Schedule"
msgstr "Program (EPG)"
#. TRANSLATORS: note the leading blank!
msgid " Stop replaying"
-msgstr " Opreşte redarea"
+msgstr " OpreĊŸte redarea"
msgid "Button$Pause"
-msgstr "Pauz"
+msgstr "Pauză"
msgid "Button$Stop"
msgstr "Stop"
@@ -1180,56 +1180,59 @@ msgstr "Continuare"
#. TRANSLATORS: note the leading blank!
msgid " Cancel editing"
-msgstr " Opreşte montajul înregistrrii"
+msgstr " OpreĊŸte montajul nregistrării"
msgid "Stop recording?"
-msgstr "Opresc înregistrarea?"
+msgstr "Opresc nregistrarea?"
msgid "Cancel editing?"
-msgstr "Opresc montajul înregistrrii?"
+msgstr "Opresc montajul nregistrării?"
msgid "No audio available!"
-msgstr "Lipseşte sunetul!"
+msgstr "LipseĊŸte sunetul!"
msgid "No subtitles"
-msgstr "Nu afişeaz subtirare"
+msgstr "Nu afiĊŸează subtirare"
msgid "No subtitles available!"
-msgstr "Subtitrare indisponibil!"
+msgstr "Subtitrare indisponibilă!"
msgid "Not enough disk space to start recording!"
-msgstr "Insuficient spaŝiul pe disc pentru înregistrare!"
+msgstr "Insuficient spaĊ£iul pe disc pentru nregistrare!"
msgid "No free DVB device to record!"
-msgstr "Nu mai sunt dispozitive DVB disponibile pentru înregistrare!"
+msgstr "Nu mai sunt receptoare DVB disponibile pentru nregistrare!"
msgid "Pausing live video..."
-msgstr "Trec în pauz emisiunea transmis..."
+msgstr "Trec n pauză emisiunea transmisă..."
msgid "Delete timeshift recording?"
-msgstr "Şterg înregistrarea pentru vizionare decalat?"
+msgstr "Ċžterg nregistrarea pentru vizionare decalată?"
#. TRANSLATORS: note the trailing blank!
msgid "Jump: "
msgstr "Salt la: "
msgid "No editing marks defined!"
-msgstr "Nu s-au pus marcaje de montaj pentru aceast înregistrare"
+msgstr "Nu s-au pus marcaje de montaj pentru această nregistrare"
+
+msgid "No editing sequences defined!"
+msgstr ""
msgid "Can't start editing process!"
-msgstr "Nu pot porni montajul înregistrrii!"
+msgstr "Nu pot porni montajul nregistrării!"
msgid "Editing process started"
-msgstr "Montajul înregistrrii a început"
+msgstr "Montajul nregistrării a nceput"
msgid "Editing process already active!"
-msgstr "Montajul înregistrrii este deja activ!"
+msgstr "Montajul nregistrării este deja activ!"
msgid "FileNameChars$ abcdefghijklmnopqrstuvwxyz0123456789-.,#~\\^$[]|()*+?{}/:%@&"
-msgstr " aâbcdefghiîjklmnopqrsştŝuvwxyz0123456789-.,#~\\^$[]|()*+?{}/:%@&"
+msgstr " aă˘bcdefghijklmnopqrsĊŸtĊ£uvwxyz0123456789-.,#~\\^$[]|()*+?{}/:%@&"
msgid "CharMap$ 0\t-.,1#~\\^$[]|()*+?{}/:%@&\tabc2\tdef3\tghi4\tjkl5\tmno6\tpqrs7\ttuv8\twxyz9"
-msgstr " 0\t-.,1#~\\^$[]|()*+?{}/:%@&\taâbc2\tdef3\tghiî4\tjkl5\tmno6\tpqrsş7\ttŝuv8\twxyz9"
+msgstr " 0\t-.,1#~\\^$[]|()*+?{}/:%@&\taă˘bc2\tdef3\tghi4\tjkl5\tmno6\tpqrsĊŸ7\ttĊ£uv8\twxyz9"
msgid "Button$ABC/abc"
msgstr "ABC/abc"
@@ -1238,19 +1241,19 @@ msgid "Button$Overwrite"
msgstr "Suprascrie"
msgid "Button$Insert"
-msgstr "Insereaz"
+msgstr "Inserează"
msgid "Plugin"
-msgstr "Plugin (modul adiŝional)"
+msgstr "Plugin (modul adiĊ£ional)"
msgid "Up/Dn for new location - OK to move"
-msgstr "Sus/Jos pentru noua locaŝie - OK pentru a muta"
+msgstr "Sus/Jos pentru noua locaĊ£ie - OK pentru a muta"
msgid "Channel locked (recording)!"
-msgstr "Canal blocat (înregistrare)!"
+msgstr "Canal blocat (nregistrare)!"
msgid "Low disk space!"
-msgstr "Spaŝiul pe disc e foarte sczut!"
+msgstr "SpaĊ£iul pe disc e foarte scăzut!"
msgid "Regenerating index file"
msgstr "Generez index"
@@ -1259,36 +1262,36 @@ msgid "Index file regeneration complete"
msgstr "Generarea indexului s-a incheiat"
msgid "Index file regeneration failed!"
-msgstr ""
+msgstr "Generarea indexului a eșuat!"
msgid "Can't shutdown - option '-s' not given!"
-msgstr "Nu pot închide - vezi opŝiunea '-s'"
+msgstr "Nu pot nchide - vezi opĊ£iunea '-s'"
msgid "Editing - shut down anyway?"
-msgstr "Montajul tocmai se efectueaz - închid, totuşi?"
+msgstr "Montajul tocmai se efectuează - nchid, totuĊŸi?"
msgid "Recording - shut down anyway?"
-msgstr "Tocmai se înregistreaz - închid, totuşi?"
+msgstr "Tocmai se nregistrează - nchid, totuĊŸi?"
#, c-format
msgid "Recording in %ld minutes, shut down anyway?"
-msgstr "Înregistrez peste %ld minute - închid, totuşi?"
+msgstr "Žnregistrez peste %ld minute - nchid, totuĊŸi?"
msgid "shut down anyway?"
-msgstr "închid, totuşi?"
+msgstr "nchid, totuĊŸi?"
#, c-format
msgid "Plugin %s wakes up in %ld min, continue?"
msgstr "Plugin-ul %s se va trezi +n %ld min, continui?"
msgid "Editing - restart anyway?"
-msgstr "Montajul tocmai se efectueaz - repornesc, totuşi?"
+msgstr "Montajul tocmai se efectuează - repornesc, totuĊŸi?"
msgid "Recording - restart anyway?"
-msgstr "Tocmai se înregistreaz - repornesc, totuşi?"
+msgstr "Tocmai se nregistrează - repornesc, totuĊŸi?"
msgid "restart anyway?"
-msgstr "repornesc, totuşi?"
+msgstr "repornesc, totuĊŸi?"
#. TRANSLATORS: note the trailing blank!
msgid "Volume "
@@ -1298,22 +1301,22 @@ msgid "Classic VDR"
msgstr "VDR clasic"
msgid "DISK"
-msgstr ""
+msgstr "HARD-DISC"
msgid "LOAD"
-msgstr ""
+msgstr "SARCINĂ"
msgid "TIMERS"
-msgstr ""
+msgstr "TIMER-E"
msgid "DEVICES"
-msgstr ""
+msgstr "RECEPTOARE"
msgid "LIVE"
-msgstr ""
+msgstr "LIVE"
msgid "PLAY"
-msgstr ""
+msgstr "REDARE"
msgid "ST:TNG Panels"
msgstr "Cons. ST:TNG"
@@ -1324,13 +1327,13 @@ msgstr "LMMJVSD"
#. TRANSLATORS: abbreviated weekdays, beginning with monday (must all be 3 letters!)
msgid "MonTueWedThuFriSatSun"
-msgstr "LunMarMieJoiVinSâmDum"
+msgstr "LunMarMieJoiVinS˘mDum"
msgid "Monday"
msgstr "Luni"
msgid "Tuesday"
-msgstr "Marŝi"
+msgstr "MarĊ£i"
msgid "Wednesday"
msgstr "Miercuri"
@@ -1342,41 +1345,41 @@ msgid "Friday"
msgstr "Vineri"
msgid "Saturday"
-msgstr "Sâmbt"
+msgstr "S˘mbătă"
msgid "Sunday"
-msgstr "Duminic"
+msgstr "Duminică"
msgid "Upcoming recording!"
-msgstr "Urmeaz o înregistrare!"
+msgstr "Urmează o nregistrare!"
msgid "Pause live video?"
-msgstr "Înregistrez emisiunea?"
+msgstr "Žnregistrez emisiunea?"
msgid "Recording started"
-msgstr "A început înregistrarea"
+msgstr "A nceput nregistrarea"
msgid "VDR will shut down later - press Power to force"
-msgstr "VDR se va închide mai târziu - apsaŝi 'Power' pentru a forŝa"
+msgstr "VDR se va nchide mai t˘rziu - apăsaĊ£i 'Power' pentru a forĊ£a"
msgid "Press any key to cancel shutdown"
-msgstr "Apas orice tast pentru a anula închiderea"
+msgstr "Apasă orice tastă pentru a anula nchiderea"
msgid "Switching primary DVB..."
msgstr "Comut dispozitiv DVB primar..."
msgid "Editing process failed!"
-msgstr "Montajul înregistrrii a eşuat"
+msgstr "Montajul nregistrării a eĊŸuat"
msgid "Editing process finished"
-msgstr "Montajul înregistrrii s-a terminat"
+msgstr "Montajul nregistrării s-a terminat"
msgid "Press any key to cancel restart"
-msgstr "Apsaŝi orice tast pentru a anula repornirea"
+msgstr "ApăsaĊ£i orice tastă pentru a anula repornirea"
#, c-format
msgid "VDR will shut down in %s minutes"
-msgstr "VDR se va închide în %s minute"
+msgstr "VDR se va nchide n %s minute"
msgid "Disk"
msgstr "Disc"
diff --git a/po/ru_RU.po b/po/ru_RU.po
index d8e1e8e..b58fd9a 100644
--- a/po/ru_RU.po
+++ b/po/ru_RU.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-12-15 14:37+0100\n"
"Last-Translator: Oleg Roitburd <oleg@roitburd.de>\n"
"Language-Team: Russian <vdr@linuxtv.org>\n"
@@ -1214,6 +1214,9 @@ msgstr "żĠàĠÙâĜ: "
msgid "No editing marks defined!"
msgstr "½Ġ ×ÔŬë ÜĠâÚĜ ÔÛï ÜŜŬâÖ!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "½ĠÒŜ×ÜŜÖŬŜ Ŭçâì ÜŜŬâÖ ×ßĜáĜ!"
diff --git a/po/sk_SK.po b/po/sk_SK.po
index 0de2d06..ab5035e 100644
--- a/po/sk_SK.po
+++ b/po/sk_SK.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.7.16\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2011-02-15 16:29+0100\n"
"Last-Translator: Milan Hrala <hrala.milan@gmail.com>\n"
"Language-Team: Slovak <vdr@linuxtv.org>\n"
@@ -1213,6 +1213,9 @@ msgstr "Skok: "
msgid "No editing marks defined!"
msgstr "Nie sú urèené znaèky úprav!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Nemôe zaèağ spracovanie úprav!"
diff --git a/po/sl_SI.po b/po/sl_SI.po
index 9556868..9326d85 100644
--- a/po/sl_SI.po
+++ b/po/sl_SI.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-02-28 19:44+0100\n"
"Last-Translator: Matjaz Thaler <matjaz.thaler@guest.arnes.si>\n"
"Language-Team: Slovenian <vdr@linuxtv.org>\n"
@@ -1214,6 +1214,9 @@ msgstr "Skoèi: "
msgid "No editing marks defined!"
msgstr "Nobena prekinitvena toèka ni definirana!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Ne morem zaèeti urejanja!"
diff --git a/po/sr_SR.po b/po/sr_SR.po
index c4149dd..c7b97d5 100644
--- a/po/sr_SR.po
+++ b/po/sr_SR.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.7.1\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2011-01-09 15:57+0100\n"
"Last-Translator: Milan Cvijanoviĉ <elcom_cvijo@hotmail.com>\n"
"Language-Team: Serbian <vdr@linuxtv.org>\n"
@@ -1239,6 +1239,9 @@ msgstr "Skoèi: "
msgid "No editing marks defined!"
msgstr "Nijedna taèka rezanja nije odreena!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Ne mogu zapoèeti ureivanje!"
diff --git a/po/sv_SE.po b/po/sv_SE.po
index 951dd04..dc4d620 100644
--- a/po/sv_SE.po
+++ b/po/sv_SE.po
@@ -10,7 +10,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-03-12 18:25+0100\n"
"Last-Translator: Magnus Andersson <svankan@bahnhof.se>\n"
"Language-Team: Swedish <vdr@linuxtv.org>\n"
@@ -1216,6 +1216,9 @@ msgstr "Hopp: "
msgid "No editing marks defined!"
msgstr "Det finns inga redigeringsmärken"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Kan inte starta redigering!"
diff --git a/po/tr_TR.po b/po/tr_TR.po
index 8b161b3..1f61944 100644
--- a/po/tr_TR.po
+++ b/po/tr_TR.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2008-02-28 00:33+0100\n"
"Last-Translator: Oktay Yolgeçen <oktay_73@yahoo.de>\n"
"Language-Team: Turkish <vdr@linuxtv.org>\n"
@@ -1213,6 +1213,9 @@ msgstr "Atla: "
msgid "No editing marks defined!"
msgstr "Kesim iŝaretleri belirtilmemiŝ!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "Kesim baŝlatŭlamŭyor!"
diff --git a/po/uk_UA.po b/po/uk_UA.po
index 45e57ee..72fe84c 100644
--- a/po/uk_UA.po
+++ b/po/uk_UA.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.7.7\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2010-04-25 16:35+0200\n"
"Last-Translator: Yarema aka Knedlyk <yupadmin@gmail.com>\n"
"Language-Team: Ukrainian <vdr@linuxtv.org>\n"
@@ -1213,6 +1213,9 @@ msgstr "ŸµÑ€µıт¸: "
msgid "No editing marks defined!"
msgstr "µ ·°´°½ ĵітş ´ğя ĵ½Ñ‚°ĥу!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "µĵĥ𸲠żÑ‡°Ñ‚¸ ĵ½Ñ‚°ĥ ·°ż¸ÑÑƒ!"
diff --git a/po/zh_CN.po b/po/zh_CN.po
index 4e2b951..56b2de0 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VDR 1.6.0\n"
"Report-Msgid-Bugs-To: <vdr-bugs@tvdr.de>\n"
-"POT-Creation-Date: 2012-09-15 14:04+0200\n"
+"POT-Creation-Date: 2012-11-18 14:31+0100\n"
"PO-Revision-Date: 2009-09-23 23:50+0800\n"
"Last-Translator: Nan Feng <nfgx@21cn.com>\n"
"Language-Team: Chinese (simplified) <vdr@linuxtv.org>\n"
@@ -1216,6 +1216,9 @@ msgstr "è·³èż‡: "
msgid "No editing marks defined!"
msgstr "ĉ— çĵ–è‘ĉ ‡è°ċšäı‰!"
+msgid "No editing sequences defined!"
+msgstr ""
+
msgid "Can't start editing process!"
msgstr "不能ċĵ€ċ§‹çĵ–è‘ċ¤„理"
diff --git a/recording.c b/recording.c
index 1eeb82d..497bf2d 100644
--- a/recording.c
+++ b/recording.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: recording.c 2.64 2012/09/30 13:05:14 kls Exp $
+ * $Id: recording.c 2.73 2012/11/13 13:46:49 kls Exp $
*/
#include "recording.h"
@@ -83,20 +83,20 @@ public:
};
cRemoveDeletedRecordingsThread::cRemoveDeletedRecordingsThread(void)
-:cThread("remove deleted recordings")
+:cThread("remove deleted recordings", true)
{
}
void cRemoveDeletedRecordingsThread::Action(void)
{
- SetPriority(19);
- SetIOPriority(7);
// Make sure only one instance of VDR does this:
cLockFile LockFile(VideoDirectory);
if (LockFile.Lock()) {
bool deleted = false;
cThreadLock DeletedRecordingsLock(&DeletedRecordings);
for (cRecording *r = DeletedRecordings.First(); r; ) {
+ if (cIoThrottle::Engaged())
+ return;
if (r->Deleted() && time(NULL) - r->Deleted() > DELETEDLIFETIME) {
cRecording *next = DeletedRecordings.Next(r);
r->Remove();
@@ -1358,8 +1358,10 @@ bool cMark::Save(FILE *f)
bool cMarks::Load(const char *RecordingFileName, double FramesPerSecond, bool IsPesRecording)
{
+ recordingFileName = RecordingFileName;
fileName = AddDirectory(RecordingFileName, IsPesRecording ? MARKSFILESUFFIX ".vdr" : MARKSFILESUFFIX);
framesPerSecond = FramesPerSecond;
+ isPesRecording = IsPesRecording;
nextUpdate = 0;
lastFileTime = -1; // the first call to Load() must take place!
lastChange = 0;
@@ -1388,6 +1390,7 @@ bool cMarks::Update(void)
cMutexLock MutexLock(&MutexMarkFramesPerSecond);
MarkFramesPerSecond = framesPerSecond;
if (cConfig<cMark>::Load(fileName)) {
+ Align();
Sort();
return true;
}
@@ -1396,6 +1399,18 @@ bool cMarks::Update(void)
return false;
}
+void cMarks::Align(void)
+{
+ cIndexFile IndexFile(recordingFileName, false, isPesRecording);
+ for (cMark *m = First(); m; m = Next(m)) {
+ int p = IndexFile.GetClosestIFrame(m->Position());
+ if (int d = m->Position() - p) {
+ isyslog("aligned editing mark %s to %s (off by %d frame%s)", *IndexToHMSF(m->Position(), true, framesPerSecond), *IndexToHMSF(p, true, framesPerSecond), d, abs(d) > 1 ? "s" : "");
+ m->SetPosition(p);
+ }
+ }
+}
+
void cMarks::Sort(void)
{
for (cMark *m1 = First(); m1; m1 = Next(m1)) {
@@ -1408,14 +1423,10 @@ void cMarks::Sort(void)
}
}
-cMark *cMarks::Add(int Position)
+void cMarks::Add(int Position)
{
- cMark *m = Get(Position);
- if (!m) {
- cConfig<cMark>::Add(m = new cMark(Position, NULL, framesPerSecond));
- Sort();
- }
- return m;
+ cConfig<cMark>::Add(new cMark(Position, NULL, framesPerSecond));
+ Sort();
}
cMark *cMarks::Get(int Position)
@@ -1445,6 +1456,54 @@ cMark *cMarks::GetNext(int Position)
return NULL;
}
+cMark *cMarks::GetNextBegin(cMark *EndMark)
+{
+ cMark *BeginMark = EndMark ? Next(EndMark) : First();
+ if (BeginMark) {
+ while (cMark *NextMark = Next(BeginMark)) {
+ if (BeginMark->Position() == NextMark->Position()) { // skip Begin/End at the same position
+ if (!(BeginMark = Next(NextMark)))
+ break;
+ }
+ else
+ break;
+ }
+ }
+ return BeginMark;
+}
+
+cMark *cMarks::GetNextEnd(cMark *BeginMark)
+{
+ if (!BeginMark)
+ return NULL;
+ cMark *EndMark = Next(BeginMark);
+ if (EndMark) {
+ while (cMark *NextMark = Next(EndMark)) {
+ if (EndMark->Position() == NextMark->Position()) { // skip End/Begin at the same position
+ if (!(EndMark = Next(NextMark)))
+ break;
+ }
+ else
+ break;
+ }
+ }
+ return EndMark;
+}
+
+int cMarks::GetNumSequences(void)
+{
+ int NumSequences = 0;
+ if (cMark *BeginMark = GetNextBegin()) {
+ while (cMark *EndMark = GetNextEnd(BeginMark)) {
+ NumSequences++;
+ BeginMark = GetNextBegin(EndMark);
+ }
+ if (NumSequences == 0 && BeginMark->Position() > 0)
+ NumSequences = 1; // there is only one actual "begin" mark at a non-zero offset, and no actual "end" mark
+ }
+ return NumSequences;
+}
+
// --- cRecordingUserCommand -------------------------------------------------
const char *cRecordingUserCommand::command = NULL;
@@ -1535,7 +1594,6 @@ void cIndexFileGenerator::Action(void)
if (Processed > 0) {
if (FrameDetector.Synced()) {
// Synced FrameDetector, so rewind for actual processing:
- FrameDetector.Reset();
Rewind = true;
}
Buffer.Del(Processed);
@@ -1546,7 +1604,7 @@ void cIndexFileGenerator::Action(void)
uchar *p = Data;
while (Length >= TS_SIZE) {
int Pid = TsPid(p);
- if (Pid == 0)
+ if (Pid == PATPID)
PatPmtParser.ParsePat(p, TS_SIZE);
else if (Pid == PatPmtParser.PmtPid())
PatPmtParser.ParsePmt(p, TS_SIZE);
@@ -1570,6 +1628,7 @@ void cIndexFileGenerator::Action(void)
ReplayFile = FileName.NextFile();
FileSize = 0;
FrameOffset = -1;
+ Buffer.Clear();
}
}
// Recording has been processed:
@@ -1753,7 +1812,7 @@ bool cIndexFile::CatchUp(int Index)
// returns true unless something really goes wrong, so that 'index' becomes NULL
if (index && f >= 0) {
cMutexLock MutexLock(&mutex);
- for (int i = 0; i <= MAXINDEXCATCHUP && (Index < 0 || Index >= last); i++) {
+ for (int i = 0; i <= MAXINDEXCATCHUP && (Index < 0 || Index > last); i++) {
struct stat buf;
if (fstat(f, &buf) == 0) {
if (!IsInIndexList(this)) {
@@ -1798,7 +1857,7 @@ bool cIndexFile::CatchUp(int Index)
}
else
LOG_ERROR_STR(*fileName);
- if (Index < last)
+ if (Index <= last)
break;
cCondWait::SleepMs(1000);
}
@@ -1826,18 +1885,22 @@ bool cIndexFile::Write(bool Independent, uint16_t FileNumber, off_t FileOffset)
bool cIndexFile::Get(int Index, uint16_t *FileNumber, off_t *FileOffset, bool *Independent, int *Length)
{
if (CatchUp(Index)) {
- if (Index >= 0 && Index < last) {
+ if (Index >= 0 && Index <= last) {
*FileNumber = index[Index].number;
*FileOffset = index[Index].offset;
if (Independent)
*Independent = index[Index].independent;
if (Length) {
- uint16_t fn = index[Index + 1].number;
- off_t fo = index[Index + 1].offset;
- if (fn == *FileNumber)
- *Length = int(fo - *FileOffset);
+ if (Index < last) {
+ uint16_t fn = index[Index + 1].number;
+ off_t fo = index[Index + 1].offset;
+ if (fn == *FileNumber)
+ *Length = int(fo - *FileOffset);
+ else
+ *Length = -1; // this means "everything up to EOF" (the buffer's Read function will act accordingly)
+ }
else
- *Length = -1; // this means "everything up to EOF" (the buffer's Read function will act accordingly)
+ *Length = -1;
}
return true;
}
@@ -1851,7 +1914,7 @@ int cIndexFile::GetNextIFrame(int Index, bool Forward, uint16_t *FileNumber, off
int d = Forward ? 1 : -1;
for (;;) {
Index += d;
- if (Index >= 0 && Index < last) {
+ if (Index >= 0 && Index <= last) {
if (index[Index].independent) {
uint16_t fn;
if (!FileNumber)
@@ -1882,12 +1945,40 @@ int cIndexFile::GetNextIFrame(int Index, bool Forward, uint16_t *FileNumber, off
return -1;
}
+int cIndexFile::GetClosestIFrame(int Index)
+{
+ if (last > 0) {
+ Index = constrain(Index, 0, last);
+ if (index[Index].independent)
+ return Index;
+ int il = Index - 1;
+ int ih = Index + 1;
+ for (;;) {
+ if (il >= 0) {
+ if (index[il].independent)
+ return il;
+ il--;
+ }
+ else if (ih > last)
+ break;
+ if (ih <= last) {
+ if (index[ih].independent)
+ return ih;
+ ih++;
+ }
+ else if (il < 0)
+ break;
+ }
+ }
+ return 0;
+}
+
int cIndexFile::Get(uint16_t FileNumber, off_t FileOffset)
{
if (CatchUp()) {
//TODO implement binary search!
int i;
- for (i = 0; i < last; i++) {
+ for (i = 0; i <= last; i++) {
if (index[i].number > FileNumber || (index[i].number == FileNumber) && off_t(index[i].offset) >= FileOffset)
break;
}
@@ -2039,7 +2130,7 @@ bool cFileName::GetLastPatPmtVersions(int &PatVersion, int &PmtVersion)
while (read(fd, buf, sizeof(buf)) == sizeof(buf)) {
if (buf[0] == TS_SYNC_BYTE) {
int Pid = TsPid(buf);
- if (Pid == 0)
+ if (Pid == PATPID)
PatPmtParser.ParsePat(buf, sizeof(buf));
else if (Pid == PatPmtParser.PmtPid()) {
PatPmtParser.ParsePmt(buf, sizeof(buf));
diff --git a/recording.h b/recording.h
index ac44ad5..9ae9b1e 100644
--- a/recording.h
+++ b/recording.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: recording.h 2.37 2012/09/17 08:53:23 kls Exp $
+ * $Id: recording.h 2.40 2012/11/13 11:43:59 kls Exp $
*/
#ifndef __RECORDING_H
@@ -222,19 +222,35 @@ public:
class cMarks : public cConfig<cMark> {
private:
+ cString recordingFileName;
cString fileName;
double framesPerSecond;
+ bool isPesRecording;
time_t nextUpdate;
time_t lastFileTime;
time_t lastChange;
public:
bool Load(const char *RecordingFileName, double FramesPerSecond = DEFAULTFRAMESPERSECOND, bool IsPesRecording = false);
bool Update(void);
+ void Align(void);
void Sort(void);
- cMark *Add(int Position);
+ void Add(int Position);
cMark *Get(int Position);
cMark *GetPrev(int Position);
cMark *GetNext(int Position);
+ cMark *GetNextBegin(cMark *EndMark = NULL);
+ ///< Returns the next "begin" mark after EndMark, skipping any marks at the
+ ///< same position as EndMark. If EndMark is NULL, the first actual "begin"
+ ///< will be returned (if any).
+ cMark *GetNextEnd(cMark *BeginMark);
+ ///< Returns the next "end" mark after BeginMark, skipping any marks at the
+ ///< same position as BeginMark.
+ int GetNumSequences(void);
+ ///< Returns the actual number of sequences to be cut from the recording.
+ ///< If there is only one actual "begin" mark, and it is positioned at index
+ ///< 0 (the beginning of the recording), and there is no "end" mark, the
+ ///< return value is 0, which means that the result is the same as the original
+ ///< recording.
};
#define RUC_BEFORERECORDING "before"
@@ -291,8 +307,14 @@ public:
bool Write(bool Independent, uint16_t FileNumber, off_t FileOffset);
bool Get(int Index, uint16_t *FileNumber, off_t *FileOffset, bool *Independent = NULL, int *Length = NULL);
int GetNextIFrame(int Index, bool Forward, uint16_t *FileNumber = NULL, off_t *FileOffset = NULL, int *Length = NULL);
+ int GetClosestIFrame(int Index);
+ ///< Returns the index of the I-frame that is closest to the given Index (or Index itself,
+ ///< if it already points to an I-frame). Index may be any value, even outside the current
+ ///< range of frame indexes.
+ ///< If there is no actual index data available, 0 is returned.
int Get(uint16_t FileNumber, off_t FileOffset);
int Last(void) { CatchUp(); return last; }
+ ///< Returns the index of the last entry in this file, or -1 if the file is empty.
int GetResume(void) { return resumeFile.Read(); }
bool StoreResume(int Index) { return resumeFile.Save(Index); }
bool IsStillRecording(void);
diff --git a/remux.c b/remux.c
index 6450da4..e3b34c6 100644
--- a/remux.c
+++ b/remux.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: remux.c 2.67 2012/09/19 10:28:42 kls Exp $
+ * $Id: remux.c 2.71 2012/11/18 12:18:08 kls Exp $
*/
#include "remux.h"
@@ -23,6 +23,8 @@ static bool DebugFrames = false;
#define dbgpatpmt(a...) if (DebugPatPmt) fprintf(stderr, a)
#define dbgframes(a...) if (DebugFrames) fprintf(stderr, a)
+#define EMPTY_SCANNER (0xFFFFFFFF)
+
ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
{
if (Count < 7)
@@ -112,6 +114,32 @@ void cRemux::SetBrokenLink(uchar *Data, int Length)
// --- Some TS handling tools ------------------------------------------------
+void TsHidePayload(uchar *p)
+{
+ p[1] &= ~TS_PAYLOAD_START;
+ p[3] |= TS_ADAPT_FIELD_EXISTS;
+ p[3] &= ~TS_PAYLOAD_EXISTS;
+ p[4] = TS_SIZE - 5;
+ p[5] = 0x00;
+ memset(p + 6, 0xFF, TS_SIZE - 6);
+}
+
+void TsSetPcr(uchar *p, int64_t Pcr)
+{
+ if (TsHasAdaptationField(p)) {
+ if (p[4] >= 7 && (p[5] & TS_ADAPT_PCR)) {
+ int64_t b = Pcr / PCRFACTOR;
+ int e = Pcr % PCRFACTOR;
+ p[ 6] = b >> 25;
+ p[ 7] = b >> 17;
+ p[ 8] = b >> 9;
+ p[ 9] = b >> 1;
+ p[10] = (b << 7) | (p[10] & 0x7E) | ((e >> 8) & 0x01);
+ p[11] = e;
+ }
+ }
+}
+
int64_t TsGetPts(const uchar *p, int l)
{
// Find the first packet with a PTS and use it:
@@ -125,27 +153,165 @@ int64_t TsGetPts(const uchar *p, int l)
return -1;
}
-void TsSetTeiOnBrokenPackets(uchar *p, int l)
+int64_t TsGetDts(const uchar *p, int l)
{
- bool Processed[MAXPID] = { false };
- while (l >= TS_SIZE) {
- if (*p != TS_SYNC_BYTE)
- break;
- int Pid = TsPid(p);
- if (!Processed[Pid]) {
- if (!TsPayloadStart(p))
- p[1] |= TS_ERROR;
- else {
- Processed[Pid] = true;
- int offs = TsPayloadOffset(p);
- cRemux::SetBrokenLink(p + offs, TS_SIZE - offs);
- }
+ // Find the first packet with a DTS and use it:
+ while (l > 0) {
+ const uchar *d = p;
+ if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasDts(d))
+ return PesGetDts(d);
+ p += TS_SIZE;
+ l -= TS_SIZE;
+ }
+ return -1;
+}
+
+void TsSetPts(uchar *p, int l, int64_t Pts)
+{
+ // Find the first packet with a PTS and use it:
+ while (l > 0) {
+ const uchar *d = p;
+ if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasPts(d)) {
+ PesSetPts(const_cast<uchar *>(d), Pts);
+ return;
}
+ p += TS_SIZE;
l -= TS_SIZE;
+ }
+}
+
+void TsSetDts(uchar *p, int l, int64_t Dts)
+{
+ // Find the first packet with a DTS and use it:
+ while (l > 0) {
+ const uchar *d = p;
+ if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasDts(d)) {
+ PesSetDts(const_cast<uchar *>(d), Dts);
+ return;
+ }
p += TS_SIZE;
+ l -= TS_SIZE;
}
}
+// --- Some PES handling tools -----------------------------------------------
+
+void PesSetPts(uchar *p, int64_t Pts)
+{
+ p[ 9] = ((Pts >> 29) & 0x0E) | (p[9] & 0xF1);
+ p[10] = Pts >> 22;
+ p[11] = ((Pts >> 14) & 0xFE) | 0x01;
+ p[12] = Pts >> 7;
+ p[13] = ((Pts << 1) & 0xFE) | 0x01;
+}
+
+void PesSetDts(uchar *p, int64_t Dts)
+{
+ p[14] = ((Dts >> 29) & 0x0E) | (p[14] & 0xF1);
+ p[15] = Dts >> 22;
+ p[16] = ((Dts >> 14) & 0xFE) | 0x01;
+ p[17] = Dts >> 7;
+ p[18] = ((Dts << 1) & 0xFE) | 0x01;
+}
+
+int64_t PtsDiff(int64_t Pts1, int64_t Pts2)
+{
+ int64_t d = Pts2 - Pts1;
+ if (d > MAX33BIT / 2)
+ return d - (MAX33BIT + 1);
+ if (d < -MAX33BIT / 2)
+ return d + (MAX33BIT + 1);
+ return d;
+}
+
+// --- cTsPayload ------------------------------------------------------------
+
+cTsPayload::cTsPayload(void)
+{
+ data = NULL;
+ length = 0;
+ pid = -1;
+ index = 0;
+}
+
+cTsPayload::cTsPayload(uchar *Data, int Length, int Pid)
+{
+ Setup(Data, Length, Pid);
+}
+
+void cTsPayload::Setup(uchar *Data, int Length, int Pid)
+{
+ data = Data;
+ length = Length;
+ pid = Pid >= 0 ? Pid : TsPid(Data);
+ index = 0;
+}
+
+uchar cTsPayload::GetByte(void)
+{
+ if (!Eof()) {
+ if (index % TS_SIZE == 0) { // encountered the next TS header
+ for (;; index += TS_SIZE) {
+ if (data[index] == TS_SYNC_BYTE && index + TS_SIZE <= length) { // to make sure we are at a TS header start and drop incomplete TS packets at the end
+ uchar *p = data + index;
+ if (TsPid(p) == pid) { // only handle TS packets for the initial PID
+ if (TsHasPayload(p)) {
+ if (index > 0 && TsPayloadStart(p)) { // checking index to not skip the very first TS packet
+ length = index; // triggers EOF
+ return 0x00;
+ }
+ index += TsPayloadOffset(p);
+ break;
+ }
+ }
+ }
+ else {
+ length = index; // triggers EOF
+ return 0x00;
+ }
+ }
+ }
+ return data[index++];
+ }
+ return 0x00;
+}
+
+bool cTsPayload::SkipBytes(int Bytes)
+{
+ while (Bytes-- > 0)
+ GetByte();
+ return !Eof();
+}
+
+bool cTsPayload::SkipPesHeader(void)
+{
+ return SkipBytes(PesPayloadOffset(data + TsPayloadOffset(data)));
+}
+
+int cTsPayload::GetLastIndex(void)
+{
+ return index - 1;
+}
+
+void cTsPayload::SetByte(uchar Byte, int Index)
+{
+ if (Index >= 0 && Index < length)
+ data[Index] = Byte;
+}
+
+bool cTsPayload::Find(uint32_t Code)
+{
+ int OldIndex = index;
+ uint32_t Scanner = EMPTY_SCANNER;
+ while (!Eof()) {
+ Scanner = (Scanner << 8) | GetByte();
+ if (Scanner == Code)
+ return true;
+ }
+ index = OldIndex;
+ return false;
+}
+
// --- cPatPmtGenerator ------------------------------------------------------
cPatPmtGenerator::cPatPmtGenerator(const cChannel *Channel)
@@ -665,6 +831,25 @@ void cPatPmtParser::ParsePmt(const uchar *Data, int Length)
pmtSize = 0;
}
+bool cPatPmtParser::ParsePatPmt(const uchar *Data, int Length)
+{
+ while (Length >= TS_SIZE) {
+ if (*Data != TS_SYNC_BYTE)
+ break; // just for safety
+ int Pid = TsPid(Data);
+ if (Pid == PATPID)
+ ParsePat(Data, TS_SIZE);
+ else if (Pid == PmtPid()) {
+ ParsePmt(Data, TS_SIZE);
+ if (patVersion >= 0 && pmtVersion >= 0)
+ return true;
+ }
+ Data += TS_SIZE;
+ Length -= TS_SIZE;
+ }
+ return false;
+}
+
bool cPatPmtParser::GetVersions(int &PatVersion, int &PmtVersion) const
{
PatVersion = patVersion;
@@ -809,23 +994,365 @@ void PesDump(const char *Name, const u_char *Data, int Length)
TsDump(Name, Data, Length);
}
-// --- cFrameDetector --------------------------------------------------------
+// --- cFrameParser ----------------------------------------------------------
+
+class cFrameParser {
+protected:
+ bool debug;
+ bool newFrame;
+ bool independentFrame;
+public:
+ cFrameParser(void);
+ virtual ~cFrameParser() {};
+ virtual int Parse(const uchar *Data, int Length, int Pid) = 0;
+ ///< Parses the given Data, which is a sequence of Length bytes of TS packets.
+ ///< The payload in the TS packets with the given Pid is searched for just
+ ///< enough information to determine the beginning and type of the next video
+ ///< frame.
+ ///< Returns the number of bytes parsed. Upon return, the functions NewFrame()
+ ///< and IndependentFrame() can be called to retrieve the required information.
+ void SetDebug(bool Debug) { debug = Debug; }
+ bool NewFrame(void) { return newFrame; }
+ bool IndependentFrame(void) { return independentFrame; }
+ };
+
+cFrameParser::cFrameParser(void)
+{
+ debug = true;
+ newFrame = false;
+ independentFrame = false;
+}
-#define EMPTY_SCANNER (0xFFFFFFFF)
+// --- cAudioParser ----------------------------------------------------------
+
+class cAudioParser : public cFrameParser {
+public:
+ cAudioParser(void);
+ virtual int Parse(const uchar *Data, int Length, int Pid);
+ };
+
+cAudioParser::cAudioParser(void)
+{
+}
+
+int cAudioParser::Parse(const uchar *Data, int Length, int Pid)
+{
+ if (TsPayloadStart(Data)) {
+ newFrame = independentFrame = true;
+ if (debug)
+ dbgframes("/");
+ }
+ else
+ newFrame = independentFrame = false;
+ return TS_SIZE;
+}
+
+// --- cMpeg2Parser ----------------------------------------------------------
+
+class cMpeg2Parser : public cFrameParser {
+private:
+ uint32_t scanner;
+ bool seenIndependentFrame;
+public:
+ cMpeg2Parser(void);
+ virtual int Parse(const uchar *Data, int Length, int Pid);
+ };
+
+cMpeg2Parser::cMpeg2Parser(void)
+{
+ scanner = EMPTY_SCANNER;
+ seenIndependentFrame = false;
+}
+
+int cMpeg2Parser::Parse(const uchar *Data, int Length, int Pid)
+{
+ newFrame = independentFrame = false;
+ bool SeenPayloadStart = false;
+ cTsPayload tsPayload(const_cast<uchar *>(Data), Length, Pid);
+ if (TsPayloadStart(Data)) {
+ SeenPayloadStart = true;
+ tsPayload.SkipPesHeader();
+ scanner = EMPTY_SCANNER;
+ if (debug && seenIndependentFrame)
+ dbgframes("/");
+ }
+ uint32_t OldScanner = scanner; // need to remember it in case of multiple frames per payload
+ for (;;) {
+ if (!SeenPayloadStart && tsPayload.AtTsStart())
+ OldScanner = scanner;
+ scanner = (scanner << 8) | tsPayload.GetByte();
+ if (scanner == 0x00000100) { // Picture Start Code
+ if (!SeenPayloadStart && tsPayload.GetLastIndex() > TS_SIZE) {
+ scanner = OldScanner;
+ return tsPayload.Used() - TS_SIZE;
+ }
+ newFrame = true;
+ tsPayload.GetByte();
+ uchar FrameType = (tsPayload.GetByte() >> 3) & 0x07;
+ independentFrame = FrameType == 1; // I-Frame
+ if (debug) {
+ seenIndependentFrame |= independentFrame;
+ if (seenIndependentFrame) {
+ static const char FrameTypes[] = "?IPBD???";
+ dbgframes("%c", FrameTypes[FrameType]);
+ }
+ }
+ break;
+ }
+ if (tsPayload.AtPayloadStart() // stop at any new payload start to have the buffer refilled if necessary
+ || (tsPayload.Available() < MIN_TS_PACKETS_FOR_FRAME_DETECTOR * TS_SIZE // stop if the available data is below the limit...
+ && (tsPayload.Available() <= 0 || tsPayload.AtTsStart()))) // ...but only if there is no more data at all, or if we are at a TS boundary
+ break;
+ }
+ return tsPayload.Used();
+}
+
+// --- cMpeg4Parser ----------------------------------------------------------
+
+class cMpeg4Parser : public cFrameParser {
+private:
+ enum eNalUnitType {
+ nutCodedSliceNonIdr = 1,
+ nutCodedSliceIdr = 5,
+ nutSequenceParameterSet = 7,
+ nutAccessUnitDelimiter = 9,
+ };
+ cTsPayload tsPayload;
+ uchar byte; // holds the current byte value in case of bitwise access
+ int bit; // the bit index into the current byte (-1 if we're not in bit reading mode)
+ int zeroBytes; // the number of consecutive zero bytes (to detect 0x000003)
+ uint32_t scanner;
+ // Identifiers written in '_' notation as in "ITU-T H.264":
+ bool separate_colour_plane_flag;
+ int log2_max_frame_num;
+ bool frame_mbs_only_flag;
+ //
+ bool gotAccessUnitDelimiter;
+ bool gotSequenceParameterSet;
+ uchar GetByte(bool Raw = false);
+ ///< Gets the next data byte. If Raw is true, no filtering will be done.
+ ///< With Raw set to false, if the byte sequence 0x000003 is encountered,
+ ///< the byte with 0x03 will be skipped.
+ uchar GetBit(void);
+ uint32_t GetBits(int Bits);
+ uint32_t GetGolombUe(void);
+ int32_t GetGolombSe(void);
+ void ParseAccessUnitDelimiter(void);
+ void ParseSequenceParameterSet(void);
+ void ParseSliceHeader(void);
+public:
+ cMpeg4Parser(void);
+ ///< Sets up a new MPEG-4 parser.
+ ///< This class parses only the data absolutely necessary to determine the
+ ///< frame borders and field count of the given H264 material.
+ virtual int Parse(const uchar *Data, int Length, int Pid);
+ };
+
+cMpeg4Parser::cMpeg4Parser(void)
+{
+ byte = 0;
+ bit = -1;
+ zeroBytes = 0;
+ scanner = EMPTY_SCANNER;
+ separate_colour_plane_flag = false;
+ log2_max_frame_num = 0;
+ frame_mbs_only_flag = false;
+ gotAccessUnitDelimiter = false;
+ gotSequenceParameterSet = false;
+}
+
+uchar cMpeg4Parser::GetByte(bool Raw)
+{
+ uchar b = tsPayload.GetByte();
+ if (!Raw) {
+ // If we encounter the byte sequence 0x000003, we need to skip the 0x03:
+ if (b == 0x00)
+ zeroBytes++;
+ else {
+ if (b == 0x03 && zeroBytes >= 2)
+ b = tsPayload.GetByte();
+ zeroBytes = 0;
+ }
+ }
+ else
+ zeroBytes = 0;
+ bit = -1;
+ return b;
+}
+
+uchar cMpeg4Parser::GetBit(void)
+{
+ if (bit < 0) {
+ byte = GetByte();
+ bit = 7;
+ }
+ return (byte & (1 << bit--)) ? 1 : 0;
+}
+
+uint32_t cMpeg4Parser::GetBits(int Bits)
+{
+ uint32_t b = 0;
+ while (Bits--)
+ b |= GetBit() << Bits;
+ return b;
+}
+
+uint32_t cMpeg4Parser::GetGolombUe(void)
+{
+ int z = -1;
+ for (int b = 0; !b; z++)
+ b = GetBit();
+ return (1 << z) - 1 + GetBits(z);
+}
+
+int32_t cMpeg4Parser::GetGolombSe(void)
+{
+ uint32_t v = GetGolombUe();
+ if (v) {
+ if ((v & 0x01) != 0)
+ return (v + 1) / 2; // fails for v == 0xFFFFFFFF, but that will probably never happen
+ else
+ return -int32_t(v / 2);
+ }
+ return v;
+}
+
+int cMpeg4Parser::Parse(const uchar *Data, int Length, int Pid)
+{
+ newFrame = independentFrame = false;
+ tsPayload.Setup(const_cast<uchar *>(Data), Length, Pid);
+ if (TsPayloadStart(Data)) {
+ tsPayload.SkipPesHeader();
+ scanner = EMPTY_SCANNER;
+ if (debug && gotSequenceParameterSet) {
+ dbgframes("/");
+ }
+ }
+ for (;;) {
+ scanner = (scanner << 8) | GetByte(true);
+ if ((scanner & 0xFFFFFF00) == 0x00000100) { // NAL unit start
+ uchar NalUnitType = scanner & 0x1F;
+ switch (NalUnitType) {
+ case nutAccessUnitDelimiter: ParseAccessUnitDelimiter();
+ gotAccessUnitDelimiter = true;
+ break;
+ case nutSequenceParameterSet: ParseSequenceParameterSet();
+ gotSequenceParameterSet = true;
+ break;
+ case nutCodedSliceNonIdr:
+ case nutCodedSliceIdr: if (gotAccessUnitDelimiter && gotSequenceParameterSet) {
+ ParseSliceHeader();
+ gotAccessUnitDelimiter = false;
+ return tsPayload.Used();
+ }
+ break;
+ default: ;
+ }
+ }
+ if (tsPayload.AtPayloadStart() // stop at any new payload start to have the buffer refilled if necessary
+ || (tsPayload.Available() < MIN_TS_PACKETS_FOR_FRAME_DETECTOR * TS_SIZE // stop if the available data is below the limit...
+ && (tsPayload.Available() <= 0 || tsPayload.AtTsStart()))) // ...but only if there is no more data at all, or if we are at a TS boundary
+ break;
+ }
+ return tsPayload.Used();
+}
+
+void cMpeg4Parser::ParseAccessUnitDelimiter(void)
+{
+ if (debug && gotSequenceParameterSet)
+ dbgframes("A");
+ GetByte(); // primary_pic_type
+}
+
+void cMpeg4Parser::ParseSequenceParameterSet(void)
+{
+ uchar profile_idc = GetByte(); // profile_idc
+ GetByte(); // constraint_set[0-5]_flags, reserved_zero_2bits
+ GetByte(); // level_idc
+ GetGolombUe(); // seq_parameter_set_id
+ if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 244 || profile_idc == 44 || profile_idc == 83 || profile_idc == 86 || profile_idc ==118 || profile_idc == 128) {
+ int chroma_format_idc = GetGolombUe(); // chroma_format_idc
+ if (chroma_format_idc == 3)
+ separate_colour_plane_flag = GetBit();
+ GetGolombUe(); // bit_depth_luma_minus8
+ GetGolombUe(); // bit_depth_chroma_minus8
+ GetBit(); // qpprime_y_zero_transform_bypass_flag
+ if (GetBit()) { // seq_scaling_matrix_present_flag
+ for (int i = 0; i < ((chroma_format_idc != 3) ? 8 : 12); i++) {
+ if (GetBit()) { // seq_scaling_list_present_flag
+ int SizeOfScalingList = (i < 6) ? 16 : 64;
+ int LastScale = 8;
+ int NextScale = 8;
+ for (int j = 0; j < SizeOfScalingList; j++) {
+ if (NextScale)
+ NextScale = (LastScale + GetGolombSe() + 256) % 256; // delta_scale
+ if (NextScale)
+ LastScale = NextScale;
+ }
+ }
+ }
+ }
+ }
+ log2_max_frame_num = GetGolombUe() + 4; // log2_max_frame_num_minus4
+ int pic_order_cnt_type = GetGolombUe(); // pic_order_cnt_type
+ if (pic_order_cnt_type == 0)
+ GetGolombUe(); // log2_max_pic_order_cnt_lsb_minus4
+ else if (pic_order_cnt_type == 1) {
+ GetBit(); // delta_pic_order_always_zero_flag
+ GetGolombSe(); // offset_for_non_ref_pic
+ GetGolombSe(); // offset_for_top_to_bottom_field
+ for (int i = GetGolombUe(); i--; ) // num_ref_frames_in_pic_order_cnt_cycle
+ GetGolombSe(); // offset_for_ref_frame
+ }
+ GetGolombUe(); // max_num_ref_frames
+ GetBit(); // gaps_in_frame_num_value_allowed_flag
+ GetGolombUe(); // pic_width_in_mbs_minus1
+ GetGolombUe(); // pic_height_in_map_units_minus1
+ frame_mbs_only_flag = GetBit(); // frame_mbs_only_flag
+ if (debug) {
+ if (gotAccessUnitDelimiter && !gotSequenceParameterSet)
+ dbgframes("A"); // just for completeness
+ dbgframes(frame_mbs_only_flag ? "S" : "s");
+ }
+}
+
+void cMpeg4Parser::ParseSliceHeader(void)
+{
+ newFrame = true;
+ GetGolombUe(); // first_mb_in_slice
+ int slice_type = GetGolombUe(); // slice_type, 0 = P, 1 = B, 2 = I, 3 = SP, 4 = SI
+ independentFrame = (slice_type % 5) == 2;
+ if (debug) {
+ static const char SliceTypes[] = "PBIpi";
+ dbgframes("%c", SliceTypes[slice_type % 5]);
+ }
+ if (frame_mbs_only_flag)
+ return; // don't need the rest - a frame is complete
+ GetGolombUe(); // pic_parameter_set_id
+ if (separate_colour_plane_flag)
+ GetBits(2); // colour_plane_id
+ GetBits(log2_max_frame_num); // frame_num
+ if (!frame_mbs_only_flag) {
+ if (GetBit()) // field_pic_flag
+ newFrame = !GetBit(); // bottom_field_flag
+ if (debug)
+ dbgframes(newFrame ? "t" : "b");
+ }
+}
+
+// --- cFrameDetector --------------------------------------------------------
cFrameDetector::cFrameDetector(int Pid, int Type)
{
+ parser = NULL;
SetPid(Pid, Type);
synced = false;
newFrame = independentFrame = false;
numPtsValues = 0;
- numFrames = 0;
numIFrames = 0;
framesPerSecond = 0;
framesInPayloadUnit = framesPerPayloadUnit = 0;
- payloadUnitOfFrame = 0;
scanning = false;
- scanner = EMPTY_SCANNER;
}
static int CmpUint32(const void *p1, const void *p2)
@@ -840,42 +1367,26 @@ void cFrameDetector::SetPid(int Pid, int Type)
pid = Pid;
type = Type;
isVideo = type == 0x01 || type == 0x02 || type == 0x1B; // MPEG 1, 2 or 4
-}
-
-void cFrameDetector::Reset(void)
-{
- newFrame = independentFrame = false;
- payloadUnitOfFrame = 0;
- scanning = false;
- scanner = EMPTY_SCANNER;
-}
-
-int cFrameDetector::SkipPackets(const uchar *&Data, int &Length, int &Processed, int &FrameTypeOffset)
-{
- if (!synced)
- dbgframes("%d>", FrameTypeOffset);
- while (Length >= TS_SIZE) {
- // switch to the next TS packet, but skip those that have a different PID:
- Data += TS_SIZE;
- Length -= TS_SIZE;
- Processed += TS_SIZE;
- if (TsPid(Data) == pid)
- break;
- else if (Length < TS_SIZE)
- esyslog("ERROR: out of data while skipping TS packets in cFrameDetector");
- }
- FrameTypeOffset -= TS_SIZE;
- FrameTypeOffset += TsPayloadOffset(Data);
- return FrameTypeOffset;
+ delete parser;
+ parser = NULL;
+ if (type == 0x01 || type == 0x02)
+ parser = new cMpeg2Parser;
+ else if (type == 0x1B)
+ parser = new cMpeg4Parser;
+ else if (type == 0x04 || type == 0x06) // MPEG audio or AC3 audio
+ parser = new cAudioParser;
+ else if (type != 0)
+ esyslog("ERROR: unknown stream type %d (PID %d) in frame detector", type, pid);
}
int cFrameDetector::Analyze(const uchar *Data, int Length)
{
- bool SeenPayloadStart = false;
- bool SeenAccessUnitDelimiter = false;
+ if (!parser)
+ return 0;
int Processed = 0;
newFrame = independentFrame = false;
- while (Length >= TS_SIZE) {
+ while (Length >= MIN_TS_PACKETS_FOR_FRAME_DETECTOR * TS_SIZE) { // makes sure we are looking at enough data, in case the frame type is not stored in the first TS packet
+ // Sync on TS packet borders:
if (Data[0] != TS_SYNC_BYTE) {
int Skipped = 1;
while (Skipped < Length && (Data[Skipped] != TS_SYNC_BYTE || Length - Skipped > TS_SIZE && Data[Skipped + TS_SIZE] != TS_SYNC_BYTE))
@@ -883,186 +1394,99 @@ int cFrameDetector::Analyze(const uchar *Data, int Length)
esyslog("ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
return Processed + Skipped;
}
+ // Handle one TS packet:
+ int Handled = TS_SIZE;
if (TsHasPayload(Data) && !TsIsScrambled(Data)) {
int Pid = TsPid(Data);
if (Pid == pid) {
+ if (Processed)
+ return Processed;
+ if (TsPayloadStart(Data))
+ scanning = true;
+ if (scanning) {
+ // Detect the beginning of a new frame:
+ if (TsPayloadStart(Data)) {
+ if (!framesPerPayloadUnit)
+ framesPerPayloadUnit = framesInPayloadUnit;
+ }
+ int n = parser->Parse(Data, Length, pid);
+ if (n > 0) {
+ if (parser->NewFrame()) {
+ newFrame = true;
+ independentFrame = parser->IndependentFrame();
+ if (synced) {
+ if (framesPerPayloadUnit <= 1)
+ scanning = false;
+ }
+ else {
+ framesInPayloadUnit++;
+ if (independentFrame)
+ numIFrames++;
+ }
+ }
+ Handled = n;
+ }
+ }
if (TsPayloadStart(Data)) {
- SeenPayloadStart = true;
- if (synced && Processed)
- return Processed;
- if (Length < MIN_TS_PACKETS_FOR_FRAME_DETECTOR * TS_SIZE)
- return Processed; // need more data, in case the frame type is not stored in the first TS packet
+ // Determine the frame rate from the PTS values in the PES headers:
if (framesPerSecond <= 0.0) {
// frame rate unknown, so collect a sequence of PTS values:
if (numPtsValues < 2 || numPtsValues < MaxPtsValues && numIFrames < 2) { // collect a sequence containing at least two I-frames
- const uchar *Pes = Data + TsPayloadOffset(Data);
- if (numIFrames && PesHasPts(Pes)) {
- ptsValues[numPtsValues] = PesGetPts(Pes);
- // check for rollover:
- if (numPtsValues && ptsValues[numPtsValues - 1] > 0xF0000000 && ptsValues[numPtsValues] < 0x10000000) {
- dbgframes("#");
- numPtsValues = 0;
- numIFrames = 0;
- numFrames = 0;
+ if (newFrame) { // only take PTS values at the beginning of a frame (in case if fields!)
+ const uchar *Pes = Data + TsPayloadOffset(Data);
+ if (numIFrames && PesHasPts(Pes)) {
+ ptsValues[numPtsValues] = PesGetPts(Pes);
+ // check for rollover:
+ if (numPtsValues && ptsValues[numPtsValues - 1] > 0xF0000000 && ptsValues[numPtsValues] < 0x10000000) {
+ dbgframes("#");
+ numPtsValues = 0;
+ numIFrames = 0;
+ }
+ else
+ numPtsValues++;
}
- else
- numPtsValues++;
}
}
- else {
+ if (numPtsValues >= 2 && numIFrames >= 2) {
// 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];
+ uint32_t Delta = ptsValues[0] / framesPerPayloadUnit;
// determine frame info:
if (isVideo) {
if (abs(Delta - 3600) <= 1)
framesPerSecond = 25.0;
else if (Delta % 3003 == 0)
framesPerSecond = 30.0 / 1.001;
- else if (abs(Delta - 1800) <= 1) {
- if (numFrames > 50) {
- // this is a "best guess": if there are more than 50 frames between two I-frames, we assume each "frame" actually contains a "field", so two "fields" make one "frame"
- framesPerSecond = 25.0;
- framesPerPayloadUnit = -2;
- }
- else
- framesPerSecond = 50.0;
- }
+ else if (abs(Delta - 1800) <= 1)
+ framesPerSecond = 50.0;
else if (Delta == 1501)
- if (numFrames > 50) {
- // this is a "best guess": if there are more than 50 frames between two I-frames, we assume each "frame" actually contains a "field", so two "fields" make one "frame"
- framesPerSecond = 30.0 / 1.001;
- framesPerPayloadUnit = -2;
- }
- else
- framesPerSecond = 60.0 / 1.001;
+ framesPerSecond = 60.0 / 1.001;
else {
framesPerSecond = DEFAULTFRAMESPERSECOND;
dsyslog("unknown frame delta (%d), assuming %5.2f fps", Delta, DEFAULTFRAMESPERSECOND);
}
}
else // audio
- framesPerSecond = 90000.0 / Delta; // PTS of audio frames is always increasing
- dbgframes("\nDelta = %d FPS = %5.2f FPPU = %d NF = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numFrames);
+ framesPerSecond = double(PTSTICKS) / Delta; // PTS of audio frames is always increasing
+ dbgframes("\nDelta = %d FPS = %5.2f FPPU = %d NF = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numPtsValues + 1);
+ synced = true;
+ parser->SetDebug(false);
}
}
- scanner = EMPTY_SCANNER;
- scanning = true;
- }
- if (scanning) {
- int PayloadOffset = TsPayloadOffset(Data);
- if (TsPayloadStart(Data)) {
- PayloadOffset += PesPayloadOffset(Data + PayloadOffset);
- if (!framesPerPayloadUnit)
- framesPerPayloadUnit = framesInPayloadUnit;
- if (DebugFrames && !synced)
- dbgframes("/");
- }
- for (int i = PayloadOffset; scanning && i < TS_SIZE; i++) {
- scanner <<= 8;
- scanner |= Data[i];
- switch (type) {
- case 0x01: // MPEG 1 video
- case 0x02: // MPEG 2 video
- if (scanner == 0x00000100) { // Picture Start Code
- scanner = EMPTY_SCANNER;
- if (synced && !SeenPayloadStart && Processed)
- return Processed; // flush everything before this new frame
- int FrameTypeOffset = i + 2;
- if (FrameTypeOffset >= TS_SIZE) // the byte to check is in the next TS packet
- i = SkipPackets(Data, Length, Processed, FrameTypeOffset);
- newFrame = true;
- uchar FrameType = (Data[FrameTypeOffset] >> 3) & 0x07;
- independentFrame = FrameType == 1; // I-Frame
- if (synced) {
- if (framesPerPayloadUnit <= 1)
- scanning = false;
- }
- else {
- framesInPayloadUnit++;
- if (independentFrame)
- numIFrames++;
- if (numIFrames == 1)
- numFrames++;
- dbgframes("%u ", FrameType);
- }
- if (synced)
- return Processed + TS_SIZE; // flag this new frame
- }
- break;
- case 0x1B: // MPEG 4 video
- if (scanner == 0x00000109) { // Access Unit Delimiter
- scanner = EMPTY_SCANNER;
- if (synced && !SeenPayloadStart && Processed)
- return Processed; // flush everything before this new frame
- SeenAccessUnitDelimiter = true;
- }
- else if (SeenAccessUnitDelimiter && scanner == 0x00000001) { // NALU start
- SeenAccessUnitDelimiter = false;
- int FrameTypeOffset = i + 1;
- if (FrameTypeOffset >= TS_SIZE) // the byte to check is in the next TS packet
- i = SkipPackets(Data, Length, Processed, FrameTypeOffset);
- newFrame = true;
- uchar FrameType = Data[FrameTypeOffset] & 0x1F;
- independentFrame = FrameType == 0x07;
- if (synced) {
- if (framesPerPayloadUnit < 0) {
- payloadUnitOfFrame = (payloadUnitOfFrame + 1) % -framesPerPayloadUnit;
- if (payloadUnitOfFrame != 0 && independentFrame)
- payloadUnitOfFrame = 0;
- if (payloadUnitOfFrame)
- newFrame = false;
- }
- if (framesPerPayloadUnit <= 1)
- scanning = false;
- }
- else {
- framesInPayloadUnit++;
- if (independentFrame)
- numIFrames++;
- if (numIFrames == 1)
- numFrames++;
- dbgframes("%02X ", FrameType);
- }
- if (synced)
- return Processed + TS_SIZE; // flag this new frame
- }
- break;
- case 0x04: // MPEG audio
- case 0x06: // AC3 audio
- if (synced && Processed)
- return Processed;
- newFrame = true;
- independentFrame = true;
- if (!synced) {
- framesInPayloadUnit = 1;
- if (TsPayloadStart(Data))
- numIFrames++;
- }
- scanning = false;
- break;
- default: esyslog("ERROR: unknown stream type %d (PID %d) in frame detector", type, pid);
- pid = 0; // let's just ignore any further data
- }
- }
- if (!synced && framesPerSecond > 0.0 && independentFrame) {
- synced = true;
- dbgframes("*\n");
- Reset();
- return Processed + TS_SIZE;
- }
}
}
else if (Pid == PATPID && synced && Processed)
return Processed; // allow the caller to see any PAT packets
}
- Data += TS_SIZE;
- Length -= TS_SIZE;
- Processed += TS_SIZE;
+ Data += Handled;
+ Length -= Handled;
+ Processed += Handled;
+ if (newFrame)
+ break;
}
return Processed;
}
diff --git a/remux.h b/remux.h
index b882279..dd17e0d 100644
--- a/remux.h
+++ b/remux.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: remux.h 2.32 2011/09/04 12:48:26 kls Exp $
+ * $Id: remux.h 2.35 2012/11/18 12:17:23 kls Exp $
*/
#ifndef __REMUX_H
@@ -52,6 +52,11 @@ public:
#define PATPID 0x0000 // PAT PID (constant 0)
#define MAXPID 0x2000 // for arrays that use a PID as the index
+#define PTSTICKS 90000 // number of PTS ticks per second
+#define PCRFACTOR 300 // conversion from 27MHz PCR extension to 90kHz PCR base
+#define MAX33BIT 0x00000001FFFFFFFFLL // max. possible value with 33 bit
+#define MAX27MHZ ((MAX33BIT + 1) * PCRFACTOR - 1) // max. possible PCR value
+
inline bool TsHasPayload(const uchar *p)
{
return p[3] & TS_PAYLOAD_EXISTS;
@@ -82,6 +87,16 @@ inline bool TsIsScrambled(const uchar *p)
return p[3] & TS_SCRAMBLING_CONTROL;
}
+inline uchar TsGetContinuityCounter(const uchar *p)
+{
+ return p[3] & TS_CONT_CNT_MASK;
+}
+
+inline void TsSetContinuityCounter(uchar *p, uchar Counter)
+{
+ p[3] = (p[3] & ~TS_CONT_CNT_MASK) | (Counter & TS_CONT_CNT_MASK);
+}
+
inline int TsPayloadOffset(const uchar *p)
{
int o = TsHasAdaptationField(p) ? p[4] + 5 : 4;
@@ -103,15 +118,31 @@ inline int TsContinuityCounter(const uchar *p)
return p[3] & TS_CONT_CNT_MASK;
}
-inline int TsGetAdaptationField(const uchar *p)
+inline int64_t TsGetPcr(const uchar *p)
{
- return TsHasAdaptationField(p) ? p[5] : 0x00;
+ if (TsHasAdaptationField(p)) {
+ if (p[4] >= 7 && (p[5] & TS_ADAPT_PCR)) {
+ return ((((int64_t)p[ 6]) << 25) |
+ (((int64_t)p[ 7]) << 17) |
+ (((int64_t)p[ 8]) << 9) |
+ (((int64_t)p[ 9]) << 1) |
+ (((int64_t)p[10]) >> 7)) * PCRFACTOR +
+ (((((int)p[10]) & 0x01) << 8) |
+ ( ((int)p[11])));
+ }
+ }
+ return -1;
}
+void TsHidePayload(uchar *p);
+void TsSetPcr(uchar *p, int64_t Pcr);
+
// The following functions all take a pointer to a sequence of complete TS packets.
int64_t TsGetPts(const uchar *p, int l);
-void TsSetTeiOnBrokenPackets(uchar *p, int l);
+int64_t TsGetDts(const uchar *p, int l);
+void TsSetPts(uchar *p, int l, int64_t Pts);
+void TsSetDts(uchar *p, int l, int64_t Dts);
// Some PES handling tools:
// The following functions that take a pointer to PES data all assume that
@@ -142,6 +173,11 @@ inline bool PesHasPts(const uchar *p)
return (p[7] & 0x80) && p[8] >= 5;
}
+inline bool PesHasDts(const uchar *p)
+{
+ return (p[7] & 0x40) && p[8] >= 10;
+}
+
inline int64_t PesGetPts(const uchar *p)
{
return ((((int64_t)p[ 9]) & 0x0E) << 29) |
@@ -151,6 +187,88 @@ inline int64_t PesGetPts(const uchar *p)
((((int64_t)p[13]) & 0xFE) >> 1);
}
+inline int64_t PesGetDts(const uchar *p)
+{
+ return ((((int64_t)p[14]) & 0x0E) << 29) |
+ (( (int64_t)p[15]) << 22) |
+ ((((int64_t)p[16]) & 0xFE) << 14) |
+ (( (int64_t)p[17]) << 7) |
+ ((((int64_t)p[18]) & 0xFE) >> 1);
+}
+
+void PesSetPts(uchar *p, int64_t Pts);
+void PesSetDts(uchar *p, int64_t Dts);
+
+// PTS handling:
+
+inline int64_t PtsAdd(int64_t Pts1, int64_t Pts2) { return (Pts1 + Pts2) & MAX33BIT; }
+ ///< Adds the given PTS values, taking into account the 33bit wrap around.
+int64_t PtsDiff(int64_t Pts1, int64_t Pts2);
+ ///< Returns the difference between two PTS values. The result of Pts2 - Pts1
+ ///< is the actual number of 90kHz time ticks that pass from Pts1 to Pts2,
+ ///< properly taking into account the 33bit wrap around. If Pts2 is "before"
+ ///< Pts1, the result is negative.
+
+// A transprent TS payload handler:
+
+class cTsPayload {
+private:
+ uchar *data;
+ int length;
+ int pid;
+ int index; // points to the next byte to process
+public:
+ cTsPayload(void);
+ cTsPayload(uchar *Data, int Length, int Pid = -1);
+ ///< Creates a new TS payload handler and calls Setup() with the given Data.
+ void Setup(uchar *Data, int Length, int Pid = -1);
+ ///< Sets up this TS payload handler with the given Data, which points to a
+ ///< sequence of Length bytes of complete TS packets. Any incomplete TS
+ ///< packet at the end will be ignored.
+ ///< If Pid is given, only TS packets with data for that PID will be processed.
+ ///< Otherwise the PID of the first TS packet defines which payload will be
+ ///< delivered.
+ ///< Any intermediate TS packets with different PIDs will be skipped.
+ bool AtTsStart(void) { return index < length && (index % TS_SIZE) == 0; }
+ ///< Returns true if this payload handler is currently pointing to first byte
+ ///< of a TS packet.
+ bool AtPayloadStart(void) { return AtTsStart() && TsPayloadStart(data + index); }
+ ///< Returns true if this payload handler is currently pointing to the first byte
+ ///< of a TS packet that starts a new payload.
+ int Available(void) { return length - index; }
+ ///< Returns the number of raw bytes (including any TS headers) still available
+ ///< in the TS payload handler.
+ int Used(void) { return (index + TS_SIZE - 1) / TS_SIZE * TS_SIZE; }
+ ///< Returns the number of raw bytes that have already been used (e.g. by calling
+ ///< GetByte()). Any TS packet of which at least a single byte has been delivered
+ ///< is counted with its full size.
+ bool Eof(void) const { return index >= length; }
+ ///< Returns true if all available bytes of the TS payload have been processed.
+ uchar GetByte(void);
+ ///< Gets the next byte of the TS payload, skipping any intermediate TS header data.
+ bool SkipBytes(int Bytes);
+ ///< Skips the given number of bytes in the payload and returns true if there
+ ///< is still data left to read.
+ bool SkipPesHeader(void);
+ ///< Skips all bytes belonging to the PES header of the payload.
+ int GetLastIndex(void);
+ ///< Returns the index into the TS data of the payload byte that has most recently
+ ///< been read. If no byte has been read yet, -1 will be returned.
+ void SetByte(uchar Byte, int Index);
+ ///< Sets the TS data byte at the given Index to the value Byte.
+ ///< Index should be one that has been retrieved by a previous call to GetIndex(),
+ ///< otherwise the behaviour is undefined. The current read index will not be
+ ///< altered by a call to this function.
+ bool Find(uint32_t Code);
+ ///< Searches for the four byte sequence given in Code and returns true if it
+ ///< was found within the payload data. The next call to GetByte() will return the
+ ///< value immediately following the Code. If the code was not found, the read
+ ///< index will remain the same as before this call, so that several calls to
+ ///< Find() can be performed starting at the same index..
+ ///< The special code 0xFFFFFFFF can not be searched, because this value is used
+ ///< to initialize the scanner.
+ };
+
// PAT/PMT Generator:
#define MAX_SECTION_SIZE 4096 // maximum size of an SI section
@@ -248,6 +366,10 @@ public:
///< are delivered to the parser through several subsequent calls to
///< ParsePmt(). The whole PMT data will be processed once the last packet
///< has been received.
+ bool ParsePatPmt(const uchar *Data, int Length);
+ ///< Parses the given Data (which may consist of several TS packets, typically
+ ///< an entire frame) and extracts the PAT and PMT.
+ ///< Returns true if a valid PAT/PMT has been detected.
bool GetVersions(int &PatVersion, int &PmtVersion) const;
///< Returns true if a valid PAT/PMT has been parsed and stores
///< the current version numbers in the given variables.
@@ -338,6 +460,8 @@ void PesDump(const char *Name, const u_char *Data, int Length);
#define MIN_TS_PACKETS_FOR_FRAME_DETECTOR 5
+class cFrameParser;
+
class cFrameDetector {
private:
enum { MaxPtsValues = 150 };
@@ -354,12 +478,9 @@ private:
double framesPerSecond;
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;
+ // while others put an entire GOP into one payload unit (> 1).
bool scanning;
- uint32_t scanner;
- int SkipPackets(const uchar *&Data, int &Length, int &Processed, int &FrameTypeOffset);
+ cFrameParser *parser;
public:
cFrameDetector(int Pid = 0, int Type = 0);
///< Sets up a frame detector for the given Pid and stream Type.
@@ -367,9 +488,6 @@ public:
///< call to SetPid().
void SetPid(int Pid, int Type);
///< Sets the Pid and stream Type to detect frames for.
- void Reset(void);
- ///< Resets any counters and flags used while syncing and prepares
- ///< the frame detector for actual work.
int Analyze(const uchar *Data, int Length);
///< Analyzes the TS packets pointed to by Data. Length is the number of
///< bytes Data points to, and must be a multiple of TS_SIZE.
diff --git a/sections.c b/sections.c
index c9ed0c1..991499b 100644
--- a/sections.c
+++ b/sections.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: sections.c 2.1 2012/08/26 12:53:39 kls Exp $
+ * $Id: sections.c 2.2 2012/10/04 12:21:59 kls Exp $
*/
#include "sections.h"
@@ -40,7 +40,7 @@ public:
// --- cSectionHandler -------------------------------------------------------
cSectionHandler::cSectionHandler(cDevice *Device)
-:cThread("section handler")
+:cThread("section handler", true)
{
shp = new cSectionHandlerPrivate;
device = Device;
@@ -164,7 +164,6 @@ void cSectionHandler::SetStatus(bool On)
void cSectionHandler::Action(void)
{
- SetPriority(19);
while (Running()) {
Lock();
diff --git a/skinlcars.h b/skinlcars.h
index 71117f6..7306d12 100644
--- a/skinlcars.h
+++ b/skinlcars.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: skinlcars.h 2.1 2012/04/15 13:17:35 kls Exp $
+ * $Id: skinlcars.h 1.1 2012/04/15 13:17:35 kls Exp $
*/
#ifndef __SKINLCARS_H
diff --git a/themes.h b/themes.h
index 3563bb0..e51464f 100644
--- a/themes.h
+++ b/themes.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: themes.h 2.0 2007/08/05 14:10:22 kls Exp $
+ * $Id: themes.h 2.1 2012/10/07 11:11:43 kls Exp $
*/
#ifndef __THEMES_H
@@ -56,7 +56,7 @@ public:
};
// A helper macro that simplifies defining theme colors.
-#define THEME_CLR(Theme, Subject, Color) static const int Subject = Theme.AddColor(#Subject, Color)
+#define THEME_CLR(Theme, Subject, Color) static const tColor Subject = Theme.AddColor(#Subject, Color)
class cThemes {
private:
diff --git a/thread.c b/thread.c
index a650fab..b80ee70 100644
--- a/thread.c
+++ b/thread.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: thread.c 2.5 2012/09/20 09:05:50 kls Exp $
+ * $Id: thread.c 2.6 2012/10/04 12:20:43 kls Exp $
*/
#include "thread.h"
@@ -204,7 +204,7 @@ void cMutex::Unlock(void)
tThreadId cThread::mainThreadId = 0;
-cThread::cThread(const char *Description)
+cThread::cThread(const char *Description, bool LowPriority)
{
active = running = false;
childTid = 0;
@@ -212,6 +212,7 @@ cThread::cThread(const char *Description)
description = NULL;
if (Description)
SetDescription("%s", Description);
+ lowPriority = LowPriority;
}
cThread::~cThread()
@@ -248,12 +249,16 @@ void *cThread::StartThread(cThread *Thread)
{
Thread->childThreadId = ThreadId();
if (Thread->description) {
- dsyslog("%s thread started (pid=%d, tid=%d)", Thread->description, getpid(), Thread->childThreadId);
+ dsyslog("%s thread started (pid=%d, tid=%d, prio=%s)", Thread->description, getpid(), Thread->childThreadId, Thread->lowPriority ? "low" : "high");
#ifdef PR_SET_NAME
if (prctl(PR_SET_NAME, Thread->description, 0, 0, 0) < 0)
esyslog("%s thread naming failed (pid=%d, tid=%d)", Thread->description, getpid(), Thread->childThreadId);
#endif
}
+ if (Thread->lowPriority) {
+ Thread->SetPriority(19);
+ Thread->SetIOPriority(7);
+ }
Thread->Action();
if (Thread->description)
dsyslog("%s thread ended (pid=%d, tid=%d)", Thread->description, getpid(), Thread->childThreadId);
diff --git a/thread.h b/thread.h
index f77e819..a08d40c 100644
--- a/thread.h
+++ b/thread.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: thread.h 2.2 2012/09/20 08:46:27 kls Exp $
+ * $Id: thread.h 2.3 2012/10/04 12:15:39 kls Exp $
*/
#ifndef __THREAD_H
@@ -83,6 +83,7 @@ private:
tThreadId childThreadId;
cMutex mutex;
char *description;
+ bool lowPriority;
static tThreadId mainThreadId;
static void *StartThread(cThread *Thread);
protected:
@@ -106,11 +107,13 @@ protected:
///< If WaitSeconds is -1, only 'running' is set to false and Cancel()
///< returns immediately, without killing the thread.
public:
- cThread(const char *Description = NULL);
+ cThread(const char *Description = NULL, bool LowPriority = false);
///< Creates a new thread.
///< If Description is present, a log file entry will be made when
///< the thread starts and stops. The Start() function must be called
///< to actually start the thread.
+ ///< LowPriority can be set to true to make this thread run at a lower
+ ///< priority.
virtual ~cThread();
void SetDescription(const char *Description, ...) __attribute__ ((format (printf, 2, 3)));
bool Start(void);
diff --git a/timers.c b/timers.c
index 7d4c70b..a29cf12 100644
--- a/timers.c
+++ b/timers.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: timers.c 2.12 2012/09/15 13:34:03 kls Exp $
+ * $Id: timers.c 2.14 2012/10/16 08:22:39 kls Exp $
*/
#include "timers.h"
@@ -465,10 +465,11 @@ bool cTimer::Matches(time_t t, bool Directly, int Margin) const
startTime = event->StartTime();
stopTime = event->EndTime();
if (!Margin) { // this is an actual check
- if (event->Schedule()->PresentSeenWithin(EITPRESENTFOLLOWINGRATE)) // VPS control can only work with up-to-date events...
- return event->IsRunning(true);
- else
- return startTime <= t && t < stopTime; // ...otherwise we fall back to normal timer handling
+ if (event->Schedule()->PresentSeenWithin(EITPRESENTFOLLOWINGRATE)) { // VPS control can only work with up-to-date events...
+ if (event->StartTime() > 0) // checks for "phased out" events
+ return event->IsRunning(true);
+ }
+ return startTime <= t && t < stopTime; // ...otherwise we fall back to normal timer handling
}
}
}
@@ -549,8 +550,12 @@ void cTimer::SetEventFromSchedule(const cSchedules *Schedules)
lastSetEvent = now;
const cEvent *Event = NULL;
if (HasFlags(tfVps) && Schedule->Events()->First()->Vps()) {
- if (event && Recording())
- return; // let the recording end first
+ if (event && event->StartTime() > 0) { // checks for "phased out" events
+ if (Recording())
+ return; // let the recording end first
+ if (now <= event->EndTime() || Matches(0, true))
+ return; // stay with the old event until the timer has completely expired
+ }
// VPS timers only match if their start time exactly matches the event's VPS time:
for (const cEvent *e = Schedule->Events()->First(); e; e = Schedule->Events()->Next(e)) {
if (e->StartTime() && e->RunningStatus() != SI::RunningStatusNotRunning) { // skip outdated events
@@ -562,8 +567,6 @@ void cTimer::SetEventFromSchedule(const cSchedules *Schedules)
}
}
}
- if (!Event && event && (now <= event->EndTime() || Matches(0, true)))
- return; // stay with the old event until the timer has completely expired
}
else {
// Normal timers match the event they have the most overlap with:
diff --git a/vdr.5 b/vdr.5
index a606dde..4003a5e 100644
--- a/vdr.5
+++ b/vdr.5
@@ -8,7 +8,7 @@
.\" License as specified in the file COPYING that comes with the
.\" vdr distribution.
.\"
-.\" $Id: vdr.5 2.29 2012/03/10 14:56:01 kls Exp $
+.\" $Id: vdr.5 2.30 2012/10/15 10:50:23 kls Exp $
.\"
.TH vdr 5 "10 Feb 2008" "1.6" "Video Disk Recorder Files"
.SH NAME
@@ -815,13 +815,13 @@ least one blank.
The lines in this file need not necessarily appear in the correct temporal
sequence, they will be automatically sorted by time index.
+If a frame position doesn't point to an I-frame of the corresponding recording,
+it will be shifted towards the next I-frame (either up or down, whichever is
+closer).
+
\fBCURRENT RESTRICTIONS:\fR
-\ the comment is currently not used by VDR
-.br
--\ marks must have a frame number, and that frame MUST be an I-frame (this
-means that only marks generated by VDR itself can be used, since they
-will always be guaranteed to mark I-frames).
.SS EPG DATA
The file \fIepg.data\fR contains the EPG data in an easily parsable format.
The first character of each line defines what kind of data this line contains.
diff --git a/vdr.c b/vdr.c
index 2e097ba..5494cf7 100644
--- a/vdr.c
+++ b/vdr.c
@@ -22,7 +22,7 @@
*
* The project's page is at http://www.tvdr.de
*
- * $Id: vdr.c 2.40 2012/09/24 12:43:04 kls Exp $
+ * $Id: vdr.c 2.42 2012/10/13 12:48:56 kls Exp $
*/
#include <getopt.h>
@@ -892,7 +892,7 @@ int main(int argc, char *argv[])
Timer->SetInVpsMargin(InVpsMargin);
}
else if (Timer->Event()) {
- InVpsMargin = Timer->Event()->StartTime() <= Now && Timer->Event()->RunningStatus() == SI::RunningStatusUndefined;
+ InVpsMargin = Timer->Event()->StartTime() <= Now && Now < Timer->Event()->EndTime();
NeedsTransponder = Timer->Event()->StartTime() - Now < VPSLOOKAHEADTIME * 3600 && !Timer->Event()->SeenWithin(VPSUPTODATETIME);
}
else {
@@ -1238,6 +1238,8 @@ int main(int argc, char *argv[])
cControl::Shutdown();
cControl::Launch(new cReplayControl);
}
+ else
+ DirectMainFunction(osRecordings); // no last viewed recording, so enter the Recordings menu
break;
default: break;
}