summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2005-01-02 15:11:44 +0100
committerKlaus Schmidinger <vdr@tvdr.de>2005-01-02 15:11:44 +0100
commit0b3a801ab463186519e9e1c14ea891924c64dff5 (patch)
tree9795fd31fa77a909b5a9cd19ee89a7062d381685
parent286af66cfb787b76ee7289c920a75a3dd21ce795 (diff)
downloadvdr-0b3a801ab463186519e9e1c14ea891924c64dff5.tar.gz
vdr-0b3a801ab463186519e9e1c14ea891924c64dff5.tar.bz2
Implemented audio track menu
-rw-r--r--HISTORY16
-rw-r--r--MANUAL26
-rw-r--r--PLUGINS.html3
-rw-r--r--PLUGINS/src/skincurses/HISTORY3
-rw-r--r--PLUGINS/src/skincurses/skincurses.c70
-rw-r--r--device.c27
-rw-r--r--device.h15
-rw-r--r--dvbdevice.c8
-rw-r--r--eit.c32
-rw-r--r--epg.c165
-rw-r--r--epg.h54
-rw-r--r--i18n.c23
-rw-r--r--keys.c3
-rw-r--r--keys.h3
-rw-r--r--menu.c126
-rw-r--r--menu.h19
-rw-r--r--player.h4
-rw-r--r--skinclassic.c86
-rw-r--r--skinclassic.h3
-rw-r--r--skins.h18
-rw-r--r--skinsttng.c141
-rw-r--r--skinsttng.h3
-rw-r--r--status.c8
-rw-r--r--status.h6
-rw-r--r--transfer.c8
-rw-r--r--vdr.511
-rw-r--r--vdr.c12
27 files changed, 799 insertions, 94 deletions
diff --git a/HISTORY b/HISTORY
index 09f602f3..77ad4447 100644
--- a/HISTORY
+++ b/HISTORY
@@ -3160,7 +3160,7 @@ Video Disk Recorder Revision History
right day of week for timers in the future.
- Some improvements to cPoller (thanks to Marco Schlüßler).
-2004-12-26: Version 1.3.18
+2005-01-02: Version 1.3.18
- Removed an unused variable from cTimer::GetWDayFromMDay() (thanks to Wayne Keer
for reporting this one).
@@ -3251,3 +3251,17 @@ Video Disk Recorder Revision History
Zocholl for pointing out this problem).
- Added cDevice::mutexReceiver to avoid a race condition when attaching/detaching
receivers from different threads.
+- The new remote control button "Audio" can be used to switch between different
+ audio tracks. The "Green" button in the "Main" menu has been changed from "Language"
+ to "Audio", since it now also controls switching between normal and Dolby Digital
+ audio tracks.
+- The description of the audio tracks is now taken from the "component descriptors"
+ that are broadcast in the EPG data. However (as no big surprise), not all channels
+ actually provide useful data here, so there are now some additional EPG bugfixes,
+ which can be activated by setting the "EPG bugfix level" to 3.
+- The format of the 'epg.data' files has been extended by the new tag 'X', which
+ contains the stream components of an event (see man vdr(5) for details).
+- The cStatus class now has the new member function SetAudioTrack(), which can be
+ used to get notified when the audio track has been switched.
+- Skins need to implement the new cSkinDisplayTrack class to display the audio
+ track menu.
diff --git a/MANUAL b/MANUAL
index f5a1814c..4125fe70 100644
--- a/MANUAL
+++ b/MANUAL
@@ -21,7 +21,7 @@ Version 1.2
Menu Menu on Menu off Menu off Menu off Menu off Menu off Menu on
Back - Menu off VDR menu VDR menu Discard VDR menu Recordings menu
Red - Record Edit Edit ABC/abc Play/Commands(2) Jump
- Green - Language New New Ins/Ovr Rewind Skip -60s
+ 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
0..9 Ch select - Sort(3) Day(4) Numeric inp. Exec cmd(2) Editing
@@ -49,6 +49,8 @@ Version 1.2
Volume- volume down
Mute mute
+ Audio select audio track
+
Schedule \
Channels |
Timers | directly access the VDR
@@ -187,15 +189,16 @@ Version 1.2
To bring up the channel display without switching channels you can press
the "Ok" button.
-* Selecting language specific audio track
+* Selecting audio tracks
- If the current channel provides different audio tracks (typically for
- different languages), the "Green" button in the "VDR" menu can be pressed
- to toggle between these. There can be two different audio PIDs per channel,
- assuming that typically a channel broadcasts a country specific language
- plus the movie's original soundtrack.
- Recordings made form such channels will contain both audio tracks, and when
- replaying the desired audio track can be selected the same way.
+ If the current channel or recording provides different audio tracks (for
+ different languages or Dolby Digital), the "Green" button in the "VDR" menu can
+ be pressed to bring up the "Audio" menu. Within this menu, the "Up" and "Down"
+ keys can be used to switch between the audio tracks. If your remote control has
+ a dedicated "Audio" button, the first press of that button brings up the "Audio"
+ menu, and every further press switches to the next available audio track.
+ The "Audio" menu will automatically disappear after 5 seconds of user inactivity,
+ or if any key other than the ones described above is pressed.
* Switching through channel groups
@@ -495,14 +498,15 @@ Version 1.2
A value of '0' completely turns off scanning on both single
and multiple card systems.
- EPG bugfix level = 2 Some tv stations transmit weirdly formatted EPG data.
+ EPG bugfix level = 3 Some tv stations transmit weirdly formatted EPG data.
VDR attempts to fix these bugs up to the given level:
0 = no EPG fixing
1 = basic fixing of text location (Title, Episode and
Extended Description)
2 = removal of excess whitespace and hyphens, mapping of
wrongly used characters
- Default is '2'.
+ 3 = fix stream component descriptions
+ Default is '3'.
Note that after changing the setting of this parameter
any EPG data that has already been received will remain
in its existing format - only newly received data will
diff --git a/PLUGINS.html b/PLUGINS.html
index 878c3670..6897504b 100644
--- a/PLUGINS.html
+++ b/PLUGINS.html
@@ -1362,6 +1362,9 @@ public:
virtual cSkinDisplayMenu *DisplayMenu(void);
virtual cSkinDisplayReplay *DisplayReplay(bool ModeOnly);
virtual cSkinDisplayVolume *DisplayVolume(void);
+<!--X1.3.18--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
+ virtual cSkinDisplayMessage *DisplayTrack(int NumTracks, const char * const *Tracks);
+<!--X1.3.18--></td></tr></table>
virtual cSkinDisplayMessage *DisplayMessage(void);
};
</pre></td></tr></table><p>
diff --git a/PLUGINS/src/skincurses/HISTORY b/PLUGINS/src/skincurses/HISTORY
index 057fb6f8..8ba4ae4e 100644
--- a/PLUGINS/src/skincurses/HISTORY
+++ b/PLUGINS/src/skincurses/HISTORY
@@ -9,6 +9,7 @@ VDR Plugin 'skincurses' Revision History
- Fixed some default parameters.
-2004-12-26: Version 0.0.3
+2005-01-02: Version 0.0.3
- Made several functions threadsafe.
+- New audio track display.
diff --git a/PLUGINS/src/skincurses/skincurses.c b/PLUGINS/src/skincurses/skincurses.c
index eeae1ef0..ee1df052 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.3 2004/12/26 11:36:35 kls Exp $
+ * $Id: skincurses.c 1.4 2005/01/02 15:11:29 kls Exp $
*/
#include <ncurses.h>
@@ -558,6 +558,68 @@ void cSkinCursesDisplayVolume::Flush(void)
osd->Flush();
}
+// --- cSkinCursesDisplayTracks ----------------------------------------------
+
+class cSkinCursesDisplayTracks : public cSkinDisplayTracks {
+private:
+ cOsd *osd;
+ int itemsWidth;
+ int currentIndex;
+ void SetItem(const char *Text, int Index, bool Current);
+public:
+ cSkinCursesDisplayTracks(const char *Title, int NumTracks, const char * const *Tracks);
+ virtual ~cSkinCursesDisplayTracks();
+ virtual void SetTrack(int Index, const char * const *Tracks);
+ virtual void Flush(void);
+ };
+
+cSkinCursesDisplayTracks::cSkinCursesDisplayTracks(const char *Title, int NumTracks, const char * const *Tracks)
+{
+ currentIndex = -1;
+ itemsWidth = Font.Width(Title);
+ for (int i = 0; i < NumTracks; i++)
+ itemsWidth = max(itemsWidth, Font.Width(Tracks[i]));
+ itemsWidth = min(itemsWidth, OsdWidth);
+ osd = new cCursesOsd(0, 0);
+ osd->DrawRectangle(0, 0, OsdWidth - 1, OsdHeight - 1, clrBackground);
+ osd->DrawText(0, 0, Title, clrBlack, clrCyan, &Font, itemsWidth);
+ for (int i = 0; i < NumTracks; i++)
+ SetItem(Tracks[i], i, false);
+}
+
+cSkinCursesDisplayTracks::~cSkinCursesDisplayTracks()
+{
+ delete osd;
+}
+
+void cSkinCursesDisplayTracks::SetItem(const char *Text, int Index, bool Current)
+{
+ int y = 1 + Index;
+ int ColorFg, ColorBg;
+ if (Current) {
+ ColorFg = clrBlack;
+ ColorBg = clrCyan;
+ currentIndex = Index;
+ }
+ else {
+ ColorFg = clrWhite;
+ ColorBg = clrBackground;
+ }
+ osd->DrawText(0, y, Text, ColorFg, ColorBg, &Font, itemsWidth);
+}
+
+void cSkinCursesDisplayTracks::SetTrack(int Index, const char * const *Tracks)
+{
+ if (currentIndex >= 0)
+ SetItem(Tracks[currentIndex], currentIndex, false);
+ SetItem(Tracks[Index], Index, true);
+}
+
+void cSkinCursesDisplayTracks::Flush(void)
+{
+ osd->Flush();
+}
+
// --- cSkinCursesDisplayMessage ---------------------------------------------
class cSkinCursesDisplayMessage : public cSkinDisplayMessage {
@@ -600,6 +662,7 @@ public:
virtual cSkinDisplayMenu *DisplayMenu(void);
virtual cSkinDisplayReplay *DisplayReplay(bool ModeOnly);
virtual cSkinDisplayVolume *DisplayVolume(void);
+ virtual cSkinDisplayTracks *DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks);
virtual cSkinDisplayMessage *DisplayMessage(void);
};
@@ -633,6 +696,11 @@ cSkinDisplayVolume *cSkinCurses::DisplayVolume(void)
return new cSkinCursesDisplayVolume;
}
+cSkinDisplayTracks *cSkinCurses::DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks)
+{
+ return new cSkinCursesDisplayTracks(Title, NumTracks, Tracks);
+}
+
cSkinDisplayMessage *cSkinCurses::DisplayMessage(void)
{
return new cSkinCursesDisplayMessage;
diff --git a/device.c b/device.c
index 2df50dab..20394a59 100644
--- a/device.c
+++ b/device.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: device.c 1.64 2004/12/24 15:37:11 kls Exp $
+ * $Id: device.c 1.65 2005/01/02 14:08:40 kls Exp $
*/
#include "device.h"
@@ -604,15 +604,19 @@ void cDevice::ClrAvailableTracks(void)
memset(availableTracks, 0, sizeof(availableTracks));
}
-bool cDevice::SetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language, uint32_t Flags)
+bool cDevice::SetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language, const char *Description, uint32_t Flags)
{
eTrackType t = eTrackType(Type + Index);
if ((Type == ttAudio && IS_AUDIO_TRACK(t)) ||
(Type == ttDolby && IS_DOLBY_TRACK(t))) {
if (Language)
strn0cpy(availableTracks[t].language, Language, sizeof(availableTracks[t].language));
- availableTracks[t].flags = Flags;
- availableTracks[t].id = Id; // setting 'id' last to avoid the need for extensive locking
+ if (Description)
+ strn0cpy(availableTracks[t].description, Description, sizeof(availableTracks[t].description));
+ if (Id) {
+ availableTracks[t].flags = Flags;
+ availableTracks[t].id = Id; // setting 'id' last to avoid the need for extensive locking
+ }
return true;
}
else
@@ -652,21 +656,6 @@ bool cDevice::SetCurrentAudioTrack(eTrackType Type)
return false;
}
-bool cDevice::IncCurrentAudioTrack(void)
-{
- int i = currentAudioTrack + 1;
- for (;;) {
- if (i > ttDolbyLast)
- i = ttAudioFirst;
- if (i == currentAudioTrack)
- break;
- if (availableTracks[i].id)
- return SetCurrentAudioTrack(eTrackType(i));
- i++;
- }
- return false;
-}
-
bool cDevice::CanReplay(void) const
{
return HasDecoder();
diff --git a/device.h b/device.h
index 2c147986..54e36bd2 100644
--- a/device.h
+++ b/device.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: device.h 1.48 2004/12/24 14:57:24 kls Exp $
+ * $Id: device.h 1.49 2005/01/02 14:08:36 kls Exp $
*/
#ifndef __DEVICE_H
@@ -75,8 +75,9 @@ enum eTrackType { ttNone,
#define IS_DOLBY_TRACK(t) (ttDolbyFirst <= (t) && (t) <= ttDolbyLast)
struct tTrackId {
- uint16_t id; // The PES packet id or the PID.
- char language[8]; // something like either "eng" or "deu/eng"
+ uint16_t id; // The PES packet id or the PID.
+ char language[8]; // something like either "eng" or "deu/eng"
+ char description[32]; // something like "Dolby Digital 5.1"
// for future use:
uint32_t flags; // Used to further identify the actual track.
};
@@ -319,10 +320,12 @@ protected:
///< Sets the current audio track to the given value.
public:
void ClrAvailableTracks(void);
- bool SetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language = NULL, uint32_t Flags = 0);
+ bool SetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language = NULL, const char *Description = NULL, uint32_t Flags = 0);
///< Sets the track of the given Type and Index to the given values.
///< Type must be one of the basic eTrackType values, like ttAudio or ttDolby.
///< Index tells which track of the given basic type is meant.
+ ///< If Id is 0 any existing id (and flags) will be left untouched and only the
+ ///< given Language and Description will be set.
///< \return Returns true if the track was set correctly, false otherwise.
const tTrackId *GetTrack(eTrackType Type);
///< Returns a pointer to the given track id, or NULL if Type is not
@@ -335,10 +338,6 @@ public:
bool SetCurrentAudioTrack(eTrackType Type);
///< Sets the current audio track to the given Type.
///< \return Returns true if Type is a valid audio track, false otherwise.
- bool IncCurrentAudioTrack(void);
- ///< Sets the current audio track to the next available track (wraps to
- ///< to the first one if necessary).
- ///< \return Returns true if the audio track has been changed, false otherwise.
// Audio facilities
diff --git a/dvbdevice.c b/dvbdevice.c
index ed3a710e..7264d86f 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.107 2004/12/17 14:19:48 kls Exp $
+ * $Id: dvbdevice.c 1.108 2005/01/02 11:51:18 kls Exp $
*/
#include "dvbdevice.h"
@@ -860,10 +860,8 @@ void cDvbDevice::SetAudioTrackDevice(eTrackType Type)
else if (IS_DOLBY_TRACK(Type)) {
// Currently this works only in Transfer Mode
cChannel *Channel = Channels.GetByNumber(CurrentChannel());
- if (Channel) {
- SetChannelDevice(Channel, false);
- cControl::Launch(new cTransferControl(this, Channel->Vpid(), Channel->Apid(0), Channel->Apid(1), Channel->Dpid(0), Channel->Dpid(1)));
- }
+ if (Channel)
+ SetChannelDevice(Channel, false); // this implicitly starts Transfer Mode
}
}
}
diff --git a/eit.c b/eit.c
index 3d324561..a7d60c49 100644
--- a/eit.c
+++ b/eit.c
@@ -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.101 2004/12/26 10:38:46 kls Exp $
+ * $Id: eit.c 1.102 2005/01/02 11:52:12 kls Exp $
*/
#include "eit.h"
@@ -91,6 +91,8 @@ 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];
for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext(it2)); ) {
switch (d->getDescriptorTag()) {
case SI::ExtendedEventDescriptorTag: {
@@ -186,6 +188,20 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data)
}
}
break;
+ case SI::ComponentDescriptorTag: {
+ SI::ComponentDescriptor *cd = (SI::ComponentDescriptor *)d;
+ 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);
+ }
+ }
+ break;
default: ;
}
delete d;
@@ -205,8 +221,20 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data)
delete ExtendedEventDescriptors;
delete ShortEventDescriptor;
- pEvent->FixEpgBugs();
+ 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);
+ pEvent->FixEpgBugs();
if (LinkChannels)
channel->SetLinkChannels(LinkChannels);
if (Tid == 0x4E) { // we trust only the present/following info on the actual TS
diff --git a/epg.c b/epg.c
index 2ea199c2..5539ab04 100644
--- a/epg.c
+++ b/epg.c
@@ -7,7 +7,7 @@
* Original version (as used in VDR before 1.3.0) written by
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
*
- * $Id: epg.c 1.23 2004/12/26 11:32:01 kls Exp $
+ * $Id: epg.c 1.24 2005/01/02 11:25:25 kls Exp $
*/
#include "epg.h"
@@ -16,6 +16,66 @@
#include <ctype.h>
#include <time.h>
+// --- tComponent ------------------------------------------------------------
+
+cString tComponent::ToString(void)
+{
+ char buffer[256];
+ snprintf(buffer, sizeof(buffer), "%X %02X %-3s %s", stream, type, language, description ? description : "");
+ return buffer;
+}
+
+bool tComponent::FromString(const char *s)
+{
+ unsigned int Stream, Type;
+ int n = sscanf(s, "%X %02X %3c %a[^\n]", &Stream, &Type, language, &description);
+ if (n != 4)
+ description = NULL;
+ else if (isempty(description)) {
+ free(description);
+ description = NULL;
+ }
+ stream = Stream;
+ type = Type;
+ return n >= 3;
+}
+
+// --- cComponents -----------------------------------------------------------
+
+cComponents::cComponents(int NumComponents)
+{
+ numComponents = NumComponents;
+ components = MALLOC(tComponent, numComponents);
+ memset(components, 0, sizeof(tComponent) * numComponents);
+}
+
+cComponents::~cComponents(void)
+{
+ for (int i = 0; i < numComponents; i++)
+ free(components[i].description);
+ free(components);
+}
+
+bool cComponents::SetComponent(int Index, const char *s)
+{
+ if (Index < numComponents)
+ return components[Index].FromString(s);
+ return false;
+}
+
+bool cComponents::SetComponent(int Index, uchar Stream, uchar Type, const char *Language, const char *Description)
+{
+ 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;
+}
+
// --- cEvent ----------------------------------------------------------------
cEvent::cEvent(tChannelID ChannelID, u_int16_t EventID)
@@ -28,6 +88,7 @@ cEvent::cEvent(tChannelID ChannelID, u_int16_t EventID)
title = NULL;
shortText = NULL;
description = NULL;
+ components = NULL;
startTime = 0;
duration = 0;
vps = 0;
@@ -39,6 +100,7 @@ cEvent::~cEvent()
free(title);
free(shortText);
free(description);
+ delete components;
}
int cEvent::Compare(const cListObject &ListObject) const
@@ -85,6 +147,12 @@ void cEvent::SetDescription(const char *Description)
description = strcpyrealloc(description, Description);
}
+void cEvent::SetComponents(cComponents *Components)
+{
+ delete components;
+ components = Components;
+}
+
void cEvent::SetStartTime(time_t StartTime)
{
startTime = StartTime;
@@ -168,6 +236,12 @@ void cEvent::Dump(FILE *f, const char *Prefix) const
fprintf(f, "%sD %s\n", Prefix, description);
strreplace(description, '|', '\n');
}
+ if (components) {
+ for (int i = 0; i < components->NumComponents(); i++) {
+ tComponent *p = components->Component(i);
+ fprintf(f, "%sX %s\n", Prefix, *p->ToString());
+ }
+ }
if (vps)
fprintf(f, "%sV %ld\n", Prefix, vps);
fprintf(f, "%se\n", Prefix);
@@ -178,6 +252,8 @@ 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) {
@@ -199,6 +275,7 @@ bool cEvent::Read(FILE *f, cSchedule *Schedule)
Event->SetDuration(Duration);
}
}
+ NumComponents = 0;
}
break;
case 'T': if (Event)
@@ -212,10 +289,26 @@ bool cEvent::Read(FILE *f, cSchedule *Schedule)
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': Event = NULL;
+ 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;
break;
case 'c': // to keep things simple we react on 'c' here
return true;
@@ -228,7 +321,7 @@ bool cEvent::Read(FILE *f, cSchedule *Schedule)
return false;
}
-#define MAXEPGBUGFIXSTATS 8
+#define MAXEPGBUGFIXSTATS 12
#define MAXEPGBUGFIXCHANS 100
struct tEpgBugFixStats {
int hits;
@@ -476,6 +569,72 @@ void cEvent::FixEpgBugs(void)
strreplace(title, '`', '\'');
strreplace(shortText, '`', '\'');
strreplace(description, '`', '\'');
+
+ if (Setup.EPGBugfixLevel <= 2)
+ return;
+
+ // The stream components have a "description" field which some channels
+ // apparently have no idea of how to set correctly:
+ if (components) {
+ for (int i = 0; i < components->NumComponents(); i++) {
+ tComponent *p = components->Component(i);
+ switch (p->stream) {
+ case 0x01: { // video
+ if (p->description) {
+ if (strcasecmp(p->description, "Video") == 0 ||
+ strcasecmp(p->description, "Bildformat") == 0) {
+ // Yes, we know it's video - that's what the 'stream' code
+ // is for! But _which_ video is it?
+ free(p->description);
+ p->description = NULL;
+ EpgBugFixStat(8, ChannelID());
+ }
+ }
+ if (!p->description) {
+ switch (p->type) {
+ case 0x01:
+ case 0x05: p->description = strdup("4:3"); break;
+ case 0x02:
+ case 0x03:
+ case 0x06:
+ case 0x07: p->description = strdup("16:9"); break;
+ case 0x04:
+ case 0x08: p->description = strdup(">16:9"); break;
+ case 0x09:
+ case 0x0D: p->description = strdup("HD 4:3"); break;
+ case 0x0A:
+ case 0x0B:
+ case 0x0E:
+ case 0x0F: p->description = strdup("HD 16:9"); break;
+ case 0x0C:
+ case 0x10: p->description = strdup("HD >16:9"); break;
+ }
+ EpgBugFixStat(9, ChannelID());
+ }
+ }
+ break;
+ case 0x02: { // audio
+ if (p->description) {
+ if (strcasecmp(p->description, "Audio") == 0) {
+ // Yes, we know it's audio - that's what the 'stream' code
+ // is for! But _which_ audio is it?
+ free(p->description);
+ p->description = NULL;
+ EpgBugFixStat(10, ChannelID());
+ }
+ }
+ if (!p->description) {
+ switch (p->type) {
+ case 0x05: p->description = strdup("Dolby Digital"); break;
+ // all others will just display the language
+ }
+ EpgBugFixStat(11, ChannelID());
+ }
+ }
+ break;
+ }
+ }
+ }
}
}
diff --git a/epg.h b/epg.h
index 0668c49c..88e66029 100644
--- a/epg.h
+++ b/epg.h
@@ -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.18 2004/12/26 11:31:27 kls Exp $
+ * $Id: epg.h 1.19 2005/01/02 10:44:41 kls Exp $
*/
#ifndef __EPG_H
@@ -17,26 +17,50 @@
#include "thread.h"
#include "tools.h"
-#define MAXEPGBUGFIXLEVEL 2
+#define MAXEPGBUGFIXLEVEL 3
+#define MAXCOMPONENTS 32
enum eDumpMode { dmAll, dmPresent, dmFollowing, dmAtTime };
+struct tComponent {
+ uchar stream;
+ uchar type;
+ char language[4];
+ char *description;
+ cString ToString(void);
+ bool FromString(const char *s);
+ };
+
+class cComponents {
+private:
+ int numComponents;
+ tComponent *components;
+public:
+ cComponents(int NumComponents);
+ ~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);
+ tComponent *Component(int Index) const { return (Index < numComponents) ? &components[Index] : NULL; }
+ };
+
class cSchedule;
class cEvent : public cListObject {
private:
- tChannelID channelID; // Channel ID of program for this event
- 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
- int runningStatus; // 0=undefined, 1=not running, 2=starts in a few seconds, 3=pausing, 4=running
- 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
- 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
+ tChannelID channelID; // Channel ID of program for this event
+ 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
+ int runningStatus; // 0=undefined, 1=not running, 2=starts in a few seconds, 3=pausing, 4=running
+ 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')
+ 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();
@@ -49,6 +73,7 @@ public:
const char *Title(void) const { return title; }
const char *ShortText(void) const { return shortText; }
const char *Description(void) const { return description; }
+ const cComponents *Components(void) const { return components; }
time_t StartTime(void) const { return startTime; }
time_t EndTime(void) const { return startTime + duration; }
int Duration(void) const { return duration; }
@@ -67,6 +92,7 @@ public:
void SetTitle(const char *Title);
void SetShortText(const char *ShortText);
void SetDescription(const char *Description);
+ void SetComponents(cComponents *Components); // Will take ownership of Components!
void SetStartTime(time_t StartTime);
void SetDuration(int Duration);
void SetVps(time_t Vps);
diff --git a/i18n.c b/i18n.c
index 345ee348..8c5c0cb4 100644
--- a/i18n.c
+++ b/i18n.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: i18n.c 1.166 2004/12/18 16:44:24 kls Exp $
+ * $Id: i18n.c 1.167 2004/12/27 11:10:42 kls Exp $
*
* Translations provided by:
*
@@ -4610,6 +4610,27 @@ const tI18nPhrase Phrases[] = {
"Hääletu",
"Sluk lyd",
},
+ { "Audio",
+ "Audio",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ },
// Miscellaneous:
{ "yes",
"ja",
diff --git a/keys.c b/keys.c
index aaeee97e..8a8a104e 100644
--- a/keys.c
+++ b/keys.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: keys.c 1.6 2004/12/19 11:25:47 kls Exp $
+ * $Id: keys.c 1.7 2004/12/27 11:08:34 kls Exp $
*/
#include "keys.h"
@@ -44,6 +44,7 @@ static tKey keyTable[] = { // "Up" and "Down" must be the first two keys!
{ kVolUp, "Volume+" },
{ kVolDn, "Volume-" },
{ kMute, "Mute" },
+ { kAudio, "Audio" },
{ kSchedule, "Schedule" },
{ kChannels, "Channels" },
{ kTimers, "Timers" },
diff --git a/keys.h b/keys.h
index eb4b5b34..09b2c8be 100644
--- a/keys.h
+++ b/keys.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: keys.h 1.5 2002/12/14 15:49:42 kls Exp $
+ * $Id: keys.h 1.6 2004/12/27 11:10:59 kls Exp $
*/
#ifndef __KEYS_H
@@ -38,6 +38,7 @@ enum eKeys { // "Up" and "Down" must be the first two keys!
kVolUp,
kVolDn,
kMute,
+ kAudio,
kSchedule,
kChannels,
kTimers,
diff --git a/menu.c b/menu.c
index 0c9aaf65..8815b92c 100644
--- a/menu.c
+++ b/menu.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.c 1.323 2004/12/26 12:18:29 kls Exp $
+ * $Id: menu.c 1.324 2005/01/02 15:03:53 kls Exp $
*/
#include "menu.h"
@@ -2410,7 +2410,7 @@ void cMenuMain::Set(const char *Plugin)
// Color buttons:
- SetHelp(!replaying ? tr("Record") : NULL, cDevice::PrimaryDevice()->NumAudioTracks() > 1 ? tr("Language") : NULL, replaying ? NULL : tr("Pause"), replaying ? tr("Button$Stop") : cReplayControl::LastReplayed() ? tr("Resume") : NULL);
+ SetHelp(!replaying ? tr("Record") : NULL, cDevice::PrimaryDevice()->NumAudioTracks() > 1 ? tr("Audio") : NULL, replaying ? NULL : tr("Pause"), replaying ? tr("Button$Stop") : cReplayControl::LastReplayed() ? tr("Resume") : NULL);
Display();
lastActivity = time(NULL);
}
@@ -2471,8 +2471,10 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
state = replaying ? osContinue : osRecord;
break;
case kGreen: if (!HadSubMenu) {
- cDevice::PrimaryDevice()->IncCurrentAudioTrack();
- state = osEnd;
+ if (cDevice::PrimaryDevice()->NumAudioTracks() > 1) {
+ cRemote::Put(kAudio, true);
+ state = osEnd;
+ }
}
break;
case kYellow: if (!HadSubMenu)
@@ -2764,6 +2766,122 @@ eOSState cDisplayVolume::ProcessKey(eKeys Key)
return timeout.TimedOut() ? osEnd : osContinue;
}
+// --- cDisplayTracks --------------------------------------------------------
+
+#define TRACKTIMEOUT 5000 //ms
+
+cDisplayTracks *cDisplayTracks::currentDisplayTracks = NULL;
+
+cDisplayTracks::cDisplayTracks(void)
+:cOsdObject(true)
+{
+ // Get the actual audio track descriptions from the EPG if we're not replaying:
+ if (!cDevice::PrimaryDevice()->Replaying() || cTransferControl::ReceiverDevice()) {
+ 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);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ currentDisplayTracks = this;
+ numTracks = track = 0;
+ eTrackType CurrentAudioTrack = cDevice::PrimaryDevice()->GetCurrentAudioTrack();
+ for (int i = ttAudioFirst; i <= ttDolbyLast; i++) {
+ const tTrackId *TrackId = cDevice::PrimaryDevice()->GetTrack(eTrackType(i));
+ if (TrackId && TrackId->id) {
+ types[numTracks] = eTrackType(i);
+ descriptions[numTracks] = strdup(*TrackId->description ? TrackId->description : *TrackId->language ? TrackId->language : itoa(i));
+ if (i == CurrentAudioTrack)
+ track = numTracks;
+ numTracks++;
+ }
+ }
+ timeout.Set(TRACKTIMEOUT);
+ displayTracks = Skins.Current()->DisplayTracks(tr("Audio"), numTracks, descriptions);
+ Show();
+}
+
+cDisplayTracks::~cDisplayTracks()
+{
+ delete displayTracks;
+ currentDisplayTracks = NULL;
+ for (int i = 0; i < numTracks; i++)
+ free(descriptions[i]);
+ cStatus::MsgOsdClear();
+}
+
+void cDisplayTracks::Show(void)
+{
+ displayTracks->SetTrack(track, descriptions);
+ displayTracks->Flush();
+ cStatus::MsgSetAudioTrack(track, descriptions);
+}
+
+cDisplayTracks *cDisplayTracks::Create(void)
+{
+ if (!currentDisplayTracks)
+ new cDisplayTracks;
+ return currentDisplayTracks;
+}
+
+void cDisplayTracks::Process(eKeys Key)
+{
+ if (currentDisplayTracks)
+ currentDisplayTracks->ProcessKey(Key);
+}
+
+eOSState cDisplayTracks::ProcessKey(eKeys Key)
+{
+ int oldTrack = track;
+ switch (Key) {
+ case kUp|k_Repeat:
+ case kUp:
+ case kDown|k_Repeat:
+ case kDown:
+ if (NORMALKEY(Key) == kUp && track > 0)
+ track--;
+ else if (NORMALKEY(Key) == kDown && track < numTracks - 1)
+ track++;
+ timeout.Set(TRACKTIMEOUT);
+ break;
+ case kAudio:
+ if (++track >= numTracks)
+ track = 0;
+ timeout.Set(TRACKTIMEOUT);
+ break;
+ case kNone: break;
+ default: return osEnd;
+ }
+ if (track != oldTrack) {
+ Show();
+ cDevice::PrimaryDevice()->SetCurrentAudioTrack(types[track]);
+ }
+ return timeout.TimedOut() ? osEnd : osContinue;
+}
+
// --- cRecordControl --------------------------------------------------------
cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause)
diff --git a/menu.h b/menu.h
index 3b841363..08781800 100644
--- a/menu.h
+++ b/menu.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.h 1.65 2004/12/19 17:59:47 kls Exp $
+ * $Id: menu.h 1.66 2005/01/02 14:38:00 kls Exp $
*/
#ifndef __MENU_H
@@ -75,6 +75,23 @@ public:
eOSState ProcessKey(eKeys Key);
};
+class cDisplayTracks : public cOsdObject {
+private:
+ cSkinDisplayTracks *displayTracks;
+ cTimeMs timeout;
+ eTrackType types[ttMaxTrackTypes];
+ char *descriptions[ttMaxTrackTypes];
+ int numTracks, track;
+ static cDisplayTracks *currentDisplayTracks;
+ virtual void Show(void);
+ cDisplayTracks(void);
+public:
+ virtual ~cDisplayTracks();
+ static cDisplayTracks *Create(void);
+ static void Process(eKeys Key);
+ eOSState ProcessKey(eKeys Key);
+ };
+
class cMenuCam : public cOsdMenu {
private:
cCiMenu *ciMenu;
diff --git a/player.h b/player.h
index 4ef675b7..0f73d9b0 100644
--- a/player.h
+++ b/player.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: player.h 1.13 2004/12/12 11:20:19 kls Exp $
+ * $Id: player.h 1.14 2004/12/30 10:44:34 kls Exp $
*/
#ifndef __PLAYER_H
@@ -19,7 +19,7 @@ private:
cDevice *device;
ePlayMode playMode;
protected:
- bool DeviceSetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language = NULL, uint32_t Flags = 0) { return device ? device->SetAvailableTrack(Type, Index, Id, Language, Flags) : false; }
+ bool DeviceSetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language = NULL, const char *Description = NULL, uint32_t Flags = 0) { return device ? device->SetAvailableTrack(Type, Index, Id, Language, Description, Flags) : false; }
bool DevicePoll(cPoller &Poller, int TimeoutMs = 0) { return device ? device->Poll(Poller, TimeoutMs) : false; }
bool DeviceFlush(int TimeoutMs = 0) { return device ? device->Flush(TimeoutMs) : true; }
void DeviceTrickSpeed(int Speed) { if (device) device->TrickSpeed(Speed); }
diff --git a/skinclassic.c b/skinclassic.c
index 1a14f21a..b184bc5d 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.9 2004/12/26 11:33:53 kls Exp $
+ * $Id: skinclassic.c 1.10 2005/01/02 14:41:08 kls Exp $
*/
#include "skinclassic.h"
@@ -502,6 +502,84 @@ void cSkinClassicDisplayVolume::Flush(void)
osd->Flush();
}
+// --- cSkinClassicDisplayTracks ---------------------------------------------
+
+class cSkinClassicDisplayTracks : public cSkinDisplayTracks {
+private:
+ cOsd *osd;
+ int x0, x1;
+ int y0, y1, y2;
+ int lineHeight;
+ int currentIndex;
+ void SetItem(const char *Text, int Index, bool Current);
+public:
+ cSkinClassicDisplayTracks(const char *Title, int NumTracks, const char * const *Tracks);
+ virtual ~cSkinClassicDisplayTracks();
+ virtual void SetTrack(int Index, const char * const *Tracks);
+ virtual void Flush(void);
+ };
+
+cSkinClassicDisplayTracks::cSkinClassicDisplayTracks(const char *Title, int NumTracks, const char * const *Tracks)
+{
+ const cFont *font = cFont::GetFont(fontOsd);
+ lineHeight = font->Height();
+ currentIndex = -1;
+ int ItemsWidth = font->Width(Title);
+ for (int i = 0; i < NumTracks; i++)
+ ItemsWidth = max(ItemsWidth, font->Width(Tracks[i]));
+ ItemsWidth += 10;
+ x0 = 0;
+ x1 = Setup.OSDWidth;
+ int d = x1 - x0;
+ if (d > ItemsWidth) {
+ d = (d - ItemsWidth) & ~0x07; // must be multiple of 8
+ x1 -= d;
+ }
+ y0 = 0;
+ y1 = lineHeight;
+ y2 = y1 + NumTracks * lineHeight;
+ osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - y2);
+ tArea Areas[] = { { x0, y0, x1 - 1, y2 - 1, 4 } };
+ osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+ osd->DrawText(x0, y0, Title, Theme.Color(clrMenuTitleFg), Theme.Color(clrMenuTitleBg), font, x1 - x0);
+ for (int i = 0; i < NumTracks; i++)
+ SetItem(Tracks[i], i, false);
+}
+
+cSkinClassicDisplayTracks::~cSkinClassicDisplayTracks()
+{
+ delete osd;
+}
+
+void cSkinClassicDisplayTracks::SetItem(const char *Text, int Index, bool Current)
+{
+ int y = y1 + Index * lineHeight;
+ tColor ColorFg, ColorBg;
+ if (Current) {
+ ColorFg = Theme.Color(clrMenuItemCurrentFg);
+ ColorBg = Theme.Color(clrMenuItemCurrentBg);
+ currentIndex = Index;
+ }
+ else {
+ ColorFg = Theme.Color(clrMenuItemSelectable);
+ ColorBg = Theme.Color(clrBackground);
+ }
+ const cFont *font = cFont::GetFont(fontOsd);
+ osd->DrawText(x0, y, Text, ColorFg, ColorBg, font, x1 - x0);
+}
+
+void cSkinClassicDisplayTracks::SetTrack(int Index, const char * const *Tracks)
+{
+ if (currentIndex >= 0)
+ SetItem(Tracks[currentIndex], currentIndex, false);
+ SetItem(Tracks[Index], Index, true);
+}
+
+void cSkinClassicDisplayTracks::Flush(void)
+{
+ osd->Flush();
+}
+
// --- cSkinClassicDisplayMessage --------------------------------------------
class cSkinClassicDisplayMessage : public cSkinDisplayMessage {
@@ -571,6 +649,12 @@ cSkinDisplayVolume *cSkinClassic::DisplayVolume(void)
return new cSkinClassicDisplayVolume;
}
+
+cSkinDisplayTracks *cSkinClassic::DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks)
+{
+ return new cSkinClassicDisplayTracks(Title, NumTracks, Tracks);
+}
+
cSkinDisplayMessage *cSkinClassic::DisplayMessage(void)
{
return new cSkinClassicDisplayMessage;
diff --git a/skinclassic.h b/skinclassic.h
index e990b588..2ac69b1b 100644
--- a/skinclassic.h
+++ b/skinclassic.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: skinclassic.h 1.1 2004/04/18 09:38:02 kls Exp $
+ * $Id: skinclassic.h 1.2 2005/01/02 14:38:56 kls Exp $
*/
#ifndef __SKINCLASSIC_H
@@ -20,6 +20,7 @@ public:
virtual cSkinDisplayMenu *DisplayMenu(void);
virtual cSkinDisplayReplay *DisplayReplay(bool ModeOnly);
virtual cSkinDisplayVolume *DisplayVolume(void);
+ virtual cSkinDisplayTracks *DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks);
virtual cSkinDisplayMessage *DisplayMessage(void);
};
diff --git a/skins.h b/skins.h
index c20dece0..618fd61f 100644
--- a/skins.h
+++ b/skins.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: skins.h 1.4 2004/12/26 11:57:54 kls Exp $
+ * $Id: skins.h 1.5 2005/01/02 14:36:19 kls Exp $
*/
#ifndef __SKINS_H
@@ -66,8 +66,6 @@ public:
Red = Video options
Green = Info now
Yellow = Info next
- Blue = Audio options
- AudioOptions
VideoOptions
*/
};
@@ -223,6 +221,14 @@ public:
///< indicator shall be displayed.
};
+class cSkinDisplayTracks : public cSkinDisplay {
+ ///< This class implements the track display.
+public:
+ virtual void SetTrack(int Index, const char * const *Tracks) = 0;
+ ///< Sets the current track to the one given by Index, which
+ ///< points into the Tracks array of strings.
+ };
+
class cSkinDisplayMessage : public cSkinDisplay {
///< This class implements a simple message display.
public:
@@ -275,6 +281,12 @@ public:
virtual cSkinDisplayVolume *DisplayVolume(void) = 0;
///< Creates and returns a new object for displaying the current volume.
///< The caller must delete the object after use.
+ virtual cSkinDisplayTracks *DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks) = 0;
+ ///< Creates and returns a new object for displaying the available tracks.
+ ///< NumTracks indicates how many entries in Tracks are available.
+ ///< Tracks will be valid throughout the entire lifetime of the returned
+ ///< cSkinDisplayTrack object.
+ ///< The caller must delete the object after use.
virtual cSkinDisplayMessage *DisplayMessage(void) = 0;
///< Creates and returns a new object for displaying a message.
///< The caller must delete the object after use.
diff --git a/skinsttng.c b/skinsttng.c
index 844cd29f..8ae0180a 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.9 2004/12/26 11:34:29 kls Exp $
+ * $Id: skinsttng.c 1.10 2005/01/02 14:41:49 kls Exp $
*/
// Star Trek: The Next Generation® is a registered trademark of Paramount Pictures
@@ -822,6 +822,140 @@ void cSkinSTTNGDisplayVolume::Flush(void)
osd->Flush();
}
+// --- cSkinSTTNGDisplayTracks -----------------------------------------------
+
+class cSkinSTTNGDisplayTracks : public cSkinDisplayTracks {
+private:
+ cOsd *osd;
+ int x0, x1, x2, x3, x4, x5, x6, x7;
+ int y0, y1, y2, y3, y4, y5, y6, y7;
+ int lineHeight;
+ tColor frameColor;
+ int currentIndex;
+ void SetItem(const char *Text, int Index, bool Current);
+public:
+ cSkinSTTNGDisplayTracks(const char *Title, int NumTracks, const char * const *Tracks);
+ virtual ~cSkinSTTNGDisplayTracks();
+ virtual void SetTrack(int Index, const char * const *Tracks);
+ virtual void Flush(void);
+ };
+
+cSkinSTTNGDisplayTracks::cSkinSTTNGDisplayTracks(const char *Title, int NumTracks, const char * const *Tracks)
+{
+ const cFont *font = cFont::GetFont(fontOsd);
+ lineHeight = font->Height();
+ frameColor = Theme.Color(clrMenuFrame);
+ currentIndex = -1;
+ int ItemsWidth = font->Width(Title);
+ for (int i = 0; i < NumTracks; i++)
+ ItemsWidth = max(ItemsWidth, font->Width(Tracks[i]));
+ ItemsWidth += 10;
+ x0 = 0;
+ x1 = lineHeight / 2;
+ x3 = (x1 + Roundness + Gap + 7) & ~0x07; // must be multiple of 8
+ x2 = x3 - Gap;
+ x7 = Setup.OSDWidth;
+ x6 = x7 - lineHeight / 2;
+ x4 = (x6 - lineHeight / 2 - Gap) & ~0x07; // must be multiple of 8
+ x5 = x4 + Gap;
+ int d = x4 - x3;
+ if (d > ItemsWidth) {
+ d = (d - ItemsWidth) & ~0x07; // must be multiple of 8
+ x4 -= d;
+ x5 -= d;
+ x6 -= d;
+ x7 -= d;
+ }
+ y0 = 0;
+ y1 = lineHeight;
+ y2 = y1 + Roundness;
+ y3 = y2 + Gap;
+ // limit to Setup.OSDHeight? - what if height is too big???
+ y4 = y3 + NumTracks * lineHeight + 2 * Roundness;
+ y5 = y4 + Gap;
+ y6 = y5 + Roundness;
+ y7 = y6 + cFont::GetFont(fontSml)->Height();
+ int yt = (y0 + y1) / 2;
+ int yb = (y6 + y7) / 2;
+ osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop + Setup.OSDHeight - y7);
+ tArea Areas[] = { { x0, y0, x7 - 1, y7 - 1, 4 } };
+ if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) == oeOk)
+ osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+ else {
+ tArea Areas[] = { { x0, y0, x7 - 1, y3 - 1, 2 },
+ { x0, y3, x3 - 1, y4 - 1, 1 },
+ { x3, y3, x4 - 1, y4 - 1, 2 },
+ { x4, y3, x7 - 1, y4 - 1, 2 },
+ { x0, y4, x7 - 1, y7 - 1, 4 }
+ };
+ osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+ }
+ osd->DrawRectangle(x0, y0, x7 - 1, y7 - 1, Theme.Color(clrBackground));
+ osd->DrawRectangle(x0, y0, x1 - 1, y1 - 1, clrTransparent);
+ osd->DrawRectangle(x0, y6, x1 - 1, y7 - 1, clrTransparent);
+ osd->DrawRectangle(x6, y0, x7 - 1, yt - 1, clrTransparent);
+ osd->DrawRectangle(x6, yb, x7 - 1, y7 - 1, clrTransparent);
+ osd->DrawEllipse (x0, y0, x1 - 1, y1 - 1, frameColor, 2);
+ osd->DrawRectangle(x1, y0, x2 - 1, y1 - 1, frameColor);
+ osd->DrawRectangle(x3, y0, x4 - 1, y1 - 1, frameColor);
+ osd->DrawRectangle(x5, y0, x6 - 1, y1 - 1, frameColor);
+ osd->DrawEllipse (x6, y0, x7 - 1, y1 - 1, frameColor, 5);
+ osd->DrawRectangle(x0, y1, x1 - 1, y6 - 1, frameColor);
+ osd->DrawEllipse (x1, y1, x2 - 1, y2 - 1, frameColor, -2);
+ osd->DrawEllipse (x1, y5, x2 - 1, y6 - 1, frameColor, -3);
+ osd->DrawEllipse (x0, y6, x1 - 1, y7 - 1, frameColor, 3);
+ osd->DrawRectangle(x1, y6, x2 - 1, y7 - 1, frameColor);
+ osd->DrawRectangle(x3, y6, x4 - 1, y7 - 1, frameColor);
+ osd->DrawRectangle(x5, y6, x6 - 1, y7 - 1, frameColor);
+ osd->DrawEllipse (x6, y6, x7 - 1, y7 - 1, frameColor, 5);
+ osd->DrawText(x3 + 5, y0, Title, Theme.Color(clrMenuTitle), frameColor, font, x4 - x3 - 5);
+ for (int i = 0; i < NumTracks; i++)
+ SetItem(Tracks[i], i, false);
+}
+
+cSkinSTTNGDisplayTracks::~cSkinSTTNGDisplayTracks()
+{
+ delete osd;
+}
+
+void cSkinSTTNGDisplayTracks::SetItem(const char *Text, int Index, bool Current)
+{
+ int y = y3 + Roundness + Index * lineHeight;
+ tColor ColorFg, ColorBg;
+ if (Current) {
+ ColorFg = Theme.Color(clrMenuItemCurrentFg);
+ ColorBg = Theme.Color(clrMenuItemCurrentBg);
+ osd->DrawEllipse (x1, y - Roundness, x2 - 1, y - 1, frameColor, -3);
+ osd->DrawRectangle(x1, y, x2 - 1, y + lineHeight - 1, frameColor);
+ osd->DrawEllipse (x1, y + lineHeight, x2 - 1, y + lineHeight + Roundness - 1, frameColor, -2);
+ osd->DrawRectangle(x3, y, x4 - 1, y + lineHeight - 1, ColorBg);
+ currentIndex = Index;
+ }
+ else {
+ ColorFg = Theme.Color(clrMenuItemSelectable);
+ ColorBg = Theme.Color(clrBackground);
+ if (currentIndex == Index) {
+ osd->DrawRectangle(x1, y - Roundness, x2 - 1, y + lineHeight + Roundness - 1, Theme.Color(clrBackground));
+ osd->DrawRectangle(x3, y, x4 - 1, y + lineHeight - 1, Theme.Color(clrBackground));
+ }
+ }
+ const cFont *font = cFont::GetFont(fontOsd);
+ int xt = x3 + 5;
+ osd->DrawText(xt, y, Text, ColorFg, ColorBg, font, x4 - xt);
+}
+
+void cSkinSTTNGDisplayTracks::SetTrack(int Index, const char * const *Tracks)
+{
+ if (currentIndex >= 0)
+ SetItem(Tracks[currentIndex], currentIndex, false);
+ SetItem(Tracks[Index], Index, true);
+}
+
+void cSkinSTTNGDisplayTracks::Flush(void)
+{
+ osd->Flush();
+}
+
// --- cSkinSTTNGDisplayMessage ----------------------------------------------
class cSkinSTTNGDisplayMessage : public cSkinDisplayMessage {
@@ -909,6 +1043,11 @@ cSkinDisplayVolume *cSkinSTTNG::DisplayVolume(void)
return new cSkinSTTNGDisplayVolume;
}
+cSkinDisplayTracks *cSkinSTTNG::DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks)
+{
+ return new cSkinSTTNGDisplayTracks(Title, NumTracks, Tracks);
+}
+
cSkinDisplayMessage *cSkinSTTNG::DisplayMessage(void)
{
return new cSkinSTTNGDisplayMessage;
diff --git a/skinsttng.h b/skinsttng.h
index 82b25995..11a96422 100644
--- a/skinsttng.h
+++ b/skinsttng.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: skinsttng.h 1.1 2004/04/18 09:38:47 kls Exp $
+ * $Id: skinsttng.h 1.2 2005/01/02 14:39:29 kls Exp $
*/
#ifndef __SKINSTTNG_H
@@ -20,6 +20,7 @@ public:
virtual cSkinDisplayMenu *DisplayMenu(void);
virtual cSkinDisplayReplay *DisplayReplay(bool ModeOnly);
virtual cSkinDisplayVolume *DisplayVolume(void);
+ virtual cSkinDisplayTracks *DisplayTracks(const char *Title, int NumTracks, const char * const *Tracks);
virtual cSkinDisplayMessage *DisplayMessage(void);
};
diff --git a/status.c b/status.c
index 3dbe8543..a39c7acb 100644
--- a/status.c
+++ b/status.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: status.c 1.5 2003/05/03 14:47:44 kls Exp $
+ * $Id: status.c 1.6 2005/01/02 12:09:12 kls Exp $
*/
#include "status.h"
@@ -47,6 +47,12 @@ void cStatus::MsgSetVolume(int Volume, bool Absolute)
sm->SetVolume(Volume, Absolute);
}
+void cStatus::MsgSetAudioTrack(int Index, const char * const *Tracks)
+{
+ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
+ sm->SetAudioTrack(Index, Tracks);
+}
+
void cStatus::MsgOsdClear(void)
{
for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
diff --git a/status.h b/status.h
index de0d9256..1d6494ac 100644
--- a/status.h
+++ b/status.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: status.h 1.6 2003/05/03 14:43:18 kls Exp $
+ * $Id: status.h 1.7 2005/01/02 12:08:12 kls Exp $
*/
#ifndef __STATUS_H
@@ -36,6 +36,9 @@ protected:
virtual void SetVolume(int Volume, bool Absolute) {}
// The volume has been set to the given value, either
// absolutely or relative to the current volume.
+ virtual void SetAudioTrack(int Index, const char * const *Tracks) {}
+ // The audio track has been set to the one given by Index, which
+ // points into the Tracks array of strings.
virtual void OsdClear(void) {}
// The OSD has been cleared.
virtual void OsdTitle(const char *Title) {}
@@ -67,6 +70,7 @@ public:
static void MsgRecording(const cDevice *Device, const char *Name);
static void MsgReplaying(const cControl *Control, const char *Name);
static void MsgSetVolume(int Volume, bool Absolute);
+ static void MsgSetAudioTrack(int Index, const char * const *Tracks);
static void MsgOsdClear(void);
static void MsgOsdTitle(const char *Title);
static void MsgOsdStatusMessage(const char *Message);
diff --git a/transfer.c b/transfer.c
index 056299b2..97585760 100644
--- a/transfer.c
+++ b/transfer.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: transfer.c 1.19 2004/11/28 11:51:00 kls Exp $
+ * $Id: transfer.c 1.20 2004/12/27 11:08:34 kls Exp $
*/
#include "transfer.h"
@@ -58,11 +58,7 @@ void cTransfer::Action(void)
int PollTimeouts = 0;
uchar *p = NULL;
int Result = 0;
-// XXX Apparently this isn't necessary with the new PES data handling that
-// XXX was intorduced in VDR 1.3.18. If you do need this, enable the following
-// XXX line and send an email to kls@cadsoft.de. If nobody requires this, it
-// XXX will be removed later. kls 2004-12-27
-//#define FW_NEEDS_BUFFER_RESERVE_FOR_AC3
+#define FW_NEEDS_BUFFER_RESERVE_FOR_AC3
#ifdef FW_NEEDS_BUFFER_RESERVE_FOR_AC3
bool Cleared = false;
bool GotBufferReserve = false;
diff --git a/vdr.5 b/vdr.5
index f1ce3c22..c84189bd 100644
--- a/vdr.5
+++ b/vdr.5
@@ -8,7 +8,7 @@
.\" License as specified in the file COPYING that comes with the
.\" vdr distribution.
.\"
-.\" $Id: vdr.5 1.30 2004/12/18 12:40:47 kls Exp $
+.\" $Id: vdr.5 1.31 2005/01/02 13:57:10 kls Exp $
.\"
.TH vdr 5 "19 Dec 2004" "1.3.18" "Video Disk Recorder Files"
.SH NAME
@@ -613,6 +613,7 @@ l l.
\fBT\fR@<title>
\fBS\fR@<short text>
\fBD\fR@<description>
+\fBX\fR@<stream> <type> <language> <descr>
\fBV\fR@<vps time>
\fBe\fR@
\fBc\fR@
@@ -622,8 +623,10 @@ Lowercase characters mark the end of a sequence that was started by the
corresponding uppercase character. The outer frame consists of a sequence
of one or more \fBC\fR...\fBc\fR (Channel) entries. Inside these any number of
\fBE\fR...\fBe\fR (Event) entries are allowed.
-The \fBT\fR, \fBS\fR and \fBD\fR entries are optional (although every event
+All other tags are optional (although every event
should at least have a \fBT\fR entry).
+There may be several \fBX\fR tags, depending on the number of tracks (video, audio etc.)
+the event provides.
.TS
tab (@);
@@ -636,6 +639,10 @@ l l.
<title> @is the title of the event
<short text> @is the short text of the event (typically the name of the episode etc.)
<description> @is the description of the event (any '|' characters will be interpreted as newlines)
+<stream> @is the stream content (1 = video, 2 = audio)
+<type> @is the stream type according to ETSI EN 300 468
+<language> @is the three letter language code
+<descr> @is the description of this stream component
<vps time> @is the Video Programming Service time of this event
.TE
diff --git a/vdr.c b/vdr.c
index f49a89a1..a424b27c 100644
--- a/vdr.c
+++ b/vdr.c
@@ -22,7 +22,7 @@
*
* The project's page is at http://www.cadsoft.de/vdr
*
- * $Id: vdr.c 1.196 2004/12/26 10:30:30 kls Exp $
+ * $Id: vdr.c 1.197 2005/01/02 14:39:41 kls Exp $
*/
#include <getopt.h>
@@ -678,7 +678,7 @@ int main(int argc, char *argv[])
case kChanDn:
cDevice::SwitchChannel(NORMALKEY(key) == kChanUp ? 1 : -1);
break;
- // Volume Control:
+ // Volume control:
case kVolUp|k_Repeat:
case kVolUp:
case kVolDn|k_Repeat:
@@ -697,6 +697,14 @@ int main(int argc, char *argv[])
cDisplayVolume::Process(key);
key = kNone; // nobody else needs to see these keys
break;
+ // Audio track control:
+ case kAudio:
+ if (!Menu && !cOsd::IsOpen())
+ Menu = Temp = cDisplayTracks::Create();
+ else
+ cDisplayTracks::Process(key);
+ key = kNone;
+ break;
// Pausing live video:
case kPause:
if (!cControl::Control()) {