Version 1.7.22

Original announce message:
VDR developer version 1.7.22 is now available at

       ftp://ftp.tvdr.de/vdr/Developer/vdr-1.7.22.tar.bz2

A 'diff' against the previous version is available at

       ftp://ftp.tvdr.de/vdr/Developer/vdr-1.7.21-1.7.22.diff

MD5 checksums:

b9c0fe1aac8e653c0d0234bc72c2bb2c  vdr-1.7.22.tar.bz2
868bb332342c9a78beda17cc85e0bb93  vdr-1.7.21-1.7.22.diff

WARNING:
========

This is a developer version. Even though I use it in my productive
environment. I strongly recommend that you only use it under controlled
conditions and for testing and debugging.

From the HISTORY file:
- Fixed scaling subtitles in case the primary device's GetVideoSize() function doesn't
  return actual values (thanks to Luca Olivetti).
- The DiSEqC codes are now copied in the call to cDiseqc::Execute().
- VDR now supports "Satellite Channel Routing" (SCR) according to EN50494 (based on
  the "unicable" patch from Lars Hanisch).
  Since "Unicable" is a registered trademark and stands for only one of many
  implementations of SCR, the following changes have been made compared to the patch,
  which need to be taken into account by people who have set up their system using
  the patch:
  - The 'U' parameter in the diseqc.conf file has been changed to 'S' ("Scr").
  - The configuration file name has been changed from "unicable.conf" to "scr.conf".
- Updated sources.conf (thanks to Arthur Konovalov).
- The SVDRP command LSTC now also accepts channel IDs (thanks to Dominic Evans).
- Fixed handling DVB subtitles and implemented decoding textual DVB subtitles (thanks
  to Rolf Ahrenberg).
- Added cap_net_raw to the capabilities that are not dropped (thanks to Dominic Evans).
- Fixed setting the start time of an edited recording (thanks to Christoph Haubrich).
- Temporarily switching free devices to transponders in order to have their running
  status updated is now done by marking the devices as "occupied" for a certain
  amount of time.
- The new setup options "LNB/Device n connected to sat cable" can be used to define
  which DVB-S devices are connected to the same sat cable and are therefore "bonded".
  This obsoletes the LNBSHARE patch. Users of the LNBSHARE patch will need to newly
  set up their sat devices with the above options.
- Fixed a crash when deleting a recording while cutting it (thanks to Ville Skyttä).
- Fixed several spelling errors (thanks to Ville Skyttä).
- The new SVDRP command UPDR can be used to trigger an update of the list of
  recordings (thanks to Lars Hanisch).
- Added generating a pkg-config file to the Makefile (thanks to Ville Skyttä).
- Removed the '.pl' suffix from all scripts (thanks to Ville Skyttä).
- Changed the default location for the LIRC socket to /var/run/lirc/lircd (thanks
  to Ville Skyttä).
- Added file name and line number to LOG_ERROR_STR() (thanks to Rolf Ahrenberg).
- Replaced all calls to sleep() with cCondWait::SleepMs() (thanks to Rolf Ahrenberg).
- Fixed a crash with malformed SI data (patch from vdr-portal).
This commit is contained in:
Klaus Schmidinger
2011-12-04 16:53:00 +01:00
committed by Dieter Hametner
parent 0c96d6b626
commit 5a28d99936
102 changed files with 4603 additions and 1616 deletions

View File

