📄 cc.cpp
字号:
/******************************************************************************// File: CC.cpp// Description: Closed caption module.// Copyright 2001, Carlos Hasan/*******************************************************************************/#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){ // assume the buffer is long enough (at least VBI line width bytes) if (buffer == NULL) return false; // compute low/high levels 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; // find position of the first pulse 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; // compute position of the last pulse int end = start + 17 * C_RADEON_CC_BIT_DURATION; // start in middle of first pulse int bit = 0; bool one = true; for (int offset = start + C_RADEON_CC_BIT_DURATION / 2; offset < end; offset++) { int width = 1; // search the next pulse front 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++; } // compute pulse width in bits 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 { /* channel */ C_CC1 = 0x0000, C_CC2 = 0x0800, /* address */ 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, /* color */ C_WHITE = 0x0000, C_GREEN = 0x0002, C_BLUE = 0x0004, C_CYAN = 0x0006, C_RED = 0x0008, C_YELLOW = 0x000a, C_MAGENTA = 0x000c, C_ITALICS = 0x000e, /* underline */ C_NORMAL = 0x0000, C_UNDERLINE = 0x0001, /* control */ C_RCL = 0x0000, // resume caption loading C_BS = 0x0001, // backspace C_AOF = 0x0002, // alarm off C_AON = 0x0003, // alarm on C_DER = 0x0004, // delete to end of row C_RU2 = 0x0005, // roll-up captions (2 rows) C_RU3 = 0x0006, // roll-up captions (3 rows) C_RU4 = 0x0007, // roll-up captions (4 rows) C_FON = 0x0008, // flash on C_RDC = 0x0009, // resume direct captioning C_TR = 0x000a, // text restart C_RTD = 0x000b, // resume text display C_EDM = 0x000c, // erase displayed memory C_CR = 0x000d, // carriage return C_ENM = 0x000e, // erase non-displayed memory C_EOC = 0x000f, // end of caption /* special character */ C_reg = 0x0000, // registered C_deg = 0x0001, // degree C_frac12 = 0x0002, // fraction 1/2 C_iquest = 0x0003, // invert question C_trademark = 0x0004, // trademark C_cent = 0x0005, // cent C_pound = 0x0006, // pound C_music = 0x0007, // music note C_agrave = 0x0008, // agrave C_tspace = 0x0009, // transparent space C_egrave = 0x000a, // egrave C_acirc = 0x000b, // a circ C_ecirc = 0x000c, // e circ C_icirc = 0x000d, // i circ C_ocirc = 0x000e, // o circ C_ucirc = 0x000f, // u circ /* standard character (ASCII) */ C_aacute = 0x002a, // a acute accent C_eacute = 0x005c, // e acute accent C_iacute = 0x005e, // i acute accent C_oacute = 0x005f, // o acute accent C_uacute = 0x0060, // u acute accent C_ccedil = 0x007b, // c cedilla C_division = 0x007c, // division sign C_Ntilde = 0x007d, // N tilde C_ntilde = 0x007e, // n tilde C_block = 0x007f // solid block }; int code, channel, character; /* decode next pair of bytes from the odd or even field buffer */ if (!DecodeBits(fChannel == C_RADEON_CC1 || fChannel == C_RADEON_CC2 ? buffer0 : buffer1, code)) return false; /* swap decoded bytes */ code = ((code << 8) & 0xff00) | ((code >> 8) & 0x00ff); /* check parity */ 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; } /* check channel number */ 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) { /* one-byte standard character (0?XX) */ 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) { /* middle row code (112X) */ 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) { /* two-byte special character (113X) */ 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; /* miscellaneous control code (142X) */ switch (code & 0x000f) { case C_RCL: // resume caption loading PRINT(("<rcl>")); break; case C_BS: // backspace PRINT(("<bs>")); if (fColumn > 0) fText[fRow][--fColumn] = 0x0000; break; case C_AOF: // alarm off PRINT(("<aof>")); break; case C_AON: // alarm on PRINT(("<aon>")); break; case C_DER: // delete to end of row PRINT(("<der>")); for (int column = fColumn; column < C_RADEON_CC_COLUMNS; column++) fText[fRow][column] = 0x0000; break; case C_RU2: // rollup captions (2 rows) 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: // rollup captions (3 rows) 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];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -