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
|
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
29
HISTORY
@ -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
26
MANUAL
@ -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
|
||||||
|
4
Makefile
4
Makefile
@ -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\
|
||||||
|
22
channels.c
22
channels.c
@ -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();
|
||||||
|
@ -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);
|
||||||
|
17
config.c
17
config.c
@ -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);
|
||||||
|
14
config.h
14
config.h
@ -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;
|
||||||
|
172
device.c
172
device.c
@ -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,19 +937,24 @@ 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
|
||||||
|
if (Type == ttAudio || Type == ttDolby) {
|
||||||
int numAudioTracks = NumAudioTracks();
|
int numAudioTracks = NumAudioTracks();
|
||||||
if (!availableTracks[currentAudioTrack].id && numAudioTracks && currentAudioTrackMissingCount++ > numAudioTracks * 10)
|
if (!availableTracks[currentAudioTrack].id && numAudioTracks && currentAudioTrackMissingCount++ > numAudioTracks * 10)
|
||||||
EnsureAudioTrack();
|
EnsureAudioTrack();
|
||||||
else if (t == currentAudioTrack)
|
else if (t == currentAudioTrack)
|
||||||
currentAudioTrackMissingCount = 0;
|
currentAudioTrackMissingCount = 0;
|
||||||
}
|
}
|
||||||
|
else if (Type == ttSubtitle && autoSelectPreferredSubtitleLanguage)
|
||||||
|
EnsureSubtitleTrack();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -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;
|
||||||
|
38
device.h
38
device.h
@ -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,
|
||||||
|
16
dvbosd.c
16
dvbosd.c
@ -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
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>.
|
* 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
3
keys.c
@ -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
3
keys.h
@ -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,
|
||||||
|
154
menu.c
154
menu.c
@ -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,13 +3169,17 @@ 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
20
menu.h
@ -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;
|
||||||
|
92
osd.c
92
osd.c
@ -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,10 +793,10 @@ 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) {
|
|
||||||
Result = CanHandleAreas(Areas, NumAreas);
|
|
||||||
if (Result == oeOk) {
|
if (Result == oeOk) {
|
||||||
|
while (numBitmaps)
|
||||||
|
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);
|
||||||
@ -731,8 +804,7 @@ eOsdError cOsd::SetAreas(const tArea *Areas, int NumAreas)
|
|||||||
height = max(height, Areas[i].y2 + 1);
|
height = max(height, Areas[i].y2 + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
if (Result != oeOk)
|
|
||||||
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
33
osd.h
@ -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
27
pat.c
@ -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));
|
||||||
|
13
recording.c
13
recording.c
@ -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
30
remux.c
@ -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;
|
||||||
|
4
remux.h
4
remux.h
@ -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
6
vdr.5
@ -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
14
vdr.c
@ -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()) {
|
||||||
|
Loading…
Reference in New Issue
Block a user