Implemented handling DVB subtitles

This commit is contained in:
Klaus Schmidinger 2007-10-12 14:52:30 +02:00
parent 3a4b7f065c
commit 0c8cda9bd0
26 changed files with 1774 additions and 85 deletions

View File

@ -1024,6 +1024,8 @@ Rolf Ahrenberg <rahrenbe@cc.hut.fi>
for improving cControl::Launch() to keep 'control' from pointing to uninitialized for improving cControl::Launch() to keep 'control' from pointing to uninitialized
memory memory
for adding internationalization to the "skincurses" plugin for adding internationalization to the "skincurses" plugin
for helping with adding compatibility mode for playback of recordings made with
the subtitles plugin
Ralf Klueber <ralf.klueber@vodafone.com> Ralf Klueber <ralf.klueber@vodafone.com>
for reporting a bug in cutting a recording if there is only a single editing mark for reporting a bug in cutting a recording if there is only a single editing mark
@ -1293,6 +1295,8 @@ Marcus M
Pekka Virtanen <pekka.virtanen@sci.fi> Pekka Virtanen <pekka.virtanen@sci.fi>
for adding language code handling to the subtitling descriptor in 'libsi' for adding language code handling to the subtitling descriptor in 'libsi'
for adding missing NULL checks when accessing sectionHandler in device.c for adding missing NULL checks when accessing sectionHandler in device.c
for writing the subtitle plugin, which helped in implementing subtitle handling
in VDR
John Kennedy <rkennedy@ix.netcom.com> John Kennedy <rkennedy@ix.netcom.com>
for publishing "A Fast Bresenham Algorithm For Drawing Ellipses" (found at for publishing "A Fast Bresenham Algorithm For Drawing Ellipses" (found at
@ -1419,6 +1423,8 @@ Marco Schl
for fixing a problem with characters >0x7F in the modified version of skipspace() for fixing a problem with characters >0x7F in the modified version of skipspace()
for reporting a faulty comment in Make.config.template for reporting a faulty comment in Make.config.template
for fixing checking for ttDolbyLast in cDevice::SetCurrentAudioTrack() for fixing checking for ttDolbyLast in cDevice::SetCurrentAudioTrack()
for fixing selecting the audio track when pressing Ok in the Audio menu
for implementing handling DVB subtitles
Jürgen Schmitz <j.schmitz@web.de> Jürgen Schmitz <j.schmitz@web.de>
for reporting a bug in displaying the current channel when switching via the SVDRP for reporting a bug in displaying the current channel when switching via the SVDRP

29
HISTORY
View File

@ -5416,3 +5416,32 @@ Video Disk Recorder Revision History
function to hand through the Level. function to hand through the Level.
- Fixed checking for ttDolbyLast in cDevice::SetCurrentAudioTrack() (thanks - Fixed checking for ttDolbyLast in cDevice::SetCurrentAudioTrack() (thanks
to Marco Schlüßler). to Marco Schlüßler).
2007-10-12: Version 1.5.10
- Implemented handling DVB subtitles (thanks to Marco Schlüßler, and also to
Pekka Virtanen for writing the subtitle plugin, which helped in implementing
subtitle handling in VDR).
- The new remote control key "Subtitles" can be used to bring up the list
of available subtitles.
- The new setup option "DVB/Subtitle languages" can be used to define the
preferred languages for subtitles.
- Fixed selecting the audio track when pressing Ok in the Audio menu (thanks
to Marco Schlüßler).
- Implemented display of DVB subtitles in live viewing mode.
- Implemented subtitle track selection.
- Implemented bitmap color reduction and shrinking to display subtitles even
on devices that can't display the necessary number of colors.
- Added compatibility mode for playback of recordings made with the subtitles
plugin (with some help from Rolf Ahrenberg).
- The new setup option "DVB/Subtitle offset" can be used to shift the location
of the subtitles in the vertical direction.
- The new setup options "DVB/Subtitle foreground/background transparency"
define an additional level of transparency for the foreground and background
color of subtitles.
- Existing recordings made with the subtitle plugin can be given an 'X' record
in their info.vdr file, so that subtitles can be automatically selected upon
replay, according to the preferred language setup, as in
X 3 03 ger deutsch
(see vdr.5). Note that these entries need to be added in the proper sequence,
so that they correspond with the actual track languages in the recording.

26
MANUAL
View File

@ -59,6 +59,7 @@ Version 1.4
Mute mute Mute mute
Audio select audio track Audio select audio track
Subtitles select subtitles
Schedule \ Schedule \
Channels | Channels |
@ -675,6 +676,31 @@ Version 1.4
many "Audio language" options which allow you to select the many "Audio language" options which allow you to select the
individual preferred languages. individual preferred languages.
Display subtitles = no If set to 'yes', the first available subtitles in the list
of preferred subtitle languages will be turned on when
switching to a channel that provides subtitles.
Subtitle languages = 0 Some tv stations broadcast various subtitle tracks in different
languages. This option allows you to define which language(s)
you prefer in such cases. By default, or if none of the
preferred languages is broadcast, no subtitles will
be selected when switching to such a channel. If this option
is set to a non-zero value, the menu page will contain that
many "Subtitle language" options which allow you to select the
individual preferred languages.
Subtitle offset = 0 Allows you to shift the location of the subtitles in the
vertical direction. The valid range is -50...50. This option
is only avialable if "Display subtitles" is set to 'yes'.
Subtitle foreground transparency = 0
Subtitle background transparency = 0
These define an additional level of transparency for the
foreground and background color of subtitles. Valid ranges
are 0...9 for foreground transparency, and 0...10 for
background transparency. By default the values as broadcast
are used.
LNB: LNB:
SLOF = 11700 The switching frequency (in MHz) between low and SLOF = 11700 The switching frequency (in MHz) between low and

View File

@ -4,7 +4,7 @@
# See the main source file 'vdr.c' for copyright information and # See the main source file 'vdr.c' for copyright information and
# how to reach the author. # how to reach the author.
# #
# $Id: Makefile 1.106 2007/08/25 08:52:17 kls Exp $ # $Id: Makefile 1.107 2007/09/01 12:19:53 kls Exp $
.DELETE_ON_ERROR: .DELETE_ON_ERROR:
@ -37,7 +37,7 @@ DOXYFILE = Doxyfile
SILIB = $(LSIDIR)/libsi.a SILIB = $(LSIDIR)/libsi.a
OBJS = audio.o channels.o ci.o config.o cutter.o device.o diseqc.o dvbdevice.o dvbci.o dvbosd.o\ OBJS = audio.o channels.o ci.o config.o cutter.o device.o diseqc.o dvbdevice.o dvbci.o dvbosd.o\
dvbplayer.o dvbspu.o eit.o eitscan.o epg.o filter.o font.o i18n.o interface.o keys.o\ dvbplayer.o dvbspu.o dvbsubtitle.o eit.o eitscan.o epg.o filter.o font.o i18n.o interface.o keys.o\
lirc.o menu.o menuitems.o nit.o osdbase.o osd.o pat.o player.o plugin.o rcu.o\ lirc.o menu.o menuitems.o nit.o osdbase.o osd.o pat.o player.o plugin.o rcu.o\
receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sdt.o sections.o shutdown.o\ receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sdt.o sections.o shutdown.o\
skinclassic.o skins.o skinsttng.o sources.o spu.o status.o svdrp.o themes.o thread.o\ skinclassic.o skins.o skinsttng.o sources.o spu.o status.o svdrp.o themes.o thread.o\

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: channels.c 1.54 2007/07/21 14:55:01 kls Exp $ * $Id: channels.c 1.55 2007/10/12 14:40:53 kls Exp $
*/ */
#include "channels.h" #include "channels.h"
@ -440,12 +440,12 @@ static int IntArrayToString(char *s, const int *a, int Base = 10, const char n[]
return q - s; return q - s;
} }
void cChannel::SetPids(int Vpid, int Ppid, int *Apids, char ALangs[][MAXLANGCODE2], int *Dpids, char DLangs[][MAXLANGCODE2], int Tpid) void cChannel::SetPids(int Vpid, int Ppid, int *Apids, char ALangs[][MAXLANGCODE2], int *Dpids, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid)
{ {
int mod = CHANNELMOD_NONE; int mod = CHANNELMOD_NONE;
if (vpid != Vpid || ppid != Ppid || tpid != Tpid) if (vpid != Vpid || ppid != Ppid || tpid != Tpid)
mod |= CHANNELMOD_PIDS; mod |= CHANNELMOD_PIDS;
int m = IntArraysDiffer(apids, Apids, alangs, ALangs) | IntArraysDiffer(dpids, Dpids, dlangs, DLangs); int m = IntArraysDiffer(apids, Apids, alangs, ALangs) | IntArraysDiffer(dpids, Dpids, dlangs, DLangs) | IntArraysDiffer(spids, Spids, slangs, SLangs);
if (m & STRDIFF) if (m & STRDIFF)
mod |= CHANNELMOD_LANGS; mod |= CHANNELMOD_LANGS;
if (m & VALDIFF) if (m & VALDIFF)
@ -468,7 +468,16 @@ void cChannel::SetPids(int Vpid, int Ppid, int *Apids, char ALangs[][MAXLANGCODE
q += IntArrayToString(q, Dpids, 10, DLangs); q += IntArrayToString(q, Dpids, 10, DLangs);
} }
*q = 0; *q = 0;
dsyslog("changing pids of channel %d from %d+%d:%s:%d to %d+%d:%s:%d", Number(), vpid, ppid, OldApidsBuf, tpid, Vpid, Ppid, NewApidsBuf, Tpid); const int SBufferSize = MAXSPIDS * (5 + 1 + MAXLANGCODE2) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod', +10: paranoia
char OldSpidsBuf[SBufferSize];
char NewSpidsBuf[SBufferSize];
q = OldSpidsBuf;
q += IntArrayToString(q, spids, 10, slangs);
*q = 0;
q = NewSpidsBuf;
q += IntArrayToString(q, Spids, 10, SLangs);
*q = 0;
dsyslog("changing pids of channel %d from %d+%d:%s:%s:%d to %d+%d:%s:%s:%d", Number(), vpid, ppid, OldApidsBuf, OldSpidsBuf, tpid, Vpid, Ppid, NewApidsBuf, NewSpidsBuf, Tpid);
vpid = Vpid; vpid = Vpid;
ppid = Ppid; ppid = Ppid;
for (int i = 0; i < MAXAPIDS; i++) { for (int i = 0; i < MAXAPIDS; i++) {
@ -481,6 +490,11 @@ void cChannel::SetPids(int Vpid, int Ppid, int *Apids, char ALangs[][MAXLANGCODE
strn0cpy(dlangs[i], DLangs[i], MAXLANGCODE2); strn0cpy(dlangs[i], DLangs[i], MAXLANGCODE2);
} }
dpids[MAXDPIDS] = 0; dpids[MAXDPIDS] = 0;
for (int i = 0; i < MAXSPIDS; i++) {
spids[i] = Spids[i];
strn0cpy(slangs[i], SLangs[i], MAXLANGCODE2);
}
spids[MAXSPIDS] = 0;
tpid = Tpid; tpid = Tpid;
modification |= mod; modification |= mod;
Channels.SetModified(); Channels.SetModified();

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: channels.h 1.44 2007/07/21 14:58:36 kls Exp $ * $Id: channels.h 1.45 2007/09/02 10:23:11 kls Exp $
*/ */
#ifndef __CHANNELS_H #ifndef __CHANNELS_H
@ -33,7 +33,7 @@
#define MAXAPIDS 32 // audio #define MAXAPIDS 32 // audio
#define MAXDPIDS 16 // dolby (AC3 + DTS) #define MAXDPIDS 16 // dolby (AC3 + DTS)
#define MAXSPIDS 8 // subtitles #define MAXSPIDS 32 // subtitles
#define MAXCAIDS 8 // conditional access #define MAXCAIDS 8 // conditional access
#define MAXLANGCODE1 4 // a 3 letter language code, zero terminated #define MAXLANGCODE1 4 // a 3 letter language code, zero terminated
@ -212,7 +212,7 @@ public:
void SetId(int Nid, int Tid, int Sid, int Rid = 0); void SetId(int Nid, int Tid, int Sid, int Rid = 0);
void SetName(const char *Name, const char *ShortName, const char *Provider); void SetName(const char *Name, const char *ShortName, const char *Provider);
void SetPortalName(const char *PortalName); void SetPortalName(const char *PortalName);
void SetPids(int Vpid, int Ppid, int *Apids, char ALangs[][MAXLANGCODE2], int *Dpids, char DLangs[][MAXLANGCODE2], int Tpid); void SetPids(int Vpid, int Ppid, int *Apids, char ALangs[][MAXLANGCODE2], int *Dpids, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid);
void SetCaIds(const int *CaIds); // list must be zero-terminated void SetCaIds(const int *CaIds); // list must be zero-terminated
void SetCaDescriptors(int Level); void SetCaDescriptors(int Level);
void SetLinkChannels(cLinkChannels *LinkChannels); void SetLinkChannels(cLinkChannels *LinkChannels);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: config.c 1.156 2007/08/12 12:09:37 kls Exp $ * $Id: config.c 1.157 2007/10/06 14:28:58 kls Exp $
*/ */
#include "config.h" #include "config.h"
@ -236,6 +236,11 @@ cSetup::cSetup(void)
MarginStart = 2; MarginStart = 2;
MarginStop = 10; MarginStop = 10;
AudioLanguages[0] = -1; AudioLanguages[0] = -1;
DisplaySubtitles = 0;
SubtitleLanguages[0] = -1;
SubtitleOffset = 0;
SubtitleFgTransparency = 0;
SubtitleBgTransparency = 0;
EPGLanguages[0] = -1; EPGLanguages[0] = -1;
EPGScanTimeout = 5; EPGScanTimeout = 5;
EPGBugfixLevel = 3; EPGBugfixLevel = 3;
@ -406,6 +411,11 @@ bool cSetup::Parse(const char *Name, const char *Value)
else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value); else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value);
else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value); else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value);
else if (!strcasecmp(Name, "AudioLanguages")) return ParseLanguages(Value, AudioLanguages); else if (!strcasecmp(Name, "AudioLanguages")) return ParseLanguages(Value, AudioLanguages);
else if (!strcasecmp(Name, "DisplaySubtitles")) DisplaySubtitles = atoi(Value);
else if (!strcasecmp(Name, "SubtitleLanguages")) return ParseLanguages(Value, SubtitleLanguages);
else if (!strcasecmp(Name, "SubtitleOffset")) SubtitleOffset = atoi(Value);
else if (!strcasecmp(Name, "SubtitleFgTransparency")) SubtitleFgTransparency = atoi(Value);
else if (!strcasecmp(Name, "SubtitleBgTransparency")) SubtitleBgTransparency = atoi(Value);
else if (!strcasecmp(Name, "EPGLanguages")) return ParseLanguages(Value, EPGLanguages); else if (!strcasecmp(Name, "EPGLanguages")) return ParseLanguages(Value, EPGLanguages);
else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value); else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value);
else if (!strcasecmp(Name, "EPGBugfixLevel")) EPGBugfixLevel = atoi(Value); else if (!strcasecmp(Name, "EPGBugfixLevel")) EPGBugfixLevel = atoi(Value);
@ -483,6 +493,11 @@ bool cSetup::Save(void)
Store("MarginStart", MarginStart); Store("MarginStart", MarginStart);
Store("MarginStop", MarginStop); Store("MarginStop", MarginStop);
StoreLanguages("AudioLanguages", AudioLanguages); StoreLanguages("AudioLanguages", AudioLanguages);
Store("DisplaySubtitles", DisplaySubtitles);
StoreLanguages("SubtitleLanguages", SubtitleLanguages);
Store("SubtitleOffset", SubtitleOffset);
Store("SubtitleFgTransparency", SubtitleFgTransparency);
Store("SubtitleBgTransparency", SubtitleBgTransparency);
StoreLanguages("EPGLanguages", EPGLanguages); StoreLanguages("EPGLanguages", EPGLanguages);
Store("EPGScanTimeout", EPGScanTimeout); Store("EPGScanTimeout", EPGScanTimeout);
Store("EPGBugfixLevel", EPGBugfixLevel); Store("EPGBugfixLevel", EPGBugfixLevel);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: config.h 1.298 2007/08/19 16:02:50 kls Exp $ * $Id: config.h 1.299 2007/10/06 14:27:18 kls Exp $
*/ */
#ifndef __CONFIG_H #ifndef __CONFIG_H
@ -22,13 +22,13 @@
// VDR's own version number: // VDR's own version number:
#define VDRVERSION "1.5.9" #define VDRVERSION "1.5.10"
#define VDRVERSNUM 10509 // Version * 10000 + Major * 100 + Minor #define VDRVERSNUM 10510 // Version * 10000 + Major * 100 + Minor
// The plugin API's version number: // The plugin API's version number:
#define APIVERSION "1.5.9" #define APIVERSION "1.5.10"
#define APIVERSNUM 10509 // Version * 10000 + Major * 100 + Minor #define APIVERSNUM 10510 // Version * 10000 + Major * 100 + Minor
// When loading plugins, VDR searches them by their APIVERSION, which // When loading plugins, VDR searches them by their APIVERSION, which
// may be smaller than VDRVERSION in case there have been no changes to // may be smaller than VDRVERSION in case there have been no changes to
@ -220,6 +220,10 @@ public:
int TimeTransponder; int TimeTransponder;
int MarginStart, MarginStop; int MarginStart, MarginStop;
int AudioLanguages[I18N_MAX_LANGUAGES + 1]; int AudioLanguages[I18N_MAX_LANGUAGES + 1];
int DisplaySubtitles;
int SubtitleLanguages[I18N_MAX_LANGUAGES + 1];
int SubtitleOffset;
int SubtitleFgTransparency, SubtitleBgTransparency;
int EPGLanguages[I18N_MAX_LANGUAGES + 1]; int EPGLanguages[I18N_MAX_LANGUAGES + 1];
int EPGScanTimeout; int EPGScanTimeout;
int EPGBugfixLevel; int EPGBugfixLevel;

