diff options
-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(); |