diff --git a/libavcodec/ccaption_dec.c b/libavcodec/ccaption_dec.c index 5fb2ec6293..237272c5cd 100644 --- a/libavcodec/ccaption_dec.c +++ b/libavcodec/ccaption_dec.c @@ -63,6 +63,116 @@ enum cc_font { CCFONT_UNDERLINED_ITALICS, }; +enum cc_charset { + CCSET_BASIC_AMERICAN, + CCSET_SPECIAL_AMERICAN, + CCSET_EXTENDED_SPANISH_FRENCH_MISC, + CCSET_EXTENDED_PORTUGUESE_GERMAN_DANISH, +}; + +static const char *charset_overrides[4][128] = +{ + [CCSET_BASIC_AMERICAN] = { + [0x27] = "\u2019", + [0x2a] = "\u00e1", + [0x5c] = "\u00e9", + [0x5e] = "\u00ed", + [0x5f] = "\u00f3", + [0x60] = "\u00fa", + [0x7b] = "\u00e7", + [0x7c] = "\u00f7", + [0x7d] = "\u00d1", + [0x7e] = "\u00f1", + [0x7f] = "\u2588" + }, + [CCSET_SPECIAL_AMERICAN] = { + [0x30] = "\u00ae", + [0x31] = "\u00b0", + [0x32] = "\u00bd", + [0x33] = "\u00bf", + [0x34] = "\u2122", + [0x35] = "\u00a2", + [0x36] = "\u00a3", + [0x37] = "\u266a", + [0x38] = "\u00e0", + [0x39] = "\u00A0", + [0x3a] = "\u00e8", + [0x3b] = "\u00e2", + [0x3c] = "\u00ea", + [0x3d] = "\u00ee", + [0x3e] = "\u00f4", + [0x3f] = "\u00fb", + }, + [CCSET_EXTENDED_SPANISH_FRENCH_MISC] = { + [0x20] = "\u00c1", + [0x21] = "\u00c9", + [0x22] = "\u00d3", + [0x23] = "\u00da", + [0x24] = "\u00dc", + [0x25] = "\u00fc", + [0x26] = "\u00b4", + [0x27] = "\u00a1", + [0x28] = "*", + [0x29] = "\u2018", + [0x2a] = "-", + [0x2b] = "\u00a9", + [0x2c] = "\u2120", + [0x2d] = "\u00b7", + [0x2e] = "\u201c", + [0x2f] = "\u201d", + [0x30] = "\u00c0", + [0x31] = "\u00c2", + [0x32] = "\u00c7", + [0x33] = "\u00c8", + [0x34] = "\u00ca", + [0x35] = "\u00cb", + [0x36] = "\u00eb", + [0x37] = "\u00ce", + [0x38] = "\u00cf", + [0x39] = "\u00ef", + [0x3a] = "\u00d4", + [0x3b] = "\u00d9", + [0x3c] = "\u00f9", + [0x3d] = "\u00db", + [0x3e] = "\u00ab", + [0x3f] = "\u00bb", + }, + [CCSET_EXTENDED_PORTUGUESE_GERMAN_DANISH] = { + [0x20] = "\u00c3", + [0x21] = "\u00e3", + [0x22] = "\u00cd", + [0x23] = "\u00cc", + [0x24] = "\u00ec", + [0x25] = "\u00d2", + [0x26] = "\u00f2", + [0x27] = "\u00d5", + [0x28] = "\u00f5", + [0x29] = "{", + [0x2a] = "}", + [0x2b] = "\\", + [0x2c] = "^", + [0x2d] = "_", + [0x2e] = "|", + [0x2f] = "~", + [0x30] = "\u00c4", + [0x31] = "\u00e4", + [0x32] = "\u00d6", + [0x33] = "\u00f6", + [0x34] = "\u00df", + [0x35] = "\u00a5", + [0x36] = "\u00a4", + [0x37] = "\u00a6", + [0x38] = "\u00c5", + [0x39] = "\u00e5", + [0x3a] = "\u00d8", + [0x3b] = "\u00f8", + [0x3c] = "\u250c", + [0x3d] = "\u2510", + [0x3e] = "\u2514", + [0x3f] = "\u2518", + }, +}; + static const unsigned char pac2_attribs[32][3] = // Color, font, ident { { CCCOL_WHITE, CCFONT_REGULAR, 0 }, // 0x40 || 0x60 @@ -103,6 +213,7 @@ static const unsigned char pac2_attribs[32][3] = // Color, font, ident struct Screen { /* +1 is used to compensate null character of string */ uint8_t characters[SCREEN_ROWS][SCREEN_COLUMNS+1]; + uint8_t charsets[SCREEN_ROWS][SCREEN_COLUMNS+1]; uint8_t colors[SCREEN_ROWS][SCREEN_COLUMNS+1]; uint8_t fonts[SCREEN_ROWS][SCREEN_COLUMNS+1]; /* @@ -123,6 +234,7 @@ typedef struct CCaptionSubContext { uint8_t cursor_column; uint8_t cursor_color; uint8_t cursor_font; + uint8_t cursor_charset; AVBPrint buffer; int buffer_changed; int rollup; @@ -189,6 +301,7 @@ static void flush_decoder(AVCodecContext *avctx) ctx->cursor_column = 0; ctx->cursor_font = 0; ctx->cursor_color = 0; + ctx->cursor_charset = 0; ctx->active_screen = 0; ctx->last_real_time = 0; ctx->screen_touched = 0; @@ -204,10 +317,13 @@ static int write_char(CCaptionSubContext *ctx, struct Screen *screen, char ch) uint8_t col = ctx->cursor_column; char *row = screen->characters[ctx->cursor_row]; char *font = screen->fonts[ctx->cursor_row]; + char *charset = screen->charsets[ctx->cursor_row]; if (col < SCREEN_COLUMNS) { row[col] = ch; font[col] = ctx->cursor_font; + charset[col] = ctx->cursor_charset; + ctx->cursor_charset = CCSET_BASIC_AMERICAN; if (ch) ctx->cursor_column++; return 0; } @@ -306,6 +422,7 @@ static void roll_up(CCaptionSubContext *ctx) memcpy(screen->characters[i_row], screen->characters[i_row+1], SCREEN_COLUMNS); memcpy(screen->colors[i_row], screen->colors[i_row+1], SCREEN_COLUMNS); memcpy(screen->fonts[i_row], screen->fonts[i_row+1], SCREEN_COLUMNS); + memcpy(screen->charsets[i_row], screen->charsets[i_row+1], SCREEN_COLUMNS); if (CHECK_FLAG(screen->row_used, i_row + 1)) SET_FLAG(screen->row_used, i_row); } @@ -325,10 +442,12 @@ static int capture_screen(CCaptionSubContext *ctx) if (CHECK_FLAG(screen->row_used, i)) { const char *row = screen->characters[i]; const char *font = screen->fonts[i]; + const char *charset = screen->charsets[i]; + const char *override; int j = 0; /* skip leading space */ - while (row[j] == ' ') + while (row[j] == ' ' && charset[j] == CCSET_BASIC_AMERICAN) j++; for (; j < SCREEN_COLUMNS; j++) { @@ -362,7 +481,12 @@ static int capture_screen(CCaptionSubContext *ctx) } } prev_font = font[j]; - av_bprintf(&ctx->buffer, "%s%s%c", e_tag, s_tag, row[j]); + override = charset_overrides[(int)charset[j]][(int)row[j]]; + if (override) { + av_bprintf(&ctx->buffer, "%s%s%s", e_tag, s_tag, override); + } else { + av_bprintf(&ctx->buffer, "%s%s%c", e_tag, s_tag, row[j]); + } } av_bprintf(&ctx->buffer, "\\N"); } @@ -419,6 +543,7 @@ static void handle_pac(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo) ctx->cursor_row = row_map[index] - 1; ctx->cursor_color = pac2_attribs[lo][0]; ctx->cursor_font = pac2_attribs[lo][1]; + ctx->cursor_charset = CCSET_BASIC_AMERICAN; ctx->cursor_column = 0; indent = pac2_attribs[lo][2]; for (i = 0; i < indent; i++) { @@ -474,7 +599,25 @@ static void handle_char(CCaptionSubContext *ctx, char hi, char lo, int64_t pts) SET_FLAG(screen->row_used, ctx->cursor_row); - write_char(ctx, screen, hi); + switch (hi) { + case 0x11: + ctx->cursor_charset = CCSET_SPECIAL_AMERICAN; + break; + case 0x12: + if (ctx->cursor_column > 0) + ctx->cursor_column -= 1; + ctx->cursor_charset = CCSET_EXTENDED_SPANISH_FRENCH_MISC; + break; + case 0x13: + if (ctx->cursor_column > 0) + ctx->cursor_column -= 1; + ctx->cursor_charset = CCSET_EXTENDED_PORTUGUESE_GERMAN_DANISH; + break; + default: + ctx->cursor_charset = CCSET_BASIC_AMERICAN; + write_char(ctx, screen, hi); + break; + } if (lo) { write_char(ctx, screen, lo); @@ -560,6 +703,9 @@ static void process_cc608(CCaptionSubContext *ctx, int64_t pts, uint8_t hi, uint ff_dlog(ctx, "Unknown command 0x%hhx 0x%hhx\n", hi, lo); break; } + } else if (hi >= 0x11 && hi <= 0x13) { + /* Special characters */ + handle_char(ctx, hi, lo, pts); } else if (hi >= 0x20) { /* Standard characters (always in pairs) */ handle_char(ctx, hi, lo, pts);