182
device.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: device.c 1.142 2007/08/26 11:11:42 kls Exp $ * $Id: device.c 1.143 2007/10/12 14:27:30 kls Exp $
*/ */
#include "device.h" #include "device.h"
@ -19,6 +19,75 @@
#include "status.h" #include "status.h"
#include "transfer.h" #include "transfer.h"
// --- cLiveSubtitle ---------------------------------------------------------
#define LIVESUBTITLEBUFSIZE KILOBYTE(100)
class cLiveSubtitle : public cReceiver, public cThread {
private:
cRingBufferLinear *ringBuffer;
cRemux *remux;
protected:
virtual void Activate(bool On);
virtual void Receive(uchar *Data, int Length);
virtual void Action(void);
public:
cLiveSubtitle(int SPid);
virtual ~cLiveSubtitle();
};
cLiveSubtitle::cLiveSubtitle(int SPid)
:cReceiver(tChannelID(), -1, SPid)
,cThread("live subtitle")
{
ringBuffer = new cRingBufferLinear(LIVESUBTITLEBUFSIZE, TS_SIZE * 2, true, "Live Subtitle");
int NoPids = 0;
int SPids[] = { SPid, 0 };
remux = new cRemux(0, &NoPids, &NoPids, SPids);
}
cLiveSubtitle::~cLiveSubtitle()
{
cReceiver::Detach();
delete remux;
delete ringBuffer;
}
void cLiveSubtitle::Activate(bool On)
{
if (On)
Start();
else
Cancel(3);
}
void cLiveSubtitle::Receive(uchar *Data, int Length)
{
if (Running()) {
int p = ringBuffer->Put(Data, Length);
if (p != Length && Running())
ringBuffer->ReportOverflow(Length - p);
}
}
void cLiveSubtitle::Action(void)
{
while (Running()) {
int Count;
uchar *b = ringBuffer->Get(Count);
if (b) {
Count = remux->Put(b, Count);
if (Count)
ringBuffer->Del(Count);
}
b = remux->Get(Count);
if (b) {
Count = cDevice::PrimaryDevice()->PlaySubtitle(b, Count);
remux->Del(Count);
}
}
}
// --- cPesAssembler --------------------------------------------------------- // --- cPesAssembler ---------------------------------------------------------
class cPesAssembler { class cPesAssembler {
@ -172,6 +241,10 @@ cDevice::cDevice(void)
ClrAvailableTracks(); ClrAvailableTracks();
currentAudioTrack = ttNone; currentAudioTrack = ttNone;
currentAudioTrackMissingCount = 0; currentAudioTrackMissingCount = 0;
currentSubtitleTrack = ttNone;
liveSubtitle = NULL;
dvbSubtitleConverter = NULL;
autoSelectPreferredSubtitleLanguage = true;
for (int i = 0; i < MAXRECEIVERS; i++) for (int i = 0; i < MAXRECEIVERS; i++)
receiver[i] = NULL; receiver[i] = NULL;
@ -186,6 +259,8 @@ cDevice::~cDevice()
{ {
Detach(player); Detach(player);
DetachAllReceivers(); DetachAllReceivers();
delete liveSubtitle;
delete dvbSubtitleConverter;
delete nitFilter; delete nitFilter;
delete sdtFilter; delete sdtFilter;
delete patFilter; delete patFilter;
@ -674,8 +749,11 @@ bool cDevice::SwitchChannel(int Direction)
eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView) eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
{ {
if (LiveView) if (LiveView) {
StopReplay(); StopReplay();
DELETENULL(liveSubtitle);
DELETENULL(dvbSubtitleConverter);
}
cDevice *Device = (LiveView && IsPrimaryDevice()) ? GetDevice(Channel, 0, LiveView) : this; cDevice *Device = (LiveView && IsPrimaryDevice()) ? GetDevice(Channel, 0, LiveView) : this;
@ -735,8 +813,11 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
for (int i = 0; i < MAXDPIDS; i++) for (int i = 0; i < MAXDPIDS; i++)
SetAvailableTrack(ttDolby, i, Channel->Dpid(i), Channel->Dlang(i)); SetAvailableTrack(ttDolby, i, Channel->Dpid(i), Channel->Dlang(i));
} }
for (int i = 0; i < MAXSPIDS; i++)
SetAvailableTrack(ttSubtitle, i, Channel->Spid(i), Channel->Slang(i));
if (!NeedsTransferMode) if (!NeedsTransferMode)
EnsureAudioTrack(true); EnsureAudioTrack(true);
EnsureSubtitleTrack();
} }
cStatus::MsgChannelSwitch(this, Channel->Number()); // only report status if channel switch successfull cStatus::MsgChannelSwitch(this, Channel->Number()); // only report status if channel switch successfull
} }
@ -848,6 +929,7 @@ void cDevice::ClrAvailableTracks(bool DescriptionsOnly, bool IdsOnly)
SetAudioChannel(0); // fall back to stereo SetAudioChannel(0); // fall back to stereo
currentAudioTrackMissingCount = 0; currentAudioTrackMissingCount = 0;
currentAudioTrack = ttNone; currentAudioTrack = ttNone;
currentSubtitleTrack = ttNone;
} }
} }
@ -855,18 +937,23 @@ bool cDevice::SetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const c
{ {
eTrackType t = eTrackType(Type + Index); eTrackType t = eTrackType(Type + Index);
if (Type == ttAudio && IS_AUDIO_TRACK(t) || if (Type == ttAudio && IS_AUDIO_TRACK(t) ||
Type == ttDolby && IS_DOLBY_TRACK(t)) { Type == ttDolby && IS_DOLBY_TRACK(t) ||
Type == ttSubtitle && IS_SUBTITLE_TRACK(t)) {
if (Language) if (Language)
strn0cpy(availableTracks[t].language, Language, sizeof(availableTracks[t].language)); strn0cpy(availableTracks[t].language, Language, sizeof(availableTracks[t].language));
if (Description) if (Description)
Utf8Strn0Cpy(availableTracks[t].description, Description, sizeof(availableTracks[t].description)); Utf8Strn0Cpy(availableTracks[t].description, Description, sizeof(availableTracks[t].description));
if (Id) { if (Id) {
availableTracks[t].id = Id; // setting 'id' last to avoid the need for extensive locking availableTracks[t].id = Id; // setting 'id' last to avoid the need for extensive locking
int numAudioTracks = NumAudioTracks(); if (Type == ttAudio || Type == ttDolby) {
if (!availableTracks[currentAudioTrack].id && numAudioTracks && currentAudioTrackMissingCount++ > numAudioTracks * 10) int numAudioTracks = NumAudioTracks();
EnsureAudioTrack(); if (!availableTracks[currentAudioTrack].id && numAudioTracks && currentAudioTrackMissingCount++ > numAudioTracks * 10)
else if (t == currentAudioTrack) EnsureAudioTrack();
currentAudioTrackMissingCount = 0; else if (t == currentAudioTrack)
currentAudioTrackMissingCount = 0;
}
else if (Type == ttSubtitle && autoSelectPreferredSubtitleLanguage)
EnsureSubtitleTrack();
} }
return true; return true;
} }
@ -880,16 +967,26 @@ const tTrackId *cDevice::GetTrack(eTrackType Type)
return (ttNone < Type && Type < ttMaxTrackTypes) ? &availableTracks[Type] : NULL; return (ttNone < Type && Type < ttMaxTrackTypes) ? &availableTracks[Type] : NULL;
} }
int cDevice::NumAudioTracks(void) const int cDevice::NumTracks(eTrackType FirstTrack, eTrackType LastTrack) const
{ {
int n = 0; int n = 0;
for (int i = ttAudioFirst; i <= ttDolbyLast; i++) { for (int i = FirstTrack; i <= LastTrack; i++) {
if (availableTracks[i].id) if (availableTracks[i].id)
n++; n++;
} }
return n; return n;
} }
int cDevice::NumAudioTracks(void) const
{
return NumTracks(ttAudioFirst, ttDolbyLast);
}
int cDevice::NumSubtitleTracks(void) const
{
return NumTracks(ttSubtitleFirst, ttSubtitleLast);
}
bool cDevice::SetCurrentAudioTrack(eTrackType Type) bool cDevice::SetCurrentAudioTrack(eTrackType Type)
{ {
if (ttNone < Type && Type <= ttDolbyLast) { if (ttNone < Type && Type <= ttDolbyLast) {
@ -908,6 +1005,30 @@ bool cDevice::SetCurrentAudioTrack(eTrackType Type)
return false; return false;
} }
bool cDevice::SetCurrentSubtitleTrack(eTrackType Type, bool Manual)
{
if (Type == ttNone || IS_SUBTITLE_TRACK(Type)) {
currentSubtitleTrack = Type;
autoSelectPreferredSubtitleLanguage = !Manual;
if (dvbSubtitleConverter)
dvbSubtitleConverter->Reset();
if (Type == ttNone && dvbSubtitleConverter) {
cMutexLock MutexLock(&mutexCurrentSubtitleTrack);
DELETENULL(dvbSubtitleConverter);
}
DELETENULL(liveSubtitle);
if (currentSubtitleTrack != ttNone && !Replaying() && !Transferring()) {
const tTrackId *TrackId = GetTrack(currentSubtitleTrack);
if (TrackId && TrackId->id) {
liveSubtitle = new cLiveSubtitle(TrackId->id);
AttachReceiver(liveSubtitle);
}
}
return true;
}
return false;
}
void cDevice::EnsureAudioTrack(bool Force) void cDevice::EnsureAudioTrack(bool Force)
{ {
if (Force || !availableTracks[currentAudioTrack].id) { if (Force || !availableTracks[currentAudioTrack].id) {
@ -939,6 +1060,25 @@ void cDevice::EnsureAudioTrack(bool Force)
} }
} }
void cDevice::EnsureSubtitleTrack(void)
{
if (Setup.DisplaySubtitles) {
eTrackType PreferredTrack = ttSubtitleFirst;
int LanguagePreference = -1;
for (int i = ttSubtitleFirst; i <= ttSubtitleLast; i++) {
const tTrackId *TrackId = GetTrack(eTrackType(i));
if (TrackId && TrackId->id && I18nIsPreferredLanguage(Setup.SubtitleLanguages, TrackId->language, LanguagePreference))
PreferredTrack = eTrackType(i);
}
// Make sure we're set to an available subtitle track:
const tTrackId *Track = GetTrack(GetCurrentSubtitleTrack());
if (!Track || !Track->id || PreferredTrack != GetCurrentSubtitleTrack())
SetCurrentSubtitleTrack(PreferredTrack);
}
else
SetCurrentSubtitleTrack(ttNone);
}
bool cDevice::CanReplay(void) const bool cDevice::CanReplay(void) const
{ {
return HasDecoder(); return HasDecoder();
@ -961,6 +1101,8 @@ void cDevice::TrickSpeed(int Speed)
void cDevice::Clear(void) void cDevice::Clear(void)
{ {
Audios.ClearAudio(); Audios.ClearAudio();
if (dvbSubtitleConverter)
dvbSubtitleConverter->Reset();
} }
void cDevice::Play(void) void cDevice::Play(void)
@ -1016,6 +1158,9 @@ void cDevice::Detach(cPlayer *Player)
player = NULL; // avoids recursive calls to Detach() player = NULL; // avoids recursive calls to Detach()
p->Activate(false); p->Activate(false);
p->device = NULL; p->device = NULL;
cMutexLock MutexLock(&mutexCurrentSubtitleTrack);
delete dvbSubtitleConverter;
dvbSubtitleConverter = NULL;
SetPlayMode(pmNone); SetPlayMode(pmNone);
SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat)); SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat));
Audios.ClearAudio(); Audios.ClearAudio();
@ -1051,6 +1196,13 @@ int cDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
return -1; return -1;
} }
int cDevice::PlaySubtitle(const uchar *Data, int Length)
{
if (!dvbSubtitleConverter)
dvbSubtitleConverter = new cDvbSubtitleConverter;
return dvbSubtitleConverter->Convert(Data, Length);
}
int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly) int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly)
{ {
cMutexLock MutexLock(&mutexCurrentAudioTrack); cMutexLock MutexLock(&mutexCurrentAudioTrack);
@ -1076,6 +1228,11 @@ int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly)
break; break;
case 0xBD: { // private stream 1 case 0xBD: { // private stream 1
int PayloadOffset = Data[8] + 9; int PayloadOffset = Data[8] + 9;
// Compatibility mode for old subtitles plugin:
if ((Data[PayloadOffset - 3] & 0x81) == 1 && Data[PayloadOffset - 2] == 0x81)
PayloadOffset--;
uchar SubStreamId = Data[PayloadOffset]; uchar SubStreamId = Data[PayloadOffset];
uchar SubStreamType = SubStreamId & 0xF0; uchar SubStreamType = SubStreamId & 0xF0;
uchar SubStreamIndex = SubStreamId & 0x1F; uchar SubStreamIndex = SubStreamId & 0x1F;
@ -1090,6 +1247,9 @@ pre_1_3_19_PrivateStreamDeteced:
switch (SubStreamType) { switch (SubStreamType) {
case 0x20: // SPU case 0x20: // SPU
case 0x30: // SPU case 0x30: // SPU
SetAvailableTrack(ttSubtitle, SubStreamIndex, SubStreamId);
if (!VideoOnly && currentSubtitleTrack != ttNone && SubStreamId == availableTracks[currentSubtitleTrack].id)
w = PlaySubtitle(Start, d);
break; break;
case 0x80: // AC3 & DTS case 0x80: // AC3 & DTS
if (Setup.UseDolbyDigital) { if (Setup.UseDolbyDigital) {
@ -1139,6 +1299,8 @@ int cDevice::PlayPes(const uchar *Data, int Length, bool VideoOnly)
{ {
if (!Data) { if (!Data) {
pesAssembler->Reset(); pesAssembler->Reset();
if (dvbSubtitleConverter)
dvbSubtitleConverter->Reset();
return 0; return 0;
} }
int Result = 0; int Result = 0;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: device.h 1.82 2007/07/22 11:20:13 kls Exp $ * $Id: device.h 1.83 2007/10/12 13:53:50 kls Exp $
*/ */
#ifndef __DEVICE_H #ifndef __DEVICE_H
@ -12,6 +12,7 @@
#include "channels.h" #include "channels.h"
#include "ci.h" #include "ci.h"
#include "dvbsubtitle.h"
#include "eit.h" #include "eit.h"
#include "filter.h" #include "filter.h"
#include "nit.h" #include "nit.h"
@ -70,16 +71,15 @@ enum eTrackType { ttNone,
ttDolby, ttDolby,
ttDolbyFirst = ttDolby, ttDolbyFirst = ttDolby,
ttDolbyLast = ttDolbyFirst + 15, // MAXDPIDS - 1 ttDolbyLast = ttDolbyFirst + 15, // MAXDPIDS - 1
/* future...
ttSubtitle, ttSubtitle,
ttSubtitleFirst = ttSubtitle, ttSubtitleFirst = ttSubtitle,
ttSubtitleLast = ttSubtitleFirst + 7, // MAXSPIDS - 1 ttSubtitleLast = ttSubtitleFirst + 31, // MAXSPIDS - 1
*/
ttMaxTrackTypes ttMaxTrackTypes
}; };
#define IS_AUDIO_TRACK(t) (ttAudioFirst <= (t) && (t) <= ttAudioLast) #define IS_AUDIO_TRACK(t) (ttAudioFirst <= (t) && (t) <= ttAudioLast)
#define IS_DOLBY_TRACK(t) (ttDolbyFirst <= (t) && (t) <= ttDolbyLast) #define IS_DOLBY_TRACK(t) (ttDolbyFirst <= (t) && (t) <= ttDolbyLast)
#define IS_SUBTITLE_TRACK(t) (ttSubtitleFirst <= (t) && (t) <= ttSubtitleLast)
struct tTrackId { struct tTrackId {
uint16_t id; // The PES packet id or the PID. uint16_t id; // The PES packet id or the PID.
@ -90,10 +90,12 @@ struct tTrackId {
class cPlayer; class cPlayer;
class cReceiver; class cReceiver;
class cPesAssembler; class cPesAssembler;
class cLiveSubtitle;
/// The cDevice class is the base from which actual devices can be derived. /// The cDevice class is the base from which actual devices can be derived.
class cDevice : public cThread { class cDevice : public cThread {
friend class cLiveSubtitle;
private: private:
static int numDevices; static int numDevices;
static int useDevice; static int useDevice;
@ -185,6 +187,9 @@ public:
// SPU facilities // SPU facilities
private:
cLiveSubtitle *liveSubtitle;
cDvbSubtitleConverter *dvbSubtitleConverter;
public: public:
virtual cSpuDecoder *GetSpuDecoder(void); virtual cSpuDecoder *GetSpuDecoder(void);
///< Returns a pointer to the device's SPU decoder (or NULL, if this ///< Returns a pointer to the device's SPU decoder (or NULL, if this
@ -362,8 +367,11 @@ public:
private: private:
tTrackId availableTracks[ttMaxTrackTypes]; tTrackId availableTracks[ttMaxTrackTypes];
eTrackType currentAudioTrack; eTrackType currentAudioTrack;
eTrackType currentSubtitleTrack;
cMutex mutexCurrentAudioTrack; cMutex mutexCurrentAudioTrack;
cMutex mutexCurrentSubtitleTrack;
int currentAudioTrackMissingCount; int currentAudioTrackMissingCount;
bool autoSelectPreferredSubtitleLanguage;
bool pre_1_3_19_PrivateStream; bool pre_1_3_19_PrivateStream;
protected: protected:
virtual void SetAudioTrackDevice(eTrackType Type); virtual void SetAudioTrackDevice(eTrackType Type);
@ -384,18 +392,33 @@ public:
const tTrackId *GetTrack(eTrackType Type); const tTrackId *GetTrack(eTrackType Type);
///< Returns a pointer to the given track id, or NULL if Type is not ///< Returns a pointer to the given track id, or NULL if Type is not
///< less than ttMaxTrackTypes. ///< less than ttMaxTrackTypes.
int NumTracks(eTrackType FirstTrack, eTrackType LastTrack) const;
///< Returns the number of tracks in the given range that are currently
///< available.
int NumAudioTracks(void) const; int NumAudioTracks(void) const;
///< Returns the number of audio tracks that are currently available. ///< Returns the number of audio tracks that are currently available.
///< This is just for information, to quickly find out whether there ///< This is just for information, to quickly find out whether there
///< is more than one audio track. ///< is more than one audio track.
int NumSubtitleTracks(void) const;
///< Returns the number of subtitle tracks that are currently available.
eTrackType GetCurrentAudioTrack(void) { return currentAudioTrack; } eTrackType GetCurrentAudioTrack(void) { return currentAudioTrack; }
bool SetCurrentAudioTrack(eTrackType Type); bool SetCurrentAudioTrack(eTrackType Type);
///< Sets the current audio track to the given Type. ///< Sets the current audio track to the given Type.
///< \return Returns true if Type is a valid audio track, false otherwise. ///< \return Returns true if Type is a valid audio track, false otherwise.
eTrackType GetCurrentSubtitleTrack(void) { return currentSubtitleTrack; }
bool SetCurrentSubtitleTrack(eTrackType Type, bool Manual = false);
///< Sets the current subtitle track to the given Type.
///< IF Manual is true, no automatic preferred subtitle language selection
///< will be done for the rest of the current replay session, or until
///< the channel is changed.
///< \return Returns true if Type is a valid subtitle track, false otherwise.
void EnsureAudioTrack(bool Force = false); void EnsureAudioTrack(bool Force = false);
///< Makes sure an audio track is selected that is actually available. ///< Makes sure an audio track is selected that is actually available.
///< If Force is true, the language and Dolby Digital settings will ///< If Force is true, the language and Dolby Digital settings will
///< be verified even if the current audio track is available. ///< be verified even if the current audio track is available.
void EnsureSubtitleTrack(void);
///< Makes sure one of the preferred language subtitle tracks is selected.
///< Only has an effect if Setup.DisplaySubtitles is on.
// Audio facilities // Audio facilities
@ -454,6 +477,13 @@ protected:
///< Length) or not at all (returning 0 or -1 and setting 'errno' to EAGAIN). ///< Length) or not at all (returning 0 or -1 and setting 'errno' to EAGAIN).
///< \return Returns the number of bytes actually taken from Data, or -1 ///< \return Returns the number of bytes actually taken from Data, or -1
///< in case of an error. ///< in case of an error.
virtual int PlaySubtitle(const uchar *Data, int Length);
///< Plays the given data block as a subtitle.
///< Data points to exactly one complete PES packet of the given Length.
///< PlaySubtitle() shall process the packet either as a whole (returning
///< Length) or not at all (returning 0 or -1 and setting 'errno' to EAGAIN).
///< \return Returns the number of bytes actually taken from Data, or -1
///< in case of an error.
virtual int PlayPesPacket(const uchar *Data, int Length, bool VideoOnly = false); virtual int PlayPesPacket(const uchar *Data, int Length, bool VideoOnly = false);
///< Plays the single PES packet in Data with the given Length. ///< Plays the single PES packet in Data with the given Length.
///< If VideoOnly is true, only the video will be displayed, ///< If VideoOnly is true, only the video will be displayed,

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbosd.c 1.31 2007/08/26 09:39:20 kls Exp $ * $Id: dvbosd.c 1.32 2007/09/16 08:55:54 kls Exp $
*/ */
#include "dvbosd.h" #include "dvbosd.h"
@ -32,6 +32,7 @@ public:
cDvbOsd(int Left, int Top, int OsdDev, uint Level); cDvbOsd(int Left, int Top, int OsdDev, uint Level);
virtual ~cDvbOsd(); virtual ~cDvbOsd();
virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas); virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas);
virtual eOsdError SetAreas(const tArea *Areas, int NumAreas);
virtual void Flush(void); virtual void Flush(void);
}; };
@ -106,6 +107,19 @@ eOsdError cDvbOsd::CanHandleAreas(const tArea *Areas, int NumAreas)
return Result; return Result;
} }
eOsdError cDvbOsd::SetAreas(const tArea *Areas, int NumAreas)
{
if (shown) {
cBitmap *Bitmap;
for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) {
Cmd(OSD_SetWindow, 0, i + 1);
Cmd(OSD_Close);
}
shown = false;
}
return cOsd::SetAreas(Areas, NumAreas);
}
void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, const void *data) void cDvbOsd::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, const void *data)
{ {
if (osdDev >= 0) { if (osdDev >= 0) {

1029
dvbsubtitle.c Normal file

File diff suppressed because it is too large Load Diff

43
dvbsubtitle.h Normal file
View File

@ -0,0 +1,43 @@
/*
* dvbsubtitle.h: DVB subtitles
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* Original author: Marco Schlüßler <marco@lordzodiac.de>
*
* $Id: dvbsubtitle.h 1.1 2007/10/12 14:27:30 kls Exp $
*/
#ifndef __DVBSUBTITLE_H
#define __DVBSUBTITLE_H
#include "osd.h"
#include "thread.h"
#include "tools.h"
class cDvbSubtitlePage;
class cDvbSubtitleAssembler;
class cDvbSubtitleBitmaps;
class cDvbSubtitleConverter : public cThread {
private:
static int setupLevel;
cDvbSubtitleAssembler *dvbSubtitleAssembler;
cOsd *osd;
cList<cDvbSubtitlePage> *pages;
cList<cDvbSubtitleBitmaps> *bitmaps;
tColor yuv2rgb(int Y, int Cb, int Cr);
bool AssertOsd(void);
int ExtractSegment(const uchar *Data, int Length, int64_t Pts);
void FinishPage(cDvbSubtitlePage *Page);
public:
cDvbSubtitleConverter(void);
virtual ~cDvbSubtitleConverter();
void Action(void);
void Reset(void);
int Convert(const uchar *Data, int Length);
static void SetupChanged(void);
};
#endif //__DVBSUBTITLE_H

6
eit.c
View File

@ -8,7 +8,7 @@
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>. * 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>. * Adapted to 'libsi' for VDR 1.3.0 by Marcel Wiesweg <marcel.wiesweg@gmx.de>.
* *
* $Id: eit.c 1.125 2007/07/28 13:16:43 kls Exp $ * $Id: eit.c 1.126 2007/09/26 10:56:33 kls Exp $
*/ */
#include "eit.h" #include "eit.h"
@ -219,11 +219,11 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bo
SI::ComponentDescriptor *cd = (SI::ComponentDescriptor *)d; SI::ComponentDescriptor *cd = (SI::ComponentDescriptor *)d;
uchar Stream = cd->getStreamContent(); uchar Stream = cd->getStreamContent();
uchar Type = cd->getComponentType(); uchar Type = cd->getComponentType();
if (1 <= Stream && Stream <= 2 && Type != 0) { if (1 <= Stream && Stream <= 3 && Type != 0) { // 1=video, 2=audio, 3=subtitles
if (!Components) if (!Components)
Components = new cComponents; Components = new cComponents;
char buffer[Utf8BufSize(256)]; char buffer[Utf8BufSize(256)];
Components->SetComponent(Components->NumComponents(), cd->getStreamContent(), cd->getComponentType(), I18nNormalizeLanguageCode(cd->languageCode), cd->description.getText(buffer, sizeof(buffer))); Components->SetComponent(Components->NumComponents(), Stream, Type, I18nNormalizeLanguageCode(cd->languageCode), cd->description.getText(buffer, sizeof(buffer)));
} }
} }
break; break;

3
keys.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: keys.c 1.15 2007/08/11 11:30:18 kls Exp $ * $Id: keys.c 1.16 2007/09/26 12:35:21 kls Exp $
*/ */
#include "keys.h" #include "keys.h"
@ -49,6 +49,7 @@ static tKey keyTable[] = { // "Up" and "Down" must be the first two keys!
{ kVolDn, trNOOP("Key$Volume-") }, { kVolDn, trNOOP("Key$Volume-") },
{ kMute, trNOOP("Key$Mute") }, { kMute, trNOOP("Key$Mute") },
{ kAudio, trNOOP("Key$Audio") }, { kAudio, trNOOP("Key$Audio") },
{ kSubtitles, trNOOP("Key$Subtitles") },
{ kSchedule, trNOOP("Key$Schedule") }, { kSchedule, trNOOP("Key$Schedule") },
{ kChannels, trNOOP("Key$Channels") }, { kChannels, trNOOP("Key$Channels") },
{ kTimers, trNOOP("Key$Timers") }, { kTimers, trNOOP("Key$Timers") },

3
keys.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: keys.h 1.13 2007/08/24 13:15:48 kls Exp $ * $Id: keys.h 1.14 2007/09/26 12:34:50 kls Exp $
*/ */
#ifndef __KEYS_H #ifndef __KEYS_H
@ -43,6 +43,7 @@ enum eKeys { // "Up" and "Down" must be the first two keys!
kVolDn, kVolDn,
kMute, kMute,
kAudio, kAudio,
kSubtitles,
kSchedule, kSchedule,
kChannels, kChannels,
kTimers, kTimers,

162
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menu.c 1.461 2007/08/24 13:15:48 kls Exp $ * $Id: menu.c 1.462 2007/10/12 14:30:29 kls Exp $
*/ */
#include "menu.h" #include "menu.h"
@ -260,6 +260,8 @@ void cMenuEditChannel::Setup(void)
Add(new cMenuEditIntItem( tr("Apid2"), &data.apids[1], 0, 0x1FFF)); Add(new cMenuEditIntItem( tr("Apid2"), &data.apids[1], 0, 0x1FFF));
Add(new cMenuEditIntItem( tr("Dpid1"), &data.dpids[0], 0, 0x1FFF)); Add(new cMenuEditIntItem( tr("Dpid1"), &data.dpids[0], 0, 0x1FFF));
Add(new cMenuEditIntItem( tr("Dpid2"), &data.dpids[1], 0, 0x1FFF)); Add(new cMenuEditIntItem( tr("Dpid2"), &data.dpids[1], 0, 0x1FFF));
Add(new cMenuEditIntItem( tr("Spid1"), &data.spids[0], 0, 0x1FFF));
Add(new cMenuEditIntItem( tr("Spid2"), &data.spids[1], 0, 0x1FFF));
Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 0x1FFF)); Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 0x1FFF));
Add(new cMenuEditCaItem( tr("CA"), &data.caids[0])); Add(new cMenuEditCaItem( tr("CA"), &data.caids[0]));
Add(new cMenuEditIntItem( tr("Sid"), &data.sid, 1, 0xFFFF)); Add(new cMenuEditIntItem( tr("Sid"), &data.sid, 1, 0xFFFF));
@ -2400,6 +2402,8 @@ class cMenuSetupDVB : public cMenuSetupBase {
private: private:
int originalNumAudioLanguages; int originalNumAudioLanguages;
int numAudioLanguages; int numAudioLanguages;
int originalNumSubtitleLanguages;
int numSubtitleLanguages;
void Setup(void); void Setup(void);
const char *videoDisplayFormatTexts[3]; const char *videoDisplayFormatTexts[3];
const char *updateChannelsTexts[6]; const char *updateChannelsTexts[6];
@ -2412,7 +2416,10 @@ cMenuSetupDVB::cMenuSetupDVB(void)
{ {
for (numAudioLanguages = 0; numAudioLanguages < I18nLanguages()->Size() && data.AudioLanguages[numAudioLanguages] >= 0; numAudioLanguages++) for (numAudioLanguages = 0; numAudioLanguages < I18nLanguages()->Size() && data.AudioLanguages[numAudioLanguages] >= 0; numAudioLanguages++)
; ;
for (numSubtitleLanguages = 0; numSubtitleLanguages < I18nLanguages()->Size() && data.SubtitleLanguages[numSubtitleLanguages] >= 0; numSubtitleLanguages++)
;
originalNumAudioLanguages = numAudioLanguages; originalNumAudioLanguages = numAudioLanguages;
originalNumSubtitleLanguages = numSubtitleLanguages;
videoDisplayFormatTexts[0] = tr("pan&scan"); videoDisplayFormatTexts[0] = tr("pan&scan");
videoDisplayFormatTexts[1] = tr("letterbox"); videoDisplayFormatTexts[1] = tr("letterbox");
videoDisplayFormatTexts[2] = tr("center cut out"); videoDisplayFormatTexts[2] = tr("center cut out");
@ -2442,6 +2449,15 @@ void cMenuSetupDVB::Setup(void)
Add(new cMenuEditIntItem( tr("Setup.DVB$Audio languages"), &numAudioLanguages, 0, I18nLanguages()->Size())); Add(new cMenuEditIntItem( tr("Setup.DVB$Audio languages"), &numAudioLanguages, 0, I18nLanguages()->Size()));
for (int i = 0; i < numAudioLanguages; i++) for (int i = 0; i < numAudioLanguages; i++)
Add(new cMenuEditStraItem(tr("Setup.DVB$Audio language"), &data.AudioLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0))); Add(new cMenuEditStraItem(tr("Setup.DVB$Audio language"), &data.AudioLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0)));
Add(new cMenuEditBoolItem(tr("Setup.DVB$Display subtitles"), &data.DisplaySubtitles));
if (data.DisplaySubtitles) {
Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle languages"), &numSubtitleLanguages, 0, I18nLanguages()->Size()));
for (int i = 0; i < numSubtitleLanguages; i++)
Add(new cMenuEditStraItem(tr("Setup.DVB$Subtitle language"), &data.SubtitleLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0)));
Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle offset"), &data.SubtitleOffset, -50, 50));
Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle foreground transparency"), &data.SubtitleFgTransparency, 0, 9));
Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle background transparency"), &data.SubtitleBgTransparency, 0, 10));
}
SetCurrent(Get(current)); SetCurrent(Get(current));
Display(); Display();
@ -2453,11 +2469,15 @@ eOSState cMenuSetupDVB::ProcessKey(eKeys Key)
int oldVideoDisplayFormat = ::Setup.VideoDisplayFormat; int oldVideoDisplayFormat = ::Setup.VideoDisplayFormat;
bool oldVideoFormat = ::Setup.VideoFormat; bool oldVideoFormat = ::Setup.VideoFormat;
bool newVideoFormat = data.VideoFormat; bool newVideoFormat = data.VideoFormat;
bool oldDisplaySubtitles = ::Setup.DisplaySubtitles;
bool newDisplaySubtitles = data.DisplaySubtitles;
int oldnumAudioLanguages = numAudioLanguages; int oldnumAudioLanguages = numAudioLanguages;
int oldnumSubtitleLanguages = numSubtitleLanguages;
eOSState state = cMenuSetupBase::ProcessKey(Key); eOSState state = cMenuSetupBase::ProcessKey(Key);
if (Key != kNone) { if (Key != kNone) {
bool DoSetup = data.VideoFormat != newVideoFormat; bool DoSetup = data.VideoFormat != newVideoFormat;
DoSetup |= data.DisplaySubtitles != newDisplaySubtitles;
if (numAudioLanguages != oldnumAudioLanguages) { if (numAudioLanguages != oldnumAudioLanguages) {
for (int i = oldnumAudioLanguages; i < numAudioLanguages; i++) { for (int i = oldnumAudioLanguages; i < numAudioLanguages; i++) {
data.AudioLanguages[i] = 0; data.AudioLanguages[i] = 0;
@ -2476,6 +2496,24 @@ eOSState cMenuSetupDVB::ProcessKey(eKeys Key)
data.AudioLanguages[numAudioLanguages] = -1; data.AudioLanguages[numAudioLanguages] = -1;
DoSetup = true; DoSetup = true;
} }
if (numSubtitleLanguages != oldnumSubtitleLanguages) {
for (int i = oldnumSubtitleLanguages; i < numSubtitleLanguages; i++) {
data.SubtitleLanguages[i] = 0;
for (int l = 0; l < I18nLanguages()->Size(); l++) {
int k;
for (k = 0; k < oldnumSubtitleLanguages; k++) {
if (data.SubtitleLanguages[k] == l)
break;
}
if (k >= oldnumSubtitleLanguages) {
data.SubtitleLanguages[i] = l;
break;
}
}
}
data.SubtitleLanguages[numSubtitleLanguages] = -1;
DoSetup = true;
}
if (DoSetup) if (DoSetup)
Setup(); Setup();
} }
@ -2486,6 +2524,9 @@ eOSState cMenuSetupDVB::ProcessKey(eKeys Key)
cDevice::PrimaryDevice()->SetVideoDisplayFormat(eVideoDisplayFormat(::Setup.VideoDisplayFormat)); cDevice::PrimaryDevice()->SetVideoDisplayFormat(eVideoDisplayFormat(::Setup.VideoDisplayFormat));
if (::Setup.VideoFormat != oldVideoFormat) if (::Setup.VideoFormat != oldVideoFormat)
cDevice::PrimaryDevice()->SetVideoFormat(::Setup.VideoFormat); cDevice::PrimaryDevice()->SetVideoFormat(::Setup.VideoFormat);
if (::Setup.DisplaySubtitles != oldDisplaySubtitles)
cDevice::PrimaryDevice()->EnsureSubtitleTrack();
cDvbSubtitleConverter::SetupChanged();
} }
return state; return state;
} }
@ -3128,14 +3169,18 @@ static void SetTrackDescriptions(int LiveChannel)
if (Components) { if (Components) {
int indexAudio = 0; int indexAudio = 0;
int indexDolby = 0; int indexDolby = 0;
int indexSubtitle = 0;
for (int i = 0; i < Components->NumComponents(); i++) { for (int i = 0; i < Components->NumComponents(); i++) {
const tComponent *p = Components->Component(i); const tComponent *p = Components->Component(i);
if (p->stream == 2) { switch (p->stream) {
if (p->type == 0x05) case 2: if (p->type == 0x05)
cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, LiveChannel ? NULL : p->language, p->description); cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, LiveChannel ? NULL : p->language, p->description);
else else
cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, indexAudio++, 0, LiveChannel ? NULL : p->language, p->description); cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, indexAudio++, 0, LiveChannel ? NULL : p->language, p->description);
} break;
case 3: cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, indexSubtitle++, 0, LiveChannel ? NULL : p->language, p->description);
break;
}
} }
} }
} }
@ -3491,7 +3536,7 @@ cDisplayTracks::cDisplayTracks(void)
numTracks++; numTracks++;
} }
} }
descriptions[numTracks] = 0; descriptions[numTracks] = NULL;
timeout.Set(TRACKTIMEOUT); timeout.Set(TRACKTIMEOUT);
displayTracks = Skins.Current()->DisplayTracks(tr("Button$Audio"), numTracks, descriptions); displayTracks = Skins.Current()->DisplayTracks(tr("Button$Audio"), numTracks, descriptions);
Show(); Show();
@ -3569,7 +3614,7 @@ eOSState cDisplayTracks::ProcessKey(eKeys Key)
timeout.Set(TRACKTIMEOUT); timeout.Set(TRACKTIMEOUT);
break; break;
case kOk: case kOk:
if (track != cDevice::PrimaryDevice()->GetCurrentAudioTrack()) if (types[track] != cDevice::PrimaryDevice()->GetCurrentAudioTrack())
oldTrack = -1; // make sure we explicitly switch to that track oldTrack = -1; // make sure we explicitly switch to that track
timeout.Set(); timeout.Set();
break; break;
@ -3588,6 +3633,105 @@ eOSState cDisplayTracks::ProcessKey(eKeys Key)
return timeout.TimedOut() ? osEnd : osContinue; return timeout.TimedOut() ? osEnd : osContinue;
} }
// --- cDisplaySubtitleTracks ------------------------------------------------
cDisplaySubtitleTracks *cDisplaySubtitleTracks::currentDisplayTracks = NULL;
cDisplaySubtitleTracks::cDisplaySubtitleTracks(void)
:cOsdObject(true)
{
SetTrackDescriptions(!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring() ? cDevice::CurrentChannel() : 0);
currentDisplayTracks = this;
numTracks = track = 0;
types[numTracks] = ttNone;
descriptions[numTracks] = strdup(tr("No subtitles"));
numTracks++;
eTrackType CurrentSubtitleTrack = cDevice::PrimaryDevice()->GetCurrentSubtitleTrack();
for (int i = ttSubtitleFirst; i <= ttSubtitleLast; 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 == CurrentSubtitleTrack)
track = numTracks;
numTracks++;
}
}
descriptions[numTracks] = NULL;
timeout.Set(TRACKTIMEOUT);
displayTracks = Skins.Current()->DisplayTracks(tr("Button$Subtitles"), numTracks, descriptions);
Show();
}
cDisplaySubtitleTracks::~cDisplaySubtitleTracks()
{
delete displayTracks;
currentDisplayTracks = NULL;
for (int i = 0; i < numTracks; i++)
free(descriptions[i]);
cStatus::MsgOsdClear();
}
void cDisplaySubtitleTracks::Show(void)
{
displayTracks->SetTrack(track, descriptions);
displayTracks->Flush();
//cStatus::MsgSetSubtitleTrack(track, descriptions); //TODO better make a more general cStatus::MsgSetTrack(tr("Subtitles"), track, descriptions)
}
cDisplaySubtitleTracks *cDisplaySubtitleTracks::Create(void)
{
if (cDevice::PrimaryDevice()->NumSubtitleTracks() > 0) {
if (!currentDisplayTracks)
new cDisplaySubtitleTracks;
return currentDisplayTracks;
}
Skins.Message(mtWarning, tr("No subtitles available!"));
return NULL;
}
void cDisplaySubtitleTracks::Process(eKeys Key)
{
if (currentDisplayTracks)
currentDisplayTracks->ProcessKey(Key);
}
eOSState cDisplaySubtitleTracks::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 kSubtitles|k_Repeat:
case kSubtitles:
if (++track >= numTracks)
track = 0;
timeout.Set(TRACKTIMEOUT);
break;
case kOk:
if (types[track] != cDevice::PrimaryDevice()->GetCurrentSubtitleTrack())
oldTrack = -1; // make sure we explicitly switch to that track
timeout.Set();
break;
case kNone: break;
default: if ((Key & k_Release) == 0)
return osEnd;
}
if (track != oldTrack) {
Show();
cDevice::PrimaryDevice()->SetCurrentSubtitleTrack(types[track], true);
}
return timeout.TimedOut() ? osEnd : osContinue;
}
// --- cRecordControl -------------------------------------------------------- // --- cRecordControl --------------------------------------------------------
cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause) cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause)