@@ -7,7 +7,7 @@
* Original author: Marco Schl<68><6C>ler <marco@lordzodiac.de>
* With some input from the "subtitle plugin" by Pekka Virtanen <pekka.virtanen@sci.fi>
*
* $Id: dvbsubtitle.c 2.18 2011/08/13 13:33:00 kls Exp $
* $Id: dvbsubtitle.c 2.20 2011/09/18 11:23:15 kls Exp $
*/
@@ -15,13 +15,18 @@
#define __STDC_FORMAT_MACROS // Required for format specifiers
#include <inttypes.h>
#include "device.h"
#include "libsi/si.h"
#define PAGE_COMPOSITION_SEGMENT 0x10
#define REGION_COMPOSITION_SEGMENT 0x11
#define CLUT_DEFINITION_SEGMENT 0x12
#define OBJECT_DATA_SEGMENT 0x13
#define DISPLAY_DEFINITION_SEGMENT 0x14
#define END_OF_DISPLAY_SET_SEGMENT 0x80
//#define FINISHPAGE_HACK
#define PAGE_COMPOSITION_SEGMENT 0x10
#define REGION_COMPOSITION_SEGMENT 0x11
#define CLUT_DEFINITION_SEGMENT 0x12
#define OBJECT_DATA_SEGMENT 0x13
#define DISPLAY_DEFINITION_SEGMENT 0x14
#define DISPARITY_SIGNALING_SEGMENT 0x15 // DVB BlueBook A156
#define END_OF_DISPLAY_SET_SEGMENT 0x80
#define STUFFING_SEGMENT 0xFF
// Set these to 'true' for debug output:
static bool DebugConverter = false;
@@ -61,8 +66,68 @@ cSubtitleClut::cSubtitleClut(int ClutId)
,palette4(4)
,palette8(8)
{
int a = 0, r = 0, g = 0, b = 0;
clutId = ClutId;
version = -1;
// ETSI EN 300 743 10.3: 4-entry CLUT default contents
palette2.SetColor(0, ArgbToColor( 0, 0, 0, 0));
palette2.SetColor(1, ArgbToColor(255, 255, 255, 255));
palette2.SetColor(2, ArgbToColor(255, 0, 0, 0));
palette2.SetColor(3, ArgbToColor(255, 127, 127, 127));
// ETSI EN 300 743 10.2: 16-entry CLUT default contents
palette4.SetColor(0, ArgbToColor(0, 0, 0, 0));
for (int i = 1; i < 16; ++i) {
if (i < 8) {
r = (i & 1) ? 255 : 0;
g = (i & 2) ? 255 : 0;
b = (i & 4) ? 255 : 0;
}
else {
r = (i & 1) ? 127 : 0;
g = (i & 2) ? 127 : 0;
b = (i & 4) ? 127 : 0;
}
palette4.SetColor(i, ArgbToColor(255, r, g, b));
}
// ETSI EN 300 743 10.1: 256-entry CLUT default contents
palette8.SetColor(0, ArgbToColor(0, 0, 0, 0));
for (int i = 1; i < 256; ++i) {
if (i < 8) {
r = (i & 1) ? 255 : 0;
g = (i & 2) ? 255 : 0;
b = (i & 4) ? 255 : 0;
a = 63;
}
else {
switch (i & 0x88) {
case 0x00:
r = ((i & 1) ? 85 : 0) + ((i & 0x10) ? 170 : 0);
g = ((i & 2) ? 85 : 0) + ((i & 0x20) ? 170 : 0);
b = ((i & 4) ? 85 : 0) + ((i & 0x40) ? 170 : 0);
a = 255;
break;
case 0x08:
r = ((i & 1) ? 85 : 0) + ((i & 0x10) ? 170 : 0);
g = ((i & 2) ? 85 : 0) + ((i & 0x20) ? 170 : 0);
b = ((i & 4) ? 85 : 0) + ((i & 0x40) ? 170 : 0);
a = 127;
break;
case 0x80:
r = 127 + ((i & 1) ? 43 : 0) + ((i & 0x10) ? 85 : 0);
g = 127 + ((i & 2) ? 43 : 0) + ((i & 0x20) ? 85 : 0);
b = 127 + ((i & 4) ? 43 : 0) + ((i & 0x40) ? 85 : 0);
a = 255;
break;
case 0x88:
r = ((i & 1) ? 43 : 0) + ((i & 0x10) ? 85 : 0);
g = ((i & 2) ? 43 : 0) + ((i & 0x20) ? 85 : 0);
b = ((i & 4) ? 43 : 0) + ((i & 0x40) ? 85 : 0);
a = 255;
break;
}
}
palette8.SetColor(i, ArgbToColor(a, r, g, b));
}
}
void cSubtitleClut::SetColor(int Bpp, int Index, tColor Color)
@@ -94,29 +159,33 @@ private:
int version;
int codingMethod;
bool nonModifyingColorFlag;
int nibblePos;
uchar backgroundColor;
uchar foregroundColor;
uchar backgroundPixelCode;
uchar foregroundPixelCode;
int providerFlag;
int px;
int py;
cBitmap *bitmap;
char textData[Utf8BufSize(256)]; // number of character codes is an 8-bit field
void DrawLine(int x, int y, tIndex Index, int Length);
uchar Get2Bits(const uchar *Data, int &Index);
uchar Get4Bits(const uchar *Data, int &Index);
bool Decode2BppCodeString(const uchar *Data, int &Index, int&x, int y);
bool Decode4BppCodeString(const uchar *Data, int &Index, int&x, int y);
bool Decode8BppCodeString(const uchar *Data, int &Index, int&x, int y);
bool Decode2BppCodeString(cBitStream *bs, int&x, int y, const uint8_t *MapTable);
bool Decode4BppCodeString(cBitStream *bs, int&x, int y, const uint8_t *MapTable);
bool Decode8BppCodeString(cBitStream *bs, int&x, int y);
public:
cSubtitleObject(int ObjectId, cBitmap *Bitmap);
int ObjectId(void) { return objectId; }
int Version(void) { return version; }
int CodingMethod(void) { return codingMethod; }
uchar BackgroundPixelCode(void) { return backgroundPixelCode; }
uchar ForegroundPixelCode(void) { return foregroundPixelCode; }
const char *TextData(void) { return &textData[0]; }
int X(void) { return px; }
int Y(void) { return py; }
bool NonModifyingColorFlag(void) { return nonModifyingColorFlag; }
void DecodeCharacterString(const uchar *Data, int NumberOfCodes);
void DecodeSubBlock(const uchar *Data, int Length, bool Even);
void SetVersion(int Version) { version = Version; }
void SetBackgroundColor(uchar BackgroundColor) { backgroundColor = BackgroundColor; }
void SetForegroundColor(uchar ForegroundColor) { foregroundColor = ForegroundColor; }
void SetBackgroundPixelCode(uchar BackgroundPixelCode) { backgroundPixelCode = BackgroundPixelCode; }
void SetForegroundPixelCode(uchar ForegroundPixelCode) { foregroundPixelCode = ForegroundPixelCode; }
void SetNonModifyingColorFlag(bool NonModifyingColorFlag) { nonModifyingColorFlag = NonModifyingColorFlag; }
void SetCodingMethod(int CodingMethod) { codingMethod = CodingMethod; }
void SetPosition(int x, int y) { px = x; py = y; }
@@ -129,59 +198,105 @@ cSubtitleObject::cSubtitleObject(int ObjectId, cBitmap *Bitmap)
version = -1;
codingMethod = -1;
nonModifyingColorFlag = false;
nibblePos = 0;
backgroundColor = 0;
foregroundColor = 0;
backgroundPixelCode = 0;
foregroundPixelCode = 0;
providerFlag = -1;
px = py = 0;
bitmap = Bitmap;
memset(textData, 0, sizeof(textData));
}
void cSubtitleObject::DecodeCharacterString(const uchar *Data, int NumberOfCodes)
{
if (NumberOfCodes > 0) {
bool singleByte;
const uchar *from = &Data[1];
int len = NumberOfCodes * 2 - 1;
cCharSetConv conv(SI::getCharacterTable(from, len, &singleByte));
if (singleByte) {
char txt[NumberOfCodes + 1];
char *p = txt;
for (int i = 2; i < NumberOfCodes; ++i) {
char c = Data[i * 2 + 1] & 0xFF;
if (c == 0)
break;
if (' ' <= c && c <= '~' || c == '\n' || 0xA0 <= c)
*(p++) = c;
else if (c == 0x8A)
*(p++) = '\n';
}
*p = 0;
const char *s = conv.Convert(txt);
Utf8Strn0Cpy(textData, s, Utf8StrLen(s));
}
else {
// TODO: add proper multibyte support for "UTF-16", "EUC-KR", "GB2312", "GBK", "UTF-8"
}
}
}
void cSubtitleObject::DecodeSubBlock(const uchar *Data, int Length, bool Even)
{
int x = 0;
int y = Even ? 0 : 1;
for (int index = 0; index < Length; ) {
switch (Data[index++]) {
case 0x10: {
nibblePos = 8;
while (Decode2BppCodeString(Data, index, x, y) && index < Length)
;
if (!nibblePos)
index++;
break;
}
case 0x11: {
nibblePos = 4;
while (Decode4BppCodeString(Data, index, x, y) && index < Length)
;
if (!nibblePos)
index++;
break;
}
case 0x12:
while (Decode8BppCodeString(Data, index, x, y) && index < Length)
;
break;
case 0x20: //TODO
dbgobjects("sub block 2 to 4 map\n");
index += 4;
break;
case 0x21: //TODO
dbgobjects("sub block 2 to 8 map\n");
index += 4;
break;
case 0x22: //TODO
dbgobjects("sub block 4 to 8 map\n");
index += 16;
break;
case 0xF0:
x = 0;
y += 2;
break;
default: dbgobjects("unknown sub block %s %d\n", __FUNCTION__, __LINE__);
uint8_t map2to4[ 4] = { 0x00, 0x07, 0x08, 0x0F };
uint8_t map2to8[ 4] = { 0x00, 0x77, 0x88, 0xFF };
uint8_t map4to8[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
const uint8_t *mapTable = NULL;
cBitStream bs(Data, Length * 8);
while (!bs.IsEOF()) {
switch (bs.GetBits(8)) {
case 0x10:
dbgobjects("2-bit / pixel code string\n");
switch (bitmap->Bpp()) {
case 8: mapTable = map2to8; break;
case 4: mapTable = map2to4; break;
default: mapTable = NULL; break;
}
while (Decode2BppCodeString(&bs, x, y, mapTable) && !bs.IsEOF())
;
bs.ByteAlign();
break;
case 0x11:
dbgobjects("4-bit / pixel code string\n");
switch (bitmap->Bpp()) {
case 8: mapTable = map4to8; break;
default: mapTable = NULL; break;
}
while (Decode4BppCodeString(&bs, x, y, mapTable) && !bs.IsEOF())
;
bs.ByteAlign();
break;
case 0x12:
dbgobjects("8-bit / pixel code string\n");
while (Decode8BppCodeString(&bs, x, y) && !bs.IsEOF())
;
break;
case 0x20:
dbgobjects("sub block 2 to 4 map\n");
map2to4[0] = bs.GetBits(4);
map2to4[1] = bs.GetBits(4);
map2to4[2] = bs.GetBits(4);
map2to4[3] = bs.GetBits(4);
break;
case 0x21:
dbgobjects("sub block 2 to 8 map\n");
for (int i = 0; i < 4; ++i)
map2to8[i] = bs.GetBits(8);
break;
case 0x22:
dbgobjects("sub block 4 to 8 map\n");
for (int i = 0; i < 16; ++i)
map4to8[i] = bs.GetBits(8);
break;
case 0xF0:
dbgobjects("end of object line\n");
x = 0;
y += 2;
break;
default: dbgobjects("unknown sub block %s %d\n", __FUNCTION__, __LINE__);
}
}
}
}
void cSubtitleObject::DrawLine(int x, int y, tIndex Index, int Length)
@@ -194,136 +309,110 @@ void cSubtitleObject::DrawLine(int x, int y, tIndex Index, int Length)
bitmap->SetIndex(pos, y, Index);
}
uchar cSubtitleObject::Get2Bits(const uchar *Data, int &Index)
{
uchar result = Data[Index];
if (!nibblePos) {
Index++;
nibblePos = 8;
}
nibblePos -= 2;
return (result >> nibblePos) & 0x03;
}
uchar cSubtitleObject::Get4Bits(const uchar *Data, int &Index)
{
uchar result = Data[Index];
if (!nibblePos) {
Index++;
nibblePos = 4;
}
else {
result >>= 4;
nibblePos -= 4;
}
return result & 0x0F;
}
bool cSubtitleObject::Decode2BppCodeString(const uchar *Data, int &Index, int &x, int y)
bool cSubtitleObject::Decode2BppCodeString(cBitStream *bs, int &x, int y, const uint8_t *MapTable)
{
int rl = 0;
int color = 0;
uchar code = Get2Bits(Data, Index);
uchar code = bs->GetBits(2);
if (code) {
color = code;
rl = 1;
}
else {
code = Get2Bits(Data, Index);
if (code & 2) { // switch_1
rl = ((code & 1) << 2) + Get2Bits(Data, Index) + 3;
color = Get2Bits(Data, Index);
}
else if (code & 1)
rl = 1; //color 0
else {
code = Get2Bits(Data, Index);
switch (code & 3) { //switch_3
case 0:
return false;
case 1:
rl = 2; //color 0
break;
case 2:
rl = (Get2Bits(Data, Index) << 2) + Get2Bits(Data, Index) + 12;
color = Get2Bits(Data, Index);
break;
case 3:
rl = (Get2Bits(Data, Index) << 6) + (Get2Bits(Data, Index) << 4) + (Get2Bits(Data, Index) << 2) + Get2Bits(Data, Index) + 29;
color = Get2Bits(Data, Index);
break;
default: ;
}
}
else if (bs->GetBit()) { // switch_1
rl = bs->GetBits(3) + 3;
color = bs->GetBits(2);
}
else if (bs->GetBit()) // switch_2
rl = 1; //color 0
else {
switch (bs->GetBits(2)) { // switch_3
case 0:
return false;
case 1:
rl = 2; //color 0
break;
case 2:
rl = bs->GetBits(4) + 12;
color = bs->GetBits(2);
break;
case 3:
rl = bs->GetBits(8) + 29;
color = bs->GetBits(2);
break;
default: ;
}
}
if (MapTable)
color = MapTable[color];
DrawLine(x, y, color, rl);
x += rl;
return true;
}
bool cSubtitleObject::Decode4BppCodeString(const uchar *Data, int &Index, int &x, int y)
bool cSubtitleObject::Decode4BppCodeString(cBitStream *bs, int &x, int y, const uint8_t *MapTable)
{
int rl = 0;
int color = 0;
uchar code = Get4Bits(Data, Index);
uchar code = bs->GetBits(4);
if (code) {
color = code;
rl = 1;
}
else {
code = Get4Bits(Data, Index);
if (code & 8) { // switch_1
if (code & 4) { //switch_2
switch (code & 3) { //switch_3
case 0: // color 0
rl = 1;
break;
case 1: // color 0
rl = 2;
break;
case 2:
rl = Get4Bits(Data, Index) + 9;
color = Get4Bits(Data, Index);
break;
case 3:
rl = (Get4Bits(Data, Index) << 4) + Get4Bits(Data, Index) + 25;
color = Get4Bits(Data, Index);
break;
default: ;
}
}
else {
rl = (code & 3) + 4;
color = Get4Bits(Data, Index);
}
}
else { // color 0
if (!code)
return false;
rl = code + 2;
}
else if (bs->GetBit() == 0) { // switch_1
code = bs->GetBits(3);
if (code)
rl = code + 2; //color 0
else
return false;
}
else if (bs->GetBit() == 0) { // switch_2
rl = bs->GetBits(2) + 4;
color = bs->GetBits(4);
}
else {
switch (bs->GetBits(2)) { // switch_3
case 0: // color 0
rl = 1;
break;
case 1: // color 0
rl = 2;
break;
case 2:
rl = bs->GetBits(4) + 9;
color = bs->GetBits(4);
break;
case 3:
rl = bs->GetBits(8) + 25;
color = bs->GetBits(4);
break;
}
}
if (MapTable)
color = MapTable[color];
DrawLine(x, y, color, rl);
x += rl;
return true;
}
bool cSubtitleObject::Decode8BppCodeString(const uchar *Data, int &Index, int &x, int y)
bool cSubtitleObject::Decode8BppCodeString(cBitStream *bs, int &x, int y)
{
int rl = 0;
int color = 0;
uchar code = Data[Index++];
uchar code = bs->GetBits(8);
if (code) {
color = code;
rl = 1;
}
else if (bs->GetBit()) {
rl = bs->GetBits(7);
color = bs->GetBits(8);
}
else {
code = Data[Index++];
rl = code & 0x63;
if (code & 0x80)
color = Data[Index++];
else if (!rl)
return false; //else color 0
code = bs->GetBits(7);
if (code)
rl = code; // color 0
else
return false;
}
DrawLine(x, y, color, rl);
x += rl;
@@ -340,6 +429,7 @@ private:
int horizontalAddress;
int verticalAddress;
int level;
int lineHeight;
cList<cSubtitleObject> objects;
public:
cSubtitleRegion(int RegionId);
@@ -358,6 +448,7 @@ public:
void SetDepth(int Depth);
void SetHorizontalAddress(int HorizontalAddress) { horizontalAddress = HorizontalAddress; }
void SetVerticalAddress(int VerticalAddress) { verticalAddress = VerticalAddress; }
void UpdateTextData(cSubtitleClut *Clut);
};
cSubtitleRegion::cSubtitleRegion(int RegionId)
@@ -369,6 +460,7 @@ cSubtitleRegion::cSubtitleRegion(int RegionId)
horizontalAddress = 0;
verticalAddress = 0;
level = 0;
lineHeight = 26; // configurable subtitling font size
}
void cSubtitleRegion::FillRegion(tIndex Index)
@@ -394,6 +486,22 @@ cSubtitleObject *cSubtitleRegion::GetObjectById(int ObjectId, bool New)
return result;
}
void cSubtitleRegion::UpdateTextData(cSubtitleClut *Clut)
{
const cPalette *palette = Clut ? Clut->GetPalette(Depth()) : NULL;
for (cSubtitleObject *so = objects.First(); so && palette; so = objects.Next(so)) {
if (Utf8StrLen(so->TextData()) > 0) {
const cFont *font = cFont::GetFont(fontOsd);
cBitmap *tmp = new cBitmap(font->Width(so->TextData()), font->Height(), Depth());
double factor = (double)lineHeight / font->Height();
tmp->DrawText(0, 0, so->TextData(), palette->Color(so->ForegroundPixelCode()), palette->Color(so->BackgroundPixelCode()), font);
tmp = tmp->Scaled(factor, factor, true);
DrawBitmap(so->X(), so->Y(), *tmp);
DELETENULL(tmp);
}
}
}
void cSubtitleRegion::SetLevel(int Level)
{
if (Level > 0 && Level < 4)
@@ -887,7 +995,7 @@ void cDvbSubtitleConverter::SetOsdData(void)
double VideoAspect;
cDevice::PrimaryDevice()->GetOsdSize(OsdWidth, OsdHeight, OsdAspect);
cDevice::PrimaryDevice()->GetVideoSize(VideoWidth, VideoHeight, VideoAspect);
if (OsdWidth == displayWidth && OsdHeight == displayHeight) {
if (OsdWidth == displayWidth && OsdHeight == displayHeight || VideoWidth == 0) {
osdFactorX = osdFactorY = 1.0;
osdDeltaX = osdDeltaY = 0;
}
@@ -907,12 +1015,15 @@ bool cDvbSubtitleConverter::AssertOsd(void)
int cDvbSubtitleConverter::ExtractSegment(const uchar *Data, int Length, int64_t Pts)
{
if (Length > 5 && Data[0] == 0x0F) {
int segmentLength = (Data[4] << 8) + Data[5] + 6;
if (segmentLength > Length)
cBitStream bs(Data, Length * 8);
if (Length > 5 && bs.GetBits(8) == 0x0F) { // sync byte
int segmentType = bs.GetBits(8);
if (segmentType == STUFFING_SEGMENT)
return -1;
int pageId = bs.GetBits(16);
int segmentLength = bs.GetBits(16);
if (!bs.SetLength(bs.Index() + segmentLength * 8))
return -1;
int segmentType = Data[1];
int pageId = (Data[2] << 8) + Data[3];
cDvbSubtitlePage *page = NULL;
LOCK_THREAD;
for (cDvbSubtitlePage *sp = pages->First(); sp; sp = pages->Next(sp)) {
@@ -931,154 +1042,170 @@ int cDvbSubtitleConverter::ExtractSegment(const uchar *Data, int Length, int64_t
switch (segmentType) {
case PAGE_COMPOSITION_SEGMENT: {
dbgsegments("PAGE_COMPOSITION_SEGMENT\n");
int pageVersion = (Data[6 + 1] & 0xF0) >> 4;
int pageTimeout = bs.GetBits(8);
int pageVersion = bs.GetBits(4);
if (pageVersion == page->Version())
break; // no update
page->SetVersion(pageVersion);
page->SetTimeout(Data[6]);
page->SetState((Data[6 + 1] & 0x0C) >> 2);
page->SetTimeout(pageTimeout);
page->SetState(bs.GetBits(2));
page->regions.Clear();
bs.SkipBits(2); // reserved
dbgpages("Update page id %d version %d pts %"PRId64" timeout %d state %d\n", pageId, page->Version(), page->Pts(), page->Timeout(), page->State());
for (int i = 6 + 2; i < segmentLength; i += 6) {
cSubtitleRegion *region = page->GetRegionById(Data[i], true);
region->SetHorizontalAddress((Data[i + 2] << 8) + Data[i + 3]);
region->SetVerticalAddress((Data[i + 4] << 8) + Data[i + 5]);
}
while (!bs.IsEOF()) {
cSubtitleRegion *region = page->GetRegionById(bs.GetBits(8), true);
bs.SkipBits(8); // reserved
region->SetHorizontalAddress(bs.GetBits(16));
region->SetVerticalAddress(bs.GetBits(16));
}
break;
}
case REGION_COMPOSITION_SEGMENT: {
dbgsegments("REGION_COMPOSITION_SEGMENT\n");
cSubtitleRegion *region = page->GetRegionById(Data[6]);
cSubtitleRegion *region = page->GetRegionById(bs.GetBits(8));
if (!region)
break;
int regionVersion = (Data[6 + 1] & 0xF0) >> 4;
int regionVersion = bs.GetBits(4);
if (regionVersion == region->Version())
break; // no update
region->SetVersion(regionVersion);
bool regionFillFlag = (Data[6 + 1] & 0x08) >> 3;
int regionWidth = (Data[6 + 2] << 8) | Data[6 + 3];
bool regionFillFlag = bs.GetBit();
bs.SkipBits(3); // reserved
int regionWidth = bs.GetBits(16);
if (regionWidth < 1)
regionWidth = 1;
int regionHeight = (Data[6 + 4] << 8) | Data[6 + 5];
int regionHeight = bs.GetBits(16);
if (regionHeight < 1)
regionHeight = 1;
region->SetSize(regionWidth, regionHeight);
region->SetLevel((Data[6 + 6] & 0xE0) >> 5);
region->SetDepth((Data[6 + 6] & 0x1C) >> 2);
region->SetClutId(Data[6 + 7]);
region->SetLevel(bs.GetBits(3));
region->SetDepth(bs.GetBits(3));
bs.SkipBits(2); // reserved
region->SetClutId(bs.GetBits(8));
dbgregions("Region pageId %d id %d version %d fill %d width %d height %d level %d depth %d clutId %d\n", pageId, region->RegionId(), region->Version(), regionFillFlag, regionWidth, regionHeight, region->Level(), region->Depth(), region->ClutId());
int region8bitPixelCode = bs.GetBits(8);
int region4bitPixelCode = bs.GetBits(4);
int region2bitPixelCode = bs.GetBits(2);
bs.SkipBits(2); // reserved
if (regionFillFlag) {
switch (region->Bpp()) {
case 2: region->FillRegion((Data[6 + 9] & 0x0C) >> 2); break;
case 4: region->FillRegion((Data[6 + 9] & 0xF0) >> 4); break;
case 8: region->FillRegion(Data[6 + 8]); break;
case 2: region->FillRegion(region8bitPixelCode); break;
case 4: region->FillRegion(region4bitPixelCode); break;
case 8: region->FillRegion(region2bitPixelCode); break;
default: dbgregions("unknown bpp %d (%s %d)\n", region->Bpp(), __FUNCTION__, __LINE__);
}
}
for (int i = 6 + 10; i < segmentLength; i += 6) {
cSubtitleObject *object = region->GetObjectById((Data[i] << 8) | Data[i + 1], true);
int objectType = (Data[i + 2] & 0xC0) >> 6;
object->SetCodingMethod(objectType);
object->SetProviderFlag((Data[i + 2] & 0x30) >> 4);
int objectHorizontalPosition = ((Data[i + 2] & 0x0F) << 8) | Data[i + 3];
int objectVerticalPosition = ((Data[i + 4] & 0x0F) << 8) | Data[i + 5];
object->SetPosition(objectHorizontalPosition, objectVerticalPosition);
if (objectType == 0x01 || objectType == 0x02) {
object->SetForegroundColor(Data[i + 6]);
object->SetBackgroundColor(Data[i + 7]);
i += 2;
}
}
while (!bs.IsEOF()) {
cSubtitleObject *object = region->GetObjectById(bs.GetBits(16), true);
int objectType = bs.GetBits(2);
object->SetCodingMethod(objectType);
object->SetProviderFlag(bs.GetBits(2));
int objectHorizontalPosition = bs.GetBits(12);
bs.SkipBits(4); // reserved
int objectVerticalPosition = bs.GetBits(12);
object->SetPosition(objectHorizontalPosition, objectVerticalPosition);
if (objectType == 0x01 || objectType == 0x02) {
object->SetForegroundPixelCode(bs.GetBits(8));
object->SetBackgroundPixelCode(bs.GetBits(8));
}
}
break;
}
case CLUT_DEFINITION_SEGMENT: {
dbgsegments("CLUT_DEFINITION_SEGMENT\n");
cSubtitleClut *clut = page->GetClutById(Data[6], true);
int clutVersion = (Data[6 + 1] & 0xF0) >> 4;
cSubtitleClut *clut = page->GetClutById(bs.GetBits(8), true);
int clutVersion = bs.GetBits(4);
if (clutVersion == clut->Version())
break; // no update
clut->SetVersion(clutVersion);
bs.SkipBits(4); // reserved
dbgcluts("Clut pageId %d id %d version %d\n", pageId, clut->ClutId(), clut->Version());
for (int i = 6 + 2; i < segmentLength; i += 2) {
uchar clutEntryId = Data[i];
bool fullRangeFlag = Data[i + 1] & 1;
uchar yval;
uchar crval;
uchar cbval;
uchar tval;
if (fullRangeFlag) {
yval = Data[i + 2];
crval = Data[i + 3];
cbval = Data[i + 4];
tval = Data[i + 5];
}
else {
yval = Data[i + 2] & 0xFC;
crval = (Data[i + 2] & 0x03) << 6;
crval |= (Data[i + 3] & 0xC0) >> 2;
cbval = (Data[i + 3] & 0x3C) << 2;
tval = (Data[i + 3] & 0x03) << 6;
}
tColor value = 0;
if (yval) {
value = yuv2rgb(yval, cbval, crval);
value |= ((10 - (clutEntryId ? Setup.SubtitleFgTransparency : Setup.SubtitleBgTransparency)) * (255 - tval) / 10) << 24;
}
int EntryFlags = Data[i + 1];
dbgcluts("%2d %d %d %d %08X\n", clutEntryId, (EntryFlags & 0x80) ? 2 : 0, (EntryFlags & 0x40) ? 4 : 0, (EntryFlags & 0x20) ? 8 : 0, value);
if ((EntryFlags & 0x80) != 0)
clut->SetColor(2, clutEntryId, value);
if ((EntryFlags & 0x40) != 0)
clut->SetColor(4, clutEntryId, value);
if ((EntryFlags & 0x20) != 0)
clut->SetColor(8, clutEntryId, value);
i += fullRangeFlag ? 4 : 2;
}
while (!bs.IsEOF()) {
uchar clutEntryId = bs.GetBits(8);
bool entryClut2Flag = bs.GetBit();
bool entryClut4Flag = bs.GetBit();
bool entryClut8Flag = bs.GetBit();
bs.SkipBits(4); // reserved
uchar yval;
uchar crval;
uchar cbval;
uchar tval;
if (bs.GetBit()) { // full_range_flag
yval = bs.GetBits(8);
crval = bs.GetBits(8);
cbval = bs.GetBits(8);
tval = bs.GetBits(8);
}
else {
yval = bs.GetBits(6) << 2;
crval = bs.GetBits(4) << 4;
cbval = bs.GetBits(4) << 4;
tval = bs.GetBits(2) << 6;
}
tColor value = 0;
if (yval) {
value = yuv2rgb(yval, cbval, crval);
value |= ((10 - (clutEntryId ? Setup.SubtitleFgTransparency : Setup.SubtitleBgTransparency)) * (255 - tval) / 10) << 24;
}
dbgcluts("%2d %d %d %d %08X\n", clutEntryId, entryClut2Flag ? 2 : 0, entryClut4Flag ? 4 : 0, entryClut8Flag ? 8 : 0, value);
if (entryClut2Flag)
clut->SetColor(2, clutEntryId, value);
if (entryClut4Flag)
clut->SetColor(4, clutEntryId, value);
if (entryClut8Flag)
clut->SetColor(8, clutEntryId, value);
}
dbgcluts("\n");
page->UpdateRegionPalette(clut);
break;
}
case OBJECT_DATA_SEGMENT: {
dbgsegments("OBJECT_DATA_SEGMENT\n");
cSubtitleObject *object = page->GetObjectById((Data[6] << 8) | Data[6 + 1]);
cSubtitleObject *object = page->GetObjectById(bs.GetBits(16));
if (!object)
break;
int objectVersion = (Data[6 + 2] & 0xF0) >> 4;
int objectVersion = bs.GetBits(4);
if (objectVersion == object->Version())
break; // no update
object->SetVersion(objectVersion);
int codingMethod = (Data[6 + 2] & 0x0C) >> 2;
object->SetNonModifyingColorFlag(Data[6 + 2] & 0x01);
int codingMethod = bs.GetBits(2);
object->SetNonModifyingColorFlag(bs.GetBit());
bs.SkipBit(); // reserved
dbgobjects("Object pageId %d id %d version %d method %d modify %d\n", pageId, object->ObjectId(), object->Version(), object->CodingMethod(), object->NonModifyingColorFlag());
if (codingMethod == 0) { // coding of pixels
int i = 6 + 3;
int topFieldLength = (Data[i] << 8) | Data[i + 1];
int bottomFieldLength = (Data[i + 2] << 8) | Data[i + 3];
object->DecodeSubBlock(Data + i + 4, topFieldLength, true);
int topFieldLength = bs.GetBits(16);
int bottomFieldLength = bs.GetBits(16);
object->DecodeSubBlock(bs.GetData(), topFieldLength, true);
if (bottomFieldLength)
object->DecodeSubBlock(Data + i + 4 + topFieldLength, bottomFieldLength, false);
object->DecodeSubBlock(bs.GetData() + topFieldLength, bottomFieldLength, false);
else
object->DecodeSubBlock(Data + i + 4, topFieldLength, false);
object->DecodeSubBlock(bs.GetData(), topFieldLength, false);
bs.WordAlign();
}
else if (codingMethod == 1) { // coded as a string of characters
//TODO implement textual subtitles
int numberOfCodes = bs.GetBits(8);
object->DecodeCharacterString(bs.GetData(), numberOfCodes);
}
#ifdef FINISHPAGE_HACK
FinishPage(page); // flush to OSD right away
#endif
break;
}
case DISPLAY_DEFINITION_SEGMENT: {
dbgsegments("DISPLAY_DEFINITION_SEGMENT\n");
int version = (Data[6] & 0xF0) >> 4;
int version = bs.GetBits(4);
if (version != ddsVersionNumber) {
int displayWindowFlag = (Data[6] & 0x08) >> 3;
bool displayWindowFlag = bs.GetBit();
windowHorizontalOffset = 0;
windowVerticalOffset = 0;
displayWidth = windowWidth = ((Data[7] << 8) | Data[8]) + 1;
displayHeight = windowHeight = ((Data[9] << 8) | Data[10]) + 1;
if (displayWindowFlag) {
windowHorizontalOffset = (Data[11] << 8) | Data[12]; // displayWindowHorizontalPositionMinimum
windowWidth = ((Data[13] << 8) | Data[14]) - windowHorizontalOffset + 1; // displayWindowHorizontalPositionMaximum
windowVerticalOffset = (Data[15] << 8) | Data[16]; // displayWindowVerticalPositionMinimum
windowHeight = ((Data[17] << 8) | Data[18]) - windowVerticalOffset + 1; // displayWindowVerticalPositionMaximum
bs.SkipBits(3); // reserved
displayWidth = windowWidth = bs.GetBits(16) + 1;
displayHeight = windowHeight = bs.GetBits(16) + 1;
if (displayWindowFlag) {
windowHorizontalOffset = bs.GetBits(16); // displayWindowHorizontalPositionMinimum
windowWidth = bs.GetBits(16) - windowHorizontalOffset + 1; // displayWindowHorizontalPositionMaximum
windowVerticalOffset = bs.GetBits(16); // displayWindowVerticalPositionMinimum
windowHeight = bs.GetBits(16) - windowVerticalOffset + 1; // displayWindowVerticalPositionMaximum
}
SetOsdData();
SetupChanged();
@@ -1086,15 +1213,56 @@ int cDvbSubtitleConverter::ExtractSegment(const uchar *Data, int Length, int64_t
}
break;
}
case DISPARITY_SIGNALING_SEGMENT: {
dbgsegments("DISPARITY_SIGNALING_SEGMENT\n");
bs.SkipBits(4); // dss_version_number
bool disparity_shift_update_sequence_page_flag = bs.GetBit();
bs.SkipBits(3); // reserved
bs.SkipBits(8); // page_default_disparity_shift
if (disparity_shift_update_sequence_page_flag) {
bs.SkipBits(8); // disparity_shift_update_sequence_length
bs.SkipBits(24); // interval_duration[23..0]
int division_period_count = bs.GetBits(8);
for (int i = 0; i < division_period_count; ++i) {
bs.SkipBits(8); // interval_count
bs.SkipBits(8); // disparity_shift_update_integer_part
}
}
while (!bs.IsEOF()) {
bs.SkipBits(8); // region_id
bool disparity_shift_update_sequence_region_flag = bs.GetBit();
bs.SkipBits(5); // reserved
int number_of_subregions_minus_1 = bs.GetBits(2);
for (int i = 0; i <= number_of_subregions_minus_1; ++i) {
if (number_of_subregions_minus_1 > 0) {
bs.SkipBits(16); // subregion_horizontal_position
bs.SkipBits(16); // subregion_width
}
bs.SkipBits(8); // subregion_disparity_shift_integer_part
bs.SkipBits(4); // subregion_disparity_shift_fractional_part
bs.SkipBits(4); // reserved
if (disparity_shift_update_sequence_region_flag) {
bs.SkipBits(8); // disparity_shift_update_sequence_length
bs.SkipBits(24); // interval_duration[23..0]
int division_period_count = bs.GetBits(8);
for (int i = 0; i < division_period_count; ++i) {
bs.SkipBits(8); // interval_count
bs.SkipBits(8); // disparity_shift_update_integer_part
}
}
}
}
break;
}
case END_OF_DISPLAY_SET_SEGMENT: {
dbgsegments("END_OF_DISPLAY_SET_SEGMENT\n");
FinishPage(page);
}
break;
}
default:
dbgsegments("*** unknown segment type: %02X\n", segmentType);
}
return segmentLength;
return bs.Length() / 8;
}
return -1;
}
@@ -1143,6 +1311,7 @@ void cDvbSubtitleConverter::FinishPage(cDvbSubtitlePage *Page)
cDvbSubtitleBitmaps *Bitmaps = new cDvbSubtitleBitmaps(Page->Pts(), Page->Timeout(), Areas, NumAreas, osdFactorX, osdFactorY);
bitmaps->Add(Bitmaps);
for (cSubtitleRegion *sr = Page->regions.First(); sr; sr = Page->regions.Next(sr)) {
sr->UpdateTextData(Page->GetClutById(sr->ClutId()));
int posX = sr->HorizontalAddress();
int posY = sr->VerticalAddress();
if (sr->Width() > 0 && sr->Height() > 0) {