Browse files

Fixes #9772. Applies patch by Jim Stichnoth to for CEA-608 to add col…

…or, italic and underline support.
  • Loading branch information...
1 parent 6bd5d1e commit 11adb5bf74bbf0326691f40b8c588e01d73febe2 @daniel-kristjansson daniel-kristjansson committed Aug 11, 2011
View
49 mythtv/libs/libmythtv/cc608decoder.cpp
@@ -43,6 +43,7 @@ CC608Decoder::CC608Decoder(CC608Input *ccr)
memset(lastrow, 0, sizeof(lastrow));
memset(newrow, 0, sizeof(newrow));
memset(newcol, 0, sizeof(newcol));
+ memset(newattr, 0, sizeof(newattr));
memset(timecode, 0, sizeof(timecode));
memset(row, 0, sizeof(row));
memset(col, 0, sizeof(col));
@@ -259,11 +260,27 @@ void CC608Decoder::FormatCCField(int tc, int field, int data)
newrow[mode] = lastrow[mode] + 1;
if (b2 & 0x10) //row contains indent flag
+ {
newcol[mode] = (b2 & 0x0E) << 1;
+ // Encode as 0x7020 or 0x7021 depending on the
+ // underline flag.
+ newattr[mode] = (b2 & 0x1) + 0x20;
+ LOG(VB_VBI, LOG_INFO,
+ QString("cc608 preamble indent, b2=%1")
+ .arg(b2, 2, 16));
+ }
else
+ {
newcol[mode] = 0;
+ newattr[mode] = (b2 & 0xf) + 0x10;
+ // Encode as 0x7010 through 0x702f for the 16 possible
+ // values of b2.
+ LOG(VB_VBI, LOG_INFO,
+ QString("cc608 preamble color change, b2=%1")
+ .arg(b2, 2, 16));
+ }
- // row, indent settings are not final
+ // row, indent, attribute settings are not final
// until text code arrives
}
else
@@ -283,8 +300,12 @@ void CC608Decoder::FormatCCField(int tc, int field, int data)
switch (b2 & 0x70)
{
case 0x20: //midrow attribute change
- // TODO: we _do_ want colors, is that an attribute?
- ccbuf[mode] += ' ';
+ LOG(VB_VBI, LOG_INFO,
+ QString("cc608 mid-row color change, b2=%1")
+ .arg(b2, 2, 16));
+ // Encode as 0x7000 through 0x700f for the
+ // 16 possible values of b2.
+ ccbuf[mode] += QChar(0x7000 + (b2 & 0xf));
len = ccbuf[mode].length();
col[mode]++;
break;
@@ -421,6 +442,7 @@ void CC608Decoder::FormatCCField(int tc, int field, int data)
{
newrow[mode] = 1;
newcol[mode] = 0;
+ newattr[mode] = 0;
}
style[mode] = CC_STYLE_ROLLUP;
break;
@@ -483,6 +505,7 @@ void CC608Decoder::FormatCCField(int tc, int field, int data)
// TXT starts at row 1
newrow[mode] = 1;
newcol[mode] = 0;
+ newattr[mode] = 0;
style[mode] = CC_STYLE_ROLLUP;
break;
@@ -667,7 +690,8 @@ void CC608Decoder::BufferCC(int mode, int len, int clr)
int i = 0;
while (i < dispbuf.length()) {
QChar cp = dispbuf.at(i);
- switch (cp.unicode())
+ int cpu = cp.unicode();
+ switch (cpu)
{
case 0x2120 : vbuf += "(SM)"; break;
case 0x2122 : vbuf += "(TM)"; break;
@@ -681,7 +705,10 @@ void CC608Decoder::BufferCC(int mode, int len, int clr)
case 0x2588 : vbuf += "[]"; break;
case 0x266A : vbuf += "o/~"; break;
case '\b' : vbuf += "\\b"; break;
- default : vbuf += QString(cp.toLatin1());
+ default :
+ if (cpu >= 0x7000 && cpu < 0x7000 + 0x30)
+ vbuf += QString("[%1]").arg(cpu - 0x7000, 2, 16);
+ else vbuf += QString(cp.toLatin1());
}
i++;
}
@@ -787,13 +814,23 @@ int CC608Decoder::NewRowCC(int mode, int len)
lastrow[mode] = newrow[mode];
newrow[mode] = 0;
- for (int x = 0; x < newcol[mode]; x++)
+ int limit = (newattr[mode] ? newcol[mode] - 1 : newcol[mode]);
+ for (int x = 0; x < limit; x++)
{
ccbuf[mode] += ' ';
len++;
col[mode]++;
}
+
+ if (newattr[mode])
+ {
+ ccbuf[mode] += QChar(newattr[mode] + 0x7000);
+ len++;
+ col[mode]++;
+ }
+
newcol[mode] = 0;
+ newattr[mode] = 0;
return len;
}
View
1 mythtv/libs/libmythtv/cc608decoder.h
@@ -98,6 +98,7 @@ class CC608Decoder
int lastrow[8];
int newrow[8];
int newcol[8];
+ int newattr[8]; // color+italic+underline
int timecode[8];
int row[8];
int col[8];
View
6 mythtv/libs/libmythtv/cc608reader.cpp
@@ -97,8 +97,8 @@ CC608Buffer *CC608Reader::GetOutputText(bool &changed, int &streamIdx)
memcpy(&st, inpos, sizeof(st));
inpos += sizeof(st);
- CC608Text *cc = new CC608Text(QString((const char*) inpos),
- st.row, st.col, st.fg, true);
+ CC608Text *cc = new CC608Text(
+ QString((const char*) inpos), st.row, st.col, true);
m_state[streamIdx].m_output.lock.lock();
m_state[streamIdx].m_output.buffers.push_back(cc);
@@ -234,7 +234,7 @@ int CC608Reader::Update(unsigned char *inpos)
tmpcc = new CC608Text(
m_state[streamIdx].m_outputText,
m_state[streamIdx].m_outputCol,
- m_state[streamIdx].m_outputRow, 0, false);
+ m_state[streamIdx].m_outputRow, false);
ccbuf->push_back(tmpcc);
#if 0
if (ccbuf->size() > 4)
View
5 mythtv/libs/libmythtv/cc608reader.h
@@ -15,12 +15,11 @@
class CC608Text
{
public:
- CC608Text(QString T, int X, int Y, int C, int TT)
- : text(T), x(X), y(Y), color(C), teletextmode(TT) {}
+ CC608Text(QString T, int X, int Y, int TT) :
+ text(T), x(X), y(Y), teletextmode(TT) {}
QString text;
int x;
int y;
- int color;
bool teletextmode;
};
View
142 mythtv/libs/libmythtv/subtitlescreen.cpp
@@ -339,6 +339,8 @@ void SubtitleScreen::DisplayTextSubtitles(void)
changed = true;
int height = (m_safeArea.height() * m_textFontZoom) / 1800;
gTextSubFont->GetFace()->setPixelSize(height);
+ gTextSubFont->GetFace()->setItalic(false);
+ gTextSubFont->GetFace()->setUnderline(false);
gTextSubFont->SetColor(Qt::white);
}
}
@@ -424,6 +426,8 @@ void SubtitleScreen::DisplayRawTextSubtitles(void)
{
int height = (m_safeArea.height() * m_textFontZoom) / 1800;
gTextSubFont->GetFace()->setPixelSize(height);
+ gTextSubFont->GetFace()->setItalic(false);
+ gTextSubFont->GetFace()->setUnderline(false);
gTextSubFont->SetColor(Qt::white);
}
}
@@ -572,12 +576,86 @@ void SubtitleScreen::DisplayDVDButton(AVSubtitle* dvdButton, QRect &buttonPos)
AddScaledImage(bg_image, rect);
}
+/// Extract everything from the text buffer up until the next format
+/// control character. Return that substring, and remove it from the
+/// input string. Bogus control characters are left unchanged. If the
+/// buffer starts with a valid control character, the output parameters
+/// are corresondingly updated (and the control character is stripped).
+static QString extract_cc608(
+ QString &text, bool teletextmode, int &color,
+ bool &isItalic, bool &isUnderline, bool &showedNonControl)
+{
+ QString result;
+ QString orig(text);
+
+ if (teletextmode)
+ {
+ result = text;
+ text = QString::null;
+ showedNonControl = true;
+ return result;
+ }
+
+ // Handle an initial control sequence.
+ if (text.length() >= 1 && text[0] >= 0x7000)
+ {
+ int op = text[0].unicode() - 0x7000;
+ isUnderline = (op & 0x1);
+ switch (op & ~1)
+ {
+ case 0x0e:
+ // color unchanged
+ isItalic = true;
+ break;
+ case 0x1e:
+ color = op >> 1;
+ isItalic = true;
+ break;
+ case 0x20:
+ // color unchanged
+ // italics unchanged
+ break;
+ default:
+ color = (op & 0xf) >> 1;
+ isItalic = false;
+ break;
+ }
+ text = text.mid(1);
+ }
+
+ // Copy the string into the result, up to the next control
+ // character.
+ int nextControl = text.indexOf(QRegExp("[\\x7000-\\x7fff]"));
+ if (nextControl < 0)
+ {
+ result = text;
+ text = QString::null;
+ showedNonControl = true;
+ }
+ else
+ {
+ result = text.left(nextControl);
+ // Print the space character before handling the next control
+ // character, otherwise the space character will be lost due
+ // to the text.trimmed() operation in the MythUIText
+ // constructor, combined with the left-justification of
+ // captions.
+ if (text[nextControl] < (0x7000 + 0x10))
+ result += " ";
+ text = text.mid(nextControl);
+ if (nextControl > 0)
+ showedNonControl = true;
+ }
+
+ return result;
+}
+
void SubtitleScreen::DisplayCC608Subtitles(void)
{
static const QColor clr[8] =
{
- Qt::white, Qt::red, Qt::green, Qt::yellow,
- Qt::blue, Qt::magenta, Qt::cyan, Qt::white,
+ Qt::white, Qt::green, Qt::blue, Qt::cyan,
+ Qt::red, Qt::yellow, Qt::magenta, Qt::white,
};
if (!InitialiseFont(m_fontStretch) || !m_608reader)
@@ -621,22 +699,53 @@ void SubtitleScreen::DisplayCC608Subtitles(void)
int xscale = teletextmode ? 40 : 36;
int yscale = teletextmode ? 25 : 17;
gTextSubFont->GetFace()->setPixelSize(m_safeArea.height() / (yscale * 1.2));
- QFontMetrics font(*(gTextSubFont->GetFace()));
QBrush bgfill = QBrush(QColor(0, 0, 0), Qt::SolidPattern);
- int height = font.height() * (1 + PAD_HEIGHT);
- int pad_width = font.maxWidth() * PAD_WIDTH;
for (; i != textlist->buffers.end(); i++)
{
CC608Text *cc = (*i);
+ int color = 0;
+ bool isItalic = false, isUnderline = false;
+ bool first = true;
+ bool showedNonControl = false;
+ int x = 0, width = 0;
+ QString text(cc->text);
- if (cc && (cc->text != QString::null))
+ for (int chunk = 0; text != QString::null; first = false, chunk++)
{
- int width = font.width(cc->text) + pad_width;
- int x = teletextmode ? cc->y : (cc->x + 3);
+ QString captionText =
+ extract_cc608(text, cc->teletextmode,
+ color, isItalic, isUnderline,
+ showedNonControl);
+ gTextSubFont->GetFace()->setItalic(isItalic);
+ gTextSubFont->GetFace()->setUnderline(isUnderline);
+ gTextSubFont->SetColor(clr[min(max(0, color), 7)]);
+ QFontMetrics font(*(gTextSubFont->GetFace()));
+ // XXX- could there be different heights across the same line?
+ int height = font.height() * (1 + PAD_HEIGHT);
+ if (first)
+ {
+ x = teletextmode ? cc->y : (cc->x + 3);
+ x = (int)(((float)x / (float)xscale) *
+ (float)m_safeArea.width());
+ }
+ else
+ {
+ x += width; // bump x by the previous width
+ }
+
+ int pad_width = font.maxWidth() * PAD_WIDTH;
+ width = font.width(captionText) + pad_width;
int y = teletextmode ? cc->x : cc->y;
- x = (int)(((float)x / (float)xscale) * (float)m_safeArea.width());
y = (int)(((float)y / (float)yscale) * (float)m_safeArea.height());
+ // Sometimes a line of caption text begins with a mid-row
+ // format control like italics or a color change. The
+ // spec says the mid-row control also includes a space
+ // character. But this looks clumsy when using a
+ // background, so we suppress it after the placement is
+ // calculated.
+ if (!showedNonControl)
+ continue;
QRect rect(x, y, width, height);
if (!teletextmode && m_useBackground)
@@ -648,15 +757,20 @@ void SubtitleScreen::DisplayCC608Subtitles(void)
shape->SetArea(MythRect(bgrect));
}
- gTextSubFont->SetColor(clr[min(max(0, cc->color), 7)]);
MythUIText *text = new MythUIText(
- cc->text, *gTextSubFont, rect, rect, (MythUIType*)this,
- QString("cc608txt%1%2%3").arg(cc->x).arg(cc->y).arg(width));
+ captionText, *gTextSubFont, rect, rect, (MythUIType*)this,
+ QString("cc608txt%1%2%3%4").arg(cc->x).arg(cc->y)
+ .arg(width).arg(chunk));
if (text)
text->SetJustification(Qt::AlignLeft);
+
m_refreshArea = true;
- LOG(VB_VBI, LOG_INFO, QString("x %1 y %2 String: '%3'")
- .arg(cc->x).arg(cc->y).arg(cc->text));
+
+ LOG(VB_VBI, LOG_INFO,
+ QString("x %1 y %2 uline=%4 ital=%5 "
+ "color=%6 coord=%7,%8 String: '%3'")
+ .arg(cc->x).arg(cc->y).arg(captionText)
+ .arg(isUnderline).arg(isItalic).arg(color).arg(x).arg(y));
}
}
textlist->lock.unlock();

0 comments on commit 11adb5b

Please sign in to comment.