20
menu.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menu.h 1.88 2007/08/12 10:35:42 kls Exp $ * $Id: menu.h 1.89 2007/09/26 14:35:57 kls Exp $
*/ */
#ifndef __MENU_H #ifndef __MENU_H
@ -128,6 +128,24 @@ public:
eOSState ProcessKey(eKeys Key); eOSState ProcessKey(eKeys Key);
}; };
class cDisplaySubtitleTracks : public cOsdObject {
private:
cSkinDisplayTracks *displayTracks;
cTimeMs timeout;
eTrackType types[ttMaxTrackTypes];
char *descriptions[ttMaxTrackTypes + 1]; // list is NULL terminated
int numTracks, track;
static cDisplaySubtitleTracks *currentDisplayTracks;
virtual void Show(void);
cDisplaySubtitleTracks(void);
public:
virtual ~cDisplaySubtitleTracks();
static bool IsOpen(void) { return currentDisplayTracks != NULL; }
static cDisplaySubtitleTracks *Create(void);
static void Process(eKeys Key);
eOSState ProcessKey(eKeys Key);
};
cOsdObject *CamControl(void); cOsdObject *CamControl(void);
class cMenuRecordingItem; class cMenuRecordingItem;

106
osd.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: osd.c 1.74 2007/08/26 09:44:50 kls Exp $ * $Id: osd.c 1.75 2007/10/12 12:38:36 kls Exp $
*/ */
#include "osd.h" #include "osd.h"
@ -82,7 +82,7 @@ void cPalette::SetColor(int Index, tColor Color)
} }
} }
const tColor *cPalette::Colors(int &NumColors) const tColor *cPalette::Colors(int &NumColors) const
{ {
NumColors = numColors; NumColors = numColors;
return numColors ? color : NULL; return numColors ? color : NULL;
@ -112,7 +112,7 @@ void cPalette::Replace(const cPalette &Palette)
antiAliasGranularity = Palette.antiAliasGranularity; antiAliasGranularity = Palette.antiAliasGranularity;
} }
tColor cPalette::Blend(tColor ColorFg, tColor ColorBg, uint8_t Level) tColor cPalette::Blend(tColor ColorFg, tColor ColorBg, uint8_t Level) const
{ {
if (antiAliasGranularity > 0) if (antiAliasGranularity > 0)
Level = uint8_t(int(Level / antiAliasGranularity + 0.5) * antiAliasGranularity); Level = uint8_t(int(Level / antiAliasGranularity + 0.5) * antiAliasGranularity);
@ -131,7 +131,7 @@ tColor cPalette::Blend(tColor ColorFg, tColor ColorBg, uint8_t Level)
return (A << 24) | (R << 16) | (G << 8) | B; return (A << 24) | (R << 16) | (G << 8) | B;
} }
int cPalette::ClosestColor(tColor Color, int MaxDiff) int cPalette::ClosestColor(tColor Color, int MaxDiff) const
{ {
int n = 0; int n = 0;
int d = INT_MAX; int d = INT_MAX;
@ -640,6 +640,79 @@ const tIndex *cBitmap::Data(int x, int y)
return &bitmap[y * width + x]; return &bitmap[y * width + x];
} }
void cBitmap::ReduceBpp(const cPalette &Palette)
{
int NewBpp = Palette.Bpp();
if (Bpp() == 4 && NewBpp == 2) {
for (int i = width * height; i--; ) {
tIndex p = bitmap[i];
bitmap[i] = (p >> 2) | ((p & 0x03) != 0);
}
}
else if (Bpp() == 8) {
if (NewBpp == 2) {
for (int i = width * height; i--; ) {
tIndex p = bitmap[i];
bitmap[i] = (p >> 6) | ((p & 0x30) != 0);
}
}
else if (NewBpp == 4) {
for (int i = width * height; i--; ) {
tIndex p = bitmap[i];
bitmap[i] = p >> 4;
}
}
else
return;
}
else
return;
SetBpp(NewBpp);
Replace(Palette);
}
void cBitmap::ShrinkBpp(int NewBpp)
{
int NumOldColors;
const tColor *Colors = this->Colors(NumOldColors);
if (Colors) {
// Find the most frequently used colors and create a map table:
int Used[MAXNUMCOLORS] = { 0 };
int Map[MAXNUMCOLORS] = { 0 };
for (int i = width * height; i--; )
Used[bitmap[i]]++;
int MaxNewColors = (NewBpp == 4) ? 16 : 4;
cPalette NewPalette(NewBpp);
for (int i = 0; i < MaxNewColors; i++) {
int Max = 0;
int Index = -1;
for (int n = 0; n < NumOldColors; n++) {
if (Used[n] > Max) {
Max = Used[n];
Index = n;
}
}
if (Index >= 0) {
Used[Index] = 0;
Map[Index] = i;
NewPalette.SetColor(i, Colors[Index]);
}
else
break;
}
// Complete the map table for all other colors (will be set to closest match):
for (int n = 0; n < NumOldColors; n++) {
if (Used[n])
Map[n] = NewPalette.Index(Colors[n]);
}
// Do the actual index mapping:
for (int i = width * height; i--; )
bitmap[i] = Map[bitmap[i]];
SetBpp(NewBpp);
Replace(NewPalette);
}
}
// --- cOsd ------------------------------------------------------------------ // --- cOsd ------------------------------------------------------------------
int cOsd::osdLeft = 0; int cOsd::osdLeft = 0;
@ -720,19 +793,18 @@ eOsdError cOsd::CanHandleAreas(const tArea *Areas, int NumAreas)
eOsdError cOsd::SetAreas(const tArea *Areas, int NumAreas) eOsdError cOsd::SetAreas(const tArea *Areas, int NumAreas)
{ {
eOsdError Result = oeUnknown; eOsdError Result = CanHandleAreas(Areas, NumAreas);
if (numBitmaps == 0) { if (Result == oeOk) {
Result = CanHandleAreas(Areas, NumAreas); while (numBitmaps)
if (Result == oeOk) { delete bitmaps[--numBitmaps];
width = height = 0; width = height = 0;
for (int i = 0; i < NumAreas; i++) { for (int i = 0; i < NumAreas; i++) {
bitmaps[numBitmaps++] = new cBitmap(Areas[i].Width(), Areas[i].Height(), Areas[i].bpp, Areas[i].x1, Areas[i].y1); bitmaps[numBitmaps++] = new cBitmap(Areas[i].Width(), Areas[i].Height(), Areas[i].bpp, Areas[i].x1, Areas[i].y1);
width = max(width, Areas[i].x2 + 1); width = max(width, Areas[i].x2 + 1);
height = max(height, Areas[i].y2 + 1); height = max(height, Areas[i].y2 + 1);
} }
}
} }
if (Result != oeOk) else
esyslog("ERROR: cOsd::SetAreas returned %d", Result); esyslog("ERROR: cOsd::SetAreas returned %d", Result);
return Result; return Result;
} }
@ -818,7 +890,7 @@ cOsdProvider::~cOsdProvider()
cOsd *cOsdProvider::NewOsd(int Left, int Top, uint Level) cOsd *cOsdProvider::NewOsd(int Left, int Top, uint Level)
{ {
if (Level == 0 && cOsd::IsOpen()) if (Level == OSD_LEVEL_DEFAULT && cOsd::IsOpen())
esyslog("ERROR: attempt to open OSD while it is already open - using dummy OSD!"); esyslog("ERROR: attempt to open OSD while it is already open - using dummy OSD!");
else if (osdProvider) { else if (osdProvider) {
cOsd *ActiveOsd = cOsd::Osds.Size() ? cOsd::Osds[0] : NULL; cOsd *ActiveOsd = cOsd::Osds.Size() ? cOsd::Osds[0] : NULL;

33
osd.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: osd.h 1.57 2007/08/26 09:45:38 kls Exp $ * $Id: osd.h 1.58 2007/10/12 14:28:44 kls Exp $
*/ */
#ifndef __OSD_H #ifndef __OSD_H
@ -17,6 +17,9 @@
#include "font.h" #include "font.h"
#include "tools.h" #include "tools.h"
#define OSD_LEVEL_DEFAULT 0
#define OSD_LEVEL_SUBTITLES 10
#define MAXNUMCOLORS 256 #define MAXNUMCOLORS 256
enum { enum {
@ -69,7 +72,7 @@ public:
///< a single color combination, and may not be able to serve all ///< a single color combination, and may not be able to serve all
///< requested colors. By default the palette assumes there will be ///< requested colors. By default the palette assumes there will be
///< 10 fixed colors and 10 color combinations. ///< 10 fixed colors and 10 color combinations.
int Bpp(void) { return bpp; } int Bpp(void) const { return bpp; }
void Reset(void); void Reset(void);
///< Resets the palette, making it contain no colors. ///< Resets the palette, making it contain no colors.
int Index(tColor Color); int Index(tColor Color);
@ -77,7 +80,7 @@ public:
///< If Color is not yet contained in this palette, it will be added if ///< If Color is not yet contained in this palette, it will be added if
///< there is a free slot. If the color can't be added to this palette, ///< there is a free slot. If the color can't be added to this palette,
///< the closest existing color will be returned. ///< the closest existing color will be returned.
tColor Color(int Index) { return Index < maxColors ? color[Index] : 0; } tColor Color(int Index) const { return Index < maxColors ? color[Index] : 0; }
///< Returns the color at the given Index. If Index is outside the valid ///< Returns the color at the given Index. If Index is outside the valid
///< range, 0 will be returned. ///< range, 0 will be returned.
void SetBpp(int Bpp); void SetBpp(int Bpp);
@ -87,7 +90,7 @@ public:
///< Sets the palette entry at Index to Color. If Index is larger than ///< Sets the palette entry at Index to Color. If Index is larger than
///< the number of currently used entries in this palette, the entries ///< the number of currently used entries in this palette, the entries
///< in between will have undefined values. ///< in between will have undefined values.
const tColor *Colors(int &NumColors); const tColor *Colors(int &NumColors) const;
///< Returns a pointer to the complete color table and stores the ///< Returns a pointer to the complete color table and stores the
///< number of valid entries in NumColors. If no colors have been ///< number of valid entries in NumColors. If no colors have been
///< stored yet, NumColors will be set to 0 and the function will ///< stored yet, NumColors will be set to 0 and the function will
@ -102,14 +105,14 @@ public:
void Replace(const cPalette &Palette); void Replace(const cPalette &Palette);
///< Replaces the colors of this palette with the colors from the given ///< Replaces the colors of this palette with the colors from the given
///< palette. ///< palette.
tColor Blend(tColor ColorFg, tColor ColorBg, uint8_t Level); tColor Blend(tColor ColorFg, tColor ColorBg, uint8_t Level) const;
///< Determines a color that consists of a linear blend between ColorFg ///< Determines a color that consists of a linear blend between ColorFg
///< and ColorBg. If Level is 0, the result is ColorBg, if it is 255, ///< and ColorBg. If Level is 0, the result is ColorBg, if it is 255,
///< the result is ColorFg. If SetAntiAliasGranularity() has been called previously, ///< the result is ColorFg. If SetAntiAliasGranularity() has been called previously,
///< Level will be mapped to a limited range of levels that allow to make best ///< Level will be mapped to a limited range of levels that allow to make best
///< use of the palette entries. ///< use of the palette entries.
int ClosestColor(tColor Color, int MaxDiff = INT_MAX); int ClosestColor(tColor Color, int MaxDiff = INT_MAX) const;
///< Returns the index of a color in this paltte that is closest to the given ///< Returns the index of a color in this palette that is closest to the given
///< Color. MaxDiff can be used to control the maximum allowed color difference. ///< Color. MaxDiff can be used to control the maximum allowed color difference.
///< If no color with a maximum difference of MaxDiff can be found, -1 will ///< If no color with a maximum difference of MaxDiff can be found, -1 will
///< be returned. With the default value of INT_MAX, there will always be ///< be returned. With the default value of INT_MAX, there will always be
@ -232,6 +235,17 @@ public:
///< Returns the address of the index byte at the given coordinates. ///< Returns the address of the index byte at the given coordinates.
tColor GetColor(int x, int y) { return Color(*Data(x, y)); } tColor GetColor(int x, int y) { return Color(*Data(x, y)); }
///< Returns the color at the given coordinates. ///< Returns the color at the given coordinates.
void ReduceBpp(const cPalette &Palette);
///< Reduces the color depth of the bitmap to that of the given Palette.
///< If Palette's color depth is not smaller than the bitmap's current
///< color depth, or if it is not one of 4bpp or 2bpp, nothing happens. After
///< reducing the color depth the current palette is replaced with
///< the given one.
void ShrinkBpp(int NewBpp);
///< Shrinks the color depth of the bitmap to NewBpp by keeping only
///< the 2^NewBpp most frequently used colors as defined in the current palette.
///< If NewBpp is not smaller than the bitmap's current color depth,
///< or if it is not one of 4bpp or 2bpp, nothing happens.
}; };
struct tArea { struct tArea {
@ -292,7 +306,7 @@ public:
///< This may be useful for plugins that determine the scaling of the ///< This may be useful for plugins that determine the scaling of the
///< video image and need to scale the OSD accordingly to fit on the ///< video image and need to scale the OSD accordingly to fit on the
///< screen. ///< screen.
static int IsOpen(void) { return Osds.Size() && Osds[0]->level == 0; } static int IsOpen(void) { return Osds.Size() && Osds[0]->level == OSD_LEVEL_DEFAULT; }
///< Returns true if there is currently a level 0 OSD open. ///< Returns true if there is currently a level 0 OSD open.
int Left(void) { return left; } int Left(void) { return left; }
int Top(void) { return top; } int Top(void) { return top; }
@ -327,6 +341,7 @@ public:
///< If the OSD has been divided into several sub-areas, all areas that ///< If the OSD has been divided into several sub-areas, all areas that
///< are part of the rectangle that surrounds a given drawing operation ///< are part of the rectangle that surrounds a given drawing operation
///< will be drawn into, with the proper offsets. ///< will be drawn into, with the proper offsets.
///< A new call overwrites any previous settings
virtual void SaveRegion(int x1, int y1, int x2, int y2); virtual void SaveRegion(int x1, int y1, int x2, int y2);
///< Saves the region defined by the given coordinates for later restoration ///< Saves the region defined by the given coordinates for later restoration
///< through RestoreRegion(). Only one saved region can be active at any ///< through RestoreRegion(). Only one saved region can be active at any
@ -398,7 +413,7 @@ public:
cOsdProvider(void); cOsdProvider(void);
//XXX maybe parameter to make this one "sticky"??? (frame-buffer etc.) //XXX maybe parameter to make this one "sticky"??? (frame-buffer etc.)
virtual ~cOsdProvider(); virtual ~cOsdProvider();
static cOsd *NewOsd(int Left, int Top, uint Level = 0); static cOsd *NewOsd(int Left, int Top, uint Level = OSD_LEVEL_DEFAULT);
///< Returns a pointer to a newly created cOsd object, which will be located ///< Returns a pointer to a newly created cOsd object, which will be located
///< at the given coordinates. When the cOsd object is no longer needed, the ///< at the given coordinates. When the cOsd object is no longer needed, the
///< caller must delete it. If the OSD is already in use, or there is no OSD ///< caller must delete it. If the OSD is already in use, or there is no OSD

27
pat.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: pat.c 1.17 2007/01/07 14:41:55 kls Exp $ * $Id: pat.c 1.18 2007/09/02 10:44:19 kls Exp $
*/ */
#include "pat.h" #include "pat.h"
@ -331,11 +331,14 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
int Ppid = pmt.getPCRPid(); int Ppid = pmt.getPCRPid();
int Apids[MAXAPIDS + 1] = { 0 }; // these lists are zero-terminated int Apids[MAXAPIDS + 1] = { 0 }; // these lists are zero-terminated
int Dpids[MAXDPIDS + 1] = { 0 }; int Dpids[MAXDPIDS + 1] = { 0 };
int Spids[MAXSPIDS + 1] = { 0 };
char ALangs[MAXAPIDS][MAXLANGCODE2] = { "" }; char ALangs[MAXAPIDS][MAXLANGCODE2] = { "" };
char DLangs[MAXDPIDS][MAXLANGCODE2] = { "" }; char DLangs[MAXDPIDS][MAXLANGCODE2] = { "" };
char SLangs[MAXSPIDS][MAXLANGCODE2] = { "" };
int Tpid = 0; int Tpid = 0;
int NumApids = 0; int NumApids = 0;
int NumDpids = 0; int NumDpids = 0;
int NumSpids = 0;
for (SI::Loop::Iterator it; pmt.streamLoop.getNext(stream, it); ) { for (SI::Loop::Iterator it; pmt.streamLoop.getNext(stream, it); ) {
switch (stream.getStreamType()) { switch (stream.getStreamType()) {
case 1: // STREAMTYPE_11172_VIDEO case 1: // STREAMTYPE_11172_VIDEO
@ -387,6 +390,26 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
case SI::AC3DescriptorTag: case SI::AC3DescriptorTag:
dpid = stream.getPid(); dpid = stream.getPid();
break; break;
case SI::SubtitlingDescriptorTag:
if (NumSpids < MAXSPIDS) {
Spids[NumSpids] = stream.getPid();
SI::SubtitlingDescriptor *sd = (SI::SubtitlingDescriptor *)d;
SI::SubtitlingDescriptor::Subtitling sub;
char *s = SLangs[NumSpids];
int n = 0;
for (SI::Loop::Iterator it; sd->subtitlingLoop.getNext(sub, it); ) {
if (sub.languageCode[0]) {
if (n > 0)
*s++ = '+';
strn0cpy(s, I18nNormalizeLanguageCode(sub.languageCode), MAXLANGCODE1);
s += strlen(s);
if (n++ > 1)
break;
}
}
NumSpids++;
}
break;
case SI::TeletextDescriptorTag: case SI::TeletextDescriptorTag:
Tpid = stream.getPid(); Tpid = stream.getPid();
break; break;
@ -416,7 +439,7 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
} }
} }
if (Setup.UpdateChannels >= 2) { if (Setup.UpdateChannels >= 2) {
Channel->SetPids(Vpid, Vpid ? Ppid : 0, Apids, ALangs, Dpids, DLangs, Tpid); Channel->SetPids(Vpid, Vpid ? Ppid : 0, Apids, ALangs, Dpids, DLangs, Spids, SLangs, Tpid);
Channel->SetCaIds(CaDescriptors->CaIds()); Channel->SetCaIds(CaDescriptors->CaIds());
} }
Channel->SetCaDescriptors(CaDescriptorHandler.AddCaDescriptors(CaDescriptors)); Channel->SetCaDescriptors(CaDescriptorHandler.AddCaDescriptors(CaDescriptors));

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: recording.c 1.154 2007/06/17 13:10:12 kls Exp $ * $Id: recording.c 1.155 2007/10/12 14:48:20 kls Exp $
*/ */
#include "recording.h" #include "recording.h"
@ -296,6 +296,17 @@ cRecordingInfo::cRecordingInfo(const cChannel *Channel, const cEvent *Event)
strn0cpy(Component->language, s, sizeof(Component->language)); strn0cpy(Component->language, s, sizeof(Component->language));
} }
} }
// The same applies to subtitles:
for (int i = 0; i < MAXSPIDS; i++) {
const char *s = Channel->Slang(i);
if (*s) {
tComponent *Component = Components->GetComponent(i, 3, 3);
if (!Component)
Components->SetComponent(Components->NumComponents(), 3, 3, s, NULL);
else if (strlen(s) > strlen(Component->language))
strn0cpy(Component->language, s, sizeof(Component->language));
}
}
if (Components != event->Components()) if (Components != event->Components())
((cEvent *)event)->SetComponents(Components); ((cEvent *)event)->SetComponents(Components);
} }

