diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 7f7a2d37..ca58ae8e 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -715,6 +715,7 @@ Oliver Endriss for suggesting to ignore channels with an RID that is not 0 when checking for obsolete channels for fixing a possible stack overflow in cListBase::Sort() + for reporting a crash when deleting a recording Reinhard Walter Buchner for adding some satellites to 'sources.conf' @@ -1844,6 +1845,7 @@ Lucian Muresan for exporting some libsi functions for suggesting to add functions to cDevice that allow derived output devices to implement scaling the video to a given size and location + fpr sorting sources.conf by continous azimuth Mattias Grönlund for pointing out a missing cleanup at program exit in case there is a problem @@ -2062,6 +2064,8 @@ Ville Skytt for reporting a possible NULL pointer dereference in cCiSession::SendData() for reporting a superfluous assignment in cPipe::Open() for avoiding unnecessary pkg-config warnings in plugin Makefiles + for fixing building VDR with systemd >= 230 + for avoiding some duplicate code and unnecessary work in nit.c Steffen Beyer for fixing setting the colored button help after deleting a recording in case the next @@ -2924,6 +2928,10 @@ Lars Hanisch for making VDR read command line options from *.conf files in /etc/vdr/conf.d for adding a missing backslash to the help text of the SVDRP command MOVR for fixing a memory leak in case of broken Extended Event Descriptors + for adding a 'const' version of cTimers::GetTimer() + for fixing a typo in the description of cTimers::GetTimersRead() + for suggesting to use dynamic buffering in handling CA descriptors to avoid a + possible buffer overflow Alex Lasnier for adding tuning support for ATSC devices @@ -3225,6 +3233,7 @@ Malte Forkel Marc Perrudin for translating OSD texts to the French language + for adding support for the systemd watchdog Bernard Jaulin for translating OSD texts to the French language @@ -3322,6 +3331,18 @@ Thomas Reufer ViewPort and DrawPort for suggesting to reduce the priority of the "video directory scanner" thread for making the 'newplugin' script create the 'po' subdirectory for translations + for suggesting to add a note to the description of cFont::Size(), regarding possible + differences between it and cFont::Height() + for making the cPlayer member functions FramesPerSecond, GetIndex and GetReplayMode + 'const' + for fixing resuming replay at a given position, which was off by one frame + for improving handling frame numbers to have a smoother progress display during + replay of recordings with B-frames + for fixing replaying recordings to their very end, if they don't end with an I-frame + for implementing a frame parser for H.265 (HEVC) recordings + for adding cFont::Width(void) to get the default character width and allow stretched + font drawing in high level OSDs + for fixing regenerating the index of audio recordings Eike Sauer for reporting a problem with channels that need more than 5 TS packets for detecting @@ -3428,3 +3449,13 @@ Janne P Stefan Pöschel for coding the AFFcleaner, parts of which were used to make the recorder skip empty adaptation field TS packets + +Robert Hannebauer + for fixing an overflow of PIDs in a receiver + +Aitugan Sarbassov + for adding 'S58.5E Kazsat 3' to sources.conf + +Sergey Chernyavskiy + for reporting truncated date/time strings in the skins on multi-byte UTF-8 + for adding a short sleep to cTSBuffer::Action() to avoid high CPU usage diff --git a/HISTORY b/HISTORY index 7e8fd5c6..932b9639 100644 --- a/HISTORY +++ b/HISTORY @@ -8827,3 +8827,57 @@ Video Disk Recorder Revision History live tv (suggested by Dietmar Spingler). - Empty adaptation field TS packets are now skipped when recording (thanks to Christopher Reimer, based on the "AFFcleaner" by Stefan Pöschel). + +2016-12-24: Version 2.3.2 + +- Fixed a crash when deleting a recording (reported by Oliver Endriss). +- Fixed an overflow of PIDs in a receiver (thanks to Robert Hannebauer). +- Updated the Italian OSD texts (thanks to Diego Pierotto). +- Fixed initializing device specific parameters in cDvbTransponderParameters. +- The function SetCurrentChannel(const cChannel *Channel) is now deprecated and + may be removed in a future version. Use SetCurrentChannel(int ChannelNumber) + instead. +- The SVDRP command DELC now refuses to delete the very last channel in the list, + to avoid ending up with an empty channel list. +- The cRwLock class now allows nested read locks within a write lock from the + same thread. This fixes possible crashes when moving or deleting channels in + the menu or through SVDRP (as well as other operations that try to acquire a + read lock within a write lock). +- Fixed a crash when trying to delete a channel that is being used by a timer. +- Fixed setting the current item and counter values in the Recordings menu after + deleting the last recording in a subfolder. +- Fixed a crash when deleting a recording that is currently being replayed. +- Fixed a crash when moving a recording to a folder on a different volume. + The cRecordingsHandler now performs its actual operations in a separate thread, + thus avoiding locking problems and reducing the time between subsequent + operations. +- Added a note to the description of cFont::Size(), regarding possible differences + between it and cFont::Height() (suggested to Thomas Reufer). +- Made the cPlayer member functions FramesPerSecond, GetIndex and GetReplayMode + 'const' (thanks to Thomas Reufer). +- Fixed resuming replay at a given position, which was off by one frame (thanks + to Thomas Reufer). +- Improved handling frame numbers to have a smoother progress display during + replay of recordings with B-frames (thanks to Thomas Reufer). +- Fixed replaying recordings to their very end, if they don't end with an I-frame + (thanks to Thomas Reufer). +- Implemented a frame parser for H.265 (HEVC) recordings (thanks to Thomas Reufer). +- Added cFont::Width(void) to get the default character width and allow stretched + font drawing in high level OSDs (thanks to Thomas Reufer). +- Fixed regenerating the index of audio recordings (thanks to Thomas Reufer). +- Fixed building VDR with systemd >= 230 (thanks to Ville Skyttä). +- Sorted sources.conf by continous azimuth (thanks to Lucian Muresan). +- Added 'S58.5E Kazsat 3' to sources.conf (thanks to Aitugan Sarbassov). +- Fixed truncated date/time strings in the skins on multi-byte UTF-8 systems + (reported by Sergey Chernyavskiy). +- Updated the Estonian OSD texts (thanks to Arthur Konovalov). +- Added a 'const' version of cTimers::GetTimer() (thanks to Lars Hanisch). +- Fixed a typo in the description of cTimers::GetTimersRead() (thanks to Lars + Hanisch). +- Fixed a possible buffer overflow in handling CA descriptors (suggested by + Lars Hanisch). +- Avoiding some duplicate code and unnecessary work in nit.c (thanks to Ville + Skyttä). +- Added support for the systemd watchdog (thanks to Marc Perrudin), +- Added a short sleep to cTSBuffer::Action() to avoid high CPU usage (thanks to + Sergey Chernyavskiy). diff --git a/Makefile b/Makefile index b90cbd24..a0d78b2a 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 4.0 2015/02/09 12:28:24 kls Exp $ +# $Id: Makefile 4.1 2016/12/22 13:18:32 kls Exp $ .DELETE_ON_ERROR: @@ -95,9 +95,9 @@ DEFINES += -DBIDI LIBS += $(shell pkg-config --libs fribidi) endif ifdef SDNOTIFY -INCLUDES += $(shell pkg-config --cflags libsystemd-daemon) +INCLUDES += $(shell pkg-config --silence-errors --cflags libsystemd-daemon || pkg-config --cflags libsystemd) DEFINES += -DSDNOTIFY -LIBS += $(shell pkg-config --libs libsystemd-daemon) +LIBS += $(shell pkg-config --silence-errors --libs libsystemd-daemon || pkg-config --libs libsystemd) endif LIRC_DEVICE ?= /var/run/lirc/lircd diff --git a/PLUGINS/src/skincurses/HISTORY b/PLUGINS/src/skincurses/HISTORY index f24e6766..2a2bccb0 100644 --- a/PLUGINS/src/skincurses/HISTORY +++ b/PLUGINS/src/skincurses/HISTORY @@ -130,3 +130,10 @@ VDR Plugin 'skincurses' Revision History 2015-02-19: Version 2.2.0 - Official release. + +2016-12-22: Version 2.3.2 + +- Added cFont::Width(void) to get the default character width and allow stretched + font drawing in high level OSDs (dummy for skincurses). +- Fixed truncated date/time strings in the skins on multi-byte UTF-8 systems + (reported by Sergey Chernyavskiy). diff --git a/PLUGINS/src/skincurses/skincurses.c b/PLUGINS/src/skincurses/skincurses.c index 358035e0..d11736be 100644 --- a/PLUGINS/src/skincurses/skincurses.c +++ b/PLUGINS/src/skincurses/skincurses.c @@ -3,7 +3,7 @@ * * See the README file for copyright information and how to reach the author. * - * $Id: skincurses.c 4.0 2015/02/17 13:13:17 kls Exp $ + * $Id: skincurses.c 4.2 2016/12/22 14:09:09 kls Exp $ */ #include @@ -12,7 +12,7 @@ #include #include -static const char *VERSION = "2.2.0"; +static const char *VERSION = "2.3.2"; static const char *DESCRIPTION = trNOOP("A text only skin"); static const char *MAINMENUENTRY = NULL; @@ -20,6 +20,7 @@ static const char *MAINMENUENTRY = NULL; class cCursesFont : public cFont { public: + virtual int Width(void) const { return 1; } virtual int Width(uint c) const { return 1; } virtual int Width(const char *s) const { return s ? Utf8StrLen(s) : 0; } virtual int Height(void) const { return 1; } @@ -407,8 +408,7 @@ void cSkinCursesDisplayMenu::SetEvent(const cEvent *Event) return; int y = 2; cTextScroller ts; - char t[32]; - snprintf(t, sizeof(t), "%s %s - %s", *Event->GetDateString(), *Event->GetTimeString(), *Event->GetEndTimeString()); + cString t = cString::sprintf("%s %s - %s", *Event->GetDateString(), *Event->GetTimeString(), *Event->GetEndTimeString()); ts.Set(osd, 0, y, ScOsdWidth, ScOsdHeight - y - 2, t, &Font, clrYellow, clrBackground); if (Event->Vps() && Event->Vps() != Event->StartTime()) { cString buffer = cString::sprintf(" VPS: %s", *Event->GetVpsString()); diff --git a/ci.c b/ci.c index f86f668e..606875b8 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 4.2 2015/09/05 11:45:19 kls Exp $ + * $Id: ci.c 4.3 2016/12/23 14:00:45 kls Exp $ */ #include "ci.h" @@ -756,9 +756,9 @@ class cCiCaPmt { friend class cCiConditionalAccessSupport; private: uint8_t cmdId; - int length; int esInfoLengthPos; - uint8_t capmt[2048]; ///< XXX is there a specified maximum? + cDynamicBuffer caDescriptors; + cDynamicBuffer capmt; int source; int transponder; int programNumber; @@ -768,7 +768,7 @@ public: cCiCaPmt(uint8_t CmdId, int Source, int Transponder, int ProgramNumber, const int *CaSystemIds); uint8_t CmdId(void) { return cmdId; } void SetListManagement(uint8_t ListManagement); - uint8_t ListManagement(void) { return capmt[0]; } + uint8_t ListManagement(void) { return capmt.Get(0); } void AddPid(int Pid, uint8_t StreamType); }; @@ -784,55 +784,46 @@ cCiCaPmt::cCiCaPmt(uint8_t CmdId, int Source, int Transponder, int ProgramNumber caSystemIds[i] = CaSystemIds[i]; } caSystemIds[i] = 0; - uint8_t caDescriptors[512]; - int caDescriptorsLength = GetCaDescriptors(source, transponder, programNumber, caSystemIds, sizeof(caDescriptors), caDescriptors, 0); - length = 0; - capmt[length++] = CPLM_ONLY; - capmt[length++] = (ProgramNumber >> 8) & 0xFF; - capmt[length++] = ProgramNumber & 0xFF; - capmt[length++] = 0x01; // version_number, current_next_indicator - apparently vn doesn't matter, but cni must be 1 - esInfoLengthPos = length; - capmt[length++] = 0x00; // program_info_length H (at program level) - capmt[length++] = 0x00; // program_info_length L - AddCaDescriptors(caDescriptorsLength, caDescriptors); + GetCaDescriptors(source, transponder, programNumber, caSystemIds, caDescriptors, 0); + capmt.Append(CPLM_ONLY); + capmt.Append((ProgramNumber >> 8) & 0xFF); + capmt.Append( ProgramNumber & 0xFF); + capmt.Append(0x01); // version_number, current_next_indicator - apparently vn doesn't matter, but cni must be 1 + esInfoLengthPos = capmt.Length(); + capmt.Append(0x00); // program_info_length H (at program level) + capmt.Append(0x00); // program_info_length L + AddCaDescriptors(caDescriptors.Length(), caDescriptors.Data()); } void cCiCaPmt::SetListManagement(uint8_t ListManagement) { - capmt[0] = ListManagement; + capmt.Set(0, ListManagement); } void cCiCaPmt::AddPid(int Pid, uint8_t StreamType) { if (Pid) { - uint8_t caDescriptors[512]; - int caDescriptorsLength = GetCaDescriptors(source, transponder, programNumber, caSystemIds, sizeof(caDescriptors), caDescriptors, Pid); - //XXX buffer overflow check??? - capmt[length++] = StreamType; - capmt[length++] = (Pid >> 8) & 0xFF; - capmt[length++] = Pid & 0xFF; - esInfoLengthPos = length; - capmt[length++] = 0x00; // ES_info_length H (at ES level) - capmt[length++] = 0x00; // ES_info_length L - AddCaDescriptors(caDescriptorsLength, caDescriptors); + GetCaDescriptors(source, transponder, programNumber, caSystemIds, caDescriptors, Pid); + capmt.Append(StreamType); + capmt.Append((Pid >> 8) & 0xFF); + capmt.Append( Pid & 0xFF); + esInfoLengthPos = capmt.Length(); + capmt.Append(0x00); // ES_info_length H (at ES level) + capmt.Append(0x00); // ES_info_length L + AddCaDescriptors(caDescriptors.Length(), caDescriptors.Data()); } } void cCiCaPmt::AddCaDescriptors(int Length, const uint8_t *Data) { if (esInfoLengthPos) { - if (length + Length < int(sizeof(capmt))) { - if (Length || cmdId == CPCI_QUERY) { - capmt[length++] = cmdId; - memcpy(capmt + length, Data, Length); - length += Length; - int l = length - esInfoLengthPos - 2; - capmt[esInfoLengthPos] = (l >> 8) & 0xFF; - capmt[esInfoLengthPos + 1] = l & 0xFF; - } + if (Length || cmdId == CPCI_QUERY) { + capmt.Append(cmdId); + capmt.Append(Data, Length); + int l = capmt.Length() - esInfoLengthPos - 2; + capmt.Set(esInfoLengthPos, (l >> 8) & 0xFF); + capmt.Set(esInfoLengthPos + 1, l & 0xFF); } - else - esyslog("ERROR: buffer overflow in CA descriptor"); esInfoLengthPos = 0; } else @@ -995,7 +986,7 @@ void cCiConditionalAccessSupport::SendPMT(cCiCaPmt *CaPmt) { if (CaPmt && state >= 2) { dbgprotocol("Slot %d: ==> Ca Pmt (%d) %d %d\n", Tc()->CamSlot()->SlotNumber(), SessionId(), CaPmt->ListManagement(), CaPmt->CmdId()); - SendData(AOT_CA_PMT, CaPmt->length, CaPmt->capmt); + SendData(AOT_CA_PMT, CaPmt->capmt.Length(), CaPmt->capmt.Data()); state = 4; // sent ca pmt } } diff --git a/config.h b/config.h index e5565da3..16630b3a 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 4.5 2015/09/11 08:07:34 kls Exp $ + * $Id: config.h 4.6 2015/09/16 11:11:42 kls Exp $ */ #ifndef __CONFIG_H @@ -22,13 +22,13 @@ // VDR's own version number: -#define VDRVERSION "2.3.1" -#define VDRVERSNUM 20301 // Version * 10000 + Major * 100 + Minor +#define VDRVERSION "2.3.2" +#define VDRVERSNUM 20302 // Version * 10000 + Major * 100 + Minor // The plugin API's version number: -#define APIVERSION "2.3.1" -#define APIVERSNUM 20301 // Version * 10000 + Major * 100 + Minor +#define APIVERSION "2.3.2" +#define APIVERSNUM 20302 // 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/device.c b/device.c index 174281f4..3c97b8ce 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 4.2 2015/09/05 11:42:17 kls Exp $ + * $Id: device.c 4.3 2016/12/23 14:43:44 kls Exp $ */ #include "device.h" @@ -1768,6 +1768,7 @@ void cTSBuffer::Action(void) break; } } + cCondWait::SleepMs(10); // avoids small chunks of data, which cause high CPU usage, esp. on ARM CPUs } } } diff --git a/device.h b/device.h index 31ee3038..9475d23a 100644 --- a/device.h +++ b/device.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: device.h 4.1 2015/04/19 12:12:43 kls Exp $ + * $Id: device.h 4.2 2016/12/06 14:12:39 kls Exp $ */ #ifndef __DEVICE_H @@ -322,7 +322,11 @@ protected: public: static int CurrentChannel(void) { return primaryDevice ? currentChannel : 0; } ///< Returns the number of the current channel on the primary device. +#define DEPRECATED_SETCURRENTCHANNEL +#ifdef DEPRECATED_SETCURRENTCHANNEL static void SetCurrentChannel(const cChannel *Channel) { currentChannel = Channel ? Channel->Number() : 0; } +#endif + static void SetCurrentChannel(int ChannelNumber) { currentChannel = ChannelNumber; } ///< Sets the number of the current channel on the primary device, without ///< actually switching to it. This can be used to correct the current ///< channel number while replaying. diff --git a/dvbdevice.c b/dvbdevice.c index 63af52e7..b3d54c6d 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 4.2 2015/04/18 16:19:28 kls Exp $ + * $Id: dvbdevice.c 4.3 2016/11/07 13:55:58 kls Exp $ */ #include "dvbdevice.h" @@ -201,21 +201,6 @@ int MapToDriver(int Value, const tDvbParameterMap *Map) cDvbTransponderParameters::cDvbTransponderParameters(const char *Parameters) { - polarization = 0; - inversion = INVERSION_AUTO; - bandwidth = 8000000; - coderateH = FEC_AUTO; - coderateL = FEC_AUTO; - modulation = QPSK; - system = DVB_SYSTEM_1; - transmission = TRANSMISSION_MODE_AUTO; - guard = GUARD_INTERVAL_AUTO; - hierarchy = HIERARCHY_AUTO; - rollOff = ROLLOFF_AUTO; - streamId = 0; - t2systemId = 0; - sisoMiso = 0; - pilot = PILOT_AUTO; Parse(Parameters); } @@ -266,6 +251,21 @@ const char *cDvbTransponderParameters::ParseParameter(const char *s, int &Value, bool cDvbTransponderParameters::Parse(const char *s) { + polarization = 0; + inversion = INVERSION_AUTO; + bandwidth = 8000000; + coderateH = FEC_AUTO; + coderateL = FEC_AUTO; + modulation = QPSK; + system = DVB_SYSTEM_1; + transmission = TRANSMISSION_MODE_AUTO; + guard = GUARD_INTERVAL_AUTO; + hierarchy = HIERARCHY_AUTO; + rollOff = ROLLOFF_AUTO; + streamId = 0; + t2systemId = 0; + sisoMiso = 0; + pilot = PILOT_AUTO; while (s && *s) { switch (toupper(*s)) { case 'B': s = ParseParameter(s, bandwidth, BandwidthValues); break; diff --git a/dvbplayer.c b/dvbplayer.c index ca4007e3..ca007353 100644 --- a/dvbplayer.c +++ b/dvbplayer.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbplayer.c 4.1 2015/08/06 13:09:19 kls Exp $ + * $Id: dvbplayer.c 4.4 2016/12/22 11:34:31 kls Exp $ */ #include "dvbplayer.h" @@ -17,13 +17,14 @@ // --- cPtsIndex ------------------------------------------------------------- -#define PTSINDEX_ENTRIES 500 +#define PTSINDEX_ENTRIES 1024 class cPtsIndex { private: struct tPtsIndex { uint32_t pts; // no need for 33 bit - some devices don't even supply the msb int index; + bool independent; }; tPtsIndex pi[PTSINDEX_ENTRIES]; int w, r; @@ -33,8 +34,9 @@ public: cPtsIndex(void); void Clear(void); bool IsEmpty(void); - void Put(uint32_t Pts, int Index); + void Put(uint32_t Pts, int Index, bool Independent); int FindIndex(uint32_t Pts); + int FindFrameNumber(uint32_t Pts); }; cPtsIndex::cPtsIndex(void) @@ -55,10 +57,11 @@ bool cPtsIndex::IsEmpty(void) return w == r; } -void cPtsIndex::Put(uint32_t Pts, int Index) +void cPtsIndex::Put(uint32_t Pts, int Index, bool Independent) { cMutexLock MutexLock(&mutex); pi[w].pts = Pts; + pi[w].independent = Independent; pi[w].index = Index; w = (w + 1) % PTSINDEX_ENTRIES; if (w == r) @@ -87,6 +90,36 @@ int cPtsIndex::FindIndex(uint32_t Pts) return Index; } +int cPtsIndex::FindFrameNumber(uint32_t Pts) +{ + cMutexLock MutexLock(&mutex); + if (w == r) + return lastFound; // replay always starts at an I frame + bool Valid = false; + int d; + int FrameNumber = 0; + int UnplayedIFrame = 2; // GOPs may intersect, so we're looping until we found two unplayed I frames + for (int i = r; i != w && UnplayedIFrame; ) { + d = Pts - pi[i].pts; + if (d > 0x7FFFFFFF) + d = 0xFFFFFFFF - d; // handle rollover + if (d > 0) { + if (pi[i].independent) { + FrameNumber = pi[i].index; // an I frame's index represents its frame number + Valid = true; + } + else + FrameNumber++; // for every played non-I frame, increase frame number + } + else + if (pi[i].independent) + --UnplayedIFrame; + if (++i >= PTSINDEX_ENTRIES) + i = 0; + } + return Valid ? FrameNumber : FindIndex(Pts); // fall back during trick speeds +} + // --- cNonBlockingFileReader ------------------------------------------------ class cNonBlockingFileReader : public cThread { @@ -251,6 +284,7 @@ public: virtual double FramesPerSecond(void) { return framesPerSecond; } virtual void SetAudioTrack(eTrackType Type, const tTrackId *TrackId); virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false); + virtual bool GetFrameNumber(int &Current, int &Total); virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed); }; @@ -433,6 +467,8 @@ void cDvbPlayer::Action(void) } StateKey.Remove(); } + if (readIndex > 0) // will first be incremented in the loop! + --readIndex; nonBlockingFileReader = new cNonBlockingFileReader; int Length = 0; @@ -440,7 +476,7 @@ void cDvbPlayer::Action(void) bool WaitingForData = false; time_t StuckAtEof = 0; uint32_t LastStc = 0; - int LastReadIFrame = -1; + int LastReadFrame = -1; int SwitchToPlayFrame = 0; bool CutIn = false; bool AtLastMark = false; @@ -544,12 +580,9 @@ void cDvbPlayer::Action(void) int r = nonBlockingFileReader->Result(&b); if (r > 0) { WaitingForData = false; - uint32_t Pts = 0; - if (readIndependent) { - Pts = isPesRecording ? PesGetPts(b) : TsGetPts(b, r); - LastReadIFrame = readIndex; - } - readFrame = new cFrame(b, -r, ftUnknown, readIndex, Pts); // hands over b to the ringBuffer + LastReadFrame = readIndex; + uint32_t Pts = isPesRecording ? (PesHasPts(b) ? PesGetPts(b) : -1) : TsGetPts(b, r); + readFrame = new cFrame(b, -r, ftUnknown, readIndex, Pts, readIndependent); // hands over b to the ringBuffer } else if (r < 0) { if (errno == EAGAIN) @@ -604,7 +637,7 @@ void cDvbPlayer::Action(void) pc = playFrame->Count(); if (p) { if (playFrame->Index() >= 0 && playFrame->Pts() != 0) - ptsIndex.Put(playFrame->Pts(), playFrame->Index()); + ptsIndex.Put(playFrame->Pts(), playFrame->Index(), playFrame->Independent()); if (firstPacket) { if (isPesRecording) { PlayPes(NULL, 0); @@ -667,7 +700,7 @@ void cDvbPlayer::Action(void) LastStc = Stc; int Index = ptsIndex.FindIndex(Stc); if (playDir == pdForward && !SwitchToPlayFrame) { - if (Index >= LastReadIFrame) + if (Index >= LastReadFrame) break; // automatically stop at end of recording } else if (Index <= 0 || SwitchToPlayFrame && Index >= SwitchToPlayFrame) @@ -878,7 +911,7 @@ void cDvbPlayer::Goto(int Index, bool Still) if (playMode == pmPause) DevicePlay(); DeviceStillPicture(b, r); - ptsIndex.Put(isPesRecording ? PesGetPts(b) : TsGetPts(b, r), Index); + ptsIndex.Put(isPesRecording ? PesGetPts(b) : TsGetPts(b, r), Index, true); } playMode = pmStill; readIndex = Index; @@ -923,6 +956,17 @@ bool cDvbPlayer::GetIndex(int &Current, int &Total, bool SnapToIFrame) return false; } +bool cDvbPlayer::GetFrameNumber(int &Current, int &Total) +{ + if (index) { + Current = ptsIndex.FindFrameNumber(DeviceGetSTC()); + Total = index->Last(); + return true; + } + Current = Total = -1; + return false; +} + bool cDvbPlayer::GetReplayMode(bool &Play, bool &Forward, int &Speed) { Play = (playMode == pmPlay || playMode == pmFast); @@ -1009,6 +1053,15 @@ bool cDvbPlayerControl::GetIndex(int &Current, int &Total, bool SnapToIFrame) return false; } +bool cDvbPlayerControl::GetFrameNumber(int &Current, int &Total) +{ + if (player) { + player->GetFrameNumber(Current, Total); + return true; + } + return false; +} + bool cDvbPlayerControl::GetReplayMode(bool &Play, bool &Forward, int &Speed) { return player && player->GetReplayMode(Play, Forward, Speed); diff --git a/dvbplayer.h b/dvbplayer.h index ef6f1fce..2fe6e4c9 100644 --- a/dvbplayer.h +++ b/dvbplayer.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbplayer.h 4.1 2015/08/02 13:01:44 kls Exp $ + * $Id: dvbplayer.h 4.2 2016/12/22 10:36:50 kls Exp $ */ #ifndef __DVBPLAYER_H @@ -50,6 +50,10 @@ public: bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false); // Returns the current and total frame index, optionally snapped to the // nearest I-frame. + bool GetFrameNumber(int &Current, int &Total); + // Returns the current and total frame number. In contrast to GetIndex(), + // this function respects the chronological order of frames, which is + // different from its index for streams containing B frames (e.g. H264) bool GetReplayMode(bool &Play, bool &Forward, int &Speed); // Returns the current replay mode (if applicable). // 'Play' tells whether we are playing or pausing, 'Forward' tells whether diff --git a/font.c b/font.c index 29256e05..2a92c34b 100644 --- a/font.c +++ b/font.c @@ -6,7 +6,7 @@ * * BiDi support by Osama Alrawab @2008 Tripoli-Libya. * - * $Id: font.c 4.1 2015/04/19 11:13:45 kls Exp $ + * $Id: font.c 4.2 2016/12/22 12:31:23 kls Exp $ */ #include "font.h" @@ -100,6 +100,7 @@ class cFreetypeFont : public cFont { private: cString fontName; int size; + int width; int height; int bottom; FT_Library library; ///< Handle to library @@ -114,6 +115,7 @@ public: virtual ~cFreetypeFont(); virtual const char *FontName(void) const { return fontName; } virtual int Size(void) const { return size; } + virtual int Width(void) const { return width; } virtual int Width(uint c) const; virtual int Width(const char *s) const; virtual int Height(void) const { return height; } @@ -125,6 +127,7 @@ cFreetypeFont::cFreetypeFont(const char *Name, int CharHeight, int CharWidth) { fontName = Name; size = CharHeight; + width = CharWidth; height = 0; bottom = 0; int error = FT_Init_FreeType(&library); @@ -384,10 +387,12 @@ void cFreetypeFont::DrawText(cPixmap *Pixmap, int x, int y, const char *s, tColo class cDummyFont : public cFont { private: int height; + int width; public: - cDummyFont(int CharHeight) { height = CharHeight; } - virtual int Width(uint c) const { return height; } - virtual int Width(const char *s) const { return height; } + cDummyFont(int CharHeight, int CharWidth) { height = CharHeight; width = CharWidth; } + virtual int Width(void) const { return width ? width : height; } + virtual int Width(uint c) const { return width ? width : height; } + virtual int Width(const char *s) const { return width ? width : height; } virtual int Height(void) const { return height; } virtual void DrawText(cBitmap *Bitmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const {} virtual void DrawText(cPixmap *Pixmap, int x, int y, const char *s, tColor ColorFg, tColor ColorBg, int Width) const {}; @@ -425,7 +430,7 @@ cFont *cFont::CreateFont(const char *Name, int CharHeight, int CharWidth) cString fn = GetFontFileName(Name); cFont *f = *fn ? new cFreetypeFont(fn, CharHeight, CharWidth) : NULL; if (!f || !f->Height()) - f = new cDummyFont(CharHeight); + f = new cDummyFont(CharHeight, CharWidth); return f; } diff --git a/font.h b/font.h index 3932f602..9d18bde2 100644 --- a/font.h +++ b/font.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: font.h 4.0 2014/01/07 12:11:55 kls Exp $ + * $Id: font.h 4.2 2016/12/22 12:43:24 kls Exp $ */ #ifndef __FONT_H @@ -43,7 +43,11 @@ public: ///< Returns the font name. virtual int Size(void) const { return Height(); } ///< Returns the original size as requested when the font was created. - ///< This may be different than the actual height. + ///< This may be smaller than the actual height, for instance if the + ///< font contains descenders. + virtual int Width(void) const = 0; + ///< Returns the original character width as requested when the font was + ///< created, or 0 if the default width is used. virtual int Width(uint c) const = 0; ///< Returns the width of the given character in pixel. virtual int Width(const char *s) const = 0; diff --git a/menu.c b/menu.c index 569900ce..30c95f8d 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 4.12 2015/09/14 13:22:49 kls Exp $ + * $Id: menu.c 4.19 2016/12/22 11:00:13 kls Exp $ */ #include "menu.h" @@ -498,6 +498,7 @@ eOSState cMenuChannels::Delete(void) int DeletedChannel = Channel->Number(); // Check if there is a timer using this channel: if (Timers->UsesChannel(Channel)) { + channelsStateKey.Remove(false); Skins.Message(mtError, tr("Channel is being used by a timer!")); return osContinue; } @@ -519,7 +520,7 @@ eOSState cMenuChannels::Delete(void) if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) Channels->SwitchTo(CurrentChannel->Number()); else - cDevice::SetCurrentChannel(CurrentChannel); + cDevice::SetCurrentChannel(CurrentChannel->Number()); } } channelsStateKey.Remove(Deleted); @@ -546,7 +547,7 @@ void cMenuChannels::Move(int From, int To) if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) Channels->SwitchTo(CurrentChannel->Number()); else - cDevice::SetCurrentChannel(CurrentChannel); + cDevice::SetCurrentChannel(CurrentChannel->Number()); } } channelsStateKey.Remove(); @@ -2686,14 +2687,15 @@ eOSState cMenuRecordingEdit::ApplyChanges(void) cRecordings *Recordings = cRecordings::GetRecordingsWrite(StateKey); cRecording *Recording = Recordings->GetByName(recording->FileName()); if (!Recording) { + StateKey.Remove(false); Skins.Message(mtWarning, tr("Recording vanished!")); return osBack; } bool Modified = false; if (priority != recording->Priority() || lifetime != recording->Lifetime()) { if (!Recording->ChangePriorityLifetime(priority, lifetime)) { - Skins.Message(mtError, tr("Error while changing priority/lifetime!")); StateKey.Remove(Modified); + Skins.Message(mtError, tr("Error while changing priority/lifetime!")); return osContinue; } Modified = true; @@ -2706,8 +2708,8 @@ eOSState cMenuRecordingEdit::ApplyChanges(void) NewName.CompactChars(FOLDERDELIMCHAR); if (strcmp(NewName, Recording->Name())) { if (!Recording->ChangeName(NewName)) { - Skins.Message(mtError, tr("Error while changing folder/name!")); StateKey.Remove(Modified); + Skins.Message(mtError, tr("Error while changing folder/name!")); return osContinue; } Modified = true; @@ -2953,10 +2955,9 @@ void cMenuRecordings::Set(bool Refresh) const char *CurrentRecording = *fileName ? *fileName : cReplayControl::LastReplayed(); cRecordings *Recordings = cRecordings::GetRecordingsWrite(recordingsStateKey); // write access is necessary for sorting! cMenuRecordingItem *LastItem = NULL; - if (Refresh) { - if (cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current())) - CurrentRecording = ri->Recording()->FileName(); - } + if (cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current())) + CurrentRecording = ri->Recording()->FileName(); + int current = Current(); Clear(); GetRecordingsSortMode(DirectoryName()); Recordings->Sort(); @@ -2993,11 +2994,13 @@ void cMenuRecordings::Set(bool Refresh) LastDir->IncrementCounter(Recording->IsNew()); } } + if (Current() < 0) + SetCurrent(Get(current)); // last resort, in case the recording was deleted SetMenuSortMode(RecordingsSortMode == rsmName ? msmName : msmTime); recordingsStateKey.Remove(false); // sorting doesn't count as a real modification + if (Refresh) + Display(); } - if (Refresh) - Display(); } void cMenuRecordings::SetPath(const char *Path) @@ -3087,38 +3090,32 @@ eOSState cMenuRecordings::Delete(void) else return osContinue; } - cRecordings *Recordings = cRecordings::GetRecordingsWrite(recordingsStateKey); - Recordings->SetExplicitModify(); - cRecording *Recording = Recordings->GetByName(ri->Recording()->FileName()); - if (!Recording) { - Skins.Message(mtWarning, tr("Recording vanished!")); - recordingsStateKey.Remove(); - return osContinue; - } - cString FileName = Recording->FileName(); - if (RecordingsHandler.GetUsage(FileName)) { - if (Interface->Confirm(tr("Recording is being edited - really delete?"))) { - RecordingsHandler.Del(FileName); - Recording = Recordings->GetByName(FileName); // RecordingsHandler.Del() might have deleted it if it was the edited version - // we continue with the code below even if Recording is NULL, - // in order to have the menu updated etc. - } - else { - recordingsStateKey.Remove(); - return osContinue; - } - } + cString FileName; + { + LOCK_RECORDINGS_READ; + if (const cRecording *Recording = Recordings->GetByName(ri->Recording()->FileName())) { + FileName = Recording->FileName(); + if (RecordingsHandler.GetUsage(FileName)) { + if (!Interface->Confirm(tr("Recording is being edited - really delete?"))) + return osContinue; + } + } + } + RecordingsHandler.Del(FileName); // must do this w/o holding a lock, because the cleanup section in cDirCopier::Action() might request one! if (cReplayControl::NowReplaying() && strcmp(cReplayControl::NowReplaying(), FileName) == 0) cControl::Shutdown(); + cRecordings *Recordings = cRecordings::GetRecordingsWrite(recordingsStateKey); + Recordings->SetExplicitModify(); + cRecording *Recording = Recordings->GetByName(FileName); if (!Recording || Recording->Delete()) { cReplayControl::ClearLastReplayed(FileName); Recordings->DelByName(FileName); cOsdMenu::Del(Current()); SetHelpKeys(); cVideoDiskUsage::ForceCheck(); - Display(); Recordings->SetModified(); recordingsStateKey.Remove(); + Display(); if (!Count()) return osBack; return osUser2; @@ -3171,8 +3168,6 @@ eOSState cMenuRecordings::Sort(void) eOSState cMenuRecordings::ProcessKey(eKeys Key) { - if (!HasSubMenu()) - Set(); // react on any changes to the recordings list bool HadSubMenu = HasSubMenu(); eOSState state = cOsdMenu::ProcessKey(Key); @@ -3198,7 +3193,8 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key) return state; // closes all recording menus except for the top one Set(); // this is the top level menu, so we refresh it... Open(true); // ...and open any necessary submenus to show the new name - Display(); + if (!HasSubMenu()) + Display(); path = NULL; fileName = NULL; } @@ -3210,14 +3206,16 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key) ri->SetRecording(riSub->Recording()); } } - if (Key == kYellow && HadSubMenu && !HasSubMenu()) { - // the last recording in a subdirectory was deleted, so let's go back up - cOsdMenu::Del(Current()); - if (!Count()) - return osBack; - Display(); - } if (!HasSubMenu()) { + if (HadSubMenu) { + if (Key == kYellow) { + // the last recording in a subdirectory was deleted, so let's go back up + cOsdMenu::Del(Current()); + if (!Count()) + return osBack; + } + } + Set(true); if (Key != kNone) SetHelpKeys(); } @@ -5437,6 +5435,7 @@ cReplayControl::cReplayControl(bool PauseLive) lastPlay = lastForward = false; lastSpeed = -2; // an invalid value timeoutShow = 0; + lastProgressUpdate = 0; timeSearchActive = false; cRecording Recording(fileName); cStatus::MsgReplaying(this, Recording.Name(), Recording.FileName(), true); @@ -5585,41 +5584,43 @@ void cReplayControl::ShowMode(void) bool cReplayControl::ShowProgress(bool Initial) { int Current, Total; - - if (GetIndex(Current, Total) && Total > 0) { - if (!visible) { - displayReplay = Skins.Current()->DisplayReplay(modeOnly); - displayReplay->SetMarks(&marks); - SetNeedsFastResponse(true); - visible = true; - } - if (Initial) { - if (*fileName) { - LOCK_RECORDINGS_READ; - if (const cRecording *Recording = Recordings->GetByName(fileName)) - displayReplay->SetRecording(Recording); + if (Initial || time(NULL) - lastProgressUpdate >= 1) { + if (GetFrameNumber(Current, Total) && Total > 0) { + if (!visible) { + displayReplay = Skins.Current()->DisplayReplay(modeOnly); + displayReplay->SetMarks(&marks); + SetNeedsFastResponse(true); + visible = true; } - lastCurrent = lastTotal = -1; - } - if (Current != lastCurrent || Total != lastTotal) { - if (Setup.ShowRemainingTime || Total != lastTotal) { - int Index = Total; - if (Setup.ShowRemainingTime) - Index = Current - Index; - displayReplay->SetTotal(IndexToHMSF(Index, false, FramesPerSecond())); + if (Initial) { + if (*fileName) { + LOCK_RECORDINGS_READ; + if (const cRecording *Recording = Recordings->GetByName(fileName)) + displayReplay->SetRecording(Recording); + } + lastCurrent = lastTotal = -1; + } + if (Current != lastCurrent || Total != lastTotal) { + time(&lastProgressUpdate); + if (Setup.ShowRemainingTime || Total != lastTotal) { + int Index = Total; + if (Setup.ShowRemainingTime) + Index = Current - Index; + displayReplay->SetTotal(IndexToHMSF(Index, false, FramesPerSecond())); + if (!Initial) + displayReplay->Flush(); + } + displayReplay->SetProgress(Current, Total); if (!Initial) displayReplay->Flush(); - } - displayReplay->SetProgress(Current, Total); - if (!Initial) + displayReplay->SetCurrent(IndexToHMSF(Current, displayFrames, FramesPerSecond())); displayReplay->Flush(); - displayReplay->SetCurrent(IndexToHMSF(Current, displayFrames, FramesPerSecond())); - displayReplay->Flush(); - lastCurrent = Current; + lastCurrent = Current; + } + lastTotal = Total; + ShowMode(); + return true; } - lastTotal = Total; - ShowMode(); - return true; } return false; } @@ -5860,6 +5861,8 @@ eOSState cReplayControl::ProcessKey(eKeys Key) return osEnd; if (Key == kNone && !marksModified) marks.Update(); + if (Key != kNone) + lastProgressUpdate = 0; if (visible) { if (timeoutShow && time(NULL) > timeoutShow) { Hide(); diff --git a/menu.h b/menu.h index 3f2878b3..9a971ad0 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 4.4 2015/09/13 14:17:56 kls Exp $ + * $Id: menu.h 4.5 2016/12/22 10:55:36 kls Exp $ */ #ifndef __MENU_H @@ -300,6 +300,7 @@ private: bool lastPlay, lastForward; int lastSpeed; time_t timeoutShow; + time_t lastProgressUpdate; bool timeSearchActive, timeSearchHide; int timeSearchTime, timeSearchPos; void TimeSearchDisplay(void); diff --git a/nit.c b/nit.c index 864fdac2..874367f3 100644 --- a/nit.c +++ b/nit.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: nit.c 4.3 2015/07/26 09:24:36 kls Exp $ + * $Id: nit.c 4.4 2016/12/23 14:16:59 kls Exp $ */ #include "nit.h" @@ -114,7 +114,7 @@ void cNitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length static int RollOffs[] = { ROLLOFF_35, ROLLOFF_25, ROLLOFF_20, ROLLOFF_AUTO }; dtp.SetRollOff(sd->getModulationSystem() ? RollOffs[sd->getRollOff()] : ROLLOFF_AUTO); int SymbolRate = BCD2INT(sd->getSymbolRate()) / 10; - dbgnit(" %s %d %c %d %d\n", *cSource::ToString(Source), Frequency, Polarizations[sd->getPolarization()], SymbolRate, cChannel::Transponder(Frequency, Polarizations[sd->getPolarization()])); + dbgnit(" %s %d %c %d %d\n", *cSource::ToString(Source), Frequency, dtp.Polarization(), SymbolRate, cChannel::Transponder(Frequency, dtp.Polarization())); if (Setup.UpdateChannels >= 5) { bool found = false; bool forceTransponderUpdate = false; @@ -177,7 +177,7 @@ void cNitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length static int Modulations[] = { QPSK, QAM_16, QAM_32, QAM_64, QAM_128, QAM_256, QAM_AUTO }; dtp.SetModulation(Modulations[min(sd->getModulation(), 6)]); int SymbolRate = BCD2INT(sd->getSymbolRate()) / 10; - dbgnit(" %s %d %d %d %d\n", *cSource::ToString(Source), Frequency, CodeRates[sd->getFecInner()], Modulations[min(sd->getModulation(), 6)], SymbolRate); + dbgnit(" %s %d %d %d %d\n", *cSource::ToString(Source), Frequency, dtp.CoderateH(), dtp.Modulation(), SymbolRate); if (Setup.UpdateChannels >= 5) { bool found = false; bool forceTransponderUpdate = false; @@ -233,7 +233,7 @@ void cNitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length dtp.SetGuard(GuardIntervals[sd->getGuardInterval()]); static int TransmissionModes[] = { TRANSMISSION_MODE_2K, TRANSMISSION_MODE_8K, TRANSMISSION_MODE_4K, TRANSMISSION_MODE_AUTO }; dtp.SetTransmission(TransmissionModes[sd->getTransmissionMode()]); - dbgnit(" %s %d %d %d %d %d %d %d %d\n", *cSource::ToString(Source), Frequency, Bandwidths[sd->getBandwidth()], Constellations[sd->getConstellation()], Hierarchies[sd->getHierarchy()], CodeRates[sd->getCodeRateHP()], CodeRates[sd->getCodeRateLP()], GuardIntervals[sd->getGuardInterval()], TransmissionModes[sd->getTransmissionMode()]); + dbgnit(" %s %d %d %d %d %d %d %d %d\n", *cSource::ToString(Source), Frequency, dtp.Bandwidth(), dtp.Modulation(), dtp.Hierarchy(), dtp.CoderateH(), dtp.CoderateL(), dtp.Guard(), dtp.Transmission()); if (Setup.UpdateChannels >= 5) { bool found = false; bool forceTransponderUpdate = false; @@ -310,9 +310,9 @@ void cNitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length SI::LogicalChannelDescriptor *lcd = (SI::LogicalChannelDescriptor *)d; SI::LogicalChannelDescriptor::LogicalChannel LogicalChannel; for (SI::Loop::Iterator it4; lcd->logicalChannelLoop.getNext(LogicalChannel, it4); ) { - int lcn = LogicalChannel.getLogicalChannelNumber(); - int sid = LogicalChannel.getServiceId(); if (LogicalChannel.getVisibleServiceFlag()) { + int lcn = LogicalChannel.getLogicalChannelNumber(); + int sid = LogicalChannel.getServiceId(); for (cChannel *Channel = Channels->First(); Channel; Channel = Channels->Next(Channel)) { if (!Channel->GroupSep() && Channel->Sid() == sid && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) { ChannelsModified |= Channel->SetLcn(lcn); @@ -328,9 +328,9 @@ void cNitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length SI::HdSimulcastLogicalChannelDescriptor *lcd = (SI::HdSimulcastLogicalChannelDescriptor *)d; SI::HdSimulcastLogicalChannelDescriptor::HdSimulcastLogicalChannel HdSimulcastLogicalChannel; for (SI::Loop::Iterator it4; lcd->hdSimulcastLogicalChannelLoop.getNext(HdSimulcastLogicalChannel, it4); ) { - int lcn = HdSimulcastLogicalChannel.getLogicalChannelNumber(); - int sid = HdSimulcastLogicalChannel.getServiceId(); if (HdSimulcastLogicalChannel.getVisibleServiceFlag()) { + int lcn = HdSimulcastLogicalChannel.getLogicalChannelNumber(); + int sid = HdSimulcastLogicalChannel.getServiceId(); for (cChannel *Channel = Channels->First(); Channel; Channel = Channels->Next(Channel)) { if (!Channel->GroupSep() && Channel->Sid() == sid && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) { ChannelsModified |= Channel->SetLcn(lcn); diff --git a/pat.c b/pat.c index beb5609a..e40d2d5f 100644 --- a/pat.c +++ b/pat.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: pat.c 4.1 2015/08/17 08:46:55 kls Exp $ + * $Id: pat.c 4.3 2016/12/23 14:02:07 kls Exp $ */ #include "pat.h" @@ -81,7 +81,7 @@ public: bool Is(cCaDescriptors * CaDescriptors); bool Empty(void) { return caDescriptors.Count() == 0; } void AddCaDescriptor(SI::CaDescriptor *d, int EsPid); - int GetCaDescriptors(const int *CaSystemIds, int BufSize, uchar *Data, int EsPid); + void GetCaDescriptors(const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid); int GetCaPids(const int *CaSystemIds, int BufSize, int *Pids); const int GetPmtPid(void) { return pmtPid; }; const int *CaIds(void) { return caIds; } @@ -159,30 +159,20 @@ void cCaDescriptors::AddCaDescriptor(SI::CaDescriptor *d, int EsPid) // =0 - common CaDescriptor // <0 - all CaDescriptors regardless of type (old default) -int cCaDescriptors::GetCaDescriptors(const int *CaSystemIds, int BufSize, uchar *Data, int EsPid) +void cCaDescriptors::GetCaDescriptors(const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid) { + Buffer.Clear(); if (!CaSystemIds || !*CaSystemIds) - return 0; - if (BufSize > 0 && Data) { - int length = 0; - for (cCaDescriptor *d = caDescriptors.First(); d; d = caDescriptors.Next(d)) { - if (EsPid < 0 || d->EsPid() == EsPid) { - const int *caids = CaSystemIds; - do { - if (*caids == 0xFFFF || d->CaSystem() == *caids) { - if (length + d->Length() <= BufSize) { - memcpy(Data + length, d->Data(), d->Length()); - length += d->Length(); - } - else - return -1; - } - } while (*++caids); - } + return; + for (cCaDescriptor *d = caDescriptors.First(); d; d = caDescriptors.Next(d)) { + if (EsPid < 0 || d->EsPid() == EsPid) { + const int *caids = CaSystemIds; + do { + if (*caids == 0xFFFF || d->CaSystem() == *caids) + Buffer.Append(d->Data(), d->Length()); + } while (*++caids); } - return length; - } - return -1; + } } int cCaDescriptors::GetCaPids(const int *CaSystemIds, int BufSize, int *Pids) @@ -219,7 +209,7 @@ public: // Returns 0 if this is an already known descriptor, // 1 if it is an all new descriptor with actual contents, // and 2 if an existing descriptor was changed. - int GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, uchar *Data, int EsPid); + void GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid); int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids); int GetPmtPid(int Source, int Transponder, int ServiceId); }; @@ -242,14 +232,15 @@ int cCaDescriptorHandler::AddCaDescriptors(cCaDescriptors *CaDescriptors) return CaDescriptors->Empty() ? 0 : 1; } -int cCaDescriptorHandler::GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, uchar *Data, int EsPid) +void cCaDescriptorHandler::GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid) { cMutexLock MutexLock(&mutex); for (cCaDescriptors *ca = First(); ca; ca = Next(ca)) { - if (ca->Is(Source, Transponder, ServiceId)) - return ca->GetCaDescriptors(CaSystemIds, BufSize, Data, EsPid); + if (ca->Is(Source, Transponder, ServiceId)) { + ca->GetCaDescriptors(CaSystemIds, Buffer, EsPid); + break; + } } - return 0; } int cCaDescriptorHandler::GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids) @@ -274,9 +265,9 @@ int cCaDescriptorHandler::GetPmtPid(int Source, int Transponder, int ServiceId) cCaDescriptorHandler CaDescriptorHandler; -int GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, uchar *Data, int EsPid) +void GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid) { - return CaDescriptorHandler.GetCaDescriptors(Source, Transponder, ServiceId, CaSystemIds, BufSize, Data, EsPid); + CaDescriptorHandler.GetCaDescriptors(Source, Transponder, ServiceId, CaSystemIds, Buffer, EsPid); } int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids) @@ -439,6 +430,7 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length case 1: // STREAMTYPE_11172_VIDEO case 2: // STREAMTYPE_13818_VIDEO case 0x1B: // H.264 + case 0x24: // H.265 Vpid = esPid; Ppid = pmt.getPCRPid(); Vtype = stream.getStreamType(); diff --git a/pat.h b/pat.h index 557d599c..b9929754 100644 --- a/pat.h +++ b/pat.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: pat.h 4.0 2015/01/04 13:17:22 kls Exp $ + * $Id: pat.h 4.1 2016/12/23 14:03:24 kls Exp $ */ #ifndef __PAT_H @@ -38,14 +38,12 @@ public: void Trigger(int Sid = -1); }; -int GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, uchar *Data, int EsPid); +void GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, cDynamicBuffer &Buffer, int EsPid); ///< Gets all CA descriptors for a given channel. ///< Copies all available CA descriptors for the given Source, Transponder and ServiceId - ///< into the provided buffer at Data (at most BufSize bytes). Only those CA descriptors + ///< into the provided buffer. Only those CA descriptors ///< are copied that match one of the given CA system IDs (or all of them, if CaSystemIds ///< is 0xFFFF). - ///< Returns the number of bytes copied into Data (0 if no CA descriptors are - ///< available), or -1 if BufSize was too small to hold all CA descriptors. int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids); ///< Gets all CA pids for a given channel. diff --git a/player.h b/player.h index d9ed964a..aeb8af8f 100644 --- a/player.h +++ b/player.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: player.h 4.0 2013/12/25 13:25:02 kls Exp $ + * $Id: player.h 4.2 2016/12/22 10:38:11 kls Exp $ */ #ifndef __PLAYER_H @@ -57,6 +57,10 @@ public: virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false) { return false; } // Returns the current and total frame index, optionally snapped to the // nearest I-frame. + virtual bool GetFrameNumber(int &Current, int &Total) { return false; } + // Returns the current and total frame number. In contrast to GetIndex(), + // this function respects the chronological order of frames, which is + // different from its index for streams containing B frames (e.g. H264) virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed) { return false; } // Returns the current replay mode (if applicable). // 'Play' tells whether we are playing or pausing, 'Forward' tells whether @@ -98,9 +102,10 @@ public: ///< skins as a last resort, in case they want to display the state of the ///< current player. The return value is expected to be a short, single line ///< string. The default implementation returns an empty string. - double FramesPerSecond(void) { return player->FramesPerSecond(); } - bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false) { return player->GetIndex(Current, Total, SnapToIFrame); } - bool GetReplayMode(bool &Play, bool &Forward, int &Speed) { return player->GetReplayMode(Play, Forward, Speed); } + double FramesPerSecond(void) const { return player->FramesPerSecond(); } + bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false) const { return player->GetIndex(Current, Total, SnapToIFrame); } + bool GetFrameNumber(int &Current, int &Total) const { return player->GetFrameNumber(Current, Total); } + bool GetReplayMode(bool &Play, bool &Forward, int &Speed) const { return player->GetReplayMode(Play, Forward, Speed); } static void Launch(cControl *Control); static void Attach(void); static void Shutdown(void); diff --git a/po/et_EE.po b/po/et_EE.po index 2f6e0de0..467119e6 100644 --- a/po/et_EE.po +++ b/po/et_EE.po @@ -68,7 +68,7 @@ msgid "Transmission" msgstr "Transmissioon" msgid "Guard" -msgstr "Kaitseintervall" +msgstr "Kaitsevahemik" msgid "Hierarchy" msgstr "Hierarhia" @@ -326,7 +326,7 @@ msgid "Content$Unpublished" msgstr "Avaldamata" msgid "Content$Live Broadcast" -msgstr "Otseülekanne" +msgstr "Telepilt" #, c-format msgid "ParentalRating$from %d" @@ -477,7 +477,7 @@ msgid "Key$Subtitles" msgstr "Subtiitrid" msgid "Key$Schedule" -msgstr "Kava" +msgstr "Ajakava" msgid "Key$Channels" msgstr "Kanalid" @@ -486,10 +486,10 @@ msgid "Key$Timers" msgstr "Taimerid" msgid "Key$Recordings" -msgstr "Salvestused" +msgstr "Salvestised" msgid "Key$Setup" -msgstr "Sätted" +msgstr "Seadistamine" msgid "Key$Commands" msgstr "Käsud" @@ -528,7 +528,7 @@ msgid "Free To Air" msgstr "FTA" msgid "encrypted" -msgstr "krüptitud" +msgstr "kodeeritud" msgid "Edit channel" msgstr "Kanali muutmine" @@ -588,16 +588,16 @@ msgid "Channels" msgstr "Kanalid" msgid "Button$Edit" -msgstr "Muutmine" +msgstr "Muuda" msgid "Button$New" msgstr "Uus" msgid "Button$Delete" -msgstr "Kustutada" +msgstr "Kustuta" msgid "Button$Mark" -msgstr "Märkimine" +msgstr "Märgi" msgid "Channel is being used by a timer!" msgstr "Kanal on taimeris kasutusel!" @@ -606,7 +606,7 @@ msgid "Delete channel?" msgstr "Kustutada kanal?" msgid "Edit folder" -msgstr "Kausta muutmine" +msgstr "Muuda kausta" msgid "New folder" msgstr "Uus kaust" @@ -622,7 +622,7 @@ msgid "Folder name must not contain '%c'!" msgstr "Kausta nimi ei saa sisaldada '%c' sümbolit!" msgid "Button$Open" -msgstr "Avada" +msgstr "Ava" msgid "Delete folder and all sub folders?" msgstr "Kustutada kaust ja kõik alamkaustad?" @@ -631,7 +631,7 @@ msgid "Delete folder?" msgstr "Kustutada kaust?" msgid "Edit timer" -msgstr "Taimeri redigeerimine" +msgstr "Muuda taimer" msgid "Active" msgstr "Aktiivne" @@ -661,13 +661,13 @@ msgid "File" msgstr "Fail" msgid "Record on" -msgstr "" +msgstr "Salvestamine" msgid "Button$Folder" msgstr "Kaust" msgid "Button$Single" -msgstr "Ãœks kord" +msgstr "Ãœksik" msgid "Button$Repeating" msgstr "Korduv" @@ -676,13 +676,13 @@ msgid "First day" msgstr "1. päev" msgid "Error while accessing remote timer" -msgstr "" +msgstr "Kaugtaimeri viga" msgid "Timer has been deleted!" -msgstr "" +msgstr "Taimer kustutatud" msgid "Select folder" -msgstr "Kausta valik" +msgstr "Vali kaust" msgid "Timers" msgstr "Taimerid" @@ -700,38 +700,38 @@ msgid "Timer still recording - really delete?" msgstr "Salvestus aktiivne - kas kustutada?" msgid "Event" -msgstr "Saade" +msgstr "Saateinfo" msgid "Button$Timer" msgstr "Taimer" msgid "Button$Record" -msgstr "Salvestada" +msgstr "Salvesta" msgid "Button$Switch" msgstr "Vali" msgid "What's on now?" -msgstr "Hetkel eetris" +msgstr "Hetkel" msgid "What's on next?" -msgstr "Järgmisena eetris" +msgstr "Järgmine" msgid "Button$Next" -msgstr "Tulekul" +msgstr "Järgmine" msgid "Button$Now" msgstr "Hetkel" msgid "Button$Schedule" -msgstr "Kava" +msgstr "Ajakava" msgid "Can't switch channel!" msgstr "Kanali vahetus ei ole võimalik!" #, c-format msgid "Schedule - %s" -msgstr "Kava - %s" +msgstr "Ajakava - %s" #, c-format msgid "This event - %s" @@ -761,55 +761,55 @@ msgstr "Kaust on juba kasutusel - muutmine ei ole võimalik!" #, c-format msgid "Move entire folder containing %d recordings?" -msgstr "Teisaldada kaust mis sisaldab %d salvestust?" +msgstr "Liigutada kaust mis sisaldab %d salvestist?" msgid "Error while moving folder!" -msgstr "Kausta teisaldamise viga!" +msgstr "Kausta liigutamise viga!" msgid "Edit recording" -msgstr "Salvestuse redigeerimine" +msgstr "Muuda salvestist" msgid "This recording is currently in use - no changes are possible!" -msgstr "Salvestus hetkel kasutusel - muutmine ei ole võimalik!" +msgstr "Salvestis hetkel kasutusel - muutmine ei ole võimalik!" msgid "Button$Cancel cutting" -msgstr "Lõikamise tühistamine" +msgstr "Tühista lõikamine" msgid "Button$Stop cutting" -msgstr "Lõikamise peatamine" +msgstr "Peata lõikamine" msgid "Button$Cancel moving" -msgstr "Teisaldamise tühistamine" +msgstr "Tühista liigutamine" msgid "Button$Stop moving" -msgstr "Teisaldamise peatamine" +msgstr "Peata liigutamine" msgid "Button$Cancel copying" -msgstr "Kopeerimise tühistamine" +msgstr "Tühista kopeerimine" msgid "Button$Stop copying" -msgstr "Kopeerimise peatamine" +msgstr "Peata kopeerimine" msgid "Button$Cut" msgstr "Lõika" msgid "Button$Delete marks" -msgstr "Markerite kustutamine" +msgstr "Kustuta markerid" msgid "Recording vanished!" -msgstr "Salvestus kadunud!" +msgstr "Salvestis puudub!" msgid "Edited version already exists - overwrite?" -msgstr "Redigeeritud versioon juba olemas - kirjutada üle?" +msgstr "Muudetud versioon juba olemas - kirjutada üle?" msgid "Error while queueing recording for cutting!" -msgstr "Salvestuse lisamine lõikamiseks ebaõnnestus!" +msgstr "Salvestise lisamine lõikamiseks ebaõnnestus!" msgid "Rename recording to folder name?" -msgstr "Nimetada salvestuse nimi kaustaks?" +msgstr "Ãœmbernimetada kaust salvestise nimega?" msgid "Delete editing marks for this recording?" -msgstr "Kustutada selle salvestuse markerid?" +msgstr "Kustutada selle salvestise markerid?" msgid "Error while deleting editing marks!" msgstr "Markerite kustutamine ebaõnnestus!" @@ -821,55 +821,55 @@ msgid "Error while changing folder/name!" msgstr "Kausta/nime muutmine ebaõnnestus!" msgid "Recording info" -msgstr "Salvestuse info" +msgstr "Salvestise info" msgid "Button$Play" msgstr "Start" msgid "Button$Rewind" -msgstr "Algusesse" +msgstr "Tagasikerimine" msgid "Recordings" -msgstr "Salvestused" +msgstr "Salvestised" msgid "Commands" msgstr "Käsud" msgid "Delete recording?" -msgstr "Kustutada salvestus?" +msgstr "Kustutada salvestis?" msgid "Recording is being edited - really delete?" -msgstr "Salvestust on muudetud - kas kustutada?" +msgstr "Salvestist on muudetud - kas kustutada?" msgid "Error while deleting recording!" -msgstr "Salvestuse kustutamine ebaõnnestus!" +msgstr "Salvestise kustutamine ebaõnnestus!" msgid "Recording commands" msgstr "Salvestuse käsud" msgid "never" -msgstr "ealeski" +msgstr "mitte kunagi" msgid "skin dependent" -msgstr "kestast sõltuv" +msgstr "kujundusest sõltuv" msgid "always" msgstr "alati" msgid "by name" -msgstr "" +msgstr "nime järgi" msgid "by time" -msgstr "" +msgstr "aja järgi" msgid "OSD" -msgstr "Ekraanikuva" +msgstr "OSD" msgid "Setup.OSD$Language" msgstr "Keel" msgid "Setup.OSD$Skin" -msgstr "Kest" +msgstr "Kujundus" msgid "Setup.OSD$Theme" msgstr "Teema" @@ -893,7 +893,7 @@ msgid "Setup.OSD$Use small font" msgstr "Väikese fondi kasutus" msgid "Setup.OSD$Anti-alias" -msgstr "Fondi sakitõrje" +msgstr "Fondi silumine" msgid "Setup.OSD$Default font" msgstr "Vaikefont" @@ -902,7 +902,7 @@ msgid "Setup.OSD$Small font" msgstr "Väike font" msgid "Setup.OSD$Fixed font" -msgstr "Fikseeritud font" +msgstr "Püsisammuga font" msgid "Setup.OSD$Default font size (%)" msgstr "Vaikefondi suurus (%)" @@ -911,7 +911,7 @@ msgid "Setup.OSD$Small font size (%)" msgstr "Väikese fondi suurus (%)" msgid "Setup.OSD$Fixed font size (%)" -msgstr "Fiks. fondi suurus (%)" +msgstr "Püsisammuga fondi suurus (%)" msgid "Setup.OSD$Channel info position" msgstr "Kanaliinfo asukoht" @@ -929,7 +929,7 @@ msgid "Setup.OSD$Info on channel switch" msgstr "Kanaliinfo kuvamine" msgid "Setup.OSD$Timeout requested channel info" -msgstr "Kanaliinfo ajapiirang" +msgstr "Kanaliinfo aegumine" msgid "Setup.OSD$Scroll pages" msgstr "Lehekülje kerimine" @@ -941,16 +941,16 @@ msgid "Setup.OSD$Menu key closes" msgstr "Sulgemine Menüü klahviga" msgid "Setup.OSD$Recording directories" -msgstr "Kausta nime salvestamine" +msgstr "Salvestise kaustade kuvamine" msgid "Setup.OSD$Folders in timer menu" -msgstr "Kaustad taimeri menüüs" +msgstr "Kaustade kuvamine taimeri menüüs" msgid "Setup.OSD$Always sort folders first" -msgstr "Sorteerida kaustad alati ette" +msgstr "Järjesta kaustad alati ette" msgid "Setup.OSD$Default sort mode for recordings" -msgstr "" +msgstr "Salvestiste vaikimisi järjestus" msgid "Setup.OSD$Number keys for characters" msgstr "Teksti sisestamine numbriklahvidega" @@ -971,7 +971,7 @@ msgid "EPG" msgstr "EPG" msgid "Button$Scan" -msgstr "Uuendada" +msgstr "Uuenda" msgid "Setup.EPG$EPG scan timeout (h)" msgstr "EPG skaneerimise viide (h)" @@ -983,10 +983,10 @@ msgid "Setup.EPG$EPG linger time (min)" msgstr "Vana EPG viide (min)" msgid "Setup.EPG$Set system time" -msgstr "Kella sünkroniseerimine" +msgstr "Süsteemi aja sünkimine" msgid "Setup.EPG$Use time from transponder" -msgstr "Sünkroniseerimise transponder" +msgstr "Sünkimise transponder" #. TRANSLATORS: note the plural! msgid "Setup.EPG$Preferred languages" @@ -1009,7 +1009,7 @@ msgid "no" msgstr "ei" msgid "names only" -msgstr "nimed" +msgstr "ainult nimed" msgid "PIDs only" msgstr "PID-id" @@ -1097,7 +1097,7 @@ msgid "Setup.LNB$own" msgstr "oma" msgid "Setup.LNB$Use dish positioner" -msgstr "Antenni positsioneerija kasutamine" +msgstr "Ajami kasutamine" msgid "Setup.LNB$Site latitude (degrees)" msgstr "Asukoha laiuskraad (°)" @@ -1118,32 +1118,32 @@ msgid "East" msgstr "itta (E)" msgid "Setup.LNB$Max. positioner swing (degrees)" -msgstr "Positsioneerija pöördeulatus (°)" +msgstr "Ajami pöördeulatus (°)" msgid "Setup.LNB$Positioner speed (degrees/s)" -msgstr "Positsioneerija kiirus (°/s)" +msgstr "Ajami kiirus (°/s)" msgid "CAM reset" msgstr "CAM taaskäivitamine" msgid "CAM present" -msgstr "CAM esitletud" +msgstr "CAM saadaval" msgid "CAM ready" -msgstr "CAM töövalmis" +msgstr "CAM valmis" #. TRANSLATORS: note the leading blank! msgid " (activating)" msgstr " (aktiveerimine)" msgid "@ device" -msgstr "" +msgstr "@ seade" msgid "CAM" msgstr "CAM" msgid "Button$Cancel activation" -msgstr "Aktiveerimise tühistamine" +msgstr "Tühista aktiveerimine" msgid "Button$Activate" msgstr "Aktiveeri" @@ -1152,7 +1152,7 @@ msgid "Button$Menu" msgstr "Menüü" msgid "Button$Reset" -msgstr "Reset" +msgstr "Lähtesta" msgid "Opening CAM menu..." msgstr "CAM-menüü avamine..." @@ -1164,61 +1164,61 @@ msgid "Can't activate CAM!" msgstr "Ei saa CAM'i aktiveerida!" msgid "CAM is in use - really reset?" -msgstr "CAM on kasutuses - taaskäivitada?" +msgstr "CAM on kasutuses - lähtestada?" msgid "Can't reset CAM!" -msgstr "CAM mooduli taaskäivitus ebaõnnestus!" +msgstr "CAM mooduli lähtestamine ebaõnnestus!" msgid "no instant recording" -msgstr "" +msgstr "kohene salvestus puudub" msgid "confirm instant recording" -msgstr "" +msgstr "kinnita kohene salvestus" msgid "record instantly" -msgstr "" +msgstr "kohene salvestus" msgid "do not pause live video" msgstr "mitte peatada" msgid "confirm pause live video" -msgstr "peatam. kinnitus" +msgstr "peatamise kinnitus" msgid "pause live video" -msgstr "peatada" +msgstr "peata" msgid "confirm" -msgstr "kinnitada" +msgstr "kinnita" msgid "yes" msgstr "jah" msgid "Recording" -msgstr "Salvestamine" +msgstr "Salvestus" msgid "Setup.Recording$Margin at start (min)" -msgstr "Salvestamise algusvaru (min)" +msgstr "Salvestuse algusvaru (min)" msgid "Setup.Recording$Margin at stop (min)" -msgstr "Salvestamise lõpuvaru (min)" +msgstr "Salvestuse lõpuvaru (min)" msgid "Setup.Recording$Default priority" msgstr "Vaikimisi prioriteet" msgid "Setup.Recording$Default lifetime (d)" -msgstr "Salvestuse eluiga (päevi)" +msgstr "Salvestuse eluiga (päevad)" msgid "Setup.Recording$Record key handling" -msgstr "" +msgstr "Salvestuse klahvi käsitlus" msgid "Setup.Recording$Pause key handling" -msgstr "Pausi klahvi käsitlemine" +msgstr "Pausi klahvi käsitlus" msgid "Setup.Recording$Pause priority" msgstr "Pausi prioriteet" msgid "Setup.Recording$Pause lifetime (d)" -msgstr "Pausi eluiga (päevi)" +msgstr "Pausi eluiga (päevad)" msgid "Setup.Recording$Use episode name" msgstr "Episoodinime kasutamine" @@ -1230,37 +1230,37 @@ msgid "Setup.Recording$VPS margin (s)" msgstr "VPS-i algusvaru (s)" msgid "Setup.Recording$Mark instant recording" -msgstr "Kiirsalvestuse märgistamine" +msgstr "Kohese salvestuse märgistamine" msgid "Setup.Recording$Name instant recording" -msgstr "Kiirsalvestuse nimi" +msgstr "Kohese salvestuse nimi" msgid "Setup.Recording$Instant rec. time (min)" -msgstr "Kiirsalvestuse kestus (min)" +msgstr "Kohese salvestuse kestus (min)" msgid "Setup.Recording$present event" -msgstr "hetkesündmus" +msgstr "käesolev saade" msgid "Setup.Recording$Max. video file size (MB)" msgstr "Maks. failisuurus (MB)" msgid "Setup.Recording$Split edited files" -msgstr "Redigeeritud failide tükeldamine" +msgstr "Tükelda muudetud faile" msgid "Setup.Recording$Delete timeshift recording" -msgstr "Ajanihke salvestuse kustutamine" +msgstr "Kustuta ajanihke salvestisi" msgid "Replay" msgstr "Taasesitus" msgid "Setup.Replay$Multi speed mode" -msgstr "Mitmikkiiruse režiim" +msgstr "Mitme kiiruse režiim" msgid "Setup.Replay$Show replay mode" msgstr "Korduse režiimi kuvamine" msgid "Setup.Replay$Show remaining time" -msgstr "Järelejäänud aja kuvamine" +msgstr "Kuva jäänud aega" msgid "Setup.Replay$Progress display time (s)" msgstr "Edenemiseriba kuvamise aeg (s)" @@ -1272,7 +1272,7 @@ msgid "Setup.Replay$Pause replay when jumping to a mark" msgstr "Paus markerile siirdamisel" msgid "Setup.Replay$Skip edited parts" -msgstr "Redigeeritud osade vahelejätmine" +msgstr "Markeeritud osade vahelejätmine" msgid "Setup.Replay$Pause replay at last mark" msgstr "Paus viimasel markeril" @@ -1281,7 +1281,7 @@ msgid "Setup.Replay$Initial duration for adaptive skipping (s)" msgstr "Adaptiivse hüppe pikkuse algväärtus (s)" msgid "Setup.Replay$Reset timeout for adaptive skipping (s)" -msgstr "Adaptiivse hüppe lähtestamise viide (s)" +msgstr "Adaptiivse hüppe lähtestamise aegumine (s)" msgid "Setup.Replay$Alternate behavior for adaptive skipping" msgstr "Adaptiivse hüppe vaheldumise omadus" @@ -1299,31 +1299,31 @@ msgid "Setup.Replay$Resume ID" msgstr "Taasesituse tunnus" msgid "Miscellaneous" -msgstr "Muud sätted" +msgstr "Muud seaded" msgid "Setup.Miscellaneous$Min. event timeout (min)" -msgstr "Min. aeg saateni (min)" +msgstr "Minimaalne aeg saateni (min)" msgid "Setup.Miscellaneous$Min. user inactivity (min)" -msgstr "Min. kasutaja tegevusetus (min)" +msgstr "Minimaalne kasutaja jõudeolek (min)" msgid "Setup.Miscellaneous$SVDRP timeout (s)" -msgstr "SVDRP ooteaeg (s)" +msgstr "SVDRP aegumine (s)" msgid "Setup.Miscellaneous$SVDRP peering" -msgstr "" +msgstr "SVDRP partnerlus" msgid "Setup.Miscellaneous$SVDRP host name" -msgstr "" +msgstr "SVDRP hostinimi" msgid "Setup.Miscellaneous$SVDRP default host" -msgstr "" +msgstr "SVDRP vaikehost" msgid "Setup.Miscellaneous$Zap timeout (s)" -msgstr "Kanalivahetuse ooteaeg (s)" +msgstr "Kanalivahetuse aegumine (s)" msgid "Setup.Miscellaneous$Channel entry timeout (ms)" -msgstr "Kanali sisestamise ajalimiit (ms)" +msgstr "Kanali sisestamise aegumine (ms)" msgid "Setup.Miscellaneous$Remote control repeat delay (ms)" msgstr "Kaugjuhtimispuldi kordamise viide (ms)" @@ -1356,30 +1356,30 @@ msgid "Setup.Miscellaneous$Emergency exit" msgstr "Hädaväljumine" msgid "Plugins" -msgstr "Laiendusmoodulid" +msgstr "Pluginad" msgid "This plugin has no setup parameters!" -msgstr "Sellel laienudusmoodulil ei ole seadeid!" +msgstr "Sellel pluginal seaded puuduvad!" msgid "Setup" -msgstr "Sätted" +msgstr "Seaded" msgid "Restart" -msgstr "Restart" +msgstr "Taaskäivita" msgid "Really restart?" -msgstr "Restart?" +msgstr "Taaskäivitada?" #. TRANSLATORS: note the leading and trailing blanks! msgid " Stop recording " -msgstr " Lõpetada salvestamine " +msgstr " Lõpeta salvestamine " msgid "Schedule" -msgstr "Kava" +msgstr "Ajakava" #. TRANSLATORS: note the leading blank! msgid " Stop replaying" -msgstr " Lõpetada taasesitus" +msgstr " Lõpeta taasesitus" msgid "Button$Pause" msgstr "Paus" @@ -1392,7 +1392,7 @@ msgstr "Jätkamine" #. TRANSLATORS: note the leading blank! msgid " Cancel editing" -msgstr " Tühistada töötlemine" +msgstr " Tühista töötlemine" msgid "Stop recording?" msgstr "Lõpetada salvestamine?" @@ -1416,7 +1416,7 @@ msgid "No free DVB device to record!" msgstr "Puudub vaba DVB seade salvestamiseks!" msgid "Pausing live video..." -msgstr "Otseedastuse peatamine..." +msgstr "Telepildi peatamine..." msgid "Delete timeshift recording?" msgstr "Kustutada ajanihke salvestust?" @@ -1426,19 +1426,19 @@ msgid "Jump: " msgstr "Hüpe: " msgid "No editing marks defined!" -msgstr "Redigeerimise markerid puuduvad!" +msgstr "Muutmise markerid puuduvad!" msgid "No editing sequences defined!" -msgstr "Redigeerimise järjestus määramata!" +msgstr "Muutmise järjestus määramata!" msgid "Can't start editing process!" -msgstr "Redigeerimise start ebaõnnestus!" +msgstr "Muutmise start ebaõnnestus!" msgid "Editing process started" -msgstr "Redigeerimine käivitatud" +msgstr "Töötlemine käivitatud" msgid "Editing process already active!" -msgstr "Redigeerimine juba aktiivne!" +msgstr "Töötlemine juba aktiivne!" msgid "FileNameChars$ abcdefghijklmnopqrstuvwxyz0123456789-.,#~\\^$[]|()*+?{}/:%@&" msgstr " abcdefghijklmnopqrsÅ¡zžtuvwõäöüxy0123456789-.,#~\\^$[]|()*+?{}/:%@&" @@ -1456,7 +1456,7 @@ msgid "Button$Insert" msgstr "Lisa (INS)" msgid "Plugin" -msgstr "Laiendusmoodul" +msgstr "Plugin" msgid "Up/Dn for new location - OK to move" msgstr "'Ãœles/Alla' uus asukoht - 'OK' kinnitus" @@ -1494,16 +1494,16 @@ msgstr "lülitada välja?" #, c-format msgid "Plugin %s wakes up in %ld min, continue?" -msgstr "Laiendusmoodul %s ärkab %ld minuti pärast, jätkata?" +msgstr "Plugin %s ärkab %ld minuti pärast, jätkata?" msgid "Editing - restart anyway?" -msgstr "Töötlemine aktiivne - restart?" +msgstr "Töötlemine aktiivne - taaskäivitada?" msgid "Recording - restart anyway?" -msgstr "Salvestamine aktiivne - restart?" +msgstr "Salvestamine aktiivne - taaskäivitada ikkagi?" msgid "restart anyway?" -msgstr "restart?" +msgstr "taaskäivitada ikkagi?" #. TRANSLATORS: note the trailing blank! msgid "Volume " @@ -1525,7 +1525,7 @@ msgid "DEVICES" msgstr "SEADMED" msgid "LIVE" -msgstr "LIVE" +msgstr "TELEPILT" msgid "PLAY" msgstr "ESITUS" @@ -1570,10 +1570,10 @@ msgid "Upcoming recording!" msgstr "Salvestamine tulekul!" msgid "Pause live video?" -msgstr "Peatada otseülekanne?" +msgstr "Peatada telepilt?" msgid "Start recording?" -msgstr "" +msgstr "Käivitada salvestamine?" msgid "Recording started" msgstr "Salvestamine käivitatud" @@ -1594,7 +1594,7 @@ msgid "Editing process finished" msgstr "Töötlemine lõpetatud" msgid "Press any key to cancel restart" -msgstr "Restardi katkestamiseks vajuta suvalist klahvi" +msgstr "Taaskäivitamise katkestamiseks vajuta suvalist klahvi" #, c-format msgid "VDR will shut down in %s minutes" diff --git a/po/it_IT.po b/po/it_IT.po index d54a4a39..9552f989 100644 --- a/po/it_IT.po +++ b/po/it_IT.po @@ -12,7 +12,7 @@ msgstr "" "Project-Id-Version: VDR 2.2.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-09-11 10:38+0200\n" -"PO-Revision-Date: 2015-02-12 19:31+0100\n" +"PO-Revision-Date: 2015-09-14 19:28+0100\n" "Last-Translator: Diego Pierotto \n" "Language-Team: Italian \n" "Language: it\n" @@ -667,7 +667,7 @@ msgid "File" msgstr "Nome" msgid "Record on" -msgstr "" +msgstr "Registrazione avviata" msgid "Button$Folder" msgstr "Cartella" @@ -682,10 +682,10 @@ msgid "First day" msgstr "1° giorno" msgid "Error while accessing remote timer" -msgstr "" +msgstr "Errore durante l'accesso al timer remoto" msgid "Timer has been deleted!" -msgstr "" +msgstr "Il timer è stata eliminato!" msgid "Select folder" msgstr "Seleziona cartella" @@ -863,10 +863,10 @@ msgid "always" msgstr "sempre" msgid "by name" -msgstr "" +msgstr "per nome" msgid "by time" -msgstr "" +msgstr "per ora" msgid "OSD" msgstr "OSD" @@ -956,7 +956,7 @@ msgid "Setup.OSD$Always sort folders first" msgstr "Ordina sempre per prima le cartelle" msgid "Setup.OSD$Default sort mode for recordings" -msgstr "" +msgstr "Modalità ordinamento predefinito per registrazioni" msgid "Setup.OSD$Number keys for characters" msgstr "Tasti numerici per i caratteri" @@ -1143,7 +1143,7 @@ msgid " (activating)" msgstr " (attivazione)" msgid "@ device" -msgstr "" +msgstr "@ dispositivo" msgid "CAM" msgstr "Accesso condizionato CAM" @@ -1176,13 +1176,13 @@ msgid "Can't reset CAM!" msgstr "Impossibile reimpostare il modulo CAM!" msgid "no instant recording" -msgstr "" +msgstr "nessuna registrazione istantanea" msgid "confirm instant recording" -msgstr "" +msgstr "conferma registrazione istantanea" msgid "record instantly" -msgstr "" +msgstr "registra istantaneamente" msgid "do not pause live video" msgstr "non mettere in pausa il video dal vivo" @@ -1215,7 +1215,7 @@ msgid "Setup.Recording$Default lifetime (d)" msgstr "Scadenza predefinita (gg)" msgid "Setup.Recording$Record key handling" -msgstr "" +msgstr "Gestione chiave registrazione" msgid "Setup.Recording$Pause key handling" msgstr "Gestione tasto Pausa" @@ -1317,13 +1317,13 @@ msgid "Setup.Miscellaneous$SVDRP timeout (s)" msgstr "Scadenza SVDRP (s)" msgid "Setup.Miscellaneous$SVDRP peering" -msgstr "" +msgstr "Punto SVDRP" msgid "Setup.Miscellaneous$SVDRP host name" -msgstr "" +msgstr "Nome sistema SVDRP" msgid "Setup.Miscellaneous$SVDRP default host" -msgstr "" +msgstr "Sistema predefinito SVDRP" msgid "Setup.Miscellaneous$Zap timeout (s)" msgstr "Scadenza Zapping (s)" @@ -1579,7 +1579,7 @@ msgid "Pause live video?" msgstr "Pausare video dal vivo?" msgid "Start recording?" -msgstr "" +msgstr "Avviare registrazione?" msgid "Recording started" msgstr "Registrazione avviata" diff --git a/receiver.c b/receiver.c index 9375d4f4..8d647c02 100644 --- a/receiver.c +++ b/receiver.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: receiver.c 4.0 2015/01/12 14:04:31 kls Exp $ + * $Id: receiver.c 4.1 2015/09/16 11:19:47 kls Exp $ */ #include "receiver.h" @@ -37,8 +37,10 @@ void cReceiver::SetPriority(int Priority) bool cReceiver::AddPid(int Pid) { if (Pid) { - if (numPids < MAXRECEIVEPIDS) - pids[numPids++] = Pid; + if (numPids < MAXRECEIVEPIDS) { + if (!WantsPid(Pid)) + pids[numPids++] = Pid; + } else { dsyslog("too many PIDs in cReceiver (Pid = %d)", Pid); return false; diff --git a/recording.c b/recording.c index a847c7d1..5293459e 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 4.4 2015/09/09 10:21:58 kls Exp $ + * $Id: recording.c 4.6 2016/12/22 12:58:20 kls Exp $ */ #include "recording.h" @@ -1701,7 +1701,7 @@ void cDirCopier::Action(void) int To = -1; size_t BufferSize = BUFSIZ; while (Running()) { - // Suspend cutting if we have severe throughput problems: + // Suspend copying if we have severe throughput problems: if (Throttled()) { cCondWait::SleepMs(100); continue; @@ -1900,6 +1900,7 @@ bool cRecordingsHandlerEntry::Active(bool &Error) cRecordingsHandler RecordingsHandler; cRecordingsHandler::cRecordingsHandler(void) +:cThread("recordings handler") { finished = true; error = false; @@ -1907,6 +1908,23 @@ cRecordingsHandler::cRecordingsHandler(void) cRecordingsHandler::~cRecordingsHandler() { + Cancel(3); +} + +void cRecordingsHandler::Action(void) +{ + while (Running()) { + { + cMutexLock MutexLock(&mutex); + while (cRecordingsHandlerEntry *r = operations.First()) { + if (!r->Active(error)) + operations.Del(r); + } + if (!operations.Count()) + break; + } + cCondWait::SleepMs(100); + } } cRecordingsHandlerEntry *cRecordingsHandler::Get(const char *FileName) @@ -1934,8 +1952,7 @@ bool cRecordingsHandler::Add(int Usage, const char *FileNameSrc, const char *Fil Usage |= ruPending; operations.Add(new cRecordingsHandlerEntry(Usage, FileNameSrc, FileNameDst)); finished = false; - Active(); // start it right away if possible - LOCK_RECORDINGS_WRITE; // to trigger a state change + Start(); return true; } else @@ -1955,17 +1972,17 @@ bool cRecordingsHandler::Add(int Usage, const char *FileNameSrc, const char *Fil void cRecordingsHandler::Del(const char *FileName) { cMutexLock MutexLock(&mutex); - if (cRecordingsHandlerEntry *r = Get(FileName)) { + if (cRecordingsHandlerEntry *r = Get(FileName)) operations.Del(r); - LOCK_RECORDINGS_WRITE; // to trigger a state change - } } void cRecordingsHandler::DelAll(void) { - cMutexLock MutexLock(&mutex); - operations.Clear(); - LOCK_RECORDINGS_WRITE; // to trigger a state change + { + cMutexLock MutexLock(&mutex); + operations.Clear(); + } + Cancel(3); } int cRecordingsHandler::GetUsage(const char *FileName) @@ -1976,18 +1993,6 @@ int cRecordingsHandler::GetUsage(const char *FileName) return ruNone; } -bool cRecordingsHandler::Active(void) -{ - cMutexLock MutexLock(&mutex); - while (cRecordingsHandlerEntry *r = operations.First()) { - if (r->Active(error)) - return true; - else - operations.Del(r); - } - return false; -} - bool cRecordingsHandler::Finished(bool &Error) { cMutexLock MutexLock(&mutex); @@ -2324,7 +2329,7 @@ void cIndexFileGenerator::Action(void) Buffer.Del(Processed); } } - else if (PatPmtParser.Vpid()) { + else if (PatPmtParser.Completed()) { // Step 2 - sync FrameDetector: int Processed = FrameDetector.Analyze(Data, Length); if (Processed > 0) { @@ -2346,9 +2351,9 @@ void cIndexFileGenerator::Action(void) PatPmtParser.ParsePmt(p, TS_SIZE); Length -= TS_SIZE; p += TS_SIZE; - if (PatPmtParser.Vpid()) { - // Found Vpid, so rewind to sync FrameDetector: - FrameDetector.SetPid(PatPmtParser.Vpid(), PatPmtParser.Vtype()); + if (PatPmtParser.Completed()) { + // Found pid, so rewind to sync FrameDetector: + FrameDetector.SetPid(PatPmtParser.Vpid() ? PatPmtParser.Vpid() : PatPmtParser.Apid(0), PatPmtParser.Vpid() ? PatPmtParser.Vtype() : PatPmtParser.Atype(0)); BufferChunks = IFG_BUFFER_SIZE; Rewind = true; break; diff --git a/recording.h b/recording.h index cebd2ee0..b649f6fd 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 4.3 2015/08/29 14:12:14 kls Exp $ + * $Id: recording.h 4.4 2016/12/13 13:12:12 kls Exp $ */ #ifndef __RECORDING_H @@ -302,16 +302,18 @@ DEF_LIST_LOCK2(Recordings, DeletedRecordings); class cRecordingsHandlerEntry; -class cRecordingsHandler { +class cRecordingsHandler : public cThread { private: cMutex mutex; cList operations; bool finished; bool error; cRecordingsHandlerEntry *Get(const char *FileName); +protected: + virtual void Action(void); public: cRecordingsHandler(void); - ~cRecordingsHandler(); + virtual ~cRecordingsHandler(); bool Add(int Usage, const char *FileNameSrc, const char *FileNameDst = NULL); ///< Adds the given FileNameSrc to the recordings handler for (later) ///< processing. Usage can be either ruCut, ruMove or ruCopy. FileNameDst @@ -329,12 +331,6 @@ public: ///< Deletes/terminates all operations. int GetUsage(const char *FileName); ///< Returns the usage type for the given FileName. - bool Active(void); - ///< Checks whether there is currently any operation running and starts - ///> the next one form the list if the previous one has finished. - ///< This function must be called regularly to trigger switching to the - ///< next operation in the list. - ///< Returns true if there are any operations in the list. bool Finished(bool &Error); ///< Returns true if all operations in the list have been finished. ///< If there have been any errors, Errors will be set to true. diff --git a/remux.c b/remux.c index 6c07efcb..2e1bc31f 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 4.1 2015/03/11 09:49:38 kls Exp $ + * $Id: remux.c 4.3 2016/12/22 12:58:20 kls Exp $ */ #include "remux.h" @@ -603,6 +603,7 @@ cPatPmtParser::cPatPmtParser(bool UpdatePrimaryDevice) void cPatPmtParser::Reset(void) { + completed = false; pmtSize = 0; patVersion = pmtVersion = -1; pmtPids[0] = 0; @@ -708,6 +709,7 @@ void cPatPmtParser::ParsePmt(const uchar *Data, int Length) case 0x01: // STREAMTYPE_11172_VIDEO case 0x02: // STREAMTYPE_13818_VIDEO case 0x1B: // H.264 + case 0x24: // H.265 vpid = stream.getPid(); vtype = stream.getStreamType(); ppid = Pmt.getPCRPid(); @@ -892,6 +894,7 @@ void cPatPmtParser::ParsePmt(const uchar *Data, int Length) } } pmtVersion = Pmt.getVersionNumber(); + completed = true; } else esyslog("ERROR: can't parse PMT"); @@ -1204,16 +1207,16 @@ private: 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; - // +protected: + cTsPayload tsPayload; + uint32_t scanner; bool gotAccessUnitDelimiter; bool gotSequenceParameterSet; uchar GetByte(bool Raw = false); @@ -1430,6 +1433,81 @@ void cH264Parser::ParseSliceHeader(void) } } +// --- cH265Parser ----------------------------------------------------------- + +class cH265Parser : public cH264Parser { +private: + enum eNalUnitType { + nutSliceSegmentTrailingN = 0, + nutSliceSegmentTrailingR = 1, + nutSliceSegmentTSAN = 2, + nutSliceSegmentTSAR = 3, + nutSliceSegmentSTSAN = 4, + nutSliceSegmentSTSAR = 5, + nutSliceSegmentRADLN = 6, + nutSliceSegmentRADLR = 7, + nutSliceSegmentRASLN = 8, + nutSliceSegmentRASLR = 9, + nutSliceSegmentBLAWLP = 16, + nutSliceSegmentBLAWRADL = 17, + nutSliceSegmentBLANLP = 18, + nutSliceSegmentIDRWRADL = 19, + nutSliceSegmentIDRNLP = 20, + nutSliceSegmentCRANUT = 21, + nutVideoParameterSet = 32, + nutSequenceParameterSet = 33, + nutPictureParameterSet = 34, + nutAccessUnitDelimiter = 35, + nutEndOfSequence = 36, + nutEndOfBitstream = 37, + nutFillerData = 38, + nutPrefixSEI = 39, + nutSuffixSEI = 40, + nutNonVCLRes0 = 41, + nutNonVCLRes3 = 44, + nutUnspecified0 = 48, + nutUnspecified7 = 55, + }; +public: + cH265Parser(void); + virtual int Parse(const uchar *Data, int Length, int Pid); + }; + +cH265Parser::cH265Parser(void) +:cH264Parser() +{ +} + +int cH265Parser::Parse(const uchar *Data, int Length, int Pid) +{ + newFrame = independentFrame = false; + tsPayload.Setup(const_cast(Data), Length, Pid); + if (TsPayloadStart(Data)) { + tsPayload.SkipPesHeader(); + scanner = EMPTY_SCANNER; + } + for (;;) { + scanner = (scanner << 8) | GetByte(true); + if ((scanner & 0xFFFFFF00) == 0x00000100) { // NAL unit start + uchar NalUnitType = (scanner >> 1) & 0x3F; + GetByte(); // nuh_layer_id + nuh_temporal_id_plus1 + if (NalUnitType <= nutSliceSegmentRASLR || (NalUnitType >= nutSliceSegmentBLAWLP && NalUnitType <= nutSliceSegmentCRANUT)) { + if (NalUnitType == nutSliceSegmentIDRWRADL || NalUnitType == nutSliceSegmentIDRNLP || NalUnitType == nutSliceSegmentCRANUT) + independentFrame = true; + if (GetBit()) { // first_slice_segment_in_pic_flag + newFrame = true; + tsPayload.Statistics(); + } + break; + } + } + if (tsPayload.AtPayloadStart() // stop at any new payload start to have the buffer refilled if necessary + || tsPayload.Eof()) // or if we're out of data + break; + } + return tsPayload.Used(); +} + // --- cFrameDetector -------------------------------------------------------- cFrameDetector::cFrameDetector(int Pid, int Type) @@ -1456,14 +1534,16 @@ void cFrameDetector::SetPid(int Pid, int Type) { pid = Pid; type = Type; - isVideo = type == 0x01 || type == 0x02 || type == 0x1B; // MPEG 1, 2 or H.264 + isVideo = type == 0x01 || type == 0x02 || type == 0x1B || type == 0x24; // MPEG 1, 2, H.264 or H.265 delete parser; parser = NULL; if (type == 0x01 || type == 0x02) parser = new cMpeg2Parser; else if (type == 0x1B) parser = new cH264Parser; - else if (type == 0x04 || type == 0x06) // MPEG audio or AC3 audio + else if (type == 0x24) + parser = new cH265Parser; + else if (type == 0x03 || 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); diff --git a/remux.h b/remux.h index bd0d1459..5eab076f 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 4.0 2014/03/22 14:58:24 kls Exp $ + * $Id: remux.h 4.1 2016/12/22 13:09:54 kls Exp $ */ #ifndef __REMUX_H @@ -361,6 +361,7 @@ private: uint16_t compositionPageIds[MAXSPIDS]; uint16_t ancillaryPageIds[MAXSPIDS]; bool updatePrimaryDevice; + bool completed; protected: int SectionLength(const uchar *Data, int Length) { return (Length >= 3) ? ((int(Data[1]) & 0x0F) << 8)| Data[2] : 0; } public: @@ -397,6 +398,8 @@ public: int Vtype(void) const { return vtype; } ///< Returns the video stream type as defined by the current PMT, or 0 if no video ///< stream type has been detected, yet. + bool Completed(void) { return completed; } + ///< Returns true if the PMT has been completely parsed. const int *Apids(void) const { return apids; } const int *Dpids(void) const { return dpids; } const int *Spids(void) const { return spids; } diff --git a/ringbuffer.c b/ringbuffer.c index 05e2cf66..d33a4719 100644 --- a/ringbuffer.c +++ b/ringbuffer.c @@ -7,7 +7,7 @@ * Parts of this file were inspired by the 'ringbuffy.c' from the * LinuxDVB driver (see linuxtv.org). * - * $Id: ringbuffer.c 4.0 2012/09/22 11:26:49 kls Exp $ + * $Id: ringbuffer.c 4.1 2016/12/22 10:26:13 kls Exp $ */ #include "ringbuffer.h" @@ -390,12 +390,13 @@ void cRingBufferLinear::Del(int Count) // --- cFrame ---------------------------------------------------------------- -cFrame::cFrame(const uchar *Data, int Count, eFrameType Type, int Index, uint32_t Pts) +cFrame::cFrame(const uchar *Data, int Count, eFrameType Type, int Index, uint32_t Pts, bool Independent) { count = abs(Count); type = Type; index = Index; pts = Pts; + independent = Type == ftAudio ? true : Independent; if (Count < 0) data = (uchar *)Data; else { diff --git a/ringbuffer.h b/ringbuffer.h index 70f22c69..9699bbc8 100644 --- a/ringbuffer.h +++ b/ringbuffer.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: ringbuffer.h 4.0 2013/02/16 15:20:37 kls Exp $ + * $Id: ringbuffer.h 4.1 2016/12/22 10:26:13 kls Exp $ */ #ifndef __RINGBUFFER_H @@ -113,8 +113,9 @@ private: eFrameType type; int index; uint32_t pts; + bool independent; public: - cFrame(const uchar *Data, int Count, eFrameType = ftUnknown, int Index = -1, uint32_t Pts = 0); + cFrame(const uchar *Data, int Count, eFrameType = ftUnknown, int Index = -1, uint32_t Pts = 0, bool independent = false); ///< Creates a new cFrame object. ///< If Count is negative, the cFrame object will take ownership of the given ///< Data. Otherwise it will allocate Count bytes of memory and copy Data. @@ -124,6 +125,7 @@ public: eFrameType Type(void) const { return type; } int Index(void) const { return index; } uint32_t Pts(void) const { return pts; } + bool Independent(void) const { return independent; } }; class cRingBufferFrame : public cRingBuffer { diff --git a/skinclassic.c b/skinclassic.c index b6d183b1..26408993 100644 --- a/skinclassic.c +++ b/skinclassic.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: skinclassic.c 4.0 2013/03/03 15:26:09 kls Exp $ + * $Id: skinclassic.c 4.1 2016/12/22 14:07:04 kls Exp $ */ #include "skinclassic.h" @@ -352,8 +352,7 @@ void cSkinClassicDisplayMenu::SetEvent(const cEvent *Event) const cFont *font = cFont::GetFont(fontOsd); int y = y2; cTextScroller ts; - char t[32]; - snprintf(t, sizeof(t), "%s %s - %s", *Event->GetDateString(), *Event->GetTimeString(), *Event->GetEndTimeString()); + cString t = cString::sprintf("%s %s - %s", *Event->GetDateString(), *Event->GetTimeString(), *Event->GetEndTimeString()); ts.Set(osd, x1, y, x2 - x1, y3 - y, t, font, Theme.Color(clrMenuEventTime), Theme.Color(clrBackground)); if (Event->Vps() && Event->Vps() != Event->StartTime()) { cString buffer = cString::sprintf(" VPS: %s ", *Event->GetVpsString()); diff --git a/skinlcars.c b/skinlcars.c index d84a753f..0fae3b85 100644 --- a/skinlcars.c +++ b/skinlcars.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: skinlcars.c 4.1 2015/09/01 10:07:07 kls Exp $ + * $Id: skinlcars.c 4.2 2016/12/22 14:05:56 kls Exp $ */ // "Star Trek: The Next Generation"(R) is a registered trademark of Paramount Pictures, @@ -1636,8 +1636,7 @@ void cSkinLCARSDisplayMenu::SetEvent(const cEvent *Event) int xl = xi00; int y = yi00; cTextScroller ts; - char t[32]; - snprintf(t, sizeof(t), "%s %s - %s", *Event->GetDateString(), *Event->GetTimeString(), *Event->GetEndTimeString()); + cString t = cString::sprintf("%s %s - %s", *Event->GetDateString(), *Event->GetTimeString(), *Event->GetEndTimeString()); ts.Set(osd, xl, y, xi01 - xl, yi01 - y, t, font, Theme.Color(clrEventTime), Theme.Color(clrBackground)); if (Event->Vps() && Event->Vps() != Event->StartTime()) { cString buffer = cString::sprintf(" VPS: %s ", *Event->GetVpsString()); diff --git a/skinsttng.c b/skinsttng.c index f10f1204..792652ee 100644 --- a/skinsttng.c +++ b/skinsttng.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: skinsttng.c 4.0 2013/11/15 15:33:14 kls Exp $ + * $Id: skinsttng.c 4.1 2016/12/22 14:07:22 kls Exp $ */ // "Star Trek: The Next Generation"(R) is a registered trademark of Paramount Pictures @@ -655,8 +655,7 @@ void cSkinSTTNGDisplayMenu::SetEvent(const cEvent *Event) int xl = x3 + TextSpacing; int y = y3; cTextScroller ts; - char t[32]; - snprintf(t, sizeof(t), "%s %s - %s", *Event->GetDateString(), *Event->GetTimeString(), *Event->GetEndTimeString()); + cString t = cString::sprintf("%s %s - %s", *Event->GetDateString(), *Event->GetTimeString(), *Event->GetEndTimeString()); ts.Set(osd, xl, y, x4 - xl, y4 - y, t, font, Theme.Color(clrMenuEventTime), Theme.Color(clrBackground)); if (Event->Vps() && Event->Vps() != Event->StartTime()) { cString buffer = cString::sprintf(" VPS: %s ", *Event->GetVpsString()); diff --git a/sources.conf b/sources.conf index ad4131c0..169eecf1 100644 --- a/sources.conf +++ b/sources.conf @@ -51,6 +51,7 @@ S52.5E Yahsat 1A S53E Express AM22 S56E DirecTV 1R S57E NSS 12 +S58.5E Kazsat 3 S60E Intelsat 904 S62E Intelsat 902 S64E Intelsat 906 @@ -109,80 +110,80 @@ S172E Eutelsat 172A S180E Intelsat 18 S177W NSS 9 -# Atlantic - -S0.8W Intelsat 10-02 -S1W Thor 5/6 -S4W Amos 2/3 -S5W Eutelsat 5 West A -S7W Nilesat 101/201 & Eutelsat 7 West A -S8W Eutelsat 8 West A/C -S11W Express AM44 -S12.5W Eutelsat 12 West A -S14W Express A4 -S15W Telstar 12 -S18W Intelsat 901 -S20W NSS 7 -S22W SES 4 -S24.5W Intelsat 905 -S27.5W Intelsat 907 -S30W Hispasat 1D/1E -S31.5W Intelsat 25 -S34.5W Intelsat 903 -S37.5W NSS 10 & Telstar 11N -S40.5W SES 6 -S43W Intelsat 11 -S45W Intelsat 14 -S50W Intelsat 1R -S53W Intelsat 23 -S55.5W Intelsat 805 -S58W Intelsat 21 -S61W Amazonas 2/3 - # America -S61.5W Echostar 16 -S63W Telstar 14R -S65W Star One C1 -S67W AMC 4 -S70W Star One C2 -S72W AMC 6 -S72.7W Nimiq 5 -S75W Star One C3 -S77W QuetzSat 1 -S82W Nimiq 4 -S83W AMC 9 -S84W Brasilsat B4 +S139W AMC 8 +S137W AMC 7 +S135W AMC 10 +S133W Galaxy 15 +S131W AMC 11 +S129W Ciel 2 +S127W Galaxy 13/Horizons 1 +S125W Galaxy 14 & AMC 21 +S123W Galaxy 18 +S121W Echostar 9/Galaxy 23 +S119W Echostar 14 & DirecTV 7S +S118.8W Anik F3 +S116.8W SatMex 8 +S114.9W SatMex 5 +S113W SatMex 6 +S111.1W Anik F2 +S110W DirecTV 5 & Echostar 10/11 +S107.3W Anik F1R/G1 +S105W AMC 15/18 +S103W AMC 1 +S101W DirecTV 4S/8 & SES 1 +S99.2W Galaxy 16 +S97W Galaxy 19 +S95W Galaxy 3C +S93.1W Galaxy 25 +S91W Galaxy 17 & Nimiq 6 +S89W Galaxy 28 +S87W SES 2 S85W AMC 16 S85.1W XM 3 -S87W SES 2 -S89W Galaxy 28 -S91W Galaxy 17 & Nimiq 6 -S93.1W Galaxy 25 -S95W Galaxy 3C -S97W Galaxy 19 -S99.2W Galaxy 16 -S101W DirecTV 4S/8 & SES 1 -S103W AMC 1 -S105W AMC 15/18 -S107.3W Anik F1R/G1 -S110W DirecTV 5 & Echostar 10/11 -S111.1W Anik F2 -S113W SatMex 6 -S114.9W SatMex 5 -S116.8W SatMex 8 -S118.8W Anik F3 -S119W Echostar 14 & DirecTV 7S -S121W Echostar 9/Galaxy 23 -S123W Galaxy 18 -S125W Galaxy 14 & AMC 21 -S127W Galaxy 13/Horizons 1 -S129W Ciel 2 -S131W AMC 11 -S133W Galaxy 15 -S135W AMC 10 -S137W AMC 7 -S139W AMC 8 +S84W Brasilsat B4 +S83W AMC 9 +S82W Nimiq 4 +S77W QuetzSat 1 +S75W Star One C3 +S72W AMC 6 +S72.7W Nimiq 5 +S70W Star One C2 +S67W AMC 4 +S65W Star One C1 +S63W Telstar 14R +S61.5W Echostar 16 + +# Atlantic + +S61W Amazonas 2/3 +S58W Intelsat 21 +S55.5W Intelsat 805 +S53W Intelsat 23 +S50W Intelsat 1R +S45W Intelsat 14 +S43W Intelsat 11 +S40.5W SES 6 +S37.5W NSS 10 & Telstar 11N +S34.5W Intelsat 903 +S31.5W Intelsat 25 +S30W Hispasat 1D/1E +S27.5W Intelsat 907 +S24.5W Intelsat 905 +S22W SES 4 +S20W NSS 7 +S18W Intelsat 901 +S15W Telstar 12 +S14W Express A4 +S12.5W Eutelsat 12 West A +S11W Express AM44 +S8W Eutelsat 8 West A/C +S7W Nilesat 101/201 & Eutelsat 7 West A +S5W Eutelsat 5 West A +S4W Amos 2/3 +S1W Thor 5/6 +S0.8W Intelsat 10-02 S360E Any satellite diff --git a/svdrp.c b/svdrp.c index 1a24d296..1697cc6a 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 4.9 2015/09/14 13:23:06 kls Exp $ + * $Id: svdrp.c 4.11 2016/12/08 10:48:53 kls Exp $ */ #include "svdrp.h" @@ -1228,6 +1228,10 @@ void cSVDRPServer::CmdDELC(const char *Option) int n = Channels->GetNextNormal(CurrentChannel->Index()); if (n < 0) n = Channels->GetPrevNormal(CurrentChannel->Index()); + if (n < 0) { + Reply(501, "Can't delete channel \"%s\" - list would be empty", Option); + return; + } CurrentChannel = Channels->Get(n); CurrentChannelNr = 0; // triggers channel switch below } @@ -1240,7 +1244,7 @@ void cSVDRPServer::CmdDELC(const char *Option) if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) Channels->SwitchTo(CurrentChannel->Number()); else - cDevice::SetCurrentChannel(CurrentChannel); + cDevice::SetCurrentChannel(CurrentChannel->Number()); } Reply(250, "Channel \"%s\" deleted", Option); } @@ -1899,7 +1903,7 @@ void cSVDRPServer::CmdMOVC(const char *Option) if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) Channels->SwitchTo(CurrentChannel->Number()); else - cDevice::SetCurrentChannel(CurrentChannel); + cDevice::SetCurrentChannel(CurrentChannel->Number()); } isyslog("SVDRP < %s channel %d moved to %d", *connection, FromNumber, ToNumber); Reply(250,"Channel \"%d\" moved to \"%d\"", From, To); diff --git a/thread.c b/thread.c index 993d16dd..47eb9775 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 4.1 2015/08/29 14:43:03 kls Exp $ + * $Id: thread.c 4.2 2016/12/08 09:45:25 kls Exp $ */ #include "thread.h" @@ -151,6 +151,8 @@ void cCondVar::Broadcast(void) cRwLock::cRwLock(bool PreferWriter) { + locked = 0; + writeLockThreadId = 0; pthread_rwlockattr_t attr; pthread_rwlockattr_init(&attr); pthread_rwlockattr_setkind_np(&attr, PreferWriter ? PTHREAD_RWLOCK_PREFER_WRITER_NP : PTHREAD_RWLOCK_PREFER_READER_NP); @@ -170,8 +172,15 @@ bool cRwLock::Lock(bool Write, int TimeoutMs) if (!GetAbsTime(&abstime, TimeoutMs)) TimeoutMs = 0; } - if (Write) + if (Write) { Result = TimeoutMs ? pthread_rwlock_timedwrlock(&rwlock, &abstime) : pthread_rwlock_wrlock(&rwlock); + if (Result == 0) + writeLockThreadId = cThread::ThreadId(); + } + else if (writeLockThreadId == cThread::ThreadId()) { + locked++; // there can be any number of stacked read locks, so we keep track here + Result = 0; // aquiring a read lock while holding a write lock within the same thread is OK + } else Result = TimeoutMs ? pthread_rwlock_timedrdlock(&rwlock, &abstime) : pthread_rwlock_rdlock(&rwlock); return Result == 0; @@ -179,6 +188,13 @@ bool cRwLock::Lock(bool Write, int TimeoutMs) void cRwLock::Unlock(void) { + if (writeLockThreadId == cThread::ThreadId()) { // this is the thread that obtained the initial write lock + if (locked) { // this is the unlock of a read lock within the write lock + locked--; + return; + } + } + writeLockThreadId = 0; pthread_rwlock_unlock(&rwlock); } @@ -206,8 +222,8 @@ void cMutex::Lock(void) void cMutex::Unlock(void) { - if (!--locked) - pthread_mutex_unlock(&mutex); + if (!--locked) + pthread_mutex_unlock(&mutex); } // --- cThread --------------------------------------------------------------- @@ -474,9 +490,11 @@ void cStateLock::Unlock(cStateKey &StateKey, bool IncState) if (StateKey.write && IncState && !explicitModify) state++; StateKey.state = state; - StateKey.write = false; - threadId = 0; - explicitModify = false; + if (StateKey.write) { + StateKey.write = false; + threadId = 0; + explicitModify = false; + } rwLock.Unlock(); } diff --git a/thread.h b/thread.h index b5a07c79..8cca55c0 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 4.1 2015/08/17 13:06:24 kls Exp $ + * $Id: thread.h 4.2 2016/12/08 09:11:24 kls Exp $ */ #ifndef __THREAD_H @@ -14,6 +14,8 @@ #include #include +typedef pid_t tThreadId; + class cCondWait { private: pthread_mutex_t mutex; @@ -53,6 +55,8 @@ public: class cRwLock { private: pthread_rwlock_t rwlock; + int locked; + tThreadId writeLockThreadId; public: cRwLock(bool PreferWriter = false); ~cRwLock(); @@ -72,8 +76,6 @@ public: void Unlock(void); }; -typedef pid_t tThreadId; - class cThread { friend class cThreadLock; private: diff --git a/timers.c b/timers.c index 771f66b2..5bc11036 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 4.5 2015/09/13 13:10:24 kls Exp $ + * $Id: timers.c 4.7 2016/12/23 09:48:39 kls Exp $ */ #include "timers.h" @@ -748,9 +748,9 @@ const cTimer *cTimers::GetById(int Id) const return NULL; } -cTimer *cTimers::GetTimer(cTimer *Timer) +const cTimer *cTimers::GetTimer(const cTimer *Timer) const { - for (cTimer *ti = First(); ti; ti = Next(ti)) { + for (const cTimer *ti = First(); ti; ti = Next(ti)) { if (!ti->Remote() && ti->Channel() == Timer->Channel() && (ti->WeekDays() && ti->WeekDays() == Timer->WeekDays() || !ti->WeekDays() && ti->Day() == Timer->Day()) && diff --git a/timers.h b/timers.h index 4222c104..7ee116c8 100644 --- a/timers.h +++ b/timers.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: timers.h 4.3 2015/09/09 10:40:24 kls Exp $ + * $Id: timers.h 4.6 2016/12/23 09:49:31 kls Exp $ */ #ifndef __TIMERS_H @@ -122,7 +122,7 @@ public: cTimers(void); static const cTimers *GetTimersRead(cStateKey &StateKey, int TimeoutMs = 0); ///< Gets the list of timers for read access. If TimeoutMs is given, - ///< it will wait that long to get a write lock before giving up. + ///< it will wait that long to get a read lock before giving up. ///< Otherwise it will wait indefinitely. If no read lock can be ///< obtained within the given timeout, NULL will be returned. ///< The list is locked and a pointer to it is returned if the state @@ -170,7 +170,8 @@ public: static int NewTimerId(void); const cTimer *GetById(int Id) const; cTimer *GetById(int Id) { return const_cast(static_cast(this)->GetById(Id)); }; - cTimer *GetTimer(cTimer *Timer); + const cTimer *GetTimer(const cTimer *Timer) const; + cTimer *GetTimer(const cTimer *Timer) { return const_cast(static_cast(this)->GetTimer(Timer)); }; const cTimer *GetMatch(time_t t) const; cTimer *GetMatch(time_t t) { return const_cast(static_cast(this)->GetMatch(t)); }; const cTimer *GetMatch(const cEvent *Event, eTimerMatch *Match = NULL) const; diff --git a/tools.c b/tools.c index adfff1c3..754673db 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 4.4 2015/09/10 13:17:55 kls Exp $ + * $Id: tools.c 4.5 2016/12/23 14:03:40 kls Exp $ */ #include "tools.h" @@ -2272,6 +2272,44 @@ void cListBase::Sort(void) free(a); } +// --- cDynamicBuffer -------------------------------------------------------- + +cDynamicBuffer::cDynamicBuffer(int InitialSize) +{ + initialSize = InitialSize; + buffer = NULL; + size = used = 0; +} + +cDynamicBuffer::~cDynamicBuffer() +{ + free(buffer); +} + +bool cDynamicBuffer::Realloc(int NewSize) +{ + if (size < NewSize) { + NewSize = max(NewSize, size ? size * 3 / 2 : initialSize); // increase size by at least 50% + if (uchar *NewBuffer = (uchar *)realloc(buffer, NewSize)) { + buffer = NewBuffer; + size = NewSize; + } + else { + esyslog("ERROR: out of memory"); + return false; + } + } + return true; +} + +void cDynamicBuffer::Append(const uchar *Data, int Length) +{ + if (Assert(used + Length)) { + memcpy(buffer + used, Data, Length); + used += Length; + } +} + // --- cHashBase ------------------------------------------------------------- cHashBase::cHashBase(int Size) diff --git a/tools.h b/tools.h index 1563db92..73cca5a3 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 4.3 2015/09/06 10:45:54 kls Exp $ + * $Id: tools.h 4.5 2016/12/23 13:56:35 kls Exp $ */ #ifndef __TOOLS_H @@ -609,7 +609,7 @@ public: \ else \ list = c##Class::Get##Name##Read(stateKey); \ } \ - ~c##Name##Lock() { stateKey.Remove(); } \ + ~c##Name##Lock() { if (list) stateKey.Remove(); } \ const c##Class *Name(void) const { return list; } \ c##Class *Name(void) { return const_cast(list); } \ } @@ -775,6 +775,26 @@ public: bool Load(const char *Directory, bool DirsOnly = false); }; +class cDynamicBuffer { +private: + uchar *buffer; + int initialSize; + int size; // the total size of the buffer (bytes in memory) + int used; // the number of used bytes, starting at the beginning of the buffer + bool Realloc(int NewSize); + bool Assert(int NewSize) { return size < NewSize ? Realloc(NewSize) : true; } // inline for performance! +public: + cDynamicBuffer(int InitialSize = 1024); + ~cDynamicBuffer(); + void Append(const uchar *Data, int Length); + void Append(uchar Data) { if (Assert(used + 1)) buffer[used++] = Data; } + void Set(int Index, uchar Data) { if (Assert(Index + 1)) buffer[Index] = Data; } + uchar Get(int Index) { return Index < used ? buffer[Index] : 0; } + void Clear(void) { used = 0; } + uchar *Data(void) { return buffer; } + int Length(void) { return used; } + }; + class cHashObject : public cListObject { friend class cHashBase; private: diff --git a/vdr.c b/vdr.c index 6b0bf2b0..8a494714 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.tvdr.de * - * $Id: vdr.c 4.7 2015/09/11 08:02:50 kls Exp $ + * $Id: vdr.c 4.9 2016/12/23 14:34:37 kls Exp $ */ #include @@ -171,6 +171,9 @@ static void Watchdog(int signum) // Something terrible must have happened that prevented the 'alarm()' from // being called in time, so let's get out of here: esyslog("PANIC: watchdog timer expired - exiting!"); +#ifdef SDNOTIFY + sd_notify(0, "STOPPING=1\nSTATUS=PANIC"); +#endif exit(1); } @@ -235,6 +238,10 @@ int main(int argc, char *argv[]) #if defined(VDR_USER) VdrUser = VDR_USER; #endif +#ifdef SDNOTIFY + time_t SdWatchdog; + int SdWatchdogTimeout = 0; +#endif cArgs *Args = NULL; if (argc == 1) { @@ -914,6 +921,16 @@ int main(int argc, char *argv[]) } #ifdef SDNOTIFY + if (sd_watchdog_enabled(0, NULL) > 0) { + uint64_t timeout; + SdWatchdog = time(NULL); + sd_watchdog_enabled(0, &timeout); + SdWatchdogTimeout = (int)timeout/1000000; + dsyslog("SD_WATCHDOG enabled with timeout set to %d seconds", SdWatchdogTimeout); + } + + // Startup notification: + sd_notify(0, "READY=1\nSTATUS=Ready"); #endif @@ -976,6 +993,14 @@ int main(int argc, char *argv[]) dsyslog("max. latency time %d seconds", MaxLatencyTime); } } +#ifdef SDNOTIFY + // Ping systemd watchdog when half the timeout is elapsed: + if (SdWatchdogTimeout && (Now - SdWatchdog) * 2 > SdWatchdogTimeout) { + sd_notify(0, "WATCHDOG=1"); + SdWatchdog = Now; + dsyslog("SD_WATCHDOG ping"); + } +#endif // Handle channel and timer modifications: { // Channels and timers need to be stored in a consistent manner, @@ -1480,9 +1505,6 @@ int main(int argc, char *argv[]) ShutdownHandler.countdown.Cancel(); } - // Keep the recordings handler alive: - RecordingsHandler.Active(); - if ((Now - LastInteract) > ACTIVITYTIMEOUT && !cRecordControls::Active() && !RecordingsHandler.Active() && (Now - cRemote::LastActivity()) > ACTIVITYTIMEOUT) { // Handle housekeeping tasks @@ -1568,5 +1590,11 @@ Exit: closelog(); if (HasStdin) tcsetattr(STDIN_FILENO, TCSANOW, &savedTm); +#ifdef SDNOTIFY + if (ShutdownHandler.GetExitCode() == 2) + sd_notify(0, "STOPPING=1\nSTATUS=Startup failed, exiting"); + else + sd_notify(0, "STOPPING=1\nSTATUS=Exiting"); +#endif return ShutdownHandler.GetExitCode(); }