diff options
author | Klaus Schmidinger <kls (at) cadsoft (dot) de> | 2005-05-29 18:00:00 +0200 |
---|---|---|
committer | Klaus Schmidinger <kls (at) cadsoft (dot) de> | 2005-05-29 18:00:00 +0200 |
commit | f8367110245149a1333e47118c41827288c814c3 (patch) | |
tree | 6445577ffff8fab5e188d127170c8a2f2772a194 | |
parent | c23522ade253e23b5bf6141d7d7e7335d6abcd1d (diff) | |
download | vdr-patch-lnbsharing-f8367110245149a1333e47118c41827288c814c3.tar.gz vdr-patch-lnbsharing-f8367110245149a1333e47118c41827288c814c3.tar.bz2 |
Version 1.3.25vdr-1.3.25
- Updated the Estonian OSD texts (thanks to Arthur Konovalov).
- Some cable providers don't mark short channel names according to the standard,
but rather go their own way and use "name>short name". VDR now splits at this
character for cable channels (thanks to Gerhard Steiner for reporting this one).
- Added a check for Setup.DiSEqC in cDvbDevice::ProvidesTransponder(), otherwise
the EPG scan didn't work on systems that don't use DiSEqC (thanks to Michael
Reinelt for reporting this one).
- Made the Makefile patch friendlier (thanks to Ludwig Nussel).
- Made cOsd::isOpen an integer counter to avoid problems with messages when a
cOsdObject uses the raw OSD (thanks to Andreas Regel for reporting this one).
- Updated the Danish OSD texts (thanks to Mogens Elneff).
- The file 'summary.vdr' has been replaced with 'info.vdr' and now contains the
information about a recording, in the same format as the events are stored in
'epg.data' (see man vdr(5) for details). Existing summary files can be converted
to the new format by running the Perl script 'summary2info.pl', as in
summary2info.pl /video
(the parameter given has to be the video directory). If there is no 'info.vdr'
file for a recording, an attempt is made to read a 'summary.vdr'.
- The "Summary" button in the "Recordings" menu has been renamed to "Info", and
the page it brings up now shows the recording's information, much like the EPG
event page. Therefore it now no longer uses the skin's SetText() function, but
rather the SetRecording() function. Skin plugins may need to adjust that function
accordingly (see skinsttng.c, for instance).
- The SVDRP command LSTR now lists the recording information in the same tagged
format as the LSTE command lists the EPG data.
- The audio track menu now contains track descriptions when replaying (provided
such descriptions were available in the EPG data when the recording was made,
and are stored in the info.vdr file).
- Avoiding extra blanks at the end of names of instant recordings.
- Removed converting byte order on big endian systems from cDvbOsd::Flush(),
which, according to Johannes Stezenbach and Paavo Hartikainen, is wrong.
- Added cPlayer::DeviceSetVideoDisplayFormat() (thanks to Marco Schlüßler).
- No longer saving the setup in case of a fatal error, to keep the volume level
from being set to a wrong value (thanks to Marco Schlüßler).
- Fixed a possible hangup when ending a replay session while cIndexFile::CatchUp()
is waiting (thanks to Marco Schlüßler).
- The SVDRP command DELR no longer deletes recordings that are currently being
written to by a timer (thanks to Sascha Volkenandt for pointing out this one).
- Pressing the "Play" key in live viewing mode now resumes a previous replay
session (thanks to Mirko Dölle).
- Now dropping EPG events that have a zero start time or duration (thanks to
Oliver Endriss).
- No longer stopping Transfer Mode or replay immediately when the Power button
is pressed (thanks to Rolf Ahrenberg).
- Moved the NPTL and UTF-8 checks after the version and help output (thanks to
Andreas Kool for pointing out that 'vdr --version' failed on an UTF-8 system).
- Made tChannelID::operator==() inline for better performance (thanks to Georg
Acher).
- Introduced cListBase::count for better performance (thanks to Georg Acher).
- cEvent no longer stores the channelID directly, but rather has a pointer to
the schedule it is in.
- Now using hash tables to speed up cSchedule::GetEvent() (partially based on
a patch from Georg Acher).
- Avoiding unnecessary calls to getLength() in libsi/si.c, and avoiding the
'& 0xff' in CRC32::crc32() of libsi/util.c (thanks to Georg Acher).
- Speeded up deleting duplicate channels.
- Fixed listing recordings with empty episode names in the LSTR command (thanks
to Stefan Huelswitt for pointing this out).
- Added cThread::SetPriority() and using it in cSectionHandler::Action() to
reduce the priority of the section handler threads (as suggested by Georg Acher).
-rw-r--r-- | CONTRIBUTORS | 38 | ||||
-rw-r--r-- | HISTORY | 67 | ||||
-rw-r--r-- | MANUAL | 2 | ||||
-rw-r--r-- | Make.config.template | 4 | ||||
-rw-r--r-- | Makefile | 10 | ||||
-rw-r--r-- | PLUGINS/src/skincurses/HISTORY | 4 | ||||
-rw-r--r-- | PLUGINS/src/skincurses/skincurses.c | 29 | ||||
-rw-r--r-- | channels.c | 57 | ||||
-rw-r--r-- | channels.conf | 32 | ||||
-rw-r--r-- | channels.h | 16 | ||||
-rw-r--r-- | config.h | 6 | ||||
-rw-r--r-- | cutter.c | 4 | ||||
-rw-r--r-- | dvbdevice.c | 4 | ||||
-rw-r--r-- | dvbosd.c | 6 | ||||
-rw-r--r-- | dvbplayer.c | 4 | ||||
-rw-r--r-- | eit.c | 37 | ||||
-rw-r--r-- | epg.c | 203 | ||||
-rw-r--r-- | epg.h | 27 | ||||
-rw-r--r-- | i18n.c | 39 | ||||
-rw-r--r-- | libsi/Makefile | 4 | ||||
-rw-r--r-- | libsi/si.c | 35 | ||||
-rw-r--r-- | libsi/util.c | 5 | ||||
-rw-r--r-- | menu.c | 161 | ||||
-rw-r--r-- | menu.h | 4 | ||||
-rw-r--r-- | osd.c | 8 | ||||
-rw-r--r-- | osd.h | 6 | ||||
-rw-r--r-- | player.h | 3 | ||||
-rw-r--r-- | recording.c | 206 | ||||
-rw-r--r-- | recording.h | 30 | ||||
-rw-r--r-- | sdt.c | 11 | ||||
-rw-r--r-- | sections.c | 3 | ||||
-rw-r--r-- | skinclassic.c | 30 | ||||
-rw-r--r-- | skins.h | 4 | ||||
-rw-r--r-- | skinsttng.c | 36 | ||||
-rw-r--r-- | sources.h | 5 | ||||
-rwxr-xr-x | summary2info.pl | 47 | ||||
-rw-r--r-- | svdrp.c | 32 | ||||
-rw-r--r-- | thread.c | 8 | ||||
-rw-r--r-- | thread.h | 3 | ||||
-rw-r--r-- | tools.c | 91 | ||||
-rw-r--r-- | tools.h | 39 | ||||
-rw-r--r-- | vdr.5 | 10 | ||||
-rw-r--r-- | vdr.c | 58 |
43 files changed, 1015 insertions, 413 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS index cc5bdb4..eff35c7 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -197,6 +197,8 @@ Stefan Huelswitt <huels@iname.com> for fixing handling symbolic links in cRecordings::ScanVideoDir() for reporting a memory leak in tComponent for fixing a memory leak in cDvbPlayer + for pointing out that recordings with empty episode names were not listed correctly + in the LSTR command Ulrich Röder <roeder@efr-net.de> for pointing out that there are channels that have a symbol rate higher than 27500 @@ -408,6 +410,7 @@ Mirko Dölle <mdoelle@linux-user.de> change in Daylight Saving Time for suggesting to avoid the external 'find' command to scan the video directory for reporting a problem with inconsistent channel and timer lists + for making the "Play" key in live viewing mode resume a previous replay session Michael Rakowski <mrak@gmx.de> for translating OSD texts to the Polish language @@ -563,6 +566,7 @@ Oliver Endriss <o.endriss@gmx.de> for reporting a problem with the name of the remote control for which the keys are being learned overwriting the date/time in the 'classic' skin for making cDvbOsd check available OSD memory at runtime + for making cEIT::cEIT() drop EPG events that have a zero start time or duration Reinhard Walter Buchner <rw.buchner@freenet.de> for adding some satellites to 'sources.conf' @@ -603,6 +607,8 @@ Gerhard Steiner <steiner@mail.austria.com> for reporting a problem with newly created timers in case they are not confirmed with "Ok" for reporting an occasional "Broken pipe" error in SVDRP connections + for reporting that some cable channels don't mark short channel names according + to the standard Jaakko Hyvätti <jaakko@hyvatti.iki.fi> for translating OSD texts to the Finnish language @@ -642,6 +648,7 @@ Andreas Kool <akool@akool.de> for fixing detecting the /dev/videoN devices for GRAB in case there are others before the DVB devices for fixing a possible NULL pointer access in cEITScanner::Process() + for pointing out that 'vdr --version' failed on an UTF-8 system Guy Roussin <guy.roussin@teledetection.fr> for suggesting not to display channel group delimiters without text @@ -768,6 +775,8 @@ Sascha Volkenandt <sascha@akv-soft.de> Digital audio after switching to a channel that has DD and selecting the DD audio track for reporting a bug in timeout handling in cRwLock::Lock() + for pointing out that the SVDRP command DELR deleted recordings that are currently + being written to by a timer Malcolm Caldwell <malcolm.caldwell@ntu.edu.au> for modifying LOF handling to allow for C-band reception @@ -786,6 +795,7 @@ Ludwig Nussel <ludwig.nussel@web.de> for adding some checks when canceling a thread and removing the usleep() in cThread::Start() for removing the LOCK_THREAD from the LIRC thread + for making the Makefile patch friendlier Thomas Koch <tom@harhar.net> for his support in keeping the Premiere World channels up to date in 'channels.conf' @@ -869,6 +879,7 @@ Niko Tarnanen <niko.tarnanen@hut.fi> Rolf Ahrenberg <rahrenbe@cc.hut.fi> for translating OSD texts to the Finnish language for fixing internationalization of the text for "Setup/DVB/Audio language(s)" + for making pressing the Power button not stop Transfer Mode or replay immediately Ralf Klueber <ralf.klueber@vodafone.com> for reporting a bug in cutting a recording if there is only a single editing mark @@ -941,7 +952,7 @@ Reinhard Nissl <rnissl@gmx.de> for fixing a possible freeze in pause mode in case a device's PlayPesPacket() function permanently returns 0 for fixing a typo in detecting UTF-8 - for fixing handling fragments of less than 3 byte in cPesAssembler + for fixing handling fragments of less than 4 byte in cPesAssembler for some rearrangements in cDvbPlayer::Action() to avoid lockups on NPTL systems Richard Robson <richard_robson@beeb.net> @@ -1061,6 +1072,7 @@ Andreas Regel <andreas.regel@gmx.de> for pointing out a missing call to cStatus::MsgOsdtatusMessage(NULL) in cSkins::Message() for reporting a problem in handling Transfer Mode for radio channels + for reporting a problem with messages when a cOsdObject uses the raw OSD Thomas Bergwinkl <Thomas.Bergwinkl@t-online.de> for fixing the validity check for channel IDs, because some providers use TIDs @@ -1169,6 +1181,11 @@ Marco Schlüßler <marco@lordzodiac.de> for fixing a bug in libsi's SubtitlingDescriptor::getLength() for removing scaling coordinates in letterbox mode from cDvbSpu for fixing a wrong inheritance in libsi's SubtitlingDescriptor::Subtitling + for adding cPlayer::DeviceSetVideoDisplayFormat() + for making the setup not being saved in case of a fatal error, to keep the volume + level from being set to a wrong value + for fixing a possible hangup when ending a replay session while cIndexFile::CatchUp() + is waiting Jürgen Schmitz <j.schmitz@web.de> for reporting a bug in displaying the current channel when switching via the SVDRP @@ -1331,3 +1348,22 @@ Matthias Lötzke <Matthias@Loetzke.de> Wolfgang Fritz <wolfgang.fritz@gmx.net> for making recordings avoid zero sized video data files + +Michael Reinelt <reinelt@eunet.at> + for reporting a problem with the EPG scan on systems that don't use DiSEqC + +Johannes Stezenbach <js@linuxtv.org> + for pointing out that the byte swap for big endian systems in cDvbOsd::Flush() + is wrong + +Paavo Hartikainen <pahartik@sci.fi> + for verifying that the byte swap for big endian systems in cDvbOsd::Flush() was + wrong + +Georg Acher <acher@baycom.de> + for making tChannelID::operator==() inline for better performance + for introducing cListBase::count for better performance + for a patch that was used to implement hash tables to speed up cSchedule::GetEvent() + for avoiding unnecessary calls to getLength() in libsi/si.c, and avoiding the + '& 0xff' in CRC32::crc32() of libsi/util.c + for suggesting to reduce the priority of the section handler threads @@ -3487,7 +3487,7 @@ Video Disk Recorder Revision History - Fixed handling transparent areas in cDvbSpuBitmap (thanks to Marco Schlüßler). - Now also considering the "EPG linger time" when saving the EPG data to file or listing it via LSTE (thanks to Roman Krenický). -- Fixed handling fragments of less than 3 byte in cPesAssembler (thanks to +- Fixed handling fragments of less than 4 byte in cPesAssembler (thanks to Reinhard Nissl). - Fixed a bug in libsi's SubtitlingDescriptor::getLength() (thanks to Marco Schlüßler). @@ -3512,3 +3512,68 @@ Video Disk Recorder Revision History (thanks to Reinhard Nissl). - Fixed a wrong inheritance in libsi's SubtitlingDescriptor::Subtitling (thanks to Marco Schlüßler). + +2005-05-29: Version 1.3.25 + +- Updated the Estonian OSD texts (thanks to Arthur Konovalov). +- Some cable providers don't mark short channel names according to the standard, + but rather go their own way and use "name>short name". VDR now splits at this + character for cable channels (thanks to Gerhard Steiner for reporting this one). +- Added a check for Setup.DiSEqC in cDvbDevice::ProvidesTransponder(), otherwise + the EPG scan didn't work on systems that don't use DiSEqC (thanks to Michael + Reinelt for reporting this one). +- Made the Makefile patch friendlier (thanks to Ludwig Nussel). +- Made cOsd::isOpen an integer counter to avoid problems with messages when a + cOsdObject uses the raw OSD (thanks to Andreas Regel for reporting this one). +- Updated the Danish OSD texts (thanks to Mogens Elneff). +- The file 'summary.vdr' has been replaced with 'info.vdr' and now contains the + information about a recording, in the same format as the events are stored in + 'epg.data' (see man vdr(5) for details). Existing summary files can be converted + to the new format by running the Perl script 'summary2info.pl', as in + + summary2info.pl /video + + (the parameter given has to be the video directory). If there is no 'info.vdr' + file for a recording, an attempt is made to read a 'summary.vdr'. +- The "Summary" button in the "Recordings" menu has been renamed to "Info", and + the page it brings up now shows the recording's information, much like the EPG + event page. Therefore it now no longer uses the skin's SetText() function, but + rather the SetRecording() function. Skin plugins may need to adjust that function + accordingly (see skinsttng.c, for instance). +- The SVDRP command LSTR now lists the recording information in the same tagged + format as the LSTE command lists the EPG data. +- The audio track menu now contains track descriptions when replaying (provided + such descriptions were available in the EPG data when the recording was made, + and are stored in the info.vdr file). +- Avoiding extra blanks at the end of names of instant recordings. +- Removed converting byte order on big endian systems from cDvbOsd::Flush(), + which, according to Johannes Stezenbach and Paavo Hartikainen, is wrong. +- Added cPlayer::DeviceSetVideoDisplayFormat() (thanks to Marco Schlüßler). +- No longer saving the setup in case of a fatal error, to keep the volume level + from being set to a wrong value (thanks to Marco Schlüßler). +- Fixed a possible hangup when ending a replay session while cIndexFile::CatchUp() + is waiting (thanks to Marco Schlüßler). +- The SVDRP command DELR no longer deletes recordings that are currently being + written to by a timer (thanks to Sascha Volkenandt for pointing out this one). +- Pressing the "Play" key in live viewing mode now resumes a previous replay + session (thanks to Mirko Dölle). +- Now dropping EPG events that have a zero start time or duration (thanks to + Oliver Endriss). +- No longer stopping Transfer Mode or replay immediately when the Power button + is pressed (thanks to Rolf Ahrenberg). +- Moved the NPTL and UTF-8 checks after the version and help output (thanks to + Andreas Kool for pointing out that 'vdr --version' failed on an UTF-8 system). +- Made tChannelID::operator==() inline for better performance (thanks to Georg + Acher). +- Introduced cListBase::count for better performance (thanks to Georg Acher). +- cEvent no longer stores the channelID directly, but rather has a pointer to + the schedule it is in. +- Now using hash tables to speed up cSchedule::GetEvent() (partially based on + a patch from Georg Acher). +- Avoiding unnecessary calls to getLength() in libsi/si.c, and avoiding the + '& 0xff' in CRC32::crc32() of libsi/util.c (thanks to Georg Acher). +- Speeded up deleting duplicate channels. +- Fixed listing recordings with empty episode names in the LSTR command (thanks + to Stefan Huelswitt for pointing this out). +- Added cThread::SetPriority() and using it in cSectionHandler::Action() to + reduce the priority of the section handler threads (as suggested by Georg Acher). @@ -23,7 +23,7 @@ Version 1.2 Red - Record Edit Edit ABC/abc Play/Commands(2) Jump - Green - Audio New New Ins/Ovr Rewind Skip -60s - Yellow - Pause live Delete Delete Delete Delete Skip +60s - - Blue - Stop/Resume Mark On/Off(1) - Summary Stop - + Blue - Stop/Resume Mark On/Off(1) - Info Stop - 0..9 Ch select - Sort(3) Day(4) Numeric inp. Exec cmd(2) Editing - In a numerical input field (like the response to a CAM enquiry) the keys 0..9 diff --git a/Make.config.template b/Make.config.template index b39b1f4..3c429e7 100644 --- a/Make.config.template +++ b/Make.config.template @@ -6,7 +6,7 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Make.config.template 1.3 2003/08/09 11:03:25 kls Exp $ +# $Id: Make.config.template 1.4 2005/05/14 10:32:33 kls Exp $ ### The C compiler and options: @@ -14,7 +14,7 @@ CC = gcc CFLAGS = -O2 CXX = g++ -CXXFLAGS = -g -O2 -Wall -Woverloaded-virtual +CXXFLAGS = -fPIC -g -O2 -Wall -Woverloaded-virtual ### The directory environment: @@ -4,7 +4,7 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.74 2005/02/13 10:13:45 kls Exp $ +# $Id: Makefile 1.75 2005/05/14 10:32:13 kls Exp $ .DELETE_ON_ERROR: @@ -12,12 +12,14 @@ CC ?= gcc CFLAGS ?= -O2 CXX ?= g++ -CXXFLAGS ?= -g -O2 -Wall -Woverloaded-virtual +CXXFLAGS ?= -fPIC -g -O2 -Wall -Woverloaded-virtual DVBDIR = ../DVB LSIDIR = ./libsi MANDIR = /usr/local/man BINDIR = /usr/local/bin +LIBS = -ljpeg -lpthread -ldl +INCLUDES = PLUGINDIR= ./PLUGINS PLUGINLIBDIR= $(PLUGINDIR)/lib @@ -29,7 +31,7 @@ DOXYFILE = Doxyfile -include Make.config -INCLUDES = -I$(DVBDIR)/include +INCLUDES += -I$(DVBDIR)/include SILIB = $(LSIDIR)/libsi.a @@ -106,7 +108,7 @@ $(DEPFILE): Makefile # The main program: vdr: $(OBJS) $(SILIB) - $(CXX) $(CXXFLAGS) -rdynamic $(OBJS) $(NCURSESLIB) -ljpeg -lpthread -ldl $(LIBDIRS) $(SILIB) -o vdr + $(CXX) $(CXXFLAGS) -rdynamic $(OBJS) $(NCURSESLIB) $(LIBS) $(LIBDIRS) $(SILIB) -o vdr # The font files: diff --git a/PLUGINS/src/skincurses/HISTORY b/PLUGINS/src/skincurses/HISTORY index 8ba4ae4..33119f4 100644 --- a/PLUGINS/src/skincurses/HISTORY +++ b/PLUGINS/src/skincurses/HISTORY @@ -13,3 +13,7 @@ VDR Plugin 'skincurses' Revision History - Made several functions threadsafe. - New audio track display. + +2005-05-16: Version 0.0.4 + +- New "recording info" display. diff --git a/PLUGINS/src/skincurses/skincurses.c b/PLUGINS/src/skincurses/skincurses.c index a1c5954..ad1a26b 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 1.5 2005/01/09 11:56:26 kls Exp $ + * $Id: skincurses.c 1.6 2005/05/16 10:45:12 kls Exp $ */ #include <ncurses.h> @@ -11,7 +11,7 @@ #include <vdr/plugin.h> #include <vdr/skins.h> -static const char *VERSION = "0.0.3"; +static const char *VERSION = "0.0.4"; static const char *DESCRIPTION = "A text only skin"; static const char *MAINMENUENTRY = NULL; @@ -407,7 +407,30 @@ void cSkinCursesDisplayMenu::SetEvent(const cEvent *Event) void cSkinCursesDisplayMenu::SetRecording(const cRecording *Recording) { - SetText(Recording->Summary(), false); //TODO + if (!Recording) + return; + const cRecordingInfo *Info = Recording->Info(); + int y = 2; + cTextScroller ts; + char t[32]; + snprintf(t, sizeof(t), "%s %s", *DateString(Recording->start), *TimeString(Recording->start)); + ts.Set(osd, 0, y, OsdWidth, OsdHeight - y - 2, t, &Font, clrYellow, clrBackground); + y += ts.Height(); + y += 1; + const char *Title = Info->Title(); + if (isempty(Title)) + Title = Recording->Name(); + ts.Set(osd, 0, y, OsdWidth, OsdHeight - y - 2, Title, &Font, clrCyan, clrBackground); + y += ts.Height(); + if (!isempty(Info->ShortText())) { + ts.Set(osd, 0, y, OsdWidth, OsdHeight - y - 2, Info->ShortText(), &Font, clrYellow, clrBackground); + y += ts.Height(); + } + y += 1; + if (!isempty(Info->Description())) { + textScroller.Set(osd, 0, y, OsdWidth - 2, OsdHeight - y - 2, Info->Description(), &Font, clrCyan, clrBackground); + SetScrollbar(); + } } void cSkinCursesDisplayMenu::SetText(const char *Text, bool FixedFont) @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: channels.c 1.38 2005/05/07 13:14:32 kls Exp $ + * $Id: channels.c 1.42 2005/05/29 10:32:38 kls Exp $ */ #include "channels.h" @@ -124,11 +124,6 @@ int MapToDriver(int Value, const tChannelParameterMap *Map) const tChannelID tChannelID::InvalidID; -bool tChannelID::operator== (const tChannelID &arg) const -{ - return source == arg.source && nid == arg.nid && tid == arg.tid && sid == arg.sid && rid == arg.rid; -} - tChannelID tChannelID::FromString(const char *s) { char *sourcebuf = NULL; @@ -146,7 +141,7 @@ tChannelID tChannelID::FromString(const char *s) return tChannelID::InvalidID; } -cString tChannelID::ToString(void) +cString tChannelID::ToString(void) const { char buffer[256]; snprintf(buffer, sizeof(buffer), rid ? "%s-%d-%d-%d-%d" : "%s-%d-%d-%d", *cSource::ToString(source), nid, tid, sid, rid); @@ -263,11 +258,6 @@ int cChannel::Transponder(void) const return tf; } -tChannelID cChannel::GetChannelID(void) const -{ - return tChannelID(source, nid, (nid || tid) ? tid : Transponder(), sid, rid); -} - int cChannel::Modification(int Mask) { int Result = modification & Mask; @@ -814,6 +804,22 @@ bool cChannel::Save(FILE *f) return fprintf(f, "%s", *ToText()) > 0; } +// -- cChannelSorter --------------------------------------------------------- + +class cChannelSorter : public cListObject { +public: + cChannel *channel; + tChannelID channelID; + cChannelSorter(cChannel *Channel) { + channel = Channel; + channelID = channel->GetChannelID(); + } + virtual int Compare(const cListObject &ListObject) const { + cChannelSorter *cs = (cChannelSorter *)&ListObject; + return memcmp(&channelID, &cs->channelID, sizeof(channelID)); + } + }; + // -- cChannels -------------------------------------------------------------- cChannels Channels; @@ -826,22 +832,21 @@ cChannels::cChannels(void) void cChannels::DeleteDuplicateChannels(void) { + cList<cChannelSorter> ChannelSorter; for (cChannel *channel = First(); channel; channel = Next(channel)) { - if (!channel->GroupSep()) { - tChannelID ChannelID = channel->GetChannelID(); - cChannel *other = Next(channel); - while (other) { - cChannel *d = NULL; - if (!other->GroupSep() && other->GetChannelID() == ChannelID) - d = other; - other = Next(other); - if (d) { - dsyslog("deleting duplicate channel %s", *d->ToText()); - Del(d); - } - } - } + if (!channel->GroupSep()) + ChannelSorter.Add(new cChannelSorter(channel)); } + ChannelSorter.Sort(); + cChannelSorter *cs = ChannelSorter.First(); + while (cs) { + cChannelSorter *next = ChannelSorter.Next(cs); + if (next && cs->channelID == next->channelID) { + dsyslog("deleting duplicate channel %s", *next->channel->ToText()); + Del(next->channel); + } + cs = next; + } } bool cChannels::Load(const char *FileName, bool AllowComments, bool MustExist) diff --git a/channels.conf b/channels.conf index 9f83d12..f62e0fe 100644 --- a/channels.conf +++ b/channels.conf @@ -26,14 +26,14 @@ NEUN LIVE Television,NEUN LIVE;BetaDigital:12480:vC34:S19.2E:27500:767:768=deu:3 DSF;BetaDigital:12480:vC34:S19.2E:27500:1023:1024=deu:0:0:900:133:33:0 HSE24,HSE24;BetaDigital:12480:vC34:S19.2E:27500:1279:1280=deu:37:0:40:133:33:0 Bloomberg TV Germany;Bloomberg:12551:vC56:S19.2E:22000:162:99=deu:0:0:12160:1:1108:0 -EURONEWS;CSAT:11817:vC34:S19.2E:27500:163:92=fra,93=eng,94=ita,95=esl,91=rus,98=por,99=deu:0:0:8004:1:1070:0 +EURONEWS;CSAT:11817:vC34:S19.2E:27500:163:92=fra,91=rus,93=eng,94=ita,95=esl,98=por,99=deu:0:0:8004:1:1070:0 rbb Brandenburg;ARD:12109:hC34:S19.2E:27500:601:602=deu:604:0:28205:1:1073:0 Sky News;BSkyB:11597:vC56:S19.2E:22000:305+131:306=eng:0:0:28707:1:1026:0 Veronica/JETIX;CANAL+:12574:hC56:S19.2E:22000:518+8190:92=dut:38:622,100:5020:53:1109:0 BVN;CANAL+:12574:hC56:S19.2E:22000:515+8190:96=dut:36:0:5025:53:1109:0 n-tv;RTL World:12187:hC34:S19.2E:27500:169:73=deu:80:0:12090:1:1089:0 Al Jazeera;CANALSATELLITE:11567:vC56:S19.2E:22000:55:56=ara:0:0:9021:1:1024:0 -TW1 - 28Feb05;ORF:12692:hC56:S19.2E:22000:166:167=deu:168:0:13013:1:1117:0 +TW1;ORF:12662:hC56:S19.2E:22000:1010:1011=deu:1013:0:13101:1:1115:0 Eurosport;ZDFvision:11953:hC34:S19.2E:27500:410:420=deu:430:0:28009:1:1079:0 EinsExtra;ARD:12109:hC34:S19.2E:27500:101:102=deu:0:0:28201:1:1073:0 EinsFestival;ARD:12109:hC34:S19.2E:27500:201:202=deu:0:0:28202:1:1073:0 @@ -45,10 +45,10 @@ rbb Berlin;ARD:12109:hC34:S19.2E:27500:601:602=deu:604:0:28206:1:1073:0 :Premiere World PREMIERE START,START;PREMIERE:11797:hC34:S19.2E:27500:255:256=deu:32:1702,1801,1722:8:133:2:0 PREMIERE 1,PREM 1;PREMIERE:11797:hC34:S19.2E:27500:511:512=deu,513=deu;515=deu:32:1722,1801,1702:10:133:2:0 -PREMIERE 2,PREM 2;PREMIERE:11797:hC34:S19.2E:27500:1791:1792=deu,1793=deu;1795=deu:32:1722,1801,1702:11:133:2:0 +PREMIERE 2,PREM 2;PREMIERE:11797:hC34:S19.2E:27500:1791:1792=deu;1795=deu:32:1722,1801,1702:11:133:2:0 PREMIERE 3,PREM 3;PREMIERE:11797:hC34:S19.2E:27500:2303:2304=deu,2305=deu:32:1722,1801,1702:43:133:2:0 -PREMIERE 4,PREM 4;PREMIERE:11797:hC34:S19.2E:27500:767:768=deu,769=deu:32:1801,1722,1702:9:133:2:0 -PREMIERE 5,PREM 5;PREMIERE:11797:hC34:S19.2E:27500:1279:1280=deu,1281=deu:32:1801,1722,1702:29:133:2:0 +PREMIERE 4,PREM 4;PREMIERE:11797:hC34:S19.2E:27500:767:768=deu:32:1801,1722,1702:9:133:2:0 +PREMIERE 5,PREM 5;PREMIERE:11797:hC34:S19.2E:27500:1279:1280=deu:32:1801,1722,1702:29:133:2:0 PREMIERE 6,PREM 6;PREMIERE:11797:hC34:S19.2E:27500:1535:1536=deu:32:1702,1722,1801:41:133:2:0 PREMIERE 7,PREM 7;PREMIERE:11797:hC34:S19.2E:27500:1023:1024=deu:32:1722,1702,1801:20:133:2:0 DISNEY CHANNEL,DISNEY;PREMIERE:11758:hC34:S19.2E:27500:2559:2560=deu:32:1722,1801,1702:34:133:17:0 @@ -58,7 +58,7 @@ PREMIERE DIREKT,DIREKT;PREMIERE:12031:hC34:S19.2E:27500:2815:2816=deu,2817=deu;2 BEATE-UHSE.TV,B-UHSE;PREMIERE:12070:hC34:S19.2E:27500:1023:1024=deu:32:1702,1801,1722:21:133:1:0 DIREKT EROTIK,EROTIK;PREMIERE:12031:hC34:S19.2E:27500:1279:0:0:1722,1801,1702:513:133:4:0 :Sportsworld -Konferenz:11719:hC34:S19.2E:27500:255:256=deu,257=deu:32:1702,1801,1722:17:133:3:0 +F1-Portal:11719:hC34:S19.2E:27500:255:256=deu,257=deu:32:1702,1801,1722:17:133:3:0 PREMIERE SPORT 2,SPORT 2;PREMIERE:12031:hC34:S19.2E:27500:3839:3840=deu,3841=deu:32:1722,1702,1801:27:133:4:0 :Beta Digital N24;ProSiebenSat.1:12480:vC34:S19.2E:27500:2047:2048=deu:36:0:47:133:33:0 @@ -72,14 +72,14 @@ FRANCE 5;CSAT:12207:vC34:S19.2E:27500:160:80=fra:32:500,100:8501:1:1090:0 LCP;CSAT:12207:vC34:S19.2E:27500:2047+8191:0:0:0:8506:1:1090:0 ESCALES;ABSAT:12285:vC34:S19.2E:27500:165:100:41:500,100:17025:1:1094:0 Best of Shopping;CSAT:12324:vC34:S19.2E:27500:160:80=fra:0:0:8612:1:1096:0 -ASTRA-Mosaic;ASTRA:12551:vC56:S19.2E:22000:175:176=fra:0:0:3988:1:1108:0 -ASTRA-Mosaic 2;ASTRA:12551:vC56:S19.2E:22000:179:120=fra:0:0:3987:1:1108:0 -ASTRA-Mosaic 3;ASTRA:12551:vC56:S19.2E:22000:182:169=fra:0:0:3986:1:1108:0 -ASTRA-Mosaic 4;ASTRA:12551:vC56:S19.2E:22000:185:170=fra:0:0:3985:1:1108:0 -ASTRA-Mosaic 5;ASTRA:12551:vC56:S19.2E:22000:163:164:0:0:3984:1:1108:0 +ASTRA-Mosaic;SES ASTRA:12551:vC56:S19.2E:22000:175:176=fra:0:0:3988:1:1108:0 +ASTRA-Mosaic 2;SES ASTRA:12551:vC56:S19.2E:22000:179:120=fra:0:0:3987:1:1108:0 +ASTRA-Mosaic 3;SES ASTRA:12551:vC56:S19.2E:22000:182:169=fra:0:0:3986:1:1108:0 +ASTRA-Mosaic 4;SES ASTRA:12551:vC56:S19.2E:22000:185:170=fra:0:0:3985:1:1108:0 +ASTRA-Mosaic 5;SES ASTRA:12551:vC56:S19.2E:22000:163:164:0:0:3984:1:1108:0 Chamber TV;Chambre des Députées:12551:vC56:S19.2E:22000:55:56=ltz:0:0:12180:1:1108:0 RTL TELE Letzebuerg:12551:vC56:S19.2E:22000:168:144=eng,146=fra,151=ltz:74:0:3994:1:1108:0 -Yorin;CANAL+:12574:hC56:S19.2E:22000:512+8190:84=dut:33:622,602,100:5010:53:1109:0 +Yorin;CANAL+:12574:hC56:S19.2E:22000:512+8190:84=dut:33:622,100:5010:53:1109:0 MTV2 Pop Channel;MTV Networks:12226:hC34:S19.2E:27500:513+8190:661=deu:577:0:28640:1:1091:0 MTV Central;MTV Networks:11739:vC34:S19.2E:27500:3031:3032:3034:0:28653:1:1066:0 Via 1 - Schöner Reisen:12148:h:S19.2E:27500:511:512:0:0:44:0:0:0 @@ -88,9 +88,9 @@ VIVA PLUS;VIVA Fernsehen GmbH & Co. KG:12551:vC56:S19.2E:22000:171:172=deu:173:0 QVC Deutschland;QVC:12551:vC56:S19.2E:22000:165:166:167:0:12100:1:1108:0 TELE 5;BetaDigital:12480:vC34:S19.2E:27500:1535:1536=deu:38:0:51:133:33:0 :@201 Sky -Sky One;BSkyB:12226:hC23:S28.2E:27500:2305+2304:2306=eng:2307:960,961:4705:2:2027:0 -Sky Mix;BSkyB:12226:hC23:S28.2E:27500:2311+2304:2312=eng,2313=NAR:2314:960,961:5104:2:2027:0 -ITV2;BSkyB:10906:vC56:S28.2E:22000:2350:2351=eng:2353:960,961:10240:2:2054:0 +Sky One;BSkyB:12226:hC23:S28.2E:27500:515+8190:643=eng:579:960,961:4705:2:2027:0 +Sky Mix;BSkyB:12226:hC23:S28.2E:27500:514+8190:642=eng,662=NAR:578:960,961:5104:2:2027:0 +ITV2;BSkyB:10906:vC56:S28.2E:22000:2350:2351=eng,2374=UND:2353:960,961:10240:2:2054:0 Sci-Fi;BSkyB:12148:hC23:S28.2E:27500:512+8190:640=eng:576:960,961:4905:2:2023:0 Paramount;BSkyB:12187:hC23:S28.2E:27500:2313+2304:2317=eng,2318=NAR:2315:960,961:5904:2:2025:0 Discovery;BSkyB:11875:hC23:S28.2E:27500:2304:2306=eng,2307=NAR:2305:960,961:6201:2:2009:0 @@ -113,7 +113,7 @@ Animal Plnt+;BSkyB:12070:hC23:S28.2E:27500:2314+2307:2315=eng:0:960,961:50002:2: S1T;BSkyB:12285:vC23:S28.2E:27500:513+8190:641=eng,661=NAR:577:960,961:4409:2:2030:0 CNN;BSkyB:12051:vC23:S28.2E:27500:2313:2315=eng:2314:0:7140:2:2018:0 BBC PARL'MNT:12129:vC23:S28.2E:27500:2304:2306=eng,2307=eng:2305:0:7300:2:2022:0 -BTL TV;T-Systems/MTI:11200:vC56:S13.0E:27500:413:414=ita:0:0:4733:318:13400:0 +Bethel TV;T-Systems/MTI:11200:vC56:S13.0E:27500:413:414=ita:0:0:4733:318:13400:0 Euro1080;EURO1080:12168:vC34:S19.2E:27500:308:256:0:FF:21100:1:1088:0 Astra HD:12441:vC34:S19.2E:27500:133+80:134=eng:0:FF:29700:0:0:0 eng-WRN-multi;WRN:12597:vC34:S13.0E:27500:0:2132:0:0:8230:318:9400:0 @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: channels.h 1.28 2005/05/07 13:07:09 kls Exp $ + * $Id: channels.h 1.32 2005/05/28 13:57:08 kls Exp $ */ #ifndef __CHANNELS_H @@ -65,12 +65,12 @@ private: public: tChannelID(void) { source = nid = tid = sid = rid = 0; } tChannelID(int Source, int Nid, int Tid, int Sid, int Rid = 0) { source = Source; nid = Nid; tid = Tid; sid = Sid; rid = Rid; } - bool operator== (const tChannelID &arg) const; - bool Valid(void) { return (nid || tid) && sid; } // rid is optional and source may be 0//XXX source may not be 0??? + bool operator== (const tChannelID &arg) const { return source == arg.source && nid == arg.nid && tid == arg.tid && sid == arg.sid && rid == arg.rid; } + bool Valid(void) const { return (nid || tid) && sid; } // rid is optional and source may be 0//XXX source may not be 0??? tChannelID &ClrRid(void) { rid = 0; return *this; } tChannelID &ClrPolarization(void); static tChannelID FromString(const char *s); - cString ToString(void); + cString ToString(void) const; static const tChannelID InvalidID; }; @@ -176,10 +176,10 @@ public: int Transmission(void) const { return transmission; } int Guard(void) const { return guard; } int Hierarchy(void) const { return hierarchy; } - bool IsCable(void) const { return (source & cSource::st_Mask) == cSource::stCable; } - bool IsSat(void) const { return (source & cSource::st_Mask) == cSource::stSat; } - bool IsTerr(void) const { return (source & cSource::st_Mask) == cSource::stTerr; } - tChannelID GetChannelID(void) const; + bool IsCable(void) const { return cSource::IsCable(source); } + bool IsSat(void) const { return cSource::IsSat(source); } + bool IsTerr(void) const { return cSource::IsTerr(source); } + tChannelID GetChannelID(void) const { return tChannelID(source, nid, (nid || tid) ? tid : Transponder(), sid, rid); } int Modification(int Mask = CHANNELMOD_ALL); bool SetSatTransponderData(int Source, int Frequency, char Polarization, int Srate, int CoderateH); bool SetCableTransponderData(int Source, int Frequency, int Modulation, int Srate, int CoderateH); @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.217 2005/05/05 11:04:18 kls Exp $ + * $Id: config.h 1.218 2005/05/14 09:18:08 kls Exp $ */ #ifndef __CONFIG_H @@ -20,8 +20,8 @@ #include "i18n.h" #include "tools.h" -#define VDRVERSION "1.3.24" -#define VDRVERSNUM 10324 // Version * 10000 + Major * 100 + Minor +#define VDRVERSION "1.3.25" +#define VDRVERSNUM 10325 // Version * 10000 + Major * 100 + Minor #define MAXPRIORITY 99 #define MAXLIFETIME 99 @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: cutter.c 1.7 2004/06/13 16:04:08 kls Exp $ + * $Id: cutter.c 1.8 2005/05/15 14:21:08 kls Exp $ */ #include "cutter.h" @@ -204,7 +204,7 @@ bool cCutter::Start(const char *FileName) free(s); // XXX editedVersionName = strdup(evn); - Recording.WriteSummary(); + Recording.WriteInfo(); Recordings.AddByName(editedVersionName); cuttingThread = new cCuttingThread(FileName, editedVersionName); return true; diff --git a/dvbdevice.c b/dvbdevice.c index 9c8a0ac..3a3b19b 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 1.127 2005/03/20 10:10:38 kls Exp $ + * $Id: dvbdevice.c 1.129 2005/05/16 15:23:43 kls Exp $ */ #include "dvbdevice.h" @@ -741,7 +741,7 @@ bool cDvbDevice::ProvidesSource(int Source) const bool cDvbDevice::ProvidesTransponder(const cChannel *Channel) const { - return ProvidesSource(Channel->Source()) && ((Channel->Source() & cSource::st_Mask) != cSource::stSat || Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization())); + return ProvidesSource(Channel->Source()) && (!cSource::IsSat(Channel->Source()) || !Setup.DiSEqC || Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization())); } bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.c 1.26 2005/02/12 15:36:31 kls Exp $ + * $Id: dvbosd.c 1.27 2005/05/22 10:57:45 kls Exp $ */ #include "dvbosd.h" @@ -151,10 +151,6 @@ void cDvbOsd::Flush(void) for (int i = 0; i < NumColors; i++) { // convert AARRGGBB to AABBGGRR (the driver expects the colors the wrong way): colors[i] = (Colors[i] & 0xFF000000) | ((Colors[i] & 0x0000FF) << 16) | (Colors[i] & 0x00FF00) | ((Colors[i] & 0xFF0000) >> 16); -#if __BYTE_ORDER == __BIG_ENDIAN - // actually the driver itself should access the bytes according to the current endianness! - colors[i] = ((colors[i] & 0xFF) << 24) | ((colors[i] & 0xFF00) << 8) | ((colors[i] & 0xFF0000) >> 8) | ((colors[i] & 0xFF000000) >> 24); -#endif } Colors = colors; //TODO end of stuff that should be fixed in the driver diff --git a/dvbplayer.c b/dvbplayer.c index 477a6c0..2d4e1e4 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 1.33 2005/05/08 14:52:49 kls Exp $ + * $Id: dvbplayer.c 1.34 2005/05/22 11:26:51 kls Exp $ */ #include "dvbplayer.h" @@ -355,7 +355,7 @@ void cDvbPlayer::Activate(bool On) } else if (active) { running = false; - Cancel(3); + Cancel(9); active = false; } } @@ -8,7 +8,7 @@ * Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>. * Adapted to 'libsi' for VDR 1.3.0 by Marcel Wiesweg <marcel.wiesweg@gmx.de>. * - * $Id: eit.c 1.103 2005/03/20 12:33:51 kls Exp $ + * $Id: eit.c 1.107 2005/05/28 11:35:55 kls Exp $ */ #include "eit.h" @@ -48,12 +48,16 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data) SI::EIT::Event SiEitEvent; for (SI::Loop::Iterator it; eventLoop.getNext(SiEitEvent, it); ) { + // Drop bogus events. + if (SiEitEvent.getStartTime() == 0 || SiEitEvent.getDuration() == 0) + continue; Empty = false; + cEvent *newEvent = NULL; cEvent *pEvent = (cEvent *)pSchedule->GetEvent(SiEitEvent.getEventId(), SiEitEvent.getStartTime()); if (!pEvent) { // If we don't have that event yet, we create a new one. // Otherwise we copy the information into the existing event anyway, because the data might have changed. - pEvent = pSchedule->AddEvent(new cEvent(channelID, SiEitEvent.getEventId())); + pEvent = newEvent = new cEvent(SiEitEvent.getEventId()); if (!pEvent) continue; } @@ -91,8 +95,7 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data) SI::ExtendedEventDescriptors *ExtendedEventDescriptors = NULL; SI::ShortEventDescriptor *ShortEventDescriptor = NULL; cLinkChannels *LinkChannels = NULL; - int NumComponents = 0; - SI::ComponentDescriptor *ComponentDescriptors[MAXCOMPONENTS]; + cComponents *Components = NULL; for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext(it2)); ) { switch (d->getDescriptorTag()) { case SI::ExtendedEventDescriptorTag: { @@ -193,12 +196,10 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data) uchar Stream = cd->getStreamContent(); uchar Type = cd->getComponentType(); if (1 <= Stream && Stream <= 2 && Type != 0) { - if (NumComponents < MAXCOMPONENTS) { - ComponentDescriptors[NumComponents++] = cd; - d = NULL; // so that it is not deleted - } - else - dsyslog("more than %d component descriptors!", MAXCOMPONENTS); + if (!Components) + Components = new cComponents; + char buffer[256]; + Components->SetComponent(Components->NumComponents(), cd->getStreamContent(), cd->getComponentType(), I18nNormalizeLanguageCode(cd->languageCode), cd->description.getText(buffer, sizeof(buffer))); } } break; @@ -221,18 +222,10 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data) delete ExtendedEventDescriptors; delete ShortEventDescriptor; - if (NumComponents > 0) { - cComponents *Components = new cComponents(NumComponents); - for (int i = 0; i < NumComponents; i++) { - char buffer[256]; - SI::ComponentDescriptor *cd = ComponentDescriptors[i]; - Components->SetComponent(i, cd->getStreamContent(), cd->getComponentType(), I18nNormalizeLanguageCode(cd->languageCode), cd->description.getText(buffer, sizeof(buffer))); - delete cd; - } - pEvent->SetComponents(Components); - } - else - pEvent->SetComponents(NULL); + if (newEvent) + pSchedule->AddEvent(newEvent); + + pEvent->SetComponents(Components); pEvent->FixEpgBugs(); if (LinkChannels) @@ -7,7 +7,7 @@ * Original version (as used in VDR before 1.3.0) written by * Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>. * - * $Id: epg.c 1.29 2005/05/05 13:53:19 kls Exp $ + * $Id: epg.c 1.34 2005/05/29 10:19:48 kls Exp $ */ #include "epg.h" @@ -40,11 +40,10 @@ bool tComponent::FromString(const char *s) // --- cComponents ----------------------------------------------------------- -cComponents::cComponents(int NumComponents) +cComponents::cComponents(void) { - numComponents = NumComponents; - components = MALLOC(tComponent, numComponents); - memset(components, 0, sizeof(tComponent) * numComponents); + numComponents = 0; + components = NULL; } cComponents::~cComponents(void) @@ -54,31 +53,37 @@ cComponents::~cComponents(void) free(components); } -bool cComponents::SetComponent(int Index, const char *s) +void cComponents::Realloc(int Index) { - if (Index < numComponents) - return components[Index].FromString(s); - return false; + if (Index >= numComponents) { + int n = numComponents; + numComponents = Index + 1; + components = (tComponent *)realloc(components, numComponents * sizeof(tComponent)); + memset(&components[n], 0, sizeof(tComponent) * (numComponents - n)); + } } -bool cComponents::SetComponent(int Index, uchar Stream, uchar Type, const char *Language, const char *Description) +void cComponents::SetComponent(int Index, const char *s) { - if (Index < numComponents) { - tComponent *p = &components[Index]; - p->stream = Stream; - p->type = Type; - strn0cpy(p->language, Language, sizeof(p->language)); - p->description = strcpyrealloc(p->description, !isempty(Description) ? Description : NULL); - return true; - } - return false; + Realloc(Index); + components[Index].FromString(s); +} + +void cComponents::SetComponent(int Index, uchar Stream, uchar Type, const char *Language, const char *Description) +{ + Realloc(Index); + tComponent *p = &components[Index]; + p->stream = Stream; + p->type = Type; + strn0cpy(p->language, Language, sizeof(p->language)); + p->description = strcpyrealloc(p->description, !isempty(Description) ? Description : NULL); } // --- cEvent ---------------------------------------------------------------- -cEvent::cEvent(tChannelID ChannelID, u_int16_t EventID) +cEvent::cEvent(u_int16_t EventID) { - channelID = ChannelID; + schedule = NULL; eventID = EventID; tableID = 0; version = 0xFF; // actual version numbers are 0..31 @@ -107,9 +112,20 @@ int cEvent::Compare(const cListObject &ListObject) const return startTime - e->startTime; } +tChannelID cEvent::ChannelID(void) const +{ + return schedule ? schedule->ChannelID() : tChannelID(); +} + void cEvent::SetEventID(u_int16_t EventID) { - eventID = EventID; + if (eventID != EventID) { + if (schedule) + schedule->UnhashEvent(this); + eventID = EventID; + if (schedule) + schedule->HashEvent(this); + } } void cEvent::SetTableID(uchar TableID) @@ -153,7 +169,13 @@ void cEvent::SetComponents(cComponents *Components) void cEvent::SetStartTime(time_t StartTime) { - startTime = StartTime; + if (startTime != StartTime) { + if (schedule) + schedule->UnhashEvent(this); + startTime = StartTime; + if (schedule) + schedule->HashEvent(this); + } } void cEvent::SetDuration(int Duration) @@ -187,30 +209,17 @@ bool cEvent::IsRunning(bool OrAboutToStart) const cString cEvent::GetDateString(void) const { - char buf[32]; - struct tm tm_r; - tm *tm = localtime_r(&startTime, &tm_r); - char *p = stpcpy(buf, WeekDayName(tm->tm_wday)); - *p++ = ' '; - strftime(p, sizeof(buf) - (p - buf), "%d.%m.%Y", tm); - return buf; + return DateString(startTime); } cString cEvent::GetTimeString(void) const { - char buf[25]; - struct tm tm_r; - strftime(buf, sizeof(buf), "%R", localtime_r(&startTime, &tm_r)); - return buf; + return TimeString(startTime); } cString cEvent::GetEndTimeString(void) const { - char buf[25]; - time_t EndTime = startTime + duration; - struct tm tm_r; - strftime(buf, sizeof(buf), "%R", localtime_r(&EndTime, &tm_r)); - return buf; + return TimeString(startTime + duration); } cString cEvent::GetVpsString(void) const @@ -221,10 +230,11 @@ cString cEvent::GetVpsString(void) const return buf; } -void cEvent::Dump(FILE *f, const char *Prefix) const +void cEvent::Dump(FILE *f, const char *Prefix, bool InfoOnly) const { - if (startTime + duration + Setup.EPGLinger * 60 >= time(NULL)) { - fprintf(f, "%sE %u %ld %d %X\n", Prefix, eventID, startTime, duration, tableID); + if (InfoOnly || startTime + duration + Setup.EPGLinger * 60 >= time(NULL)) { + if (!InfoOnly) + fprintf(f, "%sE %u %ld %d %X\n", Prefix, eventID, startTime, duration, tableID); if (!isempty(title)) fprintf(f, "%sT %s\n", Prefix, title); if (!isempty(shortText)) @@ -240,18 +250,40 @@ void cEvent::Dump(FILE *f, const char *Prefix) const fprintf(f, "%sX %s\n", Prefix, *p->ToString()); } } - if (vps) + if (!InfoOnly && vps) fprintf(f, "%sV %ld\n", Prefix, vps); - fprintf(f, "%se\n", Prefix); + if (!InfoOnly) + fprintf(f, "%se\n", Prefix); } } +bool cEvent::Parse(char *s) +{ + char *t = skipspace(s + 1); + switch (*s) { + case 'T': SetTitle(t); + break; + case 'S': SetShortText(t); + break; + case 'D': strreplace(t, '|', '\n'); + SetDescription(t); + break; + case 'X': if (!components) + components = new cComponents; + components->SetComponent(components->NumComponents(), t); + break; + case 'V': SetVps(atoi(t)); + break; + default: esyslog("ERROR: unexpected tag while reading EPG data: %s", s); + return false; + } + return true; +} + bool cEvent::Read(FILE *f, cSchedule *Schedule) { if (Schedule) { cEvent *Event = NULL; - int NumComponents = 0; - char *ComponentStrings[MAXCOMPONENTS]; char *s; cReadLine ReadLine; while ((s = ReadLine.Read(f)) != NULL) { @@ -265,53 +297,25 @@ bool cEvent::Read(FILE *f, cSchedule *Schedule) int n = sscanf(t, "%u %ld %d %X", &EventID, &StartTime, &Duration, &TableID); if (n == 3 || n == 4) { Event = (cEvent *)Schedule->GetEvent(EventID, StartTime); + cEvent *newEvent = NULL; if (!Event) - Event = Schedule->AddEvent(new cEvent(Schedule->ChannelID(), EventID)); + Event = newEvent = new cEvent(EventID); if (Event) { Event->SetTableID(TableID); Event->SetStartTime(StartTime); Event->SetDuration(Duration); + if (newEvent) + Schedule->AddEvent(newEvent); } } - NumComponents = 0; - } - break; - case 'T': if (Event) - Event->SetTitle(t); - break; - case 'S': if (Event) - Event->SetShortText(t); - break; - case 'D': if (Event) { - strreplace(t, '|', '\n'); - Event->SetDescription(t); - } - break; - case 'X': if (Event) { - if (NumComponents < MAXCOMPONENTS) - ComponentStrings[NumComponents++] = strdup(t); - else - dsyslog("more than %d component descriptors!", MAXCOMPONENTS); } break; - case 'V': if (Event) - Event->SetVps(atoi(t)); - break; - case 'e': if (Event && NumComponents > 0) { - cComponents *Components = new cComponents(NumComponents); - for (int i = 0; i < NumComponents; i++) { - if (!Components->SetComponent(i, ComponentStrings[i])) - esyslog("ERROR: faulty component string in EPG data: '%s'", ComponentStrings[i]); - free(ComponentStrings[i]); - } - Event->SetComponents(Components); - } - Event = NULL; + case 'e': Event = NULL; break; case 'c': // to keep things simple we react on 'c' here return true; - default: esyslog("ERROR: unexpected tag while reading EPG data: %s", s); - return false; + default: if (Event && !Event->Parse(s)) + return false; } } esyslog("ERROR: unexpected end of file while reading EPG data"); @@ -649,9 +653,34 @@ cSchedule::cSchedule(tChannelID ChannelID) cEvent *cSchedule::AddEvent(cEvent *Event) { events.Add(Event); + Event->schedule = this; + HashEvent(Event); return Event; } +void cSchedule::DelEvent(cEvent *Event) +{ + if (Event->schedule == this) { + UnhashEvent(Event); + events.Del(Event); + Event->schedule = NULL; + } +} + +void cSchedule::HashEvent(cEvent *Event) +{ + eventsHashID.Add(Event, Event->EventID()); + if (Event->StartTime() > 0) // 'StartTime < 0' is apparently used with NVOD channels + eventsHashStartTime.Add(Event, Event->StartTime()); +} + +void cSchedule::UnhashEvent(cEvent *Event) +{ + eventsHashID.Del(Event, Event->EventID()); + if (Event->StartTime() > 0) // 'StartTime < 0' is apparently used with NVOD channels + eventsHashStartTime.Del(Event, Event->StartTime()); +} + const cEvent *cSchedule::GetPresentEvent(bool CheckRunningStatus) const { const cEvent *pe = NULL; @@ -680,13 +709,9 @@ const cEvent *cSchedule::GetEvent(u_int16_t EventID, time_t StartTime) const { // Returns either the event info with the given EventID or, if that one can't // be found, the one with the given StartTime (or NULL if neither can be found) - cEvent *pt = NULL; - for (cEvent *pe = events.First(); pe; pe = events.Next(pe)) { - if (pe->EventID() == EventID) - return pe; - if (StartTime > 0 && pe->StartTime() == StartTime) // 'StartTime < 0' is apparently used with NVOD channels - pt = pe; - } + cEvent *pt = eventsHashID.Get(EventID); + if (!pt && StartTime > 0) // 'StartTime < 0' is apparently used with NVOD channels + pt = eventsHashStartTime.Get(StartTime); return pt; } @@ -753,7 +778,7 @@ void cSchedule::Cleanup(time_t Time) if (!Event) break; if (!Event->HasTimer() && Event->EndTime() + Setup.EPGLinger * 60 + 3600 < Time) { // adding one hour for safety - events.Del(Event); + DelEvent(Event); a--; } } @@ -7,7 +7,7 @@ * Original version (as used in VDR before 1.3.0) written by * Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>. * - * $Id: epg.h 1.21 2005/03/20 12:32:36 kls Exp $ + * $Id: epg.h 1.25 2005/05/28 11:32:36 kls Exp $ */ #ifndef __EPG_H @@ -18,7 +18,6 @@ #include "tools.h" #define MAXEPGBUGFIXLEVEL 3 -#define MAXCOMPONENTS 32 enum eDumpMode { dmAll, dmPresent, dmFollowing, dmAtTime }; @@ -35,20 +34,22 @@ class cComponents { private: int numComponents; tComponent *components; + void Realloc(int Index); public: - cComponents(int NumComponents); + cComponents(void); ~cComponents(void); int NumComponents(void) const { return numComponents; } - bool SetComponent(int Index, const char *s); - bool SetComponent(int Index, uchar Stream, uchar Type, const char *Language, const char *Description); + void SetComponent(int Index, const char *s); + void SetComponent(int Index, uchar Stream, uchar Type, const char *Language, const char *Description); tComponent *Component(int Index) const { return (Index < numComponents) ? &components[Index] : NULL; } }; class cSchedule; class cEvent : public cListObject { + friend class cSchedule; private: - tChannelID channelID; // Channel ID of program for this event + cSchedule *schedule; // The Schedule this event belongs to u_int16_t eventID; // Event ID of this event uchar tableID; // Table ID this event came from uchar version; // Version number of section this event came from @@ -56,16 +57,16 @@ private: char *title; // Title of this event char *shortText; // Short description of this event (typically the episode name in case of a series) char *description; // Description of this event - cComponents *components; // The stream components of this event (separated by '\n') + cComponents *components; // The stream components of this event time_t startTime; // Start time of this event int duration; // Duration of this event in seconds time_t vps; // Video Programming Service timestamp (VPS, aka "Programme Identification Label", PIL) time_t seen; // When this event was last seen in the data stream public: - cEvent(tChannelID ChannelID, u_int16_t EventID); + cEvent(u_int16_t EventID); ~cEvent(); virtual int Compare(const cListObject &ListObject) const; - tChannelID ChannelID(void) const { return channelID; } + tChannelID ChannelID(void) const; u_int16_t EventID(void) const { return eventID; } uchar TableID(void) const { return tableID; } uchar Version(void) const { return version; } @@ -98,7 +99,8 @@ public: void SetDuration(int Duration); void SetVps(time_t Vps); void SetSeen(void); - void Dump(FILE *f, const char *Prefix = "") const; + void Dump(FILE *f, const char *Prefix = "", bool InfoOnly = false) const; + bool Parse(char *s); static bool Read(FILE *f, cSchedule *Schedule); void FixEpgBugs(void); }; @@ -109,6 +111,8 @@ class cSchedule : public cListObject { private: tChannelID channelID; cList<cEvent> events; + cHash<cEvent> eventsHashID; + cHash<cEvent> eventsHashStartTime; bool hasRunning; time_t modified; time_t presentSeen; @@ -127,6 +131,9 @@ public: void Cleanup(time_t Time); void Cleanup(void); cEvent *AddEvent(cEvent *Event); + void DelEvent(cEvent *Event); + void cSchedule::HashEvent(cEvent *Event); + void cSchedule::UnhashEvent(cEvent *Event); const cList<cEvent> *Events(void) const { return &events; } const cEvent *GetPresentEvent(bool CheckRunningStatus = false) const; const cEvent *GetFollowingEvent(bool CheckRunningStatus = false) const; @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: i18n.c 1.188 2005/05/05 13:12:54 kls Exp $ + * $Id: i18n.c 1.191 2005/05/15 14:37:59 kls Exp $ * * Translations provided by: * @@ -399,6 +399,27 @@ const tI18nPhrase Phrases[] = { "Kokkuvõte", "Omtale", }, + { "Info", + "Info", + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + }, { "Schedule - %s", "Programm - %s", "Program - %s", @@ -3112,7 +3133,7 @@ const tI18nPhrase Phrases[] = { "",//TODO "ÈØàÞÚÞíÚàÐÝÝÞÕ Ø×ÞÑàÐÖÕÝØÕ", "",//TODO - "",//TODO + "Video kuvamise formaat", "Video display format", }, { "pan&scan", @@ -3343,7 +3364,7 @@ const tI18nPhrase Phrases[] = { "",//TODO "¿àÕÔßÞçØâÐÕÜëÕ ï×ëÚØ (×ÒãÚ)", "",//TODO - "",//TODO + "Audio keeled", "Audio sprog (ant.)", }, { "Setup.DVB$Audio language", // note the singular @@ -3364,7 +3385,7 @@ const tI18nPhrase Phrases[] = { "",//TODO "²ëÑàÐÝ", "",//TODO - "",//TODO + "Audio keel", "Audio sprog", }, { "Setup.LNB$SLOF (MHz)", @@ -4039,7 +4060,7 @@ const tI18nPhrase Phrases[] = { "Fase 1: Detectant el tipus de receptor", "ÈÐÓ 1: ¾ßàÕÔÕÛÕÝØÕ âØßÐ ÚÞÔÐ ßãÛìâÐ", "Faza 1: detektiranje kôda daljinskog upravljaèa.", - "Aste 1: Koodeerimissüsteemi tuvastamine", + "Aste 1: Kodeerimissüsteemi tuvastamine", "Fase 1: Detekterer fjernbetjenings-kodetype", }, { "Press any key on the RC unit", @@ -4081,7 +4102,7 @@ const tI18nPhrase Phrases[] = { "Codi detectat!", "¾ÑÝÐàãÖÕÝ ÚÞÔ ßãÛìâÐ!", "Kôd daljinskog upravljaèa je prepoznat!", - "Koodeerimissüsteem tuvastatud!", + "Kodeerimissüsteem tuvastatud!", "Fjernbetjenings-kodetype fundet!", }, { "Do not press any key...", @@ -5049,7 +5070,7 @@ const tI18nPhrase Phrases[] = { " Aturar la reproducció", " ¿àÕÚàÐâØâì ÒÞáßàÞØ×ÒÕÔÕÝØÕ", " Prekini reprodukciju", - " Lõpeta kordus", + " Lõpeta taasesitamine", " Stop afspilning", }, { " Stop recording ", // note the leading and trailing blanks! @@ -5259,8 +5280,8 @@ const tI18nPhrase Phrases[] = { "",// TODO "",// TODO "",// TODO - "",// TODO - "",// TODO + "EPG skaneerimine käivitatud", + "Starter EPG skanning", }, { "This plugin has no setup parameters!", "Dieses Plugin hat keine Setup-Parameter!", diff --git a/libsi/Makefile b/libsi/Makefile index fdc630d..1554217 100644 --- a/libsi/Makefile +++ b/libsi/Makefile @@ -1,12 +1,12 @@ # # Makefile for a libsi # -# $Id: Makefile 1.4 2005/05/05 11:01:46 kls Exp $ +# $Id: Makefile 1.5 2005/05/29 11:47:12 kls Exp $ ### The C++ compiler and options: CXX ?= g++ -CXXFLAGS ?= -O2 -g -Wall -Woverloaded-virtual +CXXFLAGS ?= -fPIC -O2 -g -Wall -Woverloaded-virtual AR = ar ARFLAGS = ru RANLIB = ranlib @@ -6,7 +6,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: si.c 1.13 2004/10/16 15:12:57 kls Exp $ + * $Id: si.c 1.14 2005/05/28 14:11:16 kls Exp $ * * ***************************************************************************/ @@ -114,9 +114,10 @@ Descriptor *DescriptorLoop::getNext(Iterator &it) { Descriptor *DescriptorLoop::getNext(Iterator &it, DescriptorTag tag, bool returnUnimplemetedDescriptor) { Descriptor *d=0; - if (isValid() && it.i<getLength()) { + int len; + if (isValid() && it.i<(len=getLength())) { const unsigned char *p=data.getData(it.i); - const unsigned char *end=p+getLength()-it.i; + const unsigned char *end=p+len-it.i; while (p < end) { if (Descriptor::getDescriptorTag(p) == tag) { d=createDescriptor(it.i, returnUnimplemetedDescriptor); @@ -132,9 +133,10 @@ Descriptor *DescriptorLoop::getNext(Iterator &it, DescriptorTag tag, bool return Descriptor *DescriptorLoop::getNext(Iterator &it, DescriptorTag *tags, int arrayLength, bool returnUnimplementedDescriptor) { Descriptor *d=0; - if (isValid() && it.i<getLength()) { + int len; + if (isValid() && it.i<(len=getLength())) { const unsigned char *p=data.getData(it.i); - const unsigned char *end=p+getLength()-it.i; + const unsigned char *end=p+len-it.i; while (p < end) { for (int u=0; u<arrayLength;u++) if (Descriptor::getDescriptorTag(p) == tags[u]) { @@ -211,15 +213,17 @@ bool DescriptorGroup::isComplete() { } char *String::getText() { - if (getLength() < 0 || getLength() >4095) + int len=getLength(); + if (len < 0 || len > 4095) return strdup("text error"); // caller will delete it! - char *data=new char(getLength()+1); - decodeText(data, getLength()+1); + char *data=new char(len+1); + decodeText(data, len+1); return data; } char *String::getText(char *buffer, int size) { - if (getLength() < 0 || getLength() >= size) { + int len=getLength(); + if (len < 0 || len >= size) { strncpy(buffer, "text error", size); buffer[size-1] = 0; return buffer; @@ -230,7 +234,8 @@ char *String::getText(char *buffer, int size) { //taken from VDR, Copyright Klaus Schmidinger <kls@cadsoft.de> char *String::getText(char *buffer, char *shortVersion, int sizeBuffer, int sizeShortVersion) { - if (getLength() < 0 || getLength() >= sizeBuffer) { + int len=getLength(); + if (len < 0 || len >= sizeBuffer) { strncpy(buffer, "text error", sizeBuffer); buffer[sizeBuffer-1] = 0; *shortVersion = 0; @@ -254,7 +259,8 @@ void String::decodeText(char *buffer, int size) { if (*from == 0x10) from += 3; // skips code table info - for (int i = 0; i < getLength(); i++) { + int len=getLength(); + for (int i = 0; i < len; i++) { if (*from == 0) break; if ( ((' ' <= *from) && (*from <= '~')) @@ -281,9 +287,8 @@ void String::decodeText(char *buffer, char *shortVersion, int sizeBuffer, int si if (*from == 0x10) from += 3; // skips code table info - for (int i = 0; i < getLength(); i++) { - if (*from == 0) - break; + int len=getLength(); + for (int i = 0; i < len; i++) { if ( ((' ' <= *from) && (*from <= '~')) || (*from == '\n') || (0xA0 <= *from) @@ -299,6 +304,8 @@ void String::decodeText(char *buffer, char *shortVersion, int sizeBuffer, int si IsShortName++; else if (*from == 0x87) IsShortName--; + else if (*from == 0) + break; from++; if (to - buffer >= sizeBuffer - 1 || toShort - shortVersion >= sizeShortVersion - 1) break; diff --git a/libsi/util.c b/libsi/util.c index c6ad234..3465794 100644 --- a/libsi/util.c +++ b/libsi/util.c @@ -6,7 +6,7 @@ * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * - * $Id: util.c 1.4 2004/10/16 09:58:41 kls Exp $ + * $Id: util.c 1.5 2005/05/28 14:15:29 kls Exp $ * * ***************************************************************************/ @@ -263,9 +263,10 @@ u_int32_t CRC32::crc_table[256] = { u_int32_t CRC32::crc32 (const char *d, int len, u_int32_t crc) { register int i; + const unsigned char *u=(unsigned char*)d; // Saves '& 0xff' for (i=0; i<len; i++) - crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *d++) & 0xff]; + crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *u++)]; return crc; } @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.348 2005/03/20 15:14:51 kls Exp $ + * $Id: menu.c 1.349 2005/05/16 13:59:03 kls Exp $ */ #include "menu.h" @@ -872,7 +872,6 @@ eOSState cMenuTimers::Summary(void) cTimer *ti = CurrentTimer(); if (ti && !isempty(ti->Summary())) return AddSubMenu(new cMenuText(tr("Summary"), ti->Summary())); - //XXX cSkin::SetRecording()??? return Edit(); // convenience for people not using the Summary feature ;-) } @@ -1297,8 +1296,12 @@ eOSState cMenuCommands::ProcessKey(eKeys Key) if (state == osUnknown) { switch (Key) { - case kOk: return Execute(); - default: break; + case kRed: + case kGreen: + case kYellow: + case kBlue: return osContinue; + case kOk: return Execute(); + default: break; } } return state; @@ -1430,6 +1433,63 @@ cOsdObject *CamControl(void) return NULL; } +// --- cMenuRecording -------------------------------------------------------- + +class cMenuRecording : public cOsdMenu { +private: + const cRecording *recording; +public: + cMenuRecording(const cRecording *Recording); + virtual void Display(void); + virtual eOSState ProcessKey(eKeys Key); +}; + +cMenuRecording::cMenuRecording(const cRecording *Recording) +:cOsdMenu(tr("Recording")) +{ + recording = Recording; + if (recording) + SetHelp(tr("Play"), tr("Rewind")); +} + +void cMenuRecording::Display(void) +{ + cOsdMenu::Display(); + DisplayMenu()->SetRecording(recording); + cStatus::MsgOsdTextItem(recording->Info()->Description()); +} + +eOSState cMenuRecording::ProcessKey(eKeys Key) +{ + switch (Key) { + case kUp|k_Repeat: + case kUp: + case kDown|k_Repeat: + case kDown: + case kLeft|k_Repeat: + case kLeft: + case kRight|k_Repeat: + case kRight: + DisplayMenu()->Scroll(NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft, NORMALKEY(Key) == kLeft || NORMALKEY(Key) == kRight); + cStatus::MsgOsdTextItem(NULL, NORMALKEY(Key) == kUp); + return osContinue; + default: break; + } + + eOSState state = cOsdMenu::ProcessKey(Key); + + if (state == osUnknown) { + switch (Key) { + case kRed: Key = kOk; // will play the recording, even if recording commands are defined + case kGreen: cRemote::Put(Key, true); + // continue with osBack to close the info menu and process the key + case kOk: return osBack; + default: break; + } + } + return state; +} + // --- cMenuRecordingItem ---------------------------------------------------- class cMenuRecordingItem : public cOsdItem { @@ -1530,7 +1590,7 @@ void cMenuRecordings::SetHelpKeys(void) else { NewHelpKeys = 2; cRecording *recording = GetRecording(ri); - if (recording && recording->Summary()) + if (recording && recording->Info()->Title()) NewHelpKeys = 3; } } @@ -1539,7 +1599,7 @@ void cMenuRecordings::SetHelpKeys(void) case 0: SetHelp(NULL); break; case 1: SetHelp(tr("Open")); break; case 2: - case 3: SetHelp(RecordingCommands.Count() ? tr("Commands") : tr("Play"), tr("Rewind"), tr("Delete"), NewHelpKeys == 3 ? tr("Summary") : NULL); + case 3: SetHelp(RecordingCommands.Count() ? tr("Commands") : tr("Play"), tr("Rewind"), tr("Delete"), NewHelpKeys == 3 ? tr("Info") : NULL); } helpKeys = NewHelpKeys; } @@ -1644,15 +1704,15 @@ eOSState cMenuRecordings::Delete(void) return osContinue; } -eOSState cMenuRecordings::Summary(void) +eOSState cMenuRecordings::Info(void) { if (HasSubMenu() || Count() == 0) return osContinue; cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); if (ri && !ri->IsDirectory()) { cRecording *recording = GetRecording(ri); - if (recording && recording->Summary() && *recording->Summary()) - return AddSubMenu(new cMenuText(tr("Summary"), recording->Summary())); + if (recording && recording->Info()->Title()) + return AddSubMenu(new cMenuRecording(recording)); } return osContinue; } @@ -1689,7 +1749,7 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key) case kRed: return (helpKeys > 1 && RecordingCommands.Count()) ? Commands() : Play(); case kGreen: return Rewind(); case kYellow: return Delete(); - case kBlue: return Summary(); + case kBlue: return Info(); case k1...k9: return Commands(Key); default: break; } @@ -2568,36 +2628,43 @@ eOSState cMenuMain::ProcessKey(eKeys Key) // --- SetTrackDescriptions -------------------------------------------------- -static void SetTrackDescriptions(void) +static void SetTrackDescriptions(bool Live) { cDevice::PrimaryDevice()->ClrAvailableTracks(true); - cChannel *Channel = Channels.GetByNumber(cDevice::CurrentChannel()); - if (Channel) { - cSchedulesLock SchedulesLock; - const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock); - if (Schedules) { - const cSchedule *Schedule = Schedules->GetSchedule(Channel->GetChannelID()); - if (Schedule) { - const cEvent *Present = Schedule->GetPresentEvent(true); - if (Present) { - const cComponents *Components = Present->Components(); - if (Components) { - int indexAudio = 0; - int indexDolby = 0; - for (int i = 0; i < Components->NumComponents(); i++) { - const tComponent *p = Components->Component(i); - if (p->stream == 2) { - if (p->type == 0x05) - cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, NULL, p->description); - else - cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, indexAudio++, 0, NULL, p->description); - } - } - } + const cComponents *Components = NULL; + cSchedulesLock SchedulesLock; + if (Live) { + cChannel *Channel = Channels.GetByNumber(cDevice::CurrentChannel()); + if (Channel) { + const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock); + if (Schedules) { + const cSchedule *Schedule = Schedules->GetSchedule(Channel->GetChannelID()); + if (Schedule) { + const cEvent *Present = Schedule->GetPresentEvent(true); + if (Present) + Components = Present->Components(); } } } } + else if (cReplayControl::LastReplayed()) { + cRecording *Recording = Recordings.GetByName(cReplayControl::LastReplayed()); + if (Recording) + Components = Recording->Info()->Components(); + } + if (Components) { + int indexAudio = 0; + int indexDolby = 0; + for (int i = 0; i < Components->NumComponents(); i++) { + const tComponent *p = Components->Component(i); + if (p->stream == 2) { + if (p->type == 0x05) + cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, NULL, p->description); + else + cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, indexAudio++, 0, NULL, p->description); + } + } + } } // --- cDisplayChannel ------------------------------------------------------- @@ -2657,7 +2724,7 @@ void cDisplayChannel::DisplayInfo(void) const cEvent *Present = Schedule->GetPresentEvent(true); const cEvent *Following = Schedule->GetFollowingEvent(true); if (Present != lastPresent || Following != lastFollowing) { - SetTrackDescriptions(); + SetTrackDescriptions(true); displayChannel->SetEvents(Present, Following); cStatus::MsgOsdProgramme(Present ? Present->StartTime() : 0, Present ? Present->Title() : NULL, Present ? Present->ShortText() : NULL, Following ? Following->StartTime() : 0, Following ? Following->Title() : NULL, Following ? Following->ShortText() : NULL); lastPresent = Present; @@ -2877,9 +2944,7 @@ cDisplayTracks::cDisplayTracks(void) :cOsdObject(true) { cDevice::PrimaryDevice()->EnsureAudioTrack(); - // Get the actual audio track descriptions from the EPG if we're not replaying: - if (!cDevice::PrimaryDevice()->Replaying() || cTransferControl::ReceiverDevice()) - SetTrackDescriptions(); + SetTrackDescriptions(!cDevice::PrimaryDevice()->Replaying() || cTransferControl::ReceiverDevice()); currentDisplayTracks = this; numTracks = track = 0; audioChannel = cDevice::PrimaryDevice()->GetAudioChannel(); @@ -2994,6 +3059,11 @@ eOSState cDisplayTracks::ProcessKey(eKeys Key) cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause) { + // We're going to manipulate an event here, so we need to prevent + // others from modifying any EPG data: + cSchedulesLock SchedulesLock; + cSchedules::Schedules(SchedulesLock); + event = NULL; instantId = NULL; fileName = NULL; @@ -3011,16 +3081,9 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause) timer->SetRecording(true); event = timer->Event(); - const char *Title = NULL; - const char *Subtitle = NULL; - const char *Summary = NULL; - if (event || GetEvent()) { - Title = event->Title(); - Subtitle = event->ShortText(); - Summary = event->Description(); - dsyslog("Title: '%s' Subtitle: '%s'", Title, Subtitle); - } - cRecording Recording(timer, Title, Subtitle, Summary); + if (event || GetEvent()) + dsyslog("Title: '%s' Subtitle: '%s'", event->Title(), event->ShortText()); + cRecording Recording(timer, event); fileName = strdup(Recording.FileName()); // crude attempt to avoid duplicate recordings: @@ -3047,7 +3110,7 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause) const cChannel *ch = timer->Channel(); recorder = new cRecorder(fileName, ch->Ca(), timer->Priority(), ch->Vpid(), ch->Apids(), ch->Dpids(), ch->Spids()); if (device->AttachReceiver(recorder)) { - Recording.WriteSummary(); + Recording.WriteInfo(); cStatus::MsgRecording(device, Recording.Name()); if (!Timer && !cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo() cReplayControl::SetRecording(fileName, Recording.Name()); @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.69 2005/03/20 10:57:29 kls Exp $ + * $Id: menu.h 1.70 2005/05/15 14:34:54 kls Exp $ */ #ifndef __MENU_H @@ -133,7 +133,7 @@ private: eOSState Play(void); eOSState Rewind(void); eOSState Delete(void); - eOSState Summary(void); + eOSState Info(void); eOSState Commands(eKeys Key = kNone); public: cMenuRecordings(const char *Base = NULL, int Level = 0, bool OpenSubMenus = false); @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.c 1.59 2004/12/19 12:27:38 kls Exp $ + * $Id: osd.c 1.60 2005/05/14 11:16:30 kls Exp $ */ #include "osd.h" @@ -574,7 +574,7 @@ const tIndex *cBitmap::Data(int x, int y) // --- cOsd ------------------------------------------------------------------ -bool cOsd::isOpen = false; +int cOsd::isOpen = 0; cOsd::cOsd(int Left, int Top) { @@ -585,7 +585,7 @@ cOsd::cOsd(int Left, int Top) left = Left; top = Top; width = height = 0; - isOpen = true; + isOpen++; } cOsd::~cOsd() @@ -593,7 +593,7 @@ cOsd::~cOsd() for (int i = 0; i < numBitmaps; i++) delete bitmaps[i]; delete savedRegion; - isOpen = false; + isOpen--; } cBitmap *cOsd::GetBitmap(int Area) @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 1.47 2004/10/16 10:33:44 kls Exp $ + * $Id: osd.h 1.48 2005/05/14 11:15:55 kls Exp $ */ #ifndef __OSD_H @@ -210,7 +210,7 @@ struct tArea { class cOsd { friend class cOsdProvider; private: - static bool isOpen; + static int isOpen; cBitmap *savedRegion; cBitmap *bitmaps[MAXOSDAREAS]; int numBitmaps; @@ -235,7 +235,7 @@ protected: public: virtual ~cOsd(); ///< Shuts down the OSD. - static bool IsOpen(void) { return isOpen; } + static int IsOpen(void) { return isOpen; } int Left(void) { return left; } int Top(void) { return top; } int Width(void) { return width; } @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: player.h 1.16 2005/02/12 14:45:29 kls Exp $ + * $Id: player.h 1.17 2005/05/22 11:07:42 kls Exp $ */ #ifndef __PLAYER_H @@ -29,6 +29,7 @@ protected: void DevicePlay(void) { if (device) device->Play(); } void DeviceFreeze(void) { if (device) device->Freeze(); } void DeviceMute(void) { if (device) device->Mute(); } + void DeviceSetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat) { if (device) device->SetVideoDisplayFormat(VideoDisplayFormat); } void DeviceStillPicture(const uchar *Data, int Length) { if (device) device->StillPicture(Data, Length); } void Detach(void); virtual void Activate(bool On) {} diff --git a/recording.c b/recording.c index ed74c46..93b0af8 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 1.98 2005/05/07 15:25:15 kls Exp $ + * $Id: recording.c 1.107 2005/05/29 11:16:57 kls Exp $ */ #include "recording.h" @@ -23,6 +23,8 @@ #include "tools.h" #include "videodir.h" +#define SUMMARYFALLBACK + #define RECEXT ".rec" #define DELEXT ".del" /* This was the original code, which works fine in a Linux only environment. @@ -45,7 +47,10 @@ // end of implementation for brain dead systems #define RESUMEFILESUFFIX "/resume%s%s.vdr" +#ifdef SUMMARYFALLBACK #define SUMMARYFILESUFFIX "/summary.vdr" +#endif +#define INFOFILESUFFIX "/info.vdr" #define MARKSFILESUFFIX "/marks.vdr" #define MINDISKSPACE 1024 // MB @@ -213,6 +218,68 @@ void cResumeFile::Delete(void) } } +// --- cRecordingInfo -------------------------------------------------------- + +cRecordingInfo::cRecordingInfo(const cEvent *Event) +{ + if (Event) { + event = Event; + channelID = event->ChannelID(); + ownEvent = NULL; + } + else + event = ownEvent = new cEvent(0); +} + +cRecordingInfo::~cRecordingInfo() +{ + delete ownEvent; +} + +void cRecordingInfo::SetData(const char *Title, const char *ShortText, const char *Description) +{ + if (!isempty(Title)) + ((cEvent *)event)->SetTitle(Title); + if (!isempty(ShortText)) + ((cEvent *)event)->SetShortText(ShortText); + if (!isempty(Description)) + ((cEvent *)event)->SetDescription(Description); +} + +bool cRecordingInfo::Read(FILE *f) +{ + if (ownEvent) { + cReadLine ReadLine; + char *s; + while ((s = ReadLine.Read(f)) != NULL) { + char *t = skipspace(s + 1); + switch (*s) { + case 'C': { + char *p = strchr(t, ' '); + if (p) + *p = 0; // strips optional channel name + if (*t) + channelID = tChannelID::FromString(t); + } + break; + default: if (!ownEvent->Parse(s)) + return false; + break; + } + } + return true; + } + return false; +} + +bool cRecordingInfo::Write(FILE *f, const char *Prefix) const +{ + if (channelID.Valid()) + fprintf(f, "%sC %s\n", Prefix, *channelID.ToString()); + event->Dump(f, Prefix, true); + return true; +} + // --- cRecording ------------------------------------------------------------ #define RESUME_NOT_INITIALIZED (-2) @@ -308,7 +375,7 @@ static char *ExchangeChars(char *s, bool ToFileSystem) return s; } -cRecording::cRecording(cTimer *Timer, const char *Title, const char *Subtitle, const char *Summary) +cRecording::cRecording(cTimer *Timer, const cEvent *Event) { resume = RESUME_NOT_INITIALIZED; titleBuffer = NULL; @@ -316,7 +383,8 @@ cRecording::cRecording(cTimer *Timer, const char *Title, const char *Subtitle, c fileName = NULL; name = NULL; // set up the actual name: - const char *OriginalSubtitle = Subtitle; + const char *Title = Event ? Event->Title() : NULL; + const char *Subtitle = Event ? Event->ShortText() : NULL; char SubtitleBuffer[MAX_SUBTITLE_LENGTH]; if (isempty(Title)) Title = Timer->Channel()->Name(); @@ -333,6 +401,14 @@ cRecording::cRecording(cTimer *Timer, const char *Title, const char *Subtitle, c name = strdup(Timer->File()); name = strreplace(name, TIMERMACRO_TITLE, Title); name = strreplace(name, TIMERMACRO_EPISODE, Subtitle); + // avoid blanks at the end: + int l = strlen(name); + while (l-- > 2) { + if (name[l] == ' ' && name[l - 1] != '~') + name[l] = 0; + else + break; + } if (Timer->IsSingleEvent()) { Timer->SetFile(name); // this was an instant recording, so let's set the actual data Timers.SetModified(); @@ -347,17 +423,13 @@ cRecording::cRecording(cTimer *Timer, const char *Title, const char *Subtitle, c start = Timer->StartTime(); priority = Timer->Priority(); lifetime = Timer->Lifetime(); - // handle summary: - summary = !isempty(Timer->Summary()) ? strdup(Timer->Summary()) : NULL; - if (!summary) { - Subtitle = OriginalSubtitle; - if (isempty(Subtitle)) - Subtitle = ""; - if (isempty(Summary)) - Summary = ""; - if (*Subtitle || *Summary) - asprintf(&summary, "%s\n\n%s%s%s", Title, Subtitle, (*Subtitle && *Summary) ? "\n\n" : "", Summary); - } + // handle info: + info = new cRecordingInfo(Event); + // this is a somewhat ugly hack to get the 'summary' information from the + // timer into the recording info, but it saves us from having to actually + // copy the entire event data: + if (!isempty(Timer->Summary())) + info->SetData(isempty(info->Title()) ? Timer->File() : NULL, NULL, Timer->Summary()); } cRecording::cRecording(const char *FileName) @@ -370,7 +442,7 @@ cRecording::cRecording(const char *FileName) char *p = strrchr(FileName, '/'); name = NULL; - summary = NULL; + info = new cRecordingInfo; if (p) { time_t now = time(NULL); struct tm tm_r; @@ -386,39 +458,57 @@ cRecording::cRecording(const char *FileName) name[p - FileName] = 0; name = ExchangeChars(name, false); } - // read an optional summary file: - char *SummaryFileName = NULL; - asprintf(&SummaryFileName, "%s%s", fileName, SUMMARYFILESUFFIX); - int f = open(SummaryFileName, O_RDONLY); - if (f >= 0) { - struct stat buf; - if (fstat(f, &buf) == 0) { - int size = buf.st_size; - summary = MALLOC(char, size + 1); // +1 for terminating 0 - if (summary) { - int rbytes = safe_read(f, summary, size); - if (rbytes >= 0) { - summary[rbytes] = 0; - if (rbytes != size) - esyslog("%s: expected %d bytes but read %d", SummaryFileName, size, rbytes); - } - else { - LOG_ERROR_STR(SummaryFileName); - free(summary); - summary = NULL; + // read an optional info file: + char *InfoFileName = NULL; + asprintf(&InfoFileName, "%s%s", fileName, INFOFILESUFFIX); + FILE *f = fopen(InfoFileName, "r"); + if (f) { + info->Read(f); + fclose(f); + } + else if (errno != ENOENT) + LOG_ERROR_STR(InfoFileName); + free(InfoFileName); +#ifdef SUMMARYFALLBACK + // fall back to the old 'summary.vdr' if there was no 'info.vdr': + if (isempty(info->Title())) { + char *SummaryFileName = NULL; + asprintf(&SummaryFileName, "%s%s", fileName, SUMMARYFILESUFFIX); + FILE *f = fopen(SummaryFileName, "r"); + if (f) { + int line = 0; + char *data[3] = { NULL }; + cReadLine ReadLine; + char *s; + while ((s = ReadLine.Read(f)) != NULL && line < 3) { + if (*s) { + if (data[line]) { + int len = strlen(s); + len += strlen(data[line]) + 1; + data[line] = (char *)realloc(data[line], len + 1); + strcat(data[line], "\n"); + strcat(data[line], s); + } + else + data[line] = strdup(s); + } + else + line++; } - + fclose(f); + if (line == 1) { + data[2] = data[1]; + data[1] = NULL; } - else - esyslog("can't allocate %d byte of memory for summary file '%s'", size + 1, SummaryFileName); - close(f); + info->SetData(data[0], data[1], data[2]); + for (int i = 0; i < 3; i ++) + free(data[i]); } - else + else if (errno != ENOENT) LOG_ERROR_STR(SummaryFileName); + free(SummaryFileName); } - else if (errno != ENOENT) - LOG_ERROR_STR(SummaryFileName); - free(SummaryFileName); +#endif } } @@ -428,7 +518,7 @@ cRecording::~cRecording() free(sortBuffer); free(fileName); free(name); - free(summary); + delete info; } char *cRecording::StripEpisodeName(char *s) @@ -513,7 +603,8 @@ const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level) cons Delimiter, s); // let's not display a trailing '~': - stripspace(titleBuffer); + if (!NewIndicator) + stripspace(titleBuffer); s = &titleBuffer[strlen(titleBuffer) - 1]; if (*s == '~') *s = 0; @@ -568,21 +659,18 @@ bool cRecording::IsEdited(void) const return *s == '%'; } -bool cRecording::WriteSummary(void) +bool cRecording::WriteInfo(void) { - if (summary) { - char *SummaryFileName = NULL; - asprintf(&SummaryFileName, "%s%s", fileName, SUMMARYFILESUFFIX); - FILE *f = fopen(SummaryFileName, "w"); - if (f) { - if (fputs(summary, f) < 0) - LOG_ERROR_STR(SummaryFileName); - fclose(f); - } - else - LOG_ERROR_STR(SummaryFileName); - free(SummaryFileName); + char *InfoFileName = NULL; + asprintf(&InfoFileName, "%s%s", fileName, INFOFILESUFFIX); + FILE *f = fopen(InfoFileName, "w"); + if (f) { + info->Write(f); + fclose(f); } + else + LOG_ERROR_STR(InfoFileName); + free(InfoFileName); return true; } @@ -956,7 +1044,7 @@ bool cIndexFile::CatchUp(int Index) LOG_ERROR_STR(fileName); if (Index < last - (i ? 2 * INDEXSAFETYLIMIT : 0) || Index > 10 * INDEXSAFETYLIMIT) // keep off the end in case of "Pause live video" break; - sleep(1); + cCondWait::SleepMs(1000); } } return index != NULL; diff --git a/recording.h b/recording.h index be1a5c4..0adb036 100644 --- a/recording.h +++ b/recording.h @@ -4,14 +4,16 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 1.34 2005/01/16 15:11:31 kls Exp $ + * $Id: recording.h 1.38 2005/05/28 09:34:07 kls Exp $ */ #ifndef __RECORDING_H #define __RECORDING_H #include <time.h> +#include "channels.h" #include "config.h" +#include "epg.h" #include "thread.h" #include "timers.h" #include "tools.h" @@ -32,6 +34,24 @@ public: void Delete(void); }; +class cRecordingInfo { + friend class cRecording; +private: + tChannelID channelID; + const cEvent *event; + cEvent *ownEvent; + cRecordingInfo(const cEvent *Event = NULL); + void SetData(const char *Title, const char *ShortText, const char *Description); +public: + ~cRecordingInfo(); + const char *Title(void) const { return event->Title(); } + const char *ShortText(void) const { return event->ShortText(); } + const char *Description(void) const { return event->Description(); } + const cComponents *Components(void) const { return event->Components(); } + bool Read(FILE *f); + bool Write(FILE *f, const char *Prefix = "") const; + }; + class cRecording : public cListObject { private: mutable int resume; @@ -39,7 +59,7 @@ private: mutable char *sortBuffer; mutable char *fileName; mutable char *name; - char *summary; + cRecordingInfo *info; static char *StripEpisodeName(char *s); char *SortName(void) const; int GetResume(void) const; @@ -47,19 +67,19 @@ public: time_t start; int priority; int lifetime; - cRecording(cTimer *Timer, const char *Title, const char *Subtitle, const char *Summary); + cRecording(cTimer *Timer, const cEvent *Event); cRecording(const char *FileName); ~cRecording(); virtual int Compare(const cListObject &ListObject) const; const char *Name(void) const { return name; } const char *FileName(void) const; const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1) const; - const char *Summary(void) const { return summary; } + const cRecordingInfo *Info(void) const { return info; } const char *PrefixFileName(char Prefix); int HierarchyLevels(void) const; bool IsNew(void) const { return GetResume() <= 0; } bool IsEdited(void) const; - bool WriteSummary(void); + bool WriteInfo(void); bool Delete(void); // Changes the file name so that it will no longer be visible in the "Recordings" menu // Returns false in case of error @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: sdt.c 1.13 2004/10/31 12:10:20 kls Exp $ + * $Id: sdt.c 1.14 2005/05/14 09:39:46 kls Exp $ */ #include "sdt.h" @@ -62,6 +62,15 @@ void cSdtFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length sd->serviceName.getText(NameBuf, ShortNameBuf, sizeof(NameBuf), sizeof(ShortNameBuf)); char *pn = compactspace(NameBuf); char *ps = compactspace(ShortNameBuf); + if (!*ps && cSource::IsCable(Source())) { + // Some cable providers don't mark short channel names according to the + // standard, but rather go their own way and use "name>short name": + char *p = strchr(pn, '>'); + if (p && p > pn) { + *p++ = 0; + strcpy(ShortNameBuf, p); + } + } sd->providerName.getText(ProviderNameBuf, sizeof(ProviderNameBuf)); char *pp = compactspace(ProviderNameBuf); if (channel) { @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: sections.c 1.10 2004/10/24 11:05:12 kls Exp $ + * $Id: sections.c 1.11 2005/05/29 11:43:17 kls Exp $ */ #include "sections.h" @@ -167,6 +167,7 @@ void cSectionHandler::SetStatus(bool On) void cSectionHandler::Action(void) { active = true; + SetPriority(19); while (active) { Lock(); diff --git a/skinclassic.c b/skinclassic.c index 7eb0513..fd3ab0b 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 1.11 2005/01/09 11:56:29 kls Exp $ + * $Id: skinclassic.c 1.12 2005/05/16 10:45:07 kls Exp $ */ #include "skinclassic.h" @@ -326,7 +326,33 @@ void cSkinClassicDisplayMenu::SetEvent(const cEvent *Event) void cSkinClassicDisplayMenu::SetRecording(const cRecording *Recording) { - SetText(Recording->Summary(), false); //TODO + if (!Recording) + return; + const cRecordingInfo *Info = Recording->Info(); + const cFont *font = cFont::GetFont(fontOsd); + int xl = x0 + 10; + int y = y2; + cTextScroller ts; + char t[32]; + snprintf(t, sizeof(t), "%s %s", *DateString(Recording->start), *TimeString(Recording->start)); + ts.Set(osd, xl, y, x1 - xl, y3 - y, t, font, Theme.Color(clrMenuEventTime), Theme.Color(clrBackground)); + y += ts.Height(); + y += font->Height(); + const char *Title = Info->Title(); + if (isempty(Title)) + Title = Recording->Name(); + ts.Set(osd, xl, y, x1 - xl, y3 - y, Title, font, Theme.Color(clrMenuEventTitle), Theme.Color(clrBackground)); + y += ts.Height(); + if (!isempty(Info->ShortText())) { + const cFont *font = cFont::GetFont(fontSml); + ts.Set(osd, xl, y, x1 - xl, y3 - y, Info->ShortText(), font, Theme.Color(clrMenuEventShortText), Theme.Color(clrBackground)); + y += ts.Height(); + } + y += font->Height(); + if (!isempty(Info->Description())) { + textScroller.Set(osd, xl, y, x1 - xl - 2 * ScrollWidth, y3 - y, Info->Description(), font, Theme.Color(clrMenuEventDescription), Theme.Color(clrBackground)); + SetScrollbar(); + } } void cSkinClassicDisplayMenu::SetText(const char *Text, bool FixedFont) @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: skins.h 1.7 2005/02/27 14:37:37 kls Exp $ + * $Id: skins.h 1.8 2005/05/15 14:41:41 kls Exp $ */ #ifndef __SKINS_H @@ -150,7 +150,7 @@ public: ///< that text if necessary. virtual void SetRecording(const cRecording *Recording) = 0; ///< Sets the Recording that shall be displayed, using the entire central area - ///< of the menu. The Recording's 'summary' shall be displayed using a + ///< of the menu. The Recording's 'description' shall be displayed using a ///< cTextScroller, and the Scroll() function will be called to drive scrolling ///< that text if necessary. virtual void SetText(const char *Text, bool FixedFont) = 0; diff --git a/skinsttng.c b/skinsttng.c index 3760ad4..b9d9ccb 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 1.13 2005/02/27 14:45:19 kls Exp $ + * $Id: skinsttng.c 1.14 2005/05/16 10:44:58 kls Exp $ */ // Star Trek: The Next Generation® is a registered trademark of Paramount Pictures @@ -576,7 +576,39 @@ void cSkinSTTNGDisplayMenu::SetEvent(const cEvent *Event) void cSkinSTTNGDisplayMenu::SetRecording(const cRecording *Recording) { - SetText(Recording->Summary(), false); //XXX + if (!Recording) + return; + const cRecordingInfo *Info = Recording->Info(); + const cFont *font = cFont::GetFont(fontOsd); + int xl = x3 + 5; + int y = y3; + cTextScroller ts; + char t[32]; + snprintf(t, sizeof(t), "%s %s", *DateString(Recording->start), *TimeString(Recording->start)); + ts.Set(osd, xl, y, x4 - xl, y4 - y, t, font, Theme.Color(clrMenuEventTime), Theme.Color(clrBackground)); + y += ts.Height(); + y += font->Height(); + const char *Title = Info->Title(); + if (isempty(Title)) + Title = Recording->Name(); + ts.Set(osd, xl, y, x4 - xl, y4 - y, Title, font, Theme.Color(clrMenuEventTitle), Theme.Color(clrBackground)); + y += ts.Height(); + if (!isempty(Info->ShortText())) { + const cFont *font = cFont::GetFont(fontSml); + ts.Set(osd, xl, y, x4 - xl, y4 - y, Info->ShortText(), font, Theme.Color(clrMenuEventShortText), Theme.Color(clrBackground)); + y += ts.Height(); + } + y += font->Height(); + if (!isempty(Info->Description())) { + int yt = y; + int yb = y4 - Roundness; + textScroller.Set(osd, xl, yt, x4 - xl, yb - yt, Info->Description(), font, Theme.Color(clrMenuEventDescription), Theme.Color(clrBackground)); + yb = yt + textScroller.Height(); + osd->DrawEllipse (x1, yt - Roundness, x2, yt, frameColor, -3); + osd->DrawRectangle(x1, yt, x2, yb, frameColor); + osd->DrawEllipse (x1, yb, x2, yb + Roundness, frameColor, -2); + SetScrollbar(); + } } void cSkinSTTNGDisplayMenu::SetText(const char *Text, bool FixedFont) @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: sources.h 1.3 2004/12/26 11:59:21 kls Exp $ + * $Id: sources.h 1.4 2005/05/14 09:30:41 kls Exp $ */ #ifndef __SOURCES_H @@ -35,6 +35,9 @@ public: static cString ToString(int Code); static int FromString(const char *s); static int FromData(eSourceType SourceType, int Position = 0, bool East = false); + static bool IsCable(int Code) { return (Code & st_Mask) == stCable; } + static bool IsSat(int Code) { return (Code & st_Mask) == stSat; } + static bool IsTerr(int Code) { return (Code & st_Mask) == stTerr; } }; class cSources : public cConfig<cSource> { diff --git a/summary2info.pl b/summary2info.pl new file mode 100755 index 0000000..8e80abe --- /dev/null +++ b/summary2info.pl @@ -0,0 +1,47 @@ +#!/usr/bin/perl + +# Convert 'summary.vdr' files to 'info.vdr' +# +# Converts all 'summary.vdr' files in the video directory to the +# 'info.vdr' format as used from VDR version 1.3.25 upward. +# +# Usage: summary2info.pl /video +# +# See the main source file 'vdr.c' for copyright information and +# how to reach the author. +# +# $Id: summary2info.pl 1.2 2005/05/22 10:37:47 kls Exp $ + +$VideoDir = $ARGV[0] || die "please provide the name of the video directory\n"; + +@SummaryFiles = `find "$VideoDir" -name summary.vdr`; + +for $SummaryFile (@SummaryFiles) { + chomp($SummaryFile); + print STDERR "converting $SummaryFile..."; + open(F, $SummaryFile) || die "$SummaryFile: $!\n"; + $line = 0; + @data = (); + while (<F>) { + chomp; + if ($_) { + $data[$line] .= '|' if ($data[$line]); + $data[$line] .= $_; + } + else { + $line++; + } + } + close(F); + if ($line == 1) { + $data[2] = $data[1]; + $data[1] = ""; + } + ($InfoFile = $SummaryFile) =~ s/summary\.vdr$/info.vdr/; + open(F, ">$InfoFile") || die "$InfoFile: $!\n"; + print F "T $data[0]\n" if ($data[0]); + print F "S $data[1]\n" if ($data[1]); + print F "D $data[2]\n" if ($data[2]); + close(F); + print STDERR "done.\n"; + } @@ -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 1.70 2005/05/06 13:47:39 kls Exp $ + * $Id: svdrp.c 1.72 2005/05/26 09:59:09 kls Exp $ */ #include "svdrp.h" @@ -31,6 +31,7 @@ #include "device.h" #include "eitscan.h" #include "keys.h" +#include "menu.h" #include "remote.h" #include "timers.h" #include "tools.h" @@ -214,7 +215,7 @@ const char *HelpPages[] = { " events at the given time (which must be in time_t form).", "LSTR [ <number> ]\n" " List recordings. Without option, all recordings are listed. Otherwise\n" - " the summary for the given recording is listed.", + " the information for the given recording is listed.", "LSTT [ <number> ]\n" " List timers. Without option, all timers are listed. Otherwise\n" " only the given timer is listed.", @@ -281,7 +282,7 @@ const char *HelpPages[] = { /* SVDRP Reply Codes: 214 Help message - 215 EPG data record + 215 EPG or recording data record 220 VDR service ready 221 VDR service closing transmission channel 250 Requested VDR action okay, completed @@ -505,12 +506,17 @@ void cSVDRP::CmdDELR(const char *Option) if (isnumber(Option)) { cRecording *recording = Recordings.Get(strtol(Option, NULL, 10) - 1); if (recording) { - if (recording->Delete()) { - Reply(250, "Recording \"%s\" deleted", Option); - ::Recordings.Load(); // must make sure the global recordings list is updated + cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName()); + if (!rc) { + if (recording->Delete()) { + Reply(250, "Recording \"%s\" deleted", Option); + ::Recordings.Load(); // must make sure the global recordings list is updated + } + else + Reply(554, "Error while deleting recording!"); } else - Reply(554, "Error while deleting recording!"); + Reply(550, "Recording \"%s\" is in use by timer %d", Option, rc->Timer()->Index() + 1); } else Reply(550, "Recording \"%s\" not found%s", Option, Recordings.Count() ? "" : " (use LSTR before deleting)"); @@ -800,13 +806,15 @@ void cSVDRP::CmdLSTR(const char *Option) if (isnumber(Option)) { cRecording *recording = Recordings.Get(strtol(Option, NULL, 10) - 1); if (recording) { - if (recording->Summary()) { - char *summary = strdup(recording->Summary()); - Reply(250, "%s", strreplace(summary,'\n','|')); - free(summary); + FILE *f = fdopen(file, "w"); + if (f) { + recording->Info()->Write(f, "215-"); + fflush(f); + Reply(215, "End of recording information"); + // don't 'fclose(f)' here! } else - Reply(550, "No summary available"); + Reply(451, "Can't open file connection"); } else Reply(550, "Recording \"%s\" not found", Option); @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.c 1.42 2005/05/06 14:39:15 kls Exp $ + * $Id: thread.c 1.43 2005/05/29 11:40:30 kls Exp $ */ #include "thread.h" @@ -208,6 +208,12 @@ cThread::~cThread() free(description); } +void cThread::SetPriority(int Priority) +{ + if (setpriority(PRIO_PROCESS, 0, Priority) < 0) + LOG_ERROR; +} + void cThread::SetDescription(const char *Description, ...) { free(description); @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: thread.h 1.27 2005/01/14 14:02:14 kls Exp $ + * $Id: thread.h 1.28 2005/05/29 11:31:24 kls Exp $ */ #ifndef __THREAD_H @@ -82,6 +82,7 @@ private: static bool emergencyExitRequested; static void *StartThread(cThread *Thread); protected: + void SetPriority(int Priority); void Lock(void) { mutex.Lock(); } void Unlock(void) { mutex.Unlock(); } virtual void Action(void) = 0; @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.91 2005/03/20 14:44:33 kls Exp $ + * $Id: tools.c 1.95 2005/05/29 10:18:26 kls Exp $ */ #include "tools.h" @@ -571,6 +571,25 @@ cString TimeToString(time_t t) return "???"; } +cString DateString(time_t t) +{ + char buf[32]; + struct tm tm_r; + tm *tm = localtime_r(&t, &tm_r); + char *p = stpcpy(buf, WeekDayName(tm->tm_wday)); + *p++ = ' '; + strftime(p, sizeof(buf) - (p - buf), "%d.%m.%Y", tm); + return buf; +} + +cString TimeString(time_t t) +{ + char buf[25]; + struct tm tm_r; + strftime(buf, sizeof(buf), "%R", localtime_r(&t, &tm_r)); + return buf; +} + // --- cReadLine ------------------------------------------------------------- char *cReadLine::Read(FILE *f) @@ -913,6 +932,7 @@ int cListObject::Index(void) const cListBase::cListBase(void) { objects = lastObject = NULL; + count = 0; } cListBase::~cListBase() @@ -933,6 +953,7 @@ void cListBase::Add(cListObject *Object, cListObject *After) objects = Object; lastObject = Object; } + count++; } void cListBase::Ins(cListObject *Object, cListObject *Before) @@ -948,6 +969,7 @@ void cListBase::Ins(cListObject *Object, cListObject *Before) lastObject = Object; objects = Object; } + count++; } void cListBase::Del(cListObject *Object, bool DeleteObject) @@ -959,6 +981,7 @@ void cListBase::Del(cListObject *Object, bool DeleteObject) Object->Unlink(); if (DeleteObject) delete Object; + count--; } void cListBase::Move(int From, int To) @@ -998,6 +1021,7 @@ void cListBase::Clear(void) objects = object; } objects = lastObject = NULL; + count = 0; } cListObject *cListBase::Get(int Index) const @@ -1010,18 +1034,6 @@ cListObject *cListBase::Get(int Index) const return object; } -int cListBase::Count(void) const -{ - int n = 0; - cListObject *object = objects; - - while (object) { - n++; - object = object->Next(); - } - return n; -} - static int CompareListObjects(const void *a, const void *b) { const cListObject *la = *(const cListObject **)a; @@ -1043,7 +1055,60 @@ void cListBase::Sort(void) objects = lastObject = NULL; for (i = 0; i < n; i++) { a[i]->Unlink(); + count--; Add(a[i]); } } +// --- cHashBase ------------------------------------------------------------- + +cHashBase::cHashBase(int Size) +{ + size = Size; + hashTable = (cList<cHashObject>**)calloc(size, sizeof(cList<cHashObject>*)); +} + +cHashBase::~cHashBase(void) +{ + for (int i = 0; i < size; i++) + delete hashTable[i]; + free(hashTable); +} + +void cHashBase::Add(cListObject *Object, unsigned int Id) +{ + unsigned int hash = hashfn(Id); + if (!hashTable[hash]) + hashTable[hash] = new cList<cHashObject>; + hashTable[hash]->Add(new cHashObject(Object, Id)); +} + +void cHashBase::Del(cListObject *Object, unsigned int Id) +{ + cList<cHashObject> *list = hashTable[hashfn(Id)]; + if (list) { + for (cHashObject *hob = list->First(); hob; hob = list->Next(hob)) { + if (hob->object == Object) { + list->Del(hob); + break; + } + } + } +} + +cListObject *cHashBase::Get(unsigned int Id) const +{ + cList<cHashObject> *list = hashTable[hashfn(Id)]; + if (list) { + for (cHashObject *hob = list->First(); hob; hob = list->Next(hob)) { + if (hob->id == Id) + return hob->object; + } + } + return NULL; +} + +cList<cHashObject> *cHashBase::GetList(unsigned int Id) const +{ + return hashTable[hashfn(Id)]; +} @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.68 2005/03/20 14:44:24 kls Exp $ + * $Id: tools.h 1.72 2005/05/29 10:24:54 kls Exp $ */ #ifndef __TOOLS_H @@ -102,6 +102,8 @@ cString WeekDayName(int WeekDay); cString WeekDayName(time_t t); cString DayDateTime(time_t t = 0); cString TimeToString(time_t t); +cString DateString(time_t t); +cString TimeString(time_t t); class cTimeMs { private: @@ -211,6 +213,7 @@ class cListBase { protected: cListObject *objects, *lastObject; cListBase(void); + int count; public: virtual ~cListBase(); void Add(cListObject *Object, cListObject *After = NULL); @@ -220,7 +223,7 @@ public: void Move(cListObject *From, cListObject *To); virtual void Clear(void); cListObject *Get(int Index) const; - int Count(void) const; + int Count(void) const { return count; } void Sort(void); }; @@ -233,4 +236,36 @@ public: T *Next(const T *object) const { return (T *)object->cListObject::Next(); } // avoid ambiguities in case of a "list of lists" }; +class cHashObject : public cListObject { + friend class cHashBase; +private: + unsigned int id; + cListObject *object; +public: + cHashObject(cListObject *Object, unsigned int Id) { object = Object; id = Id; } + }; + +class cHashBase { +private: + cList<cHashObject> **hashTable; + int size; + unsigned int hashfn(unsigned int Id) const { return Id % size; } +protected: + cHashBase(int Size); +public: + virtual ~cHashBase(); + void Add(cListObject *Object, unsigned int Id); + void Del(cListObject *Object, unsigned int Id); + cListObject *Get(unsigned int Id) const; + cList<cHashObject> *GetList(unsigned int Id) const; + }; + +#define HASHSIZE 512 + +template<class T> class cHash : public cHashBase { +public: + cHash(int Size = HASHSIZE) : cHashBase(Size) {} + T *Get(unsigned int Id) const { return (T *)cHashBase::Get(Id); } +}; + #endif //__TOOLS_H @@ -8,7 +8,7 @@ .\" License as specified in the file COPYING that comes with the .\" vdr distribution. .\" -.\" $Id: vdr.5 1.36 2005/05/07 10:40:23 kls Exp $ +.\" $Id: vdr.5 1.37 2005/05/16 14:16:48 kls Exp $ .\" .TH vdr 5 "19 Mar 2005" "1.3.23" "Video Disk Recorder Files" .SH NAME @@ -578,11 +578,13 @@ the current position within the recording, and to implement skipping and fast forward/back functions. See the definition of the \fBcIndexFile\fR class for details about the actual contents of this file. -.SS SUMMARY -The file \fIsummary.vdr\fR (if present in a recording directory) contains +.SS INFO +The file \fIinfo.vdr\fR (if present in a recording directory) contains a description of the recording, derived from the EPG data at recording time (if such data was available) or the \fBSummary\fR field of the corresponding -timer. This is a plain ASCII file and can contain arbitrary text. +timer. This is a plain ASCII file and contains tagged lines like the \fBEPG DATA\fR +file (see the description of the \fIepg.data\fR file). Note that the tags +c, E, e and V will not appear in an \fIinfo.vdr\fR file. .SS RESUME The file \fIresume.vdr\fR (if present in a recording directory) contains the position within the recording where the last replay session left off. @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/vdr * - * $Id: vdr.c 1.203 2005/03/20 10:58:59 kls Exp $ + * $Id: vdr.c 1.207 2005/05/26 10:45:29 kls Exp $ */ #include <getopt.h> @@ -87,25 +87,6 @@ static void Watchdog(int signum) int main(int argc, char *argv[]) { -#ifdef _CS_GNU_LIBPTHREAD_VERSION - // Check for NPTL and exit if present - VDR apparently doesn't run well with NPTL: - char LibPthreadVersion[128]; - if (confstr(_CS_GNU_LIBPTHREAD_VERSION, LibPthreadVersion, sizeof(LibPthreadVersion)) > 0) { - if (strstr(LibPthreadVersion, "NPTL")) { - fprintf(stderr, "vdr: please turn off NPTL by setting 'export LD_ASSUME_KERNEL=2.4.1' before starting VDR\n"); - return 2; - } - } -#endif - - // Check for UTF-8 and exit if present - asprintf() will fail if it encounters 8 bit ASCII codes - char *LangEnv; - if ((LangEnv = getenv("LANG")) != NULL && strcasestr(LangEnv, "utf") || - (LangEnv = getenv("LC_CTYPE")) != NULL && strcasestr(LangEnv, "utf")) { - fprintf(stderr, "vdr: please turn off UTF-8 before starting VDR\n"); - return 2; - } - // Save terminal settings: struct termios savedTm; @@ -321,6 +302,25 @@ int main(int argc, char *argv[]) return 0; } +#ifdef _CS_GNU_LIBPTHREAD_VERSION + // Check for NPTL and exit if present - VDR apparently doesn't run well with NPTL: + char LibPthreadVersion[128]; + if (confstr(_CS_GNU_LIBPTHREAD_VERSION, LibPthreadVersion, sizeof(LibPthreadVersion)) > 0) { + if (strstr(LibPthreadVersion, "NPTL")) { + fprintf(stderr, "vdr: please turn off NPTL by setting 'export LD_ASSUME_KERNEL=2.4.1' before starting VDR\n"); + return 2; + } + } +#endif + + // Check for UTF-8 and exit if present - asprintf() will fail if it encounters 8 bit ASCII codes + char *LangEnv; + if ((LangEnv = getenv("LANG")) != NULL && strcasestr(LangEnv, "utf") || + (LangEnv = getenv("LC_CTYPE")) != NULL && strcasestr(LangEnv, "utf")) { + fprintf(stderr, "vdr: please turn off UTF-8 before starting VDR\n"); + return 2; + } + // Log file: if (SysLogLevel > 0) @@ -744,7 +744,6 @@ int main(int argc, char *argv[]) // Power off: case kPower: isyslog("Power button pressed"); DELETENULL(Menu); - cControl::Shutdown(); Temp = NULL; if (!Shutdown) { Skins.Message(mtError, tr("Can't shutdown - option '-s' not given!")); @@ -846,6 +845,14 @@ int main(int argc, char *argv[]) break; // Viewing Control: case kOk: LastChannel = -1; break; // forces channel display + // Instant resume of the last viewed recording: + case kPlay: + if (cReplayControl::LastReplayed()) { + cControl::Shutdown(); + Temp = NULL; + cControl::Launch(new cReplayControl); + } + break; // Key macros: case kRed: case kGreen: @@ -898,6 +905,7 @@ int main(int argc, char *argv[]) if (WatchdogTimeout > 0) signal(SIGALRM, SIG_IGN); if (Interface->Confirm(tr("Press any key to cancel shutdown"), UserShutdown ? 5 : SHUTDOWNWAIT, true)) { + cControl::Shutdown(); int Channel = timer ? timer->Channel()->Number() : 0; const char *File = timer ? timer->File() : ""; Delta = Next - time(NULL); // compensates for Confirm() timeout @@ -940,9 +948,11 @@ Exit: Remotes.Clear(); Audios.Clear(); Skins.Clear(); - Setup.CurrentChannel = cDevice::CurrentChannel(); - Setup.CurrentVolume = cDevice::CurrentVolume(); - Setup.Save(); + if (ExitCode != 2) { + Setup.CurrentChannel = cDevice::CurrentChannel(); + Setup.CurrentVolume = cDevice::CurrentVolume(); + Setup.Save(); + } cDevice::Shutdown(); PluginManager.Shutdown(); ReportEpgBugFixStats(); |