#include <stdio.h>
#include <Debug.h>
#include "CC.h"
CCaption::CCaption(CCapture & capture)
: fCapture(capture),
fChannel(C_RADEON_CC1),
fRow(0),
fColumn(0),
fColor(0),
fLastControlCode(0)
{
for (int row = 0; row < C_RADEON_CC_ROWS; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++) {
fText[row][column] = fDisplayText[row][column] = 0x0000;
}
}
}
CCaption::~CCaption()
{
}
status_t CCaption::InitCheck() const
{
return fCapture.InitCheck();
}
void CCaption::SetMode(cc_mode mode)
{
fChannel = mode;
fLastControlCode = 0;
}
bool CCaption::DecodeBits(const unsigned char * buffer, int & data)
{
if (buffer == NULL)
return false;
int low = 0xff, high = 0x00;
for (int offset = C_RADEON_CC_BLANK_START; offset < C_RADEON_CC_BLANK_START + 4 * C_RADEON_CC_BIT_DURATION; offset++) {
if (low > buffer[offset])
low = buffer[offset];
if (high < buffer[offset])
high = buffer[offset];
}
if (low + C_RADEON_CC_LEVEL_THRESHOLD >= high)
return false;
const int middle = (low + high) >> 1;
int start = C_RADEON_CC_BLANK_START + C_RADEON_CC_BIT_DURATION;
while (start <= C_RADEON_CC_BLANK_START + 4 * C_RADEON_CC_BIT_DURATION) {
if (buffer[start + 0] < middle && buffer[start + 1] < middle &&
buffer[start + 3] > middle && buffer[start + 4] > middle)
break;
start++;
}
if (start >= C_RADEON_CC_BLANK_START + 4 * C_RADEON_CC_BIT_DURATION)
return false;
int end = start + 17 * C_RADEON_CC_BIT_DURATION;
int bit = 0;
bool one = true;
for (int offset = start + C_RADEON_CC_BIT_DURATION / 2; offset < end; offset++) {
int width = 1;
while (offset < end) {
if (one) {
if (buffer[offset + 0] > middle && buffer[offset + 1] > middle &&
buffer[offset + 3] < middle && buffer[offset + 4] < middle)
break;
}
else {
if (buffer[offset + 0] < middle && buffer[offset + 1] < middle &&
buffer[offset + 3] > middle && buffer[offset + 4] > middle)
break;
}
offset++;
width++;
}
const int nbits = (width + (bit == 0 ? 0 : bit == 15 ? C_RADEON_CC_BIT_DURATION :
C_RADEON_CC_BIT_DURATION / 2)) / C_RADEON_CC_BIT_DURATION;
data >>= nbits;
if (one)
data |= (0xffff << (16 - nbits)) & 0xffff;
if ((bit += nbits) >= C_RADEON_CC_BITS_PER_FIELD)
break;
one = !one;
}
if (bit != C_RADEON_CC_BITS_PER_FIELD)
return false;
return true;
}
bool CCaption::Decode(const unsigned char * buffer0,
const unsigned char * buffer1)
{
enum caption_code {
C_CC1 = 0x0000,
C_CC2 = 0x0800,
C_ROW_1 = 0x0100,
C_ROW_2 = 0x0120,
C_ROW_3 = 0x0200,
C_ROW_4 = 0x0220,
C_ROW_5 = 0x0500,
C_ROW_6 = 0x0520,
C_ROW_7 = 0x0600,
C_ROW_8 = 0x0620,
C_ROW_9 = 0x0700,
C_ROW_10 = 0x0720,
C_ROW_11 = 0x0000,
C_ROW_12 = 0x0300,
C_ROW_13 = 0x0320,
C_ROW_14 = 0x0400,
C_ROW_15 = 0x0420,
C_WHITE = 0x0000,
C_GREEN = 0x0002,
C_BLUE = 0x0004,
C_CYAN = 0x0006,
C_RED = 0x0008,
C_YELLOW = 0x000a,
C_MAGENTA = 0x000c,
C_ITALICS = 0x000e,
C_NORMAL = 0x0000,
C_UNDERLINE = 0x0001,
C_RCL = 0x0000,
C_BS = 0x0001,
C_AOF = 0x0002,
C_AON = 0x0003,
C_DER = 0x0004,
C_RU2 = 0x0005,
C_RU3 = 0x0006,
C_RU4 = 0x0007,
C_FON = 0x0008,
C_RDC = 0x0009,
C_TR = 0x000a,
C_RTD = 0x000b,
C_EDM = 0x000c,
C_CR = 0x000d,
C_ENM = 0x000e,
C_EOC = 0x000f,
C_reg = 0x0000,
C_deg = 0x0001,
C_frac12 = 0x0002,
C_iquest = 0x0003,
C_trademark = 0x0004,
C_cent = 0x0005,
C_pound = 0x0006,
C_music = 0x0007,
C_agrave = 0x0008,
C_tspace = 0x0009,
C_egrave = 0x000a,
C_acirc = 0x000b,
C_ecirc = 0x000c,
C_icirc = 0x000d,
C_ocirc = 0x000e,
C_ucirc = 0x000f,
C_aacute = 0x002a,
C_eacute = 0x005c,
C_iacute = 0x005e,
C_oacute = 0x005f,
C_uacute = 0x0060,
C_ccedil = 0x007b,
C_division = 0x007c,
C_Ntilde = 0x007d,
C_ntilde = 0x007e,
C_block = 0x007f
};
int code, channel, character;
if (!DecodeBits(fChannel == C_RADEON_CC1 || fChannel == C_RADEON_CC2 ? buffer0 : buffer1, code))
return false;
code = ((code << 8) & 0xff00) | ((code >> 8) & 0x00ff);
for (int bit = 0; bit < 7; bit++) {
if ((code & (0x0001 << bit)) != 0)
code ^= 0x0080;
if ((code & (0x0100 << bit)) != 0)
code ^= 0x8000;
}
if ((code & 0x8080) != 0x8080) {
PRINT(("CCaption::Decode() - parity error (%04X)\n", code));
return false;
}
channel = (code & 0x0800) >> 12;
if (channel == 0) {
if (fChannel != C_RADEON_CC1 && fChannel != C_RADEON_CC3) {
PRINT(("CCaption::Decode() - ignore channel (%02X)\n", code & 0x7f7f));
return false;
}
}
else {
if (fChannel != C_RADEON_CC2 && fChannel != C_RADEON_CC4) {
PRINT(("CCaption::Decode() - ignore channel (%02X)\n", code & 0x7f7f));
return false;
}
}
if ((code & 0x7000) == 0x0000) {
character = code & 0x007f;
if (character >= 0x20) {
PRINT(("%c", character));
fText[fRow][fColumn] = (fColor << 8) + character;
if (fColumn < C_RADEON_CC_COLUMNS - 1)
fColumn++;
}
else if (character != 0x00) {
PRINT(("<%04X>", code & 0x7f7f));
}
}
else if ((code & 0x7770) == 0x1120) {
fColor = code & 0x000f;
fText[fRow][fColumn] = (fColor << 8) + ' ';
if (fColumn < C_RADEON_CC_COLUMNS - 1)
fColumn++;
switch (fColor & 0x000e) {
case C_WHITE:
PRINT(("<white"));
break;
case C_GREEN:
PRINT(("<green"));
break;
case C_BLUE:
PRINT(("<blue"));
break;
case C_CYAN:
PRINT(("<cyan"));
break;
case C_RED:
PRINT(("<red"));
break;
case C_YELLOW:
PRINT(("<yellow"));
break;
case C_MAGENTA:
PRINT(("<magenta"));
break;
case C_ITALICS:
PRINT(("<italics"));
break;
}
if ((fColor & 0x0001) != 0)
PRINT((",underline>"));
else
PRINT((">"));
}
else if ((code & 0x7770) == 0x1130) {
character = (code & 0x000f);
fText[fRow][fColumn] = (fColor << 8) + character + 0x0080;
if (fColumn < C_RADEON_CC_COLUMNS - 1)
fColumn++;
switch (character) {
case C_reg:
PRINT(("®"));
break;
case C_deg:
PRINT(("°"));
break;
case C_frac12:
PRINT(("½"));
break;
case C_iquest:
PRINT(("¿"));
break;
case C_trademark:
PRINT(("&trademark;"));
break;
case C_cent:
PRINT(("¢"));
break;
case C_pound:
PRINT(("£"));
break;
case C_music:
PRINT(("&music;"));
break;
case C_agrave:
PRINT(("à"));
break;
case C_tspace:
PRINT(("&tspace;"));
break;
case C_egrave:
PRINT(("è"));
break;
case C_acirc:
PRINT(("â"));
break;
case C_ecirc:
PRINT(("ê"));
break;
case C_icirc:
PRINT(("î"));
break;
case C_ocirc:
PRINT(("ô"));
break;
case C_ucirc:
PRINT(("û"));
break;
default:
PRINT(("<special=%04X>", code & 0x7f7f));
break;
}
}
else if ((code & 0x7770) == 0x1420) {
if (code == fLastControlCode)
return false;
fLastControlCode = code;
switch (code & 0x000f) {
case C_RCL:
PRINT(("<rcl>"));
break;
case C_BS:
PRINT(("<bs>"));
if (fColumn > 0)
fText[fRow][--fColumn] = 0x0000;
break;
case C_AOF:
PRINT(("<aof>"));
break;
case C_AON:
PRINT(("<aon>"));
break;
case C_DER:
PRINT(("<der>"));
for (int column = fColumn; column < C_RADEON_CC_COLUMNS; column++)
fText[fRow][column] = 0x0000;
break;
case C_RU2:
PRINT(("<ru2>"));
for (int row = 0; row < C_RADEON_CC_ROWS - 2; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++)
fText[row][column] = fText[row + 2][column];
}
for (int row = C_RADEON_CC_ROWS - 2; row < C_RADEON_CC_ROWS; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++)
fText[row][column] = 0x0000;
}
break;
case C_RU3:
PRINT(("<ru3>"));
for (int row = 0; row < C_RADEON_CC_ROWS - 3; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++)
fText[row][column] = fText[row + 2][column];
}
for (int row = C_RADEON_CC_ROWS - 3; row < C_RADEON_CC_ROWS; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++)
fText[row][column] = 0x0000;
}
break;
case C_RU4:
PRINT(("<ru4>"));
for (int row = 0; row < C_RADEON_CC_ROWS - 4; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++)
fText[row][column] = fText[row + 2][column];
}
for (int row = C_RADEON_CC_ROWS - 4; row < C_RADEON_CC_ROWS; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++)
fText[row][column] = 0x0000;
}
break;
case C_FON:
PRINT(("<fon>"));
break;
case C_RDC:
PRINT(("<rdc>"));
break;
case C_TR:
PRINT(("<tr>"));
fRow = fColumn = 0;
break;
case C_RTD:
PRINT(("<rtd>"));
fRow = fColumn = 0;
break;
case C_EDM:
PRINT(("<edm>\n"));
for (int row = 0; row < C_RADEON_CC_ROWS; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++)
fDisplayText[row][column] = 0x0000;
}
DisplayCaptions();
break;
case C_CR:
PRINT(("<cr>"));
break;
case C_ENM:
PRINT(("<enm>"));
for (int row = 0; row < C_RADEON_CC_ROWS; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++)
fText[row][column] = 0x0000;
}
break;
case C_EOC:
PRINT(("<eoc>\n"));
for (int row = 0; row < C_RADEON_CC_ROWS; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++) {
const int code = fText[row][column];
fText[row][column] = fDisplayText[row][column];
fDisplayText[row][column] = code;
}
}
DisplayCaptions();
break;
}
}
else if ((code & 0x7770) == 0x1720) {
const int offset = code & 0x000f;
if (offset >= 1 && offset <= 3) {
PRINT(("<tab%d>", offset));
if ((fColumn += offset) >= C_RADEON_CC_COLUMNS - 1)
fColumn = C_RADEON_CC_COLUMNS - 1;
}
else {
PRINT(("<tab=%04X>", code & 0x7f7f));
}
}
else if ((code & 0x7040) == 0x1040) {
switch (code & 0x0720) {
case C_ROW_1:
PRINT(("\n<row1"));
fRow = 0;
break;
case C_ROW_2:
PRINT(("\n<row2"));
fRow = 1;
break;
case C_ROW_3:
PRINT(("\n<row3"));
fRow = 2;
break;
case C_ROW_4:
PRINT(("\n<row4"));
fRow = 3;
break;
case C_ROW_5:
PRINT(("\n<row5"));
fRow = 4;
break;
case C_ROW_6:
PRINT(("\n<row6"));
fRow = 5;
break;
case C_ROW_7:
PRINT(("\n<row7"));
fRow = 6;
break;
case C_ROW_8:
PRINT(("\n<row8"));
fRow = 7;
break;
case C_ROW_9:
PRINT(("\n<row9"));
fRow = 8;
break;
case C_ROW_10:
PRINT(("\n<row10"));
fRow = 9;
break;
case C_ROW_11:
PRINT(("\n<row11"));
fRow = 10;
break;
case C_ROW_12:
PRINT(("\n<row12"));
fRow = 11;
break;
case C_ROW_13:
PRINT(("\n<row13"));
fRow = 12;
break;
case C_ROW_14:
PRINT(("\n<row14"));
fRow = 13;
break;
case C_ROW_15:
PRINT(("\n<row15"));
fRow = 14;
break;
default:
PRINT(("\n<pac=%04X>", code & 0x7f7f));
return false;
}
if ((code & 0x0010) == 0x0000) {
fColor = (code & 0x000f);
fColumn = 0;
switch (fColor & 0x000e) {
case C_WHITE:
PRINT((",white"));
break;
case C_GREEN:
PRINT((",green"));
break;
case C_BLUE:
PRINT((",blue"));
break;
case C_CYAN:
PRINT((",cyan"));
break;
case C_RED:
PRINT((",red"));
break;
case C_YELLOW:
PRINT((",yellow"));
break;
case C_MAGENTA:
PRINT((",magenta"));
break;
case C_ITALICS:
PRINT((",italics"));
break;
}
if ((fColor & 0x0001) != 0)
PRINT((",underline>"));
else
PRINT((">"));
}
else {
fColor = C_WHITE | (code & 0x0001);
fColumn = (code & 0x000e) << 1;
PRINT((",col%d>", fColumn));
}
}
else {
character = (code >> 8) & 0x7f;
if (character >= 0x20) {
PRINT(("%c", character));
fText[fRow][fColumn] = (fColor << 8) + character;
if (fColumn < C_RADEON_CC_COLUMNS - 1)
fColumn++;
}
else if (character != 0x00) {
PRINT(("<%02X>", character));
}
character = (code >> 0) & 0x7f;
if (character >= 0x20) {
PRINT(("%c", character));
fText[fRow][fColumn] = (fColor << 8) + character;
if (fColumn < C_RADEON_CC_COLUMNS - 1)
fColumn++;
}
else if (character != 0x00) {
PRINT(("<%02X>", character));
}
}
return true;
}
void CCaption::DisplayCaptions() const
{
printf("\x1b[H\x1b[J");
for (int row = 0; row < C_RADEON_CC_ROWS; row++) {
for (int column = 0; column < C_RADEON_CC_COLUMNS; column++) {
if (fDisplayText[row][column] == 0x0000) {
printf("\x1b[0;47;37m ");
continue;
}
const int code = (fDisplayText[row][column] >> 0) & 0xff;
const int color = (fDisplayText[row][column] >> 8) & 0xff;
switch (color & 0x000e) {
case 0x0000:
printf("\x1b[0;%d;40;37m", (color & 1) << 2);
break;
case 0x0002:
printf("\x1b[0;%d;40;32m", (color & 1) << 2);
break;
case 0x0004:
printf("\x1b[0;%d;40;34m", (color & 1) << 2);
break;
case 0x0006:
printf("\x1b[0;%d;40;35m", (color & 1) << 2);
break;
case 0x0008:
printf("\x1b[0;%d;40;31m", (color & 1) << 2);
break;
case 0x000a:
printf("\x1b[0;%d;40;33m", (color & 1) << 2);
break;
case 0x000c:
printf("\x1b[0;%d;40;36m", (color & 1) << 2);
break;
case 0x000e:
if ((color & 1) == 0)
printf("\x1b[1;40;37m");
else
printf("\x1b[1;4;40;37m");
break;
}
if (code >= 0x20 && code <= 0x7f) {
switch (code) {
case 0x002a:
printf("\xc3\xa1");
break;
case 0x005c:
printf("\xc3\xa9");
break;
case 0x005e:
printf("\xc3\xad");
break;
case 0x005f:
printf("\xc3\xb3");
break;
case 0x0060:
printf("\xc3\xba");
break;
case 0x007b:
printf("\xc3\xa7");
break;
case 0x007c:
printf("\xc3\xb7");
break;
case 0x007d:
printf("\xc3\x91");
break;
case 0x007e:
printf("\xc3\xb1");
break;
case 0x007f:
printf("\xc1\xbf");
break;
default:
printf("%c", code);
break;
}
}
else {
switch (code) {
case 0x0080:
printf("\xc2\xae");
break;
case 0x0081:
printf("\xc2\xb0");
break;
case 0x0082:
printf("\xc2\xbd");
break;
case 0x0083:
printf("\xc2\xbf");
break;
case 0x0084:
printf("\xe2\x84");
break;
case 0x0085:
printf("\xc2\xa2");
break;
case 0x0086:
printf("\xc2\xa3");
break;
case 0x0087:
printf("\xc2\xa7");
break;
case 0x0088:
printf("\xc3\xa0");
break;
case 0x0089:
printf("\x1b[0;47;37m ");
break;
case 0x008a:
printf("\xc3\xa8");
break;
case 0x008b:
printf("\xc3\xa2");
break;
case 0x008c:
printf("\xc3\xaa");
break;
case 0x008d:
printf("\xc3\xae");
break;
case 0x008e:
printf("\xc3\xb4");
break;
case 0x008f:
printf("\xc3\xbb");
break;
default:
printf("<%02X>", code);
break;
}
}
}
printf("\n");
}
printf("\x1b[0;30;47m");
}