mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Implemented handling DVB subtitles
This commit is contained in:
parent
3a4b7f065c
commit
0c8cda9bd0
@ -1024,6 +1024,8 @@ Rolf Ahrenberg <rahrenbe@cc.hut.fi>
|
||||
for improving cControl::Launch() to keep 'control' from pointing to uninitialized
|
||||
memory
|
||||
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>
|
||||
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>
|
||||
for adding language code handling to the subtitling descriptor in 'libsi'
|
||||
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>
|
||||
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 reporting a faulty comment in Make.config.template
|
||||
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>
|
||||
for reporting a bug in displaying the current channel when switching via the SVDRP
|
||||
|
29
HISTORY
29
HISTORY
@ -5416,3 +5416,32 @@ Video Disk Recorder Revision History
|
||||
function to hand through the Level.
|
||||
- Fixed checking for ttDolbyLast in cDevice::SetCurrentAudioTrack() (thanks
|
||||
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
26
MANUAL
@ -59,6 +59,7 @@ Version 1.4
|
||||
Mute mute
|
||||
|
||||
Audio select audio track
|
||||
Subtitles select subtitles
|
||||
|
||||
Schedule \
|
||||
Channels |
|
||||
@ -675,6 +676,31 @@ Version 1.4
|
||||
many "Audio language" options which allow you to select the
|
||||
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:
|
||||
|
||||
SLOF = 11700 The switching frequency (in MHz) between low and
|
||||
|
4
Makefile
4
Makefile
@ -4,7 +4,7 @@
|
||||
# See the main source file 'vdr.c' for copyright information and
|
||||
# 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:
|
||||
|
||||
@ -37,7 +37,7 @@ DOXYFILE = Doxyfile
|
||||
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\
|
||||
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\
|
||||
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\
|
||||
|
22
channels.c
22
channels.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* 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"
|
||||
@ -440,12 +440,12 @@ static int IntArrayToString(char *s, const int *a, int Base = 10, const char n[]
|
||||
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;
|
||||
if (vpid != Vpid || ppid != Ppid || tpid != Tpid)
|
||||
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)
|
||||
mod |= CHANNELMOD_LANGS;
|
||||
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 = 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;
|
||||
ppid = Ppid;
|
||||
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);
|
||||
}
|
||||
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;
|
||||
modification |= mod;
|
||||
Channels.SetModified();
|
||||
|
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* 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
|
||||
@ -33,7 +33,7 @@
|
||||
|
||||
#define MAXAPIDS 32 // audio
|
||||
#define MAXDPIDS 16 // dolby (AC3 + DTS)
|
||||
#define MAXSPIDS 8 // subtitles
|
||||
#define MAXSPIDS 32 // subtitles
|
||||
#define MAXCAIDS 8 // conditional access
|
||||
|
||||
#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 SetName(const char *Name, const char *ShortName, const char *Provider);
|
||||
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 SetCaDescriptors(int Level);
|
||||
void SetLinkChannels(cLinkChannels *LinkChannels);
|
||||
|
17
config.c
17
config.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* 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"
|
||||
@ -236,6 +236,11 @@ cSetup::cSetup(void)
|
||||
MarginStart = 2;
|
||||
MarginStop = 10;
|
||||
AudioLanguages[0] = -1;
|
||||
DisplaySubtitles = 0;
|
||||
SubtitleLanguages[0] = -1;
|
||||
SubtitleOffset = 0;
|
||||
SubtitleFgTransparency = 0;
|
||||
SubtitleBgTransparency = 0;
|
||||
EPGLanguages[0] = -1;
|
||||
EPGScanTimeout = 5;
|
||||
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, "MarginStop")) MarginStop = atoi(Value);
|
||||
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, "EPGScanTimeout")) EPGScanTimeout = atoi(Value);
|
||||
else if (!strcasecmp(Name, "EPGBugfixLevel")) EPGBugfixLevel = atoi(Value);
|
||||
@ -483,6 +493,11 @@ bool cSetup::Save(void)
|
||||
Store("MarginStart", MarginStart);
|
||||
Store("MarginStop", MarginStop);
|
||||
StoreLanguages("AudioLanguages", AudioLanguages);
|
||||
Store("DisplaySubtitles", DisplaySubtitles);
|
||||
StoreLanguages("SubtitleLanguages", SubtitleLanguages);
|
||||
Store("SubtitleOffset", SubtitleOffset);
|
||||
Store("SubtitleFgTransparency", SubtitleFgTransparency);
|
||||
Store("SubtitleBgTransparency", SubtitleBgTransparency);
|
||||
StoreLanguages("EPGLanguages", EPGLanguages);
|
||||
Store("EPGScanTimeout", EPGScanTimeout);
|
||||
Store("EPGBugfixLevel", EPGBugfixLevel);
|
||||
|
14
config.h
14
config.h
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: config.h 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
|
||||
@ -22,13 +22,13 @@
|
||||
|
||||
// VDR's own version number:
|
||||
|
||||
#define VDRVERSION "1.5.9"
|
||||
#define VDRVERSNUM 10509 // Version * 10000 + Major * 100 + Minor
|
||||
#define VDRVERSION "1.5.10"
|
||||
#define VDRVERSNUM 10510 // Version * 10000 + Major * 100 + Minor
|
||||
|
||||
// The plugin API's version number:
|
||||
|
||||
#define APIVERSION "1.5.9"
|
||||
#define APIVERSNUM 10509 // Version * 10000 + Major * 100 + Minor
|
||||
#define APIVERSION "1.5.10"
|
||||
#define APIVERSNUM 10510 // Version * 10000 + Major * 100 + Minor
|
||||
|
||||
// When loading plugins, VDR searches them by their APIVERSION, which
|
||||
// may be smaller than VDRVERSION in case there have been no changes to
|
||||
@ -220,6 +220,10 @@ public:
|
||||
int TimeTransponder;
|
||||
int MarginStart, MarginStop;
|
||||
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 EPGScanTimeout;
|
||||
int EPGBugfixLevel;
|
||||
|
182
device.c
182
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.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"
|
||||
@ -19,6 +19,75 @@
|
||||
#include "status.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 ---------------------------------------------------------
|
||||
|
||||
class cPesAssembler {
|
||||
@ -172,6 +241,10 @@ cDevice::cDevice(void)
|
||||
ClrAvailableTracks();
|
||||
currentAudioTrack = ttNone;
|
||||
currentAudioTrackMissingCount = 0;
|
||||
currentSubtitleTrack = ttNone;
|
||||
liveSubtitle = NULL;
|
||||
dvbSubtitleConverter = NULL;
|
||||
autoSelectPreferredSubtitleLanguage = true;
|
||||
|
||||
for (int i = 0; i < MAXRECEIVERS; i++)
|
||||
receiver[i] = NULL;
|
||||
@ -186,6 +259,8 @@ cDevice::~cDevice()
|
||||
{
|
||||
Detach(player);
|
||||
DetachAllReceivers();
|
||||
delete liveSubtitle;
|
||||
delete dvbSubtitleConverter;
|
||||
delete nitFilter;
|
||||
delete sdtFilter;
|
||||
delete patFilter;
|
||||
@ -674,8 +749,11 @@ bool cDevice::SwitchChannel(int Direction)
|
||||
|
||||
eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
|
||||
{
|
||||
if (LiveView)
|
||||
if (LiveView) {
|
||||
StopReplay();
|
||||
DELETENULL(liveSubtitle);
|
||||
DELETENULL(dvbSubtitleConverter);
|
||||
}
|
||||
|
||||
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++)
|
||||
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)
|
||||
EnsureAudioTrack(true);
|
||||
EnsureSubtitleTrack();
|
||||
}
|
||||
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
|
||||
currentAudioTrackMissingCount = 0;
|
||||
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);
|
||||
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)
|
||||
strn0cpy(availableTracks[t].language, Language, sizeof(availableTracks[t].language));
|
||||
if (Description)
|
||||
Utf8Strn0Cpy(availableTracks[t].description, Description, sizeof(availableTracks[t].description));
|
||||
if (Id) {
|
||||
availableTracks[t].id = Id; // setting 'id' last to avoid the need for extensive locking
|
||||
int numAudioTracks = NumAudioTracks();
|
||||
if (!availableTracks[currentAudioTrack].id && numAudioTracks && currentAudioTrackMissingCount++ > numAudioTracks * 10)
|
||||
EnsureAudioTrack();
|
||||
else if (t == currentAudioTrack)
|
||||
currentAudioTrackMissingCount = 0;
|
||||
if (Type == ttAudio || Type == ttDolby) {
|
||||
int numAudioTracks = NumAudioTracks();
|
||||
if (!availableTracks[currentAudioTrack].id && numAudioTracks && currentAudioTrackMissingCount++ > numAudioTracks * 10)
|
||||
EnsureAudioTrack();
|
||||
else if (t == currentAudioTrack)
|
||||
currentAudioTrackMissingCount = 0;
|
||||
}
|
||||
else if (Type == ttSubtitle && autoSelectPreferredSubtitleLanguage)
|
||||
EnsureSubtitleTrack();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -880,16 +967,26 @@ const tTrackId *cDevice::GetTrack(eTrackType Type)
|
||||
return (ttNone < Type && Type < ttMaxTrackTypes) ? &availableTracks[Type] : NULL;
|
||||
}
|
||||
|
||||
int cDevice::NumAudioTracks(void) const
|
||||
int cDevice::NumTracks(eTrackType FirstTrack, eTrackType LastTrack) const
|
||||
{
|
||||
int n = 0;
|
||||
for (int i = ttAudioFirst; i <= ttDolbyLast; i++) {
|
||||
for (int i = FirstTrack; i <= LastTrack; i++) {
|
||||
if (availableTracks[i].id)
|
||||
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)
|
||||
{
|
||||
if (ttNone < Type && Type <= ttDolbyLast) {
|
||||
@ -908,6 +1005,30 @@ bool cDevice::SetCurrentAudioTrack(eTrackType Type)
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
return HasDecoder();
|
||||
@ -961,6 +1101,8 @@ void cDevice::TrickSpeed(int Speed)
|
||||
void cDevice::Clear(void)
|
||||
{
|
||||
Audios.ClearAudio();
|
||||
if (dvbSubtitleConverter)
|
||||
dvbSubtitleConverter->Reset();
|
||||
}
|
||||
|
||||
void cDevice::Play(void)
|
||||
@ -1016,6 +1158,9 @@ void cDevice::Detach(cPlayer *Player)
|
||||
player = NULL; // avoids recursive calls to Detach()
|
||||
p->Activate(false);
|
||||
p->device = NULL;
|
||||
cMutexLock MutexLock(&mutexCurrentSubtitleTrack);
|
||||
delete dvbSubtitleConverter;
|
||||
dvbSubtitleConverter = NULL;
|
||||
SetPlayMode(pmNone);
|
||||
SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat));
|
||||
Audios.ClearAudio();
|
||||
@ -1051,6 +1196,13 @@ int cDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
|
||||
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)
|
||||
{
|
||||
cMutexLock MutexLock(&mutexCurrentAudioTrack);
|
||||
@ -1076,6 +1228,11 @@ int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly)
|
||||
break;
|
||||
case 0xBD: { // private stream 1
|
||||
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 SubStreamType = SubStreamId & 0xF0;
|
||||
uchar SubStreamIndex = SubStreamId & 0x1F;
|
||||
@ -1090,6 +1247,9 @@ pre_1_3_19_PrivateStreamDeteced:
|
||||
switch (SubStreamType) {
|
||||
case 0x20: // SPU
|
||||
case 0x30: // SPU
|
||||
SetAvailableTrack(ttSubtitle, SubStreamIndex, SubStreamId);
|
||||
if (!VideoOnly && currentSubtitleTrack != ttNone && SubStreamId == availableTracks[currentSubtitleTrack].id)
|
||||
w = PlaySubtitle(Start, d);
|
||||
break;
|
||||
case 0x80: // AC3 & DTS
|
||||
if (Setup.UseDolbyDigital) {
|
||||
@ -1139,6 +1299,8 @@ int cDevice::PlayPes(const uchar *Data, int Length, bool VideoOnly)
|
||||
{
|
||||
if (!Data) {
|
||||
pesAssembler->Reset();
|
||||
if (dvbSubtitleConverter)
|
||||
dvbSubtitleConverter->Reset();
|
||||
return 0;
|
||||
}
|
||||
int Result = 0;
|
||||
|
38
device.h
38
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.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
|
||||
@ -12,6 +12,7 @@
|
||||
|
||||
#include "channels.h"
|
||||
#include "ci.h"
|
||||
#include "dvbsubtitle.h"
|
||||
#include "eit.h"
|
||||
#include "filter.h"
|
||||
#include "nit.h"
|
||||
@ -70,16 +71,15 @@ enum eTrackType { ttNone,
|
||||
ttDolby,
|
||||
ttDolbyFirst = ttDolby,
|
||||
ttDolbyLast = ttDolbyFirst + 15, // MAXDPIDS - 1
|
||||
/* future...
|
||||
ttSubtitle,
|
||||
ttSubtitleFirst = ttSubtitle,
|
||||
ttSubtitleLast = ttSubtitleFirst + 7, // MAXSPIDS - 1
|
||||
*/
|
||||
ttSubtitleLast = ttSubtitleFirst + 31, // MAXSPIDS - 1
|
||||
ttMaxTrackTypes
|
||||
};
|
||||
|
||||
#define IS_AUDIO_TRACK(t) (ttAudioFirst <= (t) && (t) <= ttAudioLast)
|
||||
#define IS_DOLBY_TRACK(t) (ttDolbyFirst <= (t) && (t) <= ttDolbyLast)
|
||||
#define IS_SUBTITLE_TRACK(t) (ttSubtitleFirst <= (t) && (t) <= ttSubtitleLast)
|
||||
|
||||
struct tTrackId {
|
||||
uint16_t id; // The PES packet id or the PID.
|
||||
@ -90,10 +90,12 @@ struct tTrackId {
|
||||
class cPlayer;
|
||||
class cReceiver;
|
||||
class cPesAssembler;
|
||||
class cLiveSubtitle;
|
||||
|
||||
/// The cDevice class is the base from which actual devices can be derived.
|
||||
|
||||
class cDevice : public cThread {
|
||||
friend class cLiveSubtitle;
|
||||
private:
|
||||
static int numDevices;
|
||||
static int useDevice;
|
||||
@ -185,6 +187,9 @@ public:
|
||||
|
||||
// SPU facilities
|
||||
|
||||
private:
|
||||
cLiveSubtitle *liveSubtitle;
|
||||
cDvbSubtitleConverter *dvbSubtitleConverter;
|
||||
public:
|
||||
virtual cSpuDecoder *GetSpuDecoder(void);
|
||||
///< Returns a pointer to the device's SPU decoder (or NULL, if this
|
||||
@ -362,8 +367,11 @@ public:
|
||||
private:
|
||||
tTrackId availableTracks[ttMaxTrackTypes];
|
||||
eTrackType currentAudioTrack;
|
||||
eTrackType currentSubtitleTrack;
|
||||
cMutex mutexCurrentAudioTrack;
|
||||
cMutex mutexCurrentSubtitleTrack;
|
||||
int currentAudioTrackMissingCount;
|
||||
bool autoSelectPreferredSubtitleLanguage;
|
||||
bool pre_1_3_19_PrivateStream;
|
||||
protected:
|
||||
virtual void SetAudioTrackDevice(eTrackType Type);
|
||||
@ -384,18 +392,33 @@ public:
|
||||
const tTrackId *GetTrack(eTrackType Type);
|
||||
///< Returns a pointer to the given track id, or NULL if Type is not
|
||||
///< 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;
|
||||
///< Returns the number of audio tracks that are currently available.
|
||||
///< This is just for information, to quickly find out whether there
|
||||
///< 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; }
|
||||
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.
|
||||
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);
|
||||
///< Makes sure an audio track is selected that is actually available.
|
||||
///< If Force is true, the language and Dolby Digital settings will
|
||||
///< 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
|
||||
|
||||
@ -454,6 +477,13 @@ protected:
|
||||
///< 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 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);
|
||||
///< Plays the single PES packet in Data with the given Length.
|
||||
///< If VideoOnly is true, only the video will be displayed,
|
||||
|
16
dvbosd.c
16
dvbosd.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* 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"
|
||||
@ -32,6 +32,7 @@ public:
|
||||
cDvbOsd(int Left, int Top, int OsdDev, uint Level);
|
||||
virtual ~cDvbOsd();
|
||||
virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas);
|
||||
virtual eOsdError SetAreas(const tArea *Areas, int NumAreas);
|
||||
virtual void Flush(void);
|
||||
};
|
||||
|
||||
@ -106,6 +107,19 @@ eOsdError cDvbOsd::CanHandleAreas(const tArea *Areas, int NumAreas)
|
||||
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)
|
||||
{
|
||||
if (osdDev >= 0) {
|
||||
|
1029
dvbsubtitle.c
Normal file
1029
dvbsubtitle.c
Normal file
File diff suppressed because it is too large
Load Diff
43
dvbsubtitle.h
Normal file
43
dvbsubtitle.h
Normal 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
6
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.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"
|
||||
@ -219,11 +219,11 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bo
|
||||
SI::ComponentDescriptor *cd = (SI::ComponentDescriptor *)d;
|
||||
uchar Stream = cd->getStreamContent();
|
||||
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)
|
||||
Components = new cComponents;
|
||||
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;
|
||||
|
3
keys.c
3
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.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"
|
||||
@ -49,6 +49,7 @@ static tKey keyTable[] = { // "Up" and "Down" must be the first two keys!
|
||||
{ kVolDn, trNOOP("Key$Volume-") },
|
||||
{ kMute, trNOOP("Key$Mute") },
|
||||
{ kAudio, trNOOP("Key$Audio") },
|
||||
{ kSubtitles, trNOOP("Key$Subtitles") },
|
||||
{ kSchedule, trNOOP("Key$Schedule") },
|
||||
{ kChannels, trNOOP("Key$Channels") },
|
||||
{ kTimers, trNOOP("Key$Timers") },
|
||||
|
3
keys.h
3
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.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
|
||||
@ -43,6 +43,7 @@ enum eKeys { // "Up" and "Down" must be the first two keys!
|
||||
kVolDn,
|
||||
kMute,
|
||||
kAudio,
|
||||
kSubtitles,
|
||||
kSchedule,
|
||||
kChannels,
|
||||
kTimers,
|
||||
|
162
menu.c
162
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.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"
|
||||
@ -260,6 +260,8 @@ void cMenuEditChannel::Setup(void)
|
||||
Add(new cMenuEditIntItem( tr("Apid2"), &data.apids[1], 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("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 cMenuEditCaItem( tr("CA"), &data.caids[0]));
|
||||
Add(new cMenuEditIntItem( tr("Sid"), &data.sid, 1, 0xFFFF));
|
||||
@ -2400,6 +2402,8 @@ class cMenuSetupDVB : public cMenuSetupBase {
|
||||
private:
|
||||
int originalNumAudioLanguages;
|
||||
int numAudioLanguages;
|
||||
int originalNumSubtitleLanguages;
|
||||
int numSubtitleLanguages;
|
||||
void Setup(void);
|
||||
const char *videoDisplayFormatTexts[3];
|
||||
const char *updateChannelsTexts[6];
|
||||
@ -2412,7 +2416,10 @@ cMenuSetupDVB::cMenuSetupDVB(void)
|
||||
{
|
||||
for (numAudioLanguages = 0; numAudioLanguages < I18nLanguages()->Size() && data.AudioLanguages[numAudioLanguages] >= 0; numAudioLanguages++)
|
||||
;
|
||||
for (numSubtitleLanguages = 0; numSubtitleLanguages < I18nLanguages()->Size() && data.SubtitleLanguages[numSubtitleLanguages] >= 0; numSubtitleLanguages++)
|
||||
;
|
||||
originalNumAudioLanguages = numAudioLanguages;
|
||||
originalNumSubtitleLanguages = numSubtitleLanguages;
|
||||
videoDisplayFormatTexts[0] = tr("pan&scan");
|
||||
videoDisplayFormatTexts[1] = tr("letterbox");
|
||||
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()));
|
||||
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 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));
|
||||
Display();
|
||||
@ -2453,11 +2469,15 @@ eOSState cMenuSetupDVB::ProcessKey(eKeys Key)
|
||||
int oldVideoDisplayFormat = ::Setup.VideoDisplayFormat;
|
||||
bool oldVideoFormat = ::Setup.VideoFormat;
|
||||
bool newVideoFormat = data.VideoFormat;
|
||||
bool oldDisplaySubtitles = ::Setup.DisplaySubtitles;
|
||||
bool newDisplaySubtitles = data.DisplaySubtitles;
|
||||
int oldnumAudioLanguages = numAudioLanguages;
|
||||
int oldnumSubtitleLanguages = numSubtitleLanguages;
|
||||
eOSState state = cMenuSetupBase::ProcessKey(Key);
|
||||
|
||||
if (Key != kNone) {
|
||||
bool DoSetup = data.VideoFormat != newVideoFormat;
|
||||
DoSetup |= data.DisplaySubtitles != newDisplaySubtitles;
|
||||
if (numAudioLanguages != oldnumAudioLanguages) {
|
||||
for (int i = oldnumAudioLanguages; i < numAudioLanguages; i++) {
|
||||
data.AudioLanguages[i] = 0;
|
||||
@ -2476,6 +2496,24 @@ eOSState cMenuSetupDVB::ProcessKey(eKeys Key)
|
||||
data.AudioLanguages[numAudioLanguages] = -1;
|
||||
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)
|
||||
Setup();
|
||||
}
|
||||
@ -2486,6 +2524,9 @@ eOSState cMenuSetupDVB::ProcessKey(eKeys Key)
|
||||
cDevice::PrimaryDevice()->SetVideoDisplayFormat(eVideoDisplayFormat(::Setup.VideoDisplayFormat));
|
||||
if (::Setup.VideoFormat != oldVideoFormat)
|
||||
cDevice::PrimaryDevice()->SetVideoFormat(::Setup.VideoFormat);
|
||||
if (::Setup.DisplaySubtitles != oldDisplaySubtitles)
|
||||
cDevice::PrimaryDevice()->EnsureSubtitleTrack();
|
||||
cDvbSubtitleConverter::SetupChanged();
|
||||
}
|
||||
return state;
|
||||
}
|
||||
@ -3128,14 +3169,18 @@ static void SetTrackDescriptions(int LiveChannel)
|
||||
if (Components) {
|
||||
int indexAudio = 0;
|
||||
int indexDolby = 0;
|
||||
int indexSubtitle = 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, LiveChannel ? NULL : p->language, p->description);
|
||||
else
|
||||
cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, indexAudio++, 0, LiveChannel ? NULL : p->language, p->description);
|
||||
}
|
||||
switch (p->stream) {
|
||||
case 2: if (p->type == 0x05)
|
||||
cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, LiveChannel ? NULL : p->language, p->description);
|
||||
else
|
||||
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++;
|
||||
}
|
||||
}
|
||||
descriptions[numTracks] = 0;
|
||||
descriptions[numTracks] = NULL;
|
||||
timeout.Set(TRACKTIMEOUT);
|
||||
displayTracks = Skins.Current()->DisplayTracks(tr("Button$Audio"), numTracks, descriptions);
|
||||
Show();
|
||||
@ -3569,7 +3614,7 @@ eOSState cDisplayTracks::ProcessKey(eKeys Key)
|
||||
timeout.Set(TRACKTIMEOUT);
|
||||
break;
|
||||
case kOk:
|
||||
if (track != cDevice::PrimaryDevice()->GetCurrentAudioTrack())
|
||||
if (types[track] != cDevice::PrimaryDevice()->GetCurrentAudioTrack())
|
||||
oldTrack = -1; // make sure we explicitly switch to that track
|
||||
timeout.Set();
|
||||
break;
|
||||
@ -3588,6 +3633,105 @@ eOSState cDisplayTracks::ProcessKey(eKeys Key)
|
||||
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(cDevice *Device, cTimer *Timer, bool Pause)
|
||||
|
20
menu.h
20
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.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
|
||||
@ -128,6 +128,24 @@ public:
|
||||
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);
|
||||
|
||||
class cMenuRecordingItem;
|
||||
|
106
osd.c
106
osd.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* 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"
|
||||
@ -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;
|
||||
return numColors ? color : NULL;
|
||||
@ -112,7 +112,7 @@ void cPalette::Replace(const cPalette &Palette)
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
int cPalette::ClosestColor(tColor Color, int MaxDiff)
|
||||
int cPalette::ClosestColor(tColor Color, int MaxDiff) const
|
||||
{
|
||||
int n = 0;
|
||||
int d = INT_MAX;
|
||||
@ -640,6 +640,79 @@ const tIndex *cBitmap::Data(int x, int y)
|
||||
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 ------------------------------------------------------------------
|
||||
|
||||
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 Result = oeUnknown;
|
||||
if (numBitmaps == 0) {
|
||||
Result = CanHandleAreas(Areas, NumAreas);
|
||||
if (Result == oeOk) {
|
||||
width = height = 0;
|
||||
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);
|
||||
width = max(width, Areas[i].x2 + 1);
|
||||
height = max(height, Areas[i].y2 + 1);
|
||||
}
|
||||
}
|
||||
eOsdError Result = CanHandleAreas(Areas, NumAreas);
|
||||
if (Result == oeOk) {
|
||||
while (numBitmaps)
|
||||
delete bitmaps[--numBitmaps];
|
||||
width = height = 0;
|
||||
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);
|
||||
width = max(width, Areas[i].x2 + 1);
|
||||
height = max(height, Areas[i].y2 + 1);
|
||||
}
|
||||
}
|
||||
if (Result != oeOk)
|
||||
else
|
||||
esyslog("ERROR: cOsd::SetAreas returned %d", Result);
|
||||
return Result;
|
||||
}
|
||||
@ -818,7 +890,7 @@ cOsdProvider::~cOsdProvider()
|
||||
|
||||
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!");
|
||||
else if (osdProvider) {
|
||||
cOsd *ActiveOsd = cOsd::Osds.Size() ? cOsd::Osds[0] : NULL;
|
||||
|
33
osd.h
33
osd.h
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* 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
|
||||
@ -17,6 +17,9 @@
|
||||
#include "font.h"
|
||||
#include "tools.h"
|
||||
|
||||
#define OSD_LEVEL_DEFAULT 0
|
||||
#define OSD_LEVEL_SUBTITLES 10
|
||||
|
||||
#define MAXNUMCOLORS 256
|
||||
|
||||
enum {
|
||||
@ -69,7 +72,7 @@ public:
|
||||
///< a single color combination, and may not be able to serve all
|
||||
///< requested colors. By default the palette assumes there will be
|
||||
///< 10 fixed colors and 10 color combinations.
|
||||
int Bpp(void) { return bpp; }
|
||||
int Bpp(void) const { return bpp; }
|
||||
void Reset(void);
|
||||
///< Resets the palette, making it contain no colors.
|
||||
int Index(tColor Color);
|
||||
@ -77,7 +80,7 @@ public:
|
||||
///< 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,
|
||||
///< 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
|
||||
///< range, 0 will be returned.
|
||||
void SetBpp(int Bpp);
|
||||
@ -87,7 +90,7 @@ public:
|
||||
///< Sets the palette entry at Index to Color. If Index is larger than
|
||||
///< the number of currently used entries in this palette, the entries
|
||||
///< 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
|
||||
///< number of valid entries in NumColors. If no colors have been
|
||||
///< stored yet, NumColors will be set to 0 and the function will
|
||||
@ -102,14 +105,14 @@ public:
|
||||
void Replace(const cPalette &Palette);
|
||||
///< Replaces the colors of this palette with the colors from the given
|
||||
///< 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
|
||||
///< and ColorBg. If Level is 0, the result is ColorBg, if it is 255,
|
||||
///< 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
|
||||
///< use of the palette entries.
|
||||
int ClosestColor(tColor Color, int MaxDiff = INT_MAX);
|
||||
///< Returns the index of a color in this paltte that is closest to the given
|
||||
int ClosestColor(tColor Color, int MaxDiff = INT_MAX) const;
|
||||
///< 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.
|
||||
///< 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
|
||||
@ -232,6 +235,17 @@ public:
|
||||
///< Returns the address of the index byte at the given coordinates.
|
||||
tColor GetColor(int x, int y) { return Color(*Data(x, y)); }
|
||||
///< 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 {
|
||||
@ -292,7 +306,7 @@ public:
|
||||
///< 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
|
||||
///< 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.
|
||||
int Left(void) { return left; }
|
||||
int Top(void) { return top; }
|
||||
@ -327,6 +341,7 @@ public:
|
||||
///< If the OSD has been divided into several sub-areas, all areas that
|
||||
///< are part of the rectangle that surrounds a given drawing operation
|
||||
///< 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);
|
||||
///< Saves the region defined by the given coordinates for later restoration
|
||||
///< through RestoreRegion(). Only one saved region can be active at any
|
||||
@ -398,7 +413,7 @@ public:
|
||||
cOsdProvider(void);
|
||||
//XXX maybe parameter to make this one "sticky"??? (frame-buffer etc.)
|
||||
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
|
||||
///< 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
|
||||
|
27
pat.c
27
pat.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: pat.c 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"
|
||||
@ -331,11 +331,14 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
|
||||
int Ppid = pmt.getPCRPid();
|
||||
int Apids[MAXAPIDS + 1] = { 0 }; // these lists are zero-terminated
|
||||
int Dpids[MAXDPIDS + 1] = { 0 };
|
||||
int Spids[MAXSPIDS + 1] = { 0 };
|
||||
char ALangs[MAXAPIDS][MAXLANGCODE2] = { "" };
|
||||
char DLangs[MAXDPIDS][MAXLANGCODE2] = { "" };
|
||||
char SLangs[MAXSPIDS][MAXLANGCODE2] = { "" };
|
||||
int Tpid = 0;
|
||||
int NumApids = 0;
|
||||
int NumDpids = 0;
|
||||
int NumSpids = 0;
|
||||
for (SI::Loop::Iterator it; pmt.streamLoop.getNext(stream, it); ) {
|
||||
switch (stream.getStreamType()) {
|
||||
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:
|
||||
dpid = stream.getPid();
|
||||
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:
|
||||
Tpid = stream.getPid();
|
||||
break;
|
||||
@ -416,7 +439,7 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
|
||||
}
|
||||
}
|
||||
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->SetCaDescriptors(CaDescriptorHandler.AddCaDescriptors(CaDescriptors));
|
||||
|
13
recording.c
13
recording.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: recording.c 1.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"
|
||||
@ -296,6 +296,17 @@ cRecordingInfo::cRecordingInfo(const cChannel *Channel, const cEvent *Event)
|
||||
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())
|
||||
((cEvent *)event)->SetComponents(Components);
|
||||
}
|
||||
|
30
remux.c
30
remux.c
@ -11,7 +11,7 @@
|
||||
* 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.
|
||||
*
|
||||
* $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"
|
||||
@ -1555,6 +1555,13 @@ void cTS2PES::send_ipack(void)
|
||||
buf[7] = 0x00;
|
||||
buf[8] = 0x00;
|
||||
count = 9;
|
||||
if (!repacker && subStreamId) {
|
||||
buf[9] = subStreamId;
|
||||
buf[10] = 1;
|
||||
buf[11] = 0;
|
||||
buf[12] = 1;
|
||||
count = 13;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
buf[6] = 0x0F;
|
||||
@ -1766,6 +1773,19 @@ void cTS2PES::instant_repack(const uint8_t *Buf, int Count)
|
||||
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) {
|
||||
int l = Count - c;
|
||||
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)
|
||||
{
|
||||
exitOnFailure = ExitOnFailure;
|
||||
isRadio = VPid == 0 || VPid == 1 || VPid == 0x1FFF;
|
||||
noVideo = VPid == 0 || VPid == 1 || VPid == 0x1FFF;
|
||||
numUPTerrors = 0;
|
||||
synced = false;
|
||||
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)
|
||||
ts2pes[numTracks++] = new cTS2PES(*DPids++, resultBuffer, IPACKS, 0x00, 0x80 + n++, new cDolbyRepacker);
|
||||
}
|
||||
/* future...
|
||||
if (SPids) {
|
||||
int n = 0;
|
||||
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()
|
||||
@ -2080,7 +2098,7 @@ uchar *cRemux::Get(int &Count, uchar *PictureType)
|
||||
l = GetPacketLength(data, resultCount, i);
|
||||
if (l < 0)
|
||||
return resultData;
|
||||
if (isRadio) {
|
||||
if (noVideo) {
|
||||
if (!synced) {
|
||||
if (PictureType)
|
||||
*PictureType = I_FRAME;
|
||||
|
4
remux.h
4
remux.h
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: remux.h 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
|
||||
@ -37,7 +37,7 @@ class cTS2PES;
|
||||
class cRemux {
|
||||
private:
|
||||
bool exitOnFailure;
|
||||
bool isRadio;
|
||||
bool noVideo;
|
||||
int numUPTerrors;
|
||||
bool synced;
|
||||
int skipped;
|
||||
|
6
vdr.5
6
vdr.5
@ -8,7 +8,7 @@
|
||||
.\" License as specified in the file COPYING that comes with the
|
||||
.\" 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"
|
||||
.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).
|
||||
Dolby Digital data is stored in packets with ids 0xBD ("Private Stream 1")
|
||||
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
|
||||
The file \fIindex.vdr\fR (if present in a recording directory) contains
|
||||
the (binary) index data into each of the the recording files
|
||||
@ -646,7 +648,7 @@ 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)
|
||||
<stream> @is the stream content (1 = video, 2 = audio, 3 = subtitles)
|
||||
<type> @is the stream type according to ETSI EN 300 468
|
||||
<language> @is the three letter language code (optionally two codes, separated by '+')
|
||||
<descr> @is the description of this stream component
|
||||
|
14
vdr.c
14
vdr.c
@ -22,7 +22,7 @@
|
||||
*
|
||||
* 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>
|
||||
@ -1009,6 +1009,18 @@ int main(int argc, char *argv[])
|
||||
cDisplayTracks::Process(key);
|
||||
key = kNone;
|
||||
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:
|
||||
case kPause:
|
||||
if (!cControl::Control()) {
|
||||
|
Loading…
Reference in New Issue
Block a user