30
remux.c
View File

@ -11,7 +11,7 @@
* The cRepacker family's code was originally written by Reinhard Nissl <rnissl@gmx.de>, * The cRepacker family's code was originally written by Reinhard Nissl <rnissl@gmx.de>,
* and adapted to the VDR coding style by Klaus.Schmidinger@cadsoft.de. * and adapted to the VDR coding style by Klaus.Schmidinger@cadsoft.de.
* *
* $Id: remux.c 1.58 2007/02/24 16:36:10 kls Exp $ * $Id: remux.c 1.59 2007/09/22 12:08:22 kls Exp $
*/ */
#include "remux.h" #include "remux.h"
@ -1555,6 +1555,13 @@ void cTS2PES::send_ipack(void)
buf[7] = 0x00; buf[7] = 0x00;
buf[8] = 0x00; buf[8] = 0x00;
count = 9; count = 9;
if (!repacker && subStreamId) {
buf[9] = subStreamId;
buf[10] = 1;
buf[11] = 0;
buf[12] = 1;
count = 13;
}
break; break;
case 1: case 1:
buf[6] = 0x0F; buf[6] = 0x0F;
@ -1766,6 +1773,19 @@ void cTS2PES::instant_repack(const uint8_t *Buf, int Count)
return; return;
} }
if (!repacker && subStreamId) {
while (c < Count && found < (hlength + 9) && found < plength + 6) {
write_ipack(Buf + c, 1);
c++;
found++;
}
if (found == (hlength + 9)) {
uchar sbuf[] = { 0x01, 0x00, 0x00 };
write_ipack(&subStreamId, 1);
write_ipack(sbuf, 3);
}
}
while (c < Count && found < plength + 6) { while (c < Count && found < plength + 6) {
int l = Count - c; int l = Count - c;
if (l + found > plength + 6) if (l + found > plength + 6)
@ -1856,7 +1876,7 @@ void cTS2PES::ts_to_pes(const uint8_t *Buf) // don't need count (=188)
cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure) cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure)
{ {
exitOnFailure = ExitOnFailure; exitOnFailure = ExitOnFailure;
isRadio = VPid == 0 || VPid == 1 || VPid == 0x1FFF; noVideo = VPid == 0 || VPid == 1 || VPid == 0x1FFF;
numUPTerrors = 0; numUPTerrors = 0;
synced = false; synced = false;
skipped = 0; skipped = 0;
@ -1888,13 +1908,11 @@ cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, b
while (*DPids && numTracks < MAXTRACKS && n < MAXDPIDS) while (*DPids && numTracks < MAXTRACKS && n < MAXDPIDS)
ts2pes[numTracks++] = new cTS2PES(*DPids++, resultBuffer, IPACKS, 0x00, 0x80 + n++, new cDolbyRepacker); ts2pes[numTracks++] = new cTS2PES(*DPids++, resultBuffer, IPACKS, 0x00, 0x80 + n++, new cDolbyRepacker);
} }
/* future...
if (SPids) { if (SPids) {
int n = 0; int n = 0;
while (*SPids && numTracks < MAXTRACKS && n < MAXSPIDS) while (*SPids && numTracks < MAXTRACKS && n < MAXSPIDS)
ts2pes[numTracks++] = new cTS2PES(*SPids++, resultBuffer, IPACKS, 0x00, 0x28 + n++); ts2pes[numTracks++] = new cTS2PES(*SPids++, resultBuffer, IPACKS, 0x00, 0x20 + n++);
} }
*/
} }
cRemux::~cRemux() cRemux::~cRemux()
@ -2080,7 +2098,7 @@ uchar *cRemux::Get(int &Count, uchar *PictureType)
l = GetPacketLength(data, resultCount, i); l = GetPacketLength(data, resultCount, i);
if (l < 0) if (l < 0)
return resultData; return resultData;
if (isRadio) { if (noVideo) {
if (!synced) { if (!synced) {
if (PictureType) if (PictureType)
*PictureType = I_FRAME; *PictureType = I_FRAME;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: remux.h 1.16 2006/03/25 12:27:30 kls Exp $ * $Id: remux.h 1.17 2007/09/02 10:19:06 kls Exp $
*/ */
#ifndef __REMUX_H #ifndef __REMUX_H
@ -37,7 +37,7 @@ class cTS2PES;
class cRemux { class cRemux {
private: private:
bool exitOnFailure; bool exitOnFailure;
bool isRadio; bool noVideo;
int numUPTerrors; int numUPTerrors;
bool synced; bool synced;
int skipped; int skipped;

6
vdr.5
View File

@ -8,7 +8,7 @@
.\" License as specified in the file COPYING that comes with the .\" License as specified in the file COPYING that comes with the
.\" vdr distribution. .\" vdr distribution.
.\" .\"
.\" $Id: vdr.5 1.63 2007/08/05 12:58:35 kls Exp $ .\" $Id: vdr.5 1.64 2007/09/26 10:57:08 kls Exp $
.\" .\"
.TH vdr 5 "07 Jan 2007" "1.4.5" "Video Disk Recorder Files" .TH vdr 5 "07 Jan 2007" "1.4.5" "Video Disk Recorder Files"
.SH NAME .SH NAME
@ -557,6 +557,8 @@ a recording is split into several files. The contents of these files is
0xC0...0xDF for audio 1...32 (up to 32 audio tracks may occur). 0xC0...0xDF for audio 1...32 (up to 32 audio tracks may occur).
Dolby Digital data is stored in packets with ids 0xBD ("Private Stream 1") Dolby Digital data is stored in packets with ids 0xBD ("Private Stream 1")
and substream ids 0x80...0x87. and substream ids 0x80...0x87.
DVB subtitle data is stored in packets with ids 0xBD ("Private Stream 1")
and substream ids 0x20...0x27.
.SS INDEX .SS INDEX
The file \fIindex.vdr\fR (if present in a recording directory) contains The file \fIindex.vdr\fR (if present in a recording directory) contains
the (binary) index data into each of the the recording files the (binary) index data into each of the the recording files
@ -646,7 +648,7 @@ l l.
<title> @is the title of the event <title> @is the title of the event
<short text> @is the short text of the event (typically the name of the episode etc.) <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) <description> @is the description of the event (any '|' characters will be interpreted as newlines)
<stream> @is the stream content (1 = video, 2 = audio) <stream> @is the stream content (1 = video, 2 = audio, 3 = subtitles)
<type> @is the stream type according to ETSI EN 300 468 <type> @is the stream type according to ETSI EN 300 468
<language> @is the three letter language code (optionally two codes, separated by '+') <language> @is the three letter language code (optionally two codes, separated by '+')
<descr> @is the description of this stream component <descr> @is the description of this stream component

14
vdr.c
View File

@ -22,7 +22,7 @@
* *
* The project's page is at http://www.cadsoft.de/vdr * The project's page is at http://www.cadsoft.de/vdr
* *
* $Id: vdr.c 1.299 2007/08/25 08:51:13 kls Exp $ * $Id: vdr.c 1.300 2007/09/26 14:36:48 kls Exp $
*/ */
#include <getopt.h> #include <getopt.h>
@ -1009,6 +1009,18 @@ int main(int argc, char *argv[])
cDisplayTracks::Process(key); cDisplayTracks::Process(key);
key = kNone; key = kNone;
break; break;
// Subtitle track control:
case kSubtitles:
if (cControl::Control())
cControl::Control()->Hide();
if (!cDisplaySubtitleTracks::IsOpen()) {
DELETE_MENU;
Menu = cDisplaySubtitleTracks::Create();
}
else
cDisplaySubtitleTracks::Process(key);
key = kNone;
break;
// Pausing live video: // Pausing live video:
case kPause: case kPause:
if (!cControl::Control()) { if (!cControl::Control()) {