diff options
Diffstat (limited to 'libhb/deccc608sub.c')
-rw-r--r-- | libhb/deccc608sub.c | 1562 |
1 files changed, 492 insertions, 1070 deletions
diff --git a/libhb/deccc608sub.c b/libhb/deccc608sub.c index 85b43efab..5f4066b67 100644 --- a/libhb/deccc608sub.c +++ b/libhb/deccc608sub.c @@ -7,15 +7,12 @@ #include "hb.h" #include "deccc608sub.h" +#define SSA_PREAMBLE_LEN 24 /* * ccextractor static configuration variables. */ static int debug_608 = 0; -static int trim_subs = 1; -static int nofontcolor = 0; -static enum encoding_type encoding = ENC_UTF_8; static int cc_channel = 1; -static int sentence_cap = 0; static int subs_delay = 0; static int norollup = 0; static int direct_rollup = 0; @@ -23,28 +20,21 @@ static int direct_rollup = 0; /* * Get the time of the last buffer that we have received. */ -static int64_t get_fts(struct s_write *wb) +static int64_t get_last_pts(struct s_write *wb) { return wb->last_pts; } #define fatal(N, ...) // N -int rowdata[] = {11,-1,1,2,3,4,12,13,14,15,5,6,7,8,9,10}; +int rowdata[] = {11,-1,1,2,3,4,12,13,14,15,5,6,7,8,9,10}; // Relationship between the first PAC byte and the row number // The following enc_buffer is not used at the moment, if it does get used // we need to bring it into the swrite struct. Same for "str". #define INITIAL_ENC_BUFFER_CAPACITY 2048 -unsigned char str[2048]; // Another generic general purpose buffer - -#define GUARANTEE(wb, length) if (length>wb->enc_buffer_capacity) \ -{wb->enc_buffer_capacity*=2; wb->enc_buffer=(unsigned char*) realloc (wb->enc_buffer, wb->enc_buffer_capacity); \ - if (wb->enc_buffer==NULL) { fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory, bailing out\n"); } \ -} - -const unsigned char pac2_attribs[][3]= // Color, font, ident +static const unsigned char pac2_attribs[][3]= // Color, font, ident { {COL_WHITE, FONT_REGULAR, 0}, // 0x40 || 0x60 {COL_WHITE, FONT_UNDERLINED, 0}, // 0x41 || 0x61 @@ -80,17 +70,10 @@ const unsigned char pac2_attribs[][3]= // Color, font, ident {COL_WHITE, FONT_UNDERLINED, 28} // 0x5f || 0x7f }; -// Preencoded strings -unsigned char encoded_crlf[16]; -unsigned int encoded_crlf_length; -unsigned char encoded_br[16]; -unsigned int encoded_br_length; - // Default color -unsigned char usercolor_rgb[8]=""; -enum color_code default_color=COL_WHITE; +static enum color_code default_color=COL_WHITE; -const char *command_type[] = +static const char *command_type[] = { "Unknown", "EDM - EraseDisplayedMemory", @@ -108,7 +91,7 @@ const char *command_type[] = "RTD - Resume Text Display" }; -const char *font_text[]= +static const char *font_text[]= { "regular", "italics", @@ -116,24 +99,19 @@ const char *font_text[]= "underlined italics" }; -const char *cc_modes_text[]= -{ - "Pop-Up captions" -}; - -const char *color_text[][2]= +static const char *color_text[][2]= { - {"white",""}, - {"green","<font color=\"#00ff00\">"}, - {"blue","<font color=\"#0000ff\">"}, - {"cyan","<font color=\"#00ffff\">"}, - {"red","<font color=\"#ff0000\">"}, - {"yellow","<font color=\"#ffff00\">"}, - {"magenta","<font color=\"#ff00ff\">"}, - {"userdefined","<font color=\""} + {"white", "&HFFFFFF&"}, + {"green", "&H00FF00&"}, + {"blue", "&HFF0000&"}, + {"cyan", "&HFFFF00&"}, + {"red", "&H0000FF&"}, + {"yellow", "&H00FFFF&"}, + {"magenta", "&HFF00FF&"}, + {"userdefined", "&HFFFFFF&"} }; -int general_608_init (struct s_write *wb) +static int general_608_init (struct s_write *wb) { if( !wb->enc_buffer ) { @@ -167,7 +145,7 @@ int general_608_init (struct s_write *wb) * parallel encodes to fail - to be honest they will be stuffed anyway since * the CC's may be overwriting the buffers. */ -void general_608_close (struct s_write *wb) +static void general_608_close (struct s_write *wb) { if( wb->enc_buffer ) { free(wb->enc_buffer); @@ -186,1076 +164,501 @@ void general_608_close (struct s_write *wb) #include <ctype.h> -void get_char_in_latin_1 (unsigned char *buffer, unsigned char c) +// Returns number of bytes used +static int get_char_in_utf8(unsigned char *buffer, unsigned char c) { - unsigned char c1='?'; - if (c<0x80) - { - // Regular line-21 character set, mostly ASCII except these exceptions - switch (c) - { - case 0x2a: // lowercase a, acute accent - c1=0xe1; - break; - case 0x5c: // lowercase e, acute accent - c1=0xe9; - break; - case 0x5e: // lowercase i, acute accent - c1=0xed; - break; - case 0x5f: // lowercase o, acute accent - c1=0xf3; - break; - case 0x60: // lowercase u, acute accent - c1=0xfa; - break; - case 0x7b: // lowercase c with cedilla - c1=0xe7; - break; - case 0x7c: // division symbol - c1=0xf7; - break; - case 0x7d: // uppercase N tilde - c1=0xd1; - break; - case 0x7e: // lowercase n tilde - c1=0xf1; - break; - default: - c1=c; - break; - } - *buffer=c1; - return; - } - switch (c) - { - // THIS BLOCK INCLUDES THE 16 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS - // THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F - case 0x80: // Registered symbol (R) - c1=0xae; - break; - case 0x81: // degree sign - c1=0xb0; - break; - case 0x82: // 1/2 symbol - c1=0xbd; - break; - case 0x83: // Inverted (open) question mark - c1=0xbf; - break; - case 0x84: // Trademark symbol (TM) - Does not exist in Latin 1 - break; - case 0x85: // Cents symbol - c1=0xa2; - break; - case 0x86: // Pounds sterling - c1=0xa3; - break; - case 0x87: // Music note - Not in latin 1, so we use 'pilcrow' - c1=0xb6; - break; - case 0x88: // lowercase a, grave accent - c1=0xe0; - break; - case 0x89: // transparent space, we make it regular - c1=0x20; - break; - case 0x8a: // lowercase e, grave accent - c1=0xe8; - break; - case 0x8b: // lowercase a, circumflex accent - c1=0xe2; - break; - case 0x8c: // lowercase e, circumflex accent - c1=0xea; - break; - case 0x8d: // lowercase i, circumflex accent - c1=0xee; - break; - case 0x8e: // lowercase o, circumflex accent - c1=0xf4; - break; - case 0x8f: // lowercase u, circumflex accent - c1=0xfb; - break; - // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS - // THAT COME FROM HI BYTE=0x12 AND LOW BETWEEN 0x20 AND 0x3F - case 0x90: // capital letter A with acute - c1=0xc1; - break; - case 0x91: // capital letter E with acute - c1=0xc9; - break; - case 0x92: // capital letter O with acute - c1=0xd3; - break; - case 0x93: // capital letter U with acute - c1=0xda; - break; - case 0x94: // capital letter U with diaresis - c1=0xdc; - break; - case 0x95: // lowercase letter U with diaeresis - c1=0xfc; - break; - case 0x96: // apostrophe - c1=0x27; - break; - case 0x97: // inverted exclamation mark - c1=0xa1; - break; - case 0x98: // asterisk - c1=0x2a; - break; - case 0x99: // apostrophe (yes, duped). See CCADI source code. - c1=0x27; - break; - case 0x9a: // hyphen-minus - c1=0x2d; - break; - case 0x9b: // copyright sign - c1=0xa9; - break; - case 0x9c: // Service Mark - not available in latin 1 - break; - case 0x9d: // Full stop (.) - c1=0x2e; - break; - case 0x9e: // Quoatation mark - c1=0x22; - break; - case 0x9f: // Quoatation mark - c1=0x22; - break; - case 0xa0: // uppercase A, grave accent - c1=0xc0; - break; - case 0xa1: // uppercase A, circumflex - c1=0xc2; - break; - case 0xa2: // uppercase C with cedilla - c1=0xc7; - break; - case 0xa3: // uppercase E, grave accent - c1=0xc8; - break; - case 0xa4: // uppercase E, circumflex - c1=0xca; - break; - case 0xa5: // capital letter E with diaresis - c1=0xcb; - break; - case 0xa6: // lowercase letter e with diaresis - c1=0xeb; - break; - case 0xa7: // uppercase I, circumflex - c1=0xce; - break; - case 0xa8: // uppercase I, with diaresis - c1=0xcf; - break; - case 0xa9: // lowercase i, with diaresis - c1=0xef; - break; - case 0xaa: // uppercase O, circumflex - c1=0xd4; - break; - case 0xab: // uppercase U, grave accent - c1=0xd9; - break; - case 0xac: // lowercase u, grave accent - c1=0xf9; - break; - case 0xad: // uppercase U, circumflex - c1=0xdb; - break; - case 0xae: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - c1=0xab; - break; - case 0xaf: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - c1=0xbb; - break; - // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS - // THAT COME FROM HI BYTE=0x13 AND LOW BETWEEN 0x20 AND 0x3F - case 0xb0: // Uppercase A, tilde - c1=0xc3; - break; - case 0xb1: // Lowercase a, tilde - c1=0xe3; - break; - case 0xb2: // Uppercase I, acute accent - c1=0xcd; - break; - case 0xb3: // Uppercase I, grave accent - c1=0xcc; - break; - case 0xb4: // Lowercase i, grave accent - c1=0xec; - break; - case 0xb5: // Uppercase O, grave accent - c1=0xd2; - break; - case 0xb6: // Lowercase o, grave accent - c1=0xf2; - break; - case 0xb7: // Uppercase O, tilde - c1=0xd5; - break; - case 0xb8: // Lowercase o, tilde - c1=0xf5; - break; - case 0xb9: // Open curly brace - c1=0x7b; - break; - case 0xba: // Closing curly brace - c1=0x7d; - break; - case 0xbb: // Backslash - c1=0x5c; - break; - case 0xbc: // Caret - c1=0x5e; - break; - case 0xbd: // Underscore - c1=0x5f; - break; - case 0xbe: // Pipe (broken bar) - c1=0xa6; - break; - case 0xbf: // Tilde - c1=0x7e; - break; - case 0xc0: // Uppercase A, umlaut - c1=0xc4; - break; - case 0xc1: // Lowercase A, umlaut - c1=0xe3; - break; - case 0xc2: // Uppercase O, umlaut - c1=0xd6; - break; - case 0xc3: // Lowercase o, umlaut - c1=0xf6; - break; - case 0xc4: // Esszett (sharp S) - c1=0xdf; - break; - case 0xc5: // Yen symbol - c1=0xa5; - break; - case 0xc6: // Currency symbol - c1=0xa4; - break; - case 0xc7: // Vertical bar - c1=0x7c; - break; - case 0xc8: // Uppercase A, ring - c1=0xc5; - break; - case 0xc9: // Lowercase A, ring - c1=0xe5; - break; - case 0xca: // Uppercase O, slash - c1=0xd8; - break; - case 0xcb: // Lowercase o, slash - c1=0xf8; - break; - case 0xcc: // Upper left corner - case 0xcd: // Upper right corner - case 0xce: // Lower left corner - case 0xcf: // Lower right corner - default: // For those that don't have representation - *buffer='?'; // I'll do it eventually, I promise - break; // This are weird chars anyway - } - *buffer=c1; -} - -void get_char_in_unicode (unsigned char *buffer, unsigned char c) -{ - unsigned char c1,c2; - switch (c) - { - case 0x84: // Trademark symbol (TM) - c2=0x21; - c1=0x22; - break; - case 0x87: // Music note - c2=0x26; - c1=0x6a; - break; - case 0x9c: // Service Mark - c2=0x21; - c1=0x20; - break; - case 0xcc: // Upper left corner - c2=0x23; - c1=0x1c; - break; - case 0xcd: // Upper right corner - c2=0x23; - c1=0x1d; - break; - case 0xce: // Lower left corner - c2=0x23; - c1=0x1e; - break; - case 0xcf: // Lower right corner - c2=0x23; - c1=0x1f; - break; - default: // Everything else, same as latin-1 followed by 00 - get_char_in_latin_1 (&c1,c); - c2=0; - break; - } - *buffer=c1; - *(buffer+1)=c2; -} - -int get_char_in_utf_8 (unsigned char *buffer, unsigned char c) // Returns number of bytes used -{ - if (c==0x00) + if (c == 0x00) return 0; - if (c<0x80) // Regular line-21 character set, mostly ASCII except these exceptions + + // Regular line-21 character set, mostly ASCII except these exceptions + if (c < 0x80) { switch (c) { case 0x2a: // lowercase a, acute accent - *buffer=0xc3; - *(buffer+1)=0xa1; + *buffer = 0xc3; + *(buffer+1) = 0xa1; return 2; case 0x5c: // lowercase e, acute accent - *buffer=0xc3; - *(buffer+1)=0xa9; + *buffer = 0xc3; + *(buffer+1) = 0xa9; return 2; case 0x5e: // lowercase i, acute accent - *buffer=0xc3; - *(buffer+1)=0xad; + *buffer = 0xc3; + *(buffer+1) = 0xad; return 2; case 0x5f: // lowercase o, acute accent - *buffer=0xc3; - *(buffer+1)=0xb3; + *buffer = 0xc3; + *(buffer+1) = 0xb3; return 2; case 0x60: // lowercase u, acute accent - *buffer=0xc3; - *(buffer+1)=0xba; + *buffer = 0xc3; + *(buffer+1) = 0xba; return 2; case 0x7b: // lowercase c with cedilla - *buffer=0xc3; - *(buffer+1)=0xa7; + *buffer = 0xc3; + *(buffer+1) = 0xa7; return 2; case 0x7c: // division symbol - *buffer=0xc3; - *(buffer+1)=0xb7; + *buffer = 0xc3; + *(buffer+1) = 0xb7; return 2; case 0x7d: // uppercase N tilde - *buffer=0xc3; - *(buffer+1)=0x91; + *buffer = 0xc3; + *(buffer+1) = 0x91; return 2; case 0x7e: // lowercase n tilde - *buffer=0xc3; - *(buffer+1)=0xb1; + *buffer = 0xc3; + *(buffer+1) = 0xb1; return 2; default: - *buffer=c; + *buffer = c; return 1; } } switch (c) { // THIS BLOCK INCLUDES THE 16 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS - // THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F + // THAT COME FROM HI BYTE = 0x11 AND LOW BETWEEN 0x30 AND 0x3F case 0x80: // Registered symbol (R) - *buffer=0xc2; - *(buffer+1)=0xae; + *buffer = 0xc2; + *(buffer+1) = 0xae; return 2; case 0x81: // degree sign - *buffer=0xc2; - *(buffer+1)=0xb0; + *buffer = 0xc2; + *(buffer+1) = 0xb0; return 2; case 0x82: // 1/2 symbol - *buffer=0xc2; - *(buffer+1)=0xbd; + *buffer = 0xc2; + *(buffer+1) = 0xbd; return 2; case 0x83: // Inverted (open) question mark - *buffer=0xc2; - *(buffer+1)=0xbf; + *buffer = 0xc2; + *(buffer+1) = 0xbf; return 2; case 0x84: // Trademark symbol (TM) - *buffer=0xe2; - *(buffer+1)=0x84; - *(buffer+2)=0xa2; + *buffer = 0xe2; + *(buffer+1) = 0x84; + *(buffer+2) = 0xa2; return 3; case 0x85: // Cents symbol - *buffer=0xc2; - *(buffer+1)=0xa2; + *buffer = 0xc2; + *(buffer+1) = 0xa2; return 2; case 0x86: // Pounds sterling - *buffer=0xc2; - *(buffer+1)=0xa3; + *buffer = 0xc2; + *(buffer+1) = 0xa3; return 2; case 0x87: // Music note - *buffer=0xe2; - *(buffer+1)=0x99; - *(buffer+2)=0xaa; + *buffer = 0xe2; + *(buffer+1) = 0x99; + *(buffer+2) = 0xaa; return 3; case 0x88: // lowercase a, grave accent - *buffer=0xc3; - *(buffer+1)=0xa0; + *buffer = 0xc3; + *(buffer+1) = 0xa0; return 2; case 0x89: // transparent space, we make it regular - *buffer=0x20; + *buffer = 0x20; return 1; case 0x8a: // lowercase e, grave accent - *buffer=0xc3; - *(buffer+1)=0xa8; + *buffer = 0xc3; + *(buffer+1) = 0xa8; return 2; case 0x8b: // lowercase a, circumflex accent - *buffer=0xc3; - *(buffer+1)=0xa2; + *buffer = 0xc3; + *(buffer+1) = 0xa2; return 2; case 0x8c: // lowercase e, circumflex accent - *buffer=0xc3; - *(buffer+1)=0xaa; + *buffer = 0xc3; + *(buffer+1) = 0xaa; return 2; case 0x8d: // lowercase i, circumflex accent - *buffer=0xc3; - *(buffer+1)=0xae; + *buffer = 0xc3; + *(buffer+1) = 0xae; return 2; case 0x8e: // lowercase o, circumflex accent - *buffer=0xc3; - *(buffer+1)=0xb4; + *buffer = 0xc3; + *(buffer+1) = 0xb4; return 2; case 0x8f: // lowercase u, circumflex accent - *buffer=0xc3; - *(buffer+1)=0xbb; + *buffer = 0xc3; + *(buffer+1) = 0xbb; return 2; // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS - // THAT COME FROM HI BYTE=0x12 AND LOW BETWEEN 0x20 AND 0x3F + // THAT COME FROM HI BYTE = 0x12 AND LOW BETWEEN 0x20 AND 0x3F case 0x90: // capital letter A with acute - *buffer=0xc3; - *(buffer+1)=0x81; + *buffer = 0xc3; + *(buffer+1) = 0x81; return 2; case 0x91: // capital letter E with acute - *buffer=0xc3; - *(buffer+1)=0x89; + *buffer = 0xc3; + *(buffer+1) = 0x89; return 2; case 0x92: // capital letter O with acute - *buffer=0xc3; - *(buffer+1)=0x93; + *buffer = 0xc3; + *(buffer+1) = 0x93; return 2; case 0x93: // capital letter U with acute - *buffer=0xc3; - *(buffer+1)=0x9a; + *buffer = 0xc3; + *(buffer+1) = 0x9a; return 2; case 0x94: // capital letter U with diaresis - *buffer=0xc3; - *(buffer+1)=0x9c; + *buffer = 0xc3; + *(buffer+1) = 0x9c; return 2; case 0x95: // lowercase letter U with diaeresis - *buffer=0xc3; - *(buffer+1)=0xbc; + *buffer = 0xc3; + *(buffer+1) = 0xbc; return 2; case 0x96: // apostrophe - *buffer=0x27; + *buffer = 0x27; return 1; case 0x97: // inverted exclamation mark - *buffer=0xc2; - *(buffer+1)=0xa1; + *buffer = 0xc2; + *(buffer+1) = 0xa1; return 2; case 0x98: // asterisk - *buffer=0x2a; + *buffer = 0x2a; return 1; case 0x99: // apostrophe (yes, duped). See CCADI source code. - *buffer=0x27; + *buffer = 0x27; return 1; case 0x9a: // hyphen-minus - *buffer=0x2d; + *buffer = 0x2d; return 1; case 0x9b: // copyright sign - *buffer=0xc2; - *(buffer+1)=0xa9; + *buffer = 0xc2; + *(buffer+1) = 0xa9; return 2; case 0x9c: // Service mark - *buffer=0xe2; - *(buffer+1)=0x84; - *(buffer+2)=0xa0; + *buffer = 0xe2; + *(buffer+1) = 0x84; + *(buffer+2) = 0xa0; return 3; case 0x9d: // Full stop (.) - *buffer=0x2e; + *buffer = 0x2e; return 1; case 0x9e: // Quoatation mark - *buffer=0x22; + *buffer = 0x22; return 1; case 0x9f: // Quoatation mark - *buffer=0x22; + *buffer = 0x22; return 1; case 0xa0: // uppercase A, grave accent - *buffer=0xc3; - *(buffer+1)=0x80; + *buffer = 0xc3; + *(buffer+1) = 0x80; return 2; case 0xa1: // uppercase A, circumflex - *buffer=0xc3; - *(buffer+1)=0x82; + *buffer = 0xc3; + *(buffer+1) = 0x82; return 2; case 0xa2: // uppercase C with cedilla - *buffer=0xc3; - *(buffer+1)=0x87; + *buffer = 0xc3; + *(buffer+1) = 0x87; return 2; case 0xa3: // uppercase E, grave accent - *buffer=0xc3; - *(buffer+1)=0x88; + *buffer = 0xc3; + *(buffer+1) = 0x88; return 2; case 0xa4: // uppercase E, circumflex - *buffer=0xc3; - *(buffer+1)=0x8a; + *buffer = 0xc3; + *(buffer+1) = 0x8a; return 2; case 0xa5: // capital letter E with diaresis - *buffer=0xc3; - *(buffer+1)=0x8b; + *buffer = 0xc3; + *(buffer+1) = 0x8b; return 2; case 0xa6: // lowercase letter e with diaresis - *buffer=0xc3; - *(buffer+1)=0xab; + *buffer = 0xc3; + *(buffer+1) = 0xab; return 2; case 0xa7: // uppercase I, circumflex - *buffer=0xc3; - *(buffer+1)=0x8e; + *buffer = 0xc3; + *(buffer+1) = 0x8e; return 2; case 0xa8: // uppercase I, with diaresis - *buffer=0xc3; - *(buffer+1)=0x8f; + *buffer = 0xc3; + *(buffer+1) = 0x8f; return 2; case 0xa9: // lowercase i, with diaresis - *buffer=0xc3; - *(buffer+1)=0xaf; + *buffer = 0xc3; + *(buffer+1) = 0xaf; return 2; case 0xaa: // uppercase O, circumflex - *buffer=0xc3; - *(buffer+1)=0x94; + *buffer = 0xc3; + *(buffer+1) = 0x94; return 2; case 0xab: // uppercase U, grave accent - *buffer=0xc3; - *(buffer+1)=0x99; + *buffer = 0xc3; + *(buffer+1) = 0x99; return 2; case 0xac: // lowercase u, grave accent - *buffer=0xc3; - *(buffer+1)=0xb9; + *buffer = 0xc3; + *(buffer+1) = 0xb9; return 2; case 0xad: // uppercase U, circumflex - *buffer=0xc3; - *(buffer+1)=0x9b; + *buffer = 0xc3; + *(buffer+1) = 0x9b; return 2; case 0xae: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - *buffer=0xc2; - *(buffer+1)=0xab; + *buffer = 0xc2; + *(buffer+1) = 0xab; return 2; case 0xaf: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - *buffer=0xc2; - *(buffer+1)=0xbb; + *buffer = 0xc2; + *(buffer+1) = 0xbb; return 2; // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS - // THAT COME FROM HI BYTE=0x13 AND LOW BETWEEN 0x20 AND 0x3F + // THAT COME FROM HI BYTE = 0x13 AND LOW BETWEEN 0x20 AND 0x3F case 0xb0: // Uppercase A, tilde - *buffer=0xc3; - *(buffer+1)=0x83; + *buffer = 0xc3; + *(buffer+1) = 0x83; return 2; case 0xb1: // Lowercase a, tilde - *buffer=0xc3; - *(buffer+1)=0xa3; + *buffer = 0xc3; + *(buffer+1) = 0xa3; return 2; case 0xb2: // Uppercase I, acute accent - *buffer=0xc3; - *(buffer+1)=0x8d; + *buffer = 0xc3; + *(buffer+1) = 0x8d; return 2; case 0xb3: // Uppercase I, grave accent - *buffer=0xc3; - *(buffer+1)=0x8c; + *buffer = 0xc3; + *(buffer+1) = 0x8c; return 2; case 0xb4: // Lowercase i, grave accent - *buffer=0xc3; - *(buffer+1)=0xac; + *buffer = 0xc3; + *(buffer+1) = 0xac; return 2; case 0xb5: // Uppercase O, grave accent - *buffer=0xc3; - *(buffer+1)=0x92; + *buffer = 0xc3; + *(buffer+1) = 0x92; return 2; case 0xb6: // Lowercase o, grave accent - *buffer=0xc3; - *(buffer+1)=0xb2; + *buffer = 0xc3; + *(buffer+1) = 0xb2; return 2; case 0xb7: // Uppercase O, tilde - *buffer=0xc3; - *(buffer+1)=0x95; + *buffer = 0xc3; + *(buffer+1) = 0x95; return 2; case 0xb8: // Lowercase o, tilde - *buffer=0xc3; - *(buffer+1)=0xb5; + *buffer = 0xc3; + *(buffer+1) = 0xb5; return 2; case 0xb9: // Open curly brace - *buffer=0x7b; + *buffer = 0x7b; return 1; case 0xba: // Closing curly brace - *buffer=0x7d; + *buffer = 0x7d; return 1; case 0xbb: // Backslash - *buffer=0x5c; + *buffer = 0x5c; return 1; case 0xbc: // Caret - *buffer=0x5e; + *buffer = 0x5e; return 1; case 0xbd: // Underscore - *buffer=0x5f; + *buffer = 0x5f; return 1; case 0xbe: // Pipe (broken bar) - *buffer=0xc2; - *(buffer+1)=0xa6; + *buffer = 0xc2; + *(buffer+1) = 0xa6; return 1; case 0xbf: // Tilde - *buffer=0x7e; // Not sure + *buffer = 0x7e; // Not sure return 1; case 0xc0: // Uppercase A, umlaut - *buffer=0xc3; - *(buffer+1)=0x84; + *buffer = 0xc3; + *(buffer+1) = 0x84; return 2; case 0xc1: // Lowercase A, umlaut - *buffer=0xc3; - *(buffer+1)=0xa4; + *buffer = 0xc3; + *(buffer+1) = 0xa4; return 2; case 0xc2: // Uppercase O, umlaut - *buffer=0xc3; - *(buffer+1)=0x96; + *buffer = 0xc3; + *(buffer+1) = 0x96; return 2; case 0xc3: // Lowercase o, umlaut - *buffer=0xc3; - *(buffer+1)=0xb6; + *buffer = 0xc3; + *(buffer+1) = 0xb6; return 2; case 0xc4: // Esszett (sharp S) - *buffer=0xc3; - *(buffer+1)=0x9f; + *buffer = 0xc3; + *(buffer+1) = 0x9f; return 2; case 0xc5: // Yen symbol - *buffer=0xc2; - *(buffer+1)=0xa5; + *buffer = 0xc2; + *(buffer+1) = 0xa5; return 2; case 0xc6: // Currency symbol - *buffer=0xc2; - *(buffer+1)=0xa4; + *buffer = 0xc2; + *(buffer+1) = 0xa4; return 2; case 0xc7: // Vertical bar - *buffer=0x7c; + *buffer = 0x7c; return 1; case 0xc8: // Uppercase A, ring - *buffer=0xc3; - *(buffer+1)=0x85; + *buffer = 0xc3; + *(buffer+1) = 0x85; return 2; case 0xc9: // Lowercase A, ring - *buffer=0xc3; - *(buffer+1)=0xa5; + *buffer = 0xc3; + *(buffer+1) = 0xa5; return 2; case 0xca: // Uppercase O, slash - *buffer=0xc3; - *(buffer+1)=0x98; + *buffer = 0xc3; + *(buffer+1) = 0x98; return 2; case 0xcb: // Lowercase o, slash - *buffer=0xc3; - *(buffer+1)=0xb8; + *buffer = 0xc3; + *(buffer+1) = 0xb8; return 2; case 0xcc: // Upper left corner - *buffer=0xe2; - *(buffer+1)=0x8c; - *(buffer+2)=0x9c; + *buffer = 0xe2; + *(buffer+1) = 0x8c; + *(buffer+2) = 0x9c; return 3; case 0xcd: // Upper right corner - *buffer=0xe2; - *(buffer+1)=0x8c; - *(buffer+2)=0x9d; + *buffer = 0xe2; + *(buffer+1) = 0x8c; + *(buffer+2) = 0x9d; return 3; case 0xce: // Lower left corner - *buffer=0xe2; - *(buffer+1)=0x8c; - *(buffer+2)=0x9e; + *buffer = 0xe2; + *(buffer+1) = 0x8c; + *(buffer+2) = 0x9e; return 3; case 0xcf: // Lower right corner - *buffer=0xe2; - *(buffer+1)=0x8c; - *(buffer+2)=0x9f; + *buffer = 0xe2; + *(buffer+1) = 0x8c; + *(buffer+2) = 0x9f; return 3; default: // - *buffer='?'; // I'll do it eventually, I promise + *buffer = '?'; // I'll do it eventually, I promise return 1; // This are weird chars anyway } } -unsigned char cctolower (unsigned char c) +// Encodes a generic string. Note that since we use the encoders for closed +// caption data, text would have to be encoded as CCs... so using special +// characters here it's a bad idea. +static unsigned encode_line(unsigned char *buffer, unsigned char *text) { - if (c>='A' && c<='Z') - return tolower(c); - switch (c) - { - case 0x7d: // uppercase N tilde - return 0x7e; - case 0x90: // capital letter A with acute - return 0x2a; - case 0x91: // capital letter E with acute - return 0x5c; - case 0x92: // capital letter O with acute - return 0x5f; - case 0x93: // capital letter U with acute - return 0x60; - case 0xa2: // uppercase C with cedilla - return 0x7b; - case 0xa0: // uppercase A, grave accent - return 0x88; - case 0xa3: // uppercase E, grave accent - return 0x8a; - case 0xa1: // uppercase A, circumflex - return 0x8b; - case 0xa4: // uppercase E, circumflex - return 0x8c; - case 0xa7: // uppercase I, circumflex - return 0x8d; - case 0xaa: // uppercase O, circumflex - return 0x8e; - case 0xad: // uppercase U, circumflex - return 0x8f; - case 0x94: // capital letter U with diaresis - return 0x95; - case 0xa5: // capital letter E with diaresis - return 0xa6; - case 0xa8: // uppercase I, with diaresis - return 0xa9; - case 0xab: // uppercase U, grave accent - return 0xac; - case 0xb0: // Uppercase A, tilde - return 0xb1; - case 0xb2: // Uppercase I, acute accent - return 0x5e; - case 0xb3: // Uppercase I, grave accent - return 0xb4; - case 0xb5: // Uppercase O, grave accent - return 0xb6; - case 0xb7: // Uppercase O, tilde - return 0xb8; - case 0xc0: // Uppercase A, umlaut - return 0xc1; - case 0xc2: // Uppercase O, umlaut - return 0xc3; - case 0xc8: // Uppercase A, ring - return 0xc9; - case 0xca: // Uppercase O, slash - return 0xcb; - } - return c; -} - -unsigned char cctoupper (unsigned char c) -{ - if (c>='a' && c<='z') - return toupper(c); - switch (c) - { - case 0x7e: // lowercase n tilde - return 0x7d; - case 0x2a: // lowercase a, acute accent - return 0x90; - case 0x5c: // lowercase e, acute accent - return 0x91; - case 0x5e: // lowercase i, acute accent - return 0xb2; - case 0x5f: // lowercase o, acute accent - return 0x92; - case 0x60: // lowercase u, acute accent - return 0x93; - case 0x7b: // lowercase c with cedilla - return 0xa2; - case 0x88: // lowercase a, grave accent - return 0xa0; - case 0x8a: // lowercase e, grave accent - return 0xa3; - case 0x8b: // lowercase a, circumflex accent - return 0xa1; - case 0x8c: // lowercase e, circumflex accent - return 0xa4; - case 0x8d: // lowercase i, circumflex accent - return 0xa7; - case 0x8e: // lowercase o, circumflex accent - return 0xaa; - case 0x8f: // lowercase u, circumflex accent - return 0xad; - case 0x95: // lowercase letter U with diaeresis - return 0x94; - case 0xa6: // lowercase letter e with diaresis - return 0xa5; - case 0xa9: // lowercase i, with diaresis - return 0xa8; - case 0xac: // lowercase u, grave accent - return 0xab; - case 0xb1: // Lowercase a, tilde - return 0xb0; - case 0xb4: // Lowercase i, grave accent - return 0xb3; - case 0xb6: // Lowercase o, grave accent - return 0xb5; - case 0xb8: // Lowercase o, tilde - return 0xb7; - case 0xc1: // Lowercase A, umlaut - return 0xc0; - case 0xc3: // Lowercase o, umlaut - return 0xc2; - case 0xc9: // Lowercase A, ring - return 0xc8; - case 0xcb: // Lowercase o, slash - return 0xca; - } - return c; -} - - -// Encodes a generic string. Note that since we use the encoders for closed caption -// data, text would have to be encoded as CCs... so using special characters here -// it's a bad idea. -unsigned encode_line (unsigned char *buffer, unsigned char *text) -{ - unsigned bytes=0; + unsigned bytes = 0; while (*text) { - switch (encoding) - { - case ENC_UTF_8: - case ENC_LATIN_1: - *buffer=*text; - bytes++; - buffer++; - break; - case ENC_UNICODE: - *buffer=*text; - *(buffer+1)=0; - bytes+=2; - buffer+=2; - break; - } - text++; + *buffer++ = *text++; + bytes++; } return bytes; } -#define ISSEPARATOR(c) (c==' ' || c==0x89 || ispunct(c) \ - || c==0x99) // This is the apostrofe. We get it here in CC encoding, not ASCII - - -void correct_case (int line_num, struct eia608_screen *data) -{ -/* int i=0; */ -/* while (i<spell_words) */ -/* { */ -/* char *c=(char *) data->characters[line_num]; */ -/* size_t len=strlen (spell_correct[i]); */ -/* while ((c=strstr (c,spell_lower[i]))!=NULL) */ -/* { */ -/* // Make sure it's a whole word (start of line or */ -/* // preceded by space, and end of line or followed by */ -/* // space) */ -/* unsigned char prev; */ -/* if (c==(char *) data->characters[line_num]) // Beginning of line... */ -/* prev=' '; // ...Pretend we had a blank before */ -/* else */ -/* prev=*(c-1); */ -/* unsigned char next; */ -/* if (c-(char *) data->characters[line_num]+len==CC608_SCREEN_WIDTH) // End of line... */ -/* next=' '; // ... pretend we have a blank later */ -/* else */ -/* next=*(c+len); */ -/* if ( ISSEPARATOR(prev) && ISSEPARATOR(next)) */ -/* { */ -/* memcpy (c,spell_correct[i],len); */ -/* } */ -/* c++; */ -/* } */ -/* i++; */ -/* } */ -} - -void capitalize (int line_num, struct eia608_screen *data, int *new_sentence) +static void find_limit_characters(unsigned char *line, int *first_non_blank, + int *last_non_blank) { int i; - for (i=0;i<CC608_SCREEN_WIDTH;i++) + *last_non_blank = -1; + *first_non_blank = -1; + for (i = 0; i < CC608_SCREEN_WIDTH; i++) { - switch (data->characters[line_num][i]) + unsigned char c = line[i]; + if (c != ' ' && c != 0x89) { - case ' ': - case 0x89: // This is a transparent space - case '-': - break; - case '.': // Fallthrough - case '?': // Fallthrough - case '!': - case ':': - *new_sentence=1; - break; - default: - if (*new_sentence) - data->characters[line_num][i]=cctoupper (data->characters[line_num][i]); - else - data->characters[line_num][i]=cctolower (data->characters[line_num][i]); - *new_sentence=0; - break; + if (*first_non_blank == -1) + *first_non_blank = i; + *last_non_blank = i; } } } -void find_limit_characters (unsigned char *line, int *first_non_blank, int *last_non_blank) +static unsigned get_decoder_line_encoded(unsigned char *buffer, int line_num, + struct eia608_screen *data) { + uint8_t font_style; + uint8_t prev_font_style = FONT_REGULAR; + uint8_t font_color; + uint8_t prev_font_color = COL_WHITE; int i; - *last_non_blank=-1; - *first_non_blank=-1; - for (i=0;i<CC608_SCREEN_WIDTH;i++) - { - unsigned char c=line[i]; - if (c!=' ' && c!=0x89) - { - if (*first_non_blank==-1) - *first_non_blank=i; - *last_non_blank=i; - } - } -} - -unsigned get_decoder_line_basic (unsigned char *buffer, int line_num, struct eia608_screen *data) -{ unsigned char *line = data->characters[line_num]; - int last_non_blank=-1; - int first_non_blank=-1; - unsigned char *orig=buffer; // Keep for debugging - int i; - find_limit_characters (line, &first_non_blank, &last_non_blank); + unsigned char *orig = buffer; // Keep for debugging + int first = 0, last = 31; - if (first_non_blank==-1) + find_limit_characters(line, &first, &last); + for (i = first; i <= last; i++) { - *buffer=0; - return 0; - } + // Handle color + font_color = data->colors[line_num][i]; + font_style = data->fonts[line_num][i]; - int bytes=0; - for (i=first_non_blank;i<=last_non_blank;i++) - { - char c=line[i]; - switch (encoding) + // Handle reset to defaults + if ((font_style & FONT_STYLE_MASK) == 0 && font_color == COL_WHITE) { - case ENC_UTF_8: - bytes=get_char_in_utf_8 (buffer,c); - break; - case ENC_LATIN_1: - get_char_in_latin_1 (buffer,c); - bytes=1; - break; - case ENC_UNICODE: - get_char_in_unicode (buffer,c); - bytes=2; - break; + if (((font_style ^ prev_font_style) & FONT_STYLE_MASK) || + (font_color != prev_font_color)) + { + buffer += encode_line(buffer, (uint8_t*)"{\\r}"); + } } - buffer+=bytes; - } - *buffer=0; - return (unsigned) (buffer-orig); // Return length -} + else + { + // Open markup + if (((font_style ^ prev_font_style) & FONT_STYLE_MASK) || + (font_color != prev_font_color)) + { + // style changed + buffer += encode_line(buffer, (uint8_t*)"{"); + } -unsigned get_decoder_line_encoded (unsigned char *buffer, int line_num, struct eia608_screen *data) -{ - int col = COL_WHITE; - int underlined = 0; - int italics = 0; - int i; + // Handle underlined + if ((font_style ^ prev_font_style) & FONT_UNDERLINED) + { + int enable = !!(font_style & FONT_UNDERLINED); + buffer += encode_line(buffer, (uint8_t*)"\\u"); + *buffer++ = enable + 0x30; + } - unsigned char *line = data->characters[line_num]; - unsigned char *orig=buffer; // Keep for debugging - int first=0, last=31; - if (trim_subs) - find_limit_characters(line,&first,&last); - for (i=first;i<=last;i++) - { - // Handle color - int its_col = data->colors[line_num][i]; - if (its_col != col && !nofontcolor) - { - if (col!=COL_WHITE) // We need to close the previous font tag + // Handle italics + if ((font_style ^ prev_font_style) & FONT_ITALICS) { - buffer+= encode_line (buffer,(unsigned char *) "</font>"); + int enable = !!(font_style & FONT_ITALICS); + buffer += encode_line(buffer, (uint8_t*)"\\i"); + *buffer++ = enable + 0x30; } - // Add new font tag - buffer+=encode_line (buffer, (unsigned char*) color_text[its_col][1]); - if (its_col==COL_USERDEFINED) + + // Handle color + if (font_color != prev_font_color) { - // The previous sentence doesn't copy the whole - // <font> tag, just up to the quote before the color - buffer+=encode_line (buffer, (unsigned char*) usercolor_rgb); - buffer+=encode_line (buffer, (unsigned char*) "\">"); + buffer += encode_line(buffer, (uint8_t*)"\\1c"); + buffer += encode_line(buffer, + (uint8_t*)color_text[font_color][1]); } - col = its_col; - } - // Handle underlined - int is_underlined = data->fonts[line_num][i] & FONT_UNDERLINED; - if (is_underlined && underlined==0) // Open underline - { - buffer+=encode_line (buffer, (unsigned char *) "<u>"); - } - if (is_underlined==0 && underlined) // Close underline - { - buffer+=encode_line (buffer, (unsigned char *) "</u>"); - } - underlined=is_underlined; - // Handle italics - int has_ita = data->fonts[line_num][i] & FONT_ITALICS; - if (has_ita && italics==0) // Open italics - { - buffer+=encode_line (buffer, (unsigned char *) "<i>"); - } - if (has_ita==0 && italics) // Close italics - { - buffer+=encode_line (buffer, (unsigned char *) "</i>"); - } - italics=has_ita; - int bytes=0; - switch (encoding) - { - case ENC_UTF_8: - bytes=get_char_in_utf_8 (buffer,line[i]); - break; - case ENC_LATIN_1: - get_char_in_latin_1 (buffer,line[i]); - bytes=1; - break; - case ENC_UNICODE: - get_char_in_unicode (buffer,line[i]); - bytes=2; - break; + // Close markup + if (((font_style ^ prev_font_style) & FONT_STYLE_MASK) || + (font_color != prev_font_color)) + { + // style changed + buffer += encode_line(buffer, (uint8_t*)"}"); + } } - buffer+=bytes; - } - if (italics) - { - buffer+=encode_line (buffer, (unsigned char *) "</i>"); - } - if (underlined) - { - buffer+=encode_line (buffer, (unsigned char *) "</u>"); - } - if (col != COL_WHITE && !nofontcolor) - { - buffer+=encode_line (buffer, (unsigned char *) "</font>"); + prev_font_style = font_style; + prev_font_color = font_color; + + int bytes = 0; + bytes = get_char_in_utf8(buffer, line[i]); + buffer += bytes; } - *buffer=0; - return (unsigned) (buffer-orig); // Return length + *buffer = 0; + return (unsigned) (buffer - orig); // Return length } -void delete_all_lines_but_current (struct eia608_screen *data, int row) +static void delete_all_lines_but_current (struct eia608_screen *data, int row) { int i; for (i=0;i<15;i++) @@ -1271,7 +674,7 @@ void delete_all_lines_but_current (struct eia608_screen *data, int row) } } -void clear_eia608_cc_buffer (struct eia608_screen *data) +static void clear_eia608_cc_buffer (struct eia608_screen *data) { int i; @@ -1286,27 +689,26 @@ void clear_eia608_cc_buffer (struct eia608_screen *data) data->empty=1; } -void init_eia608 (struct eia608 *data) +static void init_eia608 (struct eia608 *data) { - data->cursor_column=0; - data->cursor_row=0; + data->cursor_column = 0; + data->cursor_row = 0; clear_eia608_cc_buffer (&data->buffer1); clear_eia608_cc_buffer (&data->buffer2); - data->visible_buffer=1; - data->last_c1=0; - data->last_c2=0; - data->mode=MODE_POPUP; - // data->current_visible_start_cc=0; - data->current_visible_start_ms=0; - data->srt_counter=0; - data->screenfuls_counter=0; - data->channel=1; - data->color=default_color; - data->font=FONT_REGULAR; - data->rollup_base_row=14; + data->visible_buffer = 1; + data->last_c1 = 0; + data->last_c2 = 0; + data->mode = MODE_POPUP; + data->current_visible_start_ms = 0; + data->ssa_counter = 0; + data->screenfuls_counter = 0; + data->channel = 1; + data->color = default_color; + data->font = FONT_REGULAR; + data->rollup_base_row = 14; } -struct eia608_screen *get_current_hidden_buffer(struct s_write *wb) +static struct eia608_screen *get_current_hidden_buffer(struct s_write *wb) { struct eia608_screen *data; if (wb->data608->visible_buffer == 1) @@ -1316,7 +718,7 @@ struct eia608_screen *get_current_hidden_buffer(struct s_write *wb) return data; } -struct eia608_screen *get_current_visible_buffer(struct s_write *wb) +static struct eia608_screen *get_current_visible_buffer(struct s_write *wb) { struct eia608_screen *data; if (wb->data608->visible_buffer == 1) @@ -1331,7 +733,7 @@ static void swap_visible_buffer(struct s_write *wb) wb->data608->visible_buffer = (wb->data608->visible_buffer == 1) ? 2 : 1; } -struct eia608_screen *get_writing_buffer (struct s_write *wb) +static struct eia608_screen *get_writing_buffer(struct s_write *wb) { struct eia608_screen *use_buffer=NULL; switch (wb->data608->mode) @@ -1350,27 +752,28 @@ struct eia608_screen *get_writing_buffer (struct s_write *wb) return use_buffer; } -void write_char (const unsigned char c, struct s_write *wb) +static void write_char(const unsigned char c, struct s_write *wb) { - if (wb->data608->mode!=MODE_TEXT) + if (wb->data608->mode != MODE_TEXT) { - struct eia608_screen * use_buffer=get_writing_buffer(wb); + struct eia608_screen * use_buffer = get_writing_buffer(wb); /* hb_log ("\rWriting char [%c] at %s:%d:%d\n",c, use_buffer == &wb->data608->buffer1?"B1":"B2", wb->data608->cursor_row,wb->data608->cursor_column); */ - use_buffer->characters[wb->data608->cursor_row][wb->data608->cursor_column]=c; - use_buffer->colors[wb->data608->cursor_row][wb->data608->cursor_column]=wb->data608->color; - use_buffer->fonts[wb->data608->cursor_row][wb->data608->cursor_column]=wb->data608->font; - use_buffer->row_used[wb->data608->cursor_row]=1; - use_buffer->empty=0; - if (wb->data608->cursor_column<31) + use_buffer->characters[wb->data608->cursor_row][wb->data608->cursor_column] = c; + use_buffer->colors[wb->data608->cursor_row][wb->data608->cursor_column] = wb->data608->color; + use_buffer->fonts[wb->data608->cursor_row][wb->data608->cursor_column] = wb->data608->font; + use_buffer->row_used[wb->data608->cursor_row] = 1; + use_buffer->empty = 0; + if (wb->data608->cursor_column < 31) wb->data608->cursor_column++; } } /* Handle MID-ROW CODES. */ -void handle_text_attr (const unsigned char c1, const unsigned char c2, struct s_write *wb) +static void handle_text_attr(const unsigned char c1, const unsigned char c2, + struct s_write *wb) { // Handle channel change wb->data608->channel=wb->new_channel; @@ -1389,56 +792,34 @@ void handle_text_attr (const unsigned char c1, const unsigned char c2, struct s_ wb->data608->color=pac2_attribs[i][0]; wb->data608->font=pac2_attribs[i][1]; if (debug_608) - hb_log (" -- Color: %s, font: %s\n", - color_text[wb->data608->color][0], - font_text[wb->data608->font]); + hb_log(" -- Color: %s, font: %s\n", + color_text[wb->data608->color][0], + font_text[wb->data608->font]); if (wb->data608->cursor_column<31) wb->data608->cursor_column++; } } -void mstotime (int64_t milli, unsigned *hours, unsigned *minutes, - unsigned *seconds, unsigned *ms) +static int write_cc_buffer_as_ssa(struct eia608_screen *data, + struct s_write *wb) { - // int64_t milli = (int64_t) ((ccblock*1000)/29.97); - *ms=(unsigned) (milli%1000); // milliseconds - milli=(milli-*ms)/1000; // Remainder, in seconds - *seconds = (int) (milli%60); - milli=(milli-*seconds)/60; // Remainder, in minutes - *minutes = (int) (milli%60); - milli=(milli-*minutes)/60; // Remainder, in hours - *hours=(int) milli; -} - -void fhb_log_encoded (FILE *fh, const char *string) -{ - //GUARANTEE(wb, strlen (string)*3); - //wb->enc_buffer_used=encode_line (wb->enc_buffer,(unsigned char *) string); - //fwrite (wb->enc_buffer,wb->enc_buffer_used,1,fh); -} - -int write_cc_buffer_as_srt(struct eia608_screen *data, struct s_write *wb) -{ - unsigned h1,m1,s1,ms1; - unsigned h2,m2,s2,ms2; int wrote_something = 0; - int64_t ms_start= wb->data608->current_visible_start_ms; int i; + int64_t ms_start = wb->data608->current_visible_start_ms; + //int64_t ms_end = get_last_pts(wb) + subs_delay; + int row = -1, col = -1; - ms_start+=subs_delay; + ms_start += subs_delay; if (ms_start<0) // Drop screens that because of subs_delay start too early return 0; - int64_t ms_end = get_fts(wb)+subs_delay; - mstotime (ms_start,&h1,&m1,&s1,&ms1); - mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line. - char timeline[128]; - wb->data608->srt_counter++; - sprintf (timeline,"%u\r\n",wb->data608->srt_counter); - if (debug_608) { - hb_log ("\n- - - SRT caption - - -\n"); + char timeline[128]; + wb->data608->ssa_counter++; + sprintf (timeline,"%u\r\n",wb->data608->ssa_counter); + + hb_log ("\n- - - SSA caption - - -\n"); hb_log ("%s", timeline); } @@ -1447,58 +828,122 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct s_write *wb) * ensure that we only have two lines, insert a newline after the first one, * and have a big bottom line (strip spaces from any joined lines). */ + int rows = 0, columns = 0; + for (i = 0; i < 15; i++) + { + if (data->row_used[i]) + { + int first, last; + + rows++; + find_limit_characters(data->characters[i], &first, &last); + if (last - first + 1 > columns) + columns = last - first + 1; + } + } + wb->enc_buffer_used = 0; int line = 1; - for (i=0;i<15;i++) + for (i = 0; i < 15; i++) { if (data->row_used[i]) { - if (sentence_cap) + // Get position for this CC + if (row == -1) { - capitalize(i,data, &wb->new_sentence); - correct_case(i,data); + int last, x, y, safe_zone, cell_width, cell_height; + int cropped_width, cropped_height, font_size; + char *pos; + + row = i; + find_limit_characters(data->characters[i], &col, &last); + + // CC grid is 16 rows by 62 colums + // Our SSA resolution is the title resolution + // Tranlate CC grid to SSA coordinates + // The numbers are tweaked to keep things off the very + // edges of the screen and in the "safe" zone + cropped_height = wb->height - wb->crop[0] - wb->crop[1]; + cropped_width = wb->width - wb->crop[2] - wb->crop[3]; + font_size = cropped_height * .066; + safe_zone = wb->height * 0.025; + cell_height = (wb->height - 2 * safe_zone) / 16; + cell_width = (wb->width - 2 * safe_zone) / 32; + + // Calculate position assuming the position defines + // the baseline of the text which is lower left corner + // of bottom row of characters + y = cell_height * (row + 1 + rows) + safe_zone - wb->crop[0]; + x = cell_width * col + safe_zone - wb->crop[2]; + if (y < 0) + y = (rows * font_size) + safe_zone; + if (x < 0) + x = safe_zone; + if (y > cropped_height) + y = cropped_height - safe_zone; + if (x + columns * cell_width > cropped_width) + x = cropped_width - columns * cell_width - safe_zone; + pos = hb_strdup_printf("{\\a1\\pos(%d,%d)}", x, y); + wb->enc_buffer_used += encode_line( + wb->enc_buffer + wb->enc_buffer_used, (uint8_t*)pos); + free(pos); } + /* - * The intention was to use a newline but QT doesn't like it, old code still - * here just in case.. + * The intention was to use a newline but QT doesn't like it, + * old code still here just in case.. */ if (line == 1) { - wb->enc_buffer_used = get_decoder_line_encoded(wb->enc_buffer, i, data); + wb->enc_buffer_used += get_decoder_line_encoded( + wb->enc_buffer + wb->enc_buffer_used, i, data); line = 2; } else { - wb->enc_buffer_used += encode_line(wb->enc_buffer+wb->enc_buffer_used, - (unsigned char *) "\n"); - wb->enc_buffer_used += get_decoder_line_encoded(wb->enc_buffer+wb->enc_buffer_used, i, data); + wb->enc_buffer_used += encode_line( + wb->enc_buffer + wb->enc_buffer_used, (uint8_t*)"\\N"); + wb->enc_buffer_used += get_decoder_line_encoded( + wb->enc_buffer + wb->enc_buffer_used, i, data); } } } - if (wb->enc_buffer_used) + if (wb->enc_buffer_used && wb->enc_buffer[0] != 0) { - hb_buffer_t *buffer = hb_buffer_init( wb->enc_buffer_used + 1 ); + hb_buffer_t *buffer; + int len; + + // bump past null terminator + wb->enc_buffer_used++; + buffer = hb_buffer_init(wb->enc_buffer_used + SSA_PREAMBLE_LEN); buffer->s.frametype = HB_FRAME_SUBTITLE; buffer->s.start = ms_start; buffer->s.stop = AV_NOPTS_VALUE; - memcpy( buffer->data, wb->enc_buffer, wb->enc_buffer_used + 1 ); - if (wb->hb_last_buffer) { + sprintf((char*)buffer->data, "%d,,Default,,0,0,0,,", ++wb->line); + len = strlen((char*)buffer->data); + memcpy(buffer->data + len, wb->enc_buffer, wb->enc_buffer_used); + if (wb->hb_last_buffer) + { wb->hb_last_buffer->next = buffer; - } else { + } + else + { wb->hb_buffer = buffer; } wb->hb_last_buffer = buffer; - wrote_something=1; wb->clear_sub_needed = 1; } else if (wb->clear_sub_needed) { - hb_buffer_t *buffer = hb_buffer_init( 1 ); + hb_buffer_t *buffer = hb_buffer_init(1); buffer->s.frametype = HB_FRAME_SUBTITLE; buffer->s.start = ms_start; buffer->s.stop = ms_start; buffer->data[0] = 0; - if (wb->hb_last_buffer != NULL) { + if (wb->hb_last_buffer != NULL) + { wb->hb_last_buffer->next = buffer; - } else { + } + else + { wb->hb_buffer = buffer; } wb->hb_last_buffer = buffer; @@ -1511,18 +956,18 @@ int write_cc_buffer_as_srt(struct eia608_screen *data, struct s_write *wb) return wrote_something; } -int write_cc_buffer(struct s_write *wb) +static int write_cc_buffer(struct s_write *wb) { struct eia608_screen *data; int wrote_something=0; data = get_current_visible_buffer(wb); wb->new_sentence=1; - wrote_something = write_cc_buffer_as_srt (data, wb); + wrote_something = write_cc_buffer_as_ssa(data, wb); return wrote_something; } -void roll_up(struct s_write *wb) +static void roll_up(struct s_write *wb) { struct eia608_screen *use_buffer; int i, j; @@ -1532,29 +977,29 @@ void roll_up(struct s_write *wb) switch (wb->data608->mode) { case MODE_ROLLUP_2: - keep_lines=2; + keep_lines = 2; break; case MODE_ROLLUP_3: - keep_lines=3; + keep_lines = 3; break; case MODE_ROLLUP_4: - keep_lines=4; + keep_lines = 4; break; default: // Shouldn't happen - keep_lines=0; + keep_lines = 0; break; } - int firstrow=-1, lastrow=-1; + int firstrow = -1, lastrow = -1; // Look for the last line used - int rows_now=0; // Number of rows in use right now - for (i=0;i<15;i++) + int rows_now = 0; // Number of rows in use right now + for (i = 0; i < 15; i++) { if (use_buffer->row_used[i]) { rows_now++; - if (firstrow==-1) - firstrow=i; - lastrow=i; + if (firstrow == -1) + firstrow = i; + lastrow = i; } } @@ -1564,37 +1009,37 @@ void roll_up(struct s_write *wb) if (lastrow==-1) // Empty screen, nothing to rollup return; - for (j=lastrow-keep_lines+1;j<lastrow; j++) + for (j = lastrow - keep_lines + 1; j < lastrow; j++) { - if (j>=0) + if (j >= 0) { - memcpy (use_buffer->characters[j],use_buffer->characters[j+1],CC608_SCREEN_WIDTH+1); - memcpy (use_buffer->colors[j],use_buffer->colors[j+1],CC608_SCREEN_WIDTH+1); - memcpy (use_buffer->fonts[j],use_buffer->fonts[j+1],CC608_SCREEN_WIDTH+1); - use_buffer->row_used[j]=use_buffer->row_used[j+1]; + memcpy(use_buffer->characters[j], use_buffer->characters[j+1], CC608_SCREEN_WIDTH+1); + memcpy(use_buffer->colors[j], use_buffer->colors[j+1], CC608_SCREEN_WIDTH+1); + memcpy(use_buffer->fonts[j], use_buffer->fonts[j+1], CC608_SCREEN_WIDTH+1); + use_buffer->row_used[j] = use_buffer->row_used[j+1]; } } - for (j=0;j<(1+wb->data608->cursor_row-keep_lines);j++) + for (j = 0; j < (1 + wb->data608->cursor_row - keep_lines); j++) { - memset(use_buffer->characters[j],' ',CC608_SCREEN_WIDTH); - memset(use_buffer->colors[j],COL_WHITE,CC608_SCREEN_WIDTH); - memset(use_buffer->fonts[j],FONT_REGULAR,CC608_SCREEN_WIDTH); - use_buffer->characters[j][CC608_SCREEN_WIDTH]=0; - use_buffer->row_used[j]=0; + memset(use_buffer->characters[j], ' ', CC608_SCREEN_WIDTH); + memset(use_buffer->colors[j], COL_WHITE, CC608_SCREEN_WIDTH); + memset(use_buffer->fonts[j], FONT_REGULAR, CC608_SCREEN_WIDTH); + use_buffer->characters[j][CC608_SCREEN_WIDTH] = 0; + use_buffer->row_used[j] = 0; } - memset(use_buffer->characters[lastrow],' ',CC608_SCREEN_WIDTH); - memset(use_buffer->colors[lastrow],COL_WHITE,CC608_SCREEN_WIDTH); - memset(use_buffer->fonts[lastrow],FONT_REGULAR,CC608_SCREEN_WIDTH); + memset(use_buffer->characters[lastrow], ' ', CC608_SCREEN_WIDTH); + memset(use_buffer->colors[lastrow], COL_WHITE, CC608_SCREEN_WIDTH); + memset(use_buffer->fonts[lastrow], FONT_REGULAR, CC608_SCREEN_WIDTH); - use_buffer->characters[lastrow][CC608_SCREEN_WIDTH]=0; - use_buffer->row_used[lastrow]=0; + use_buffer->characters[lastrow][CC608_SCREEN_WIDTH] = 0; + use_buffer->row_used[lastrow] = 0; // Sanity check - rows_now=0; - for (i=0;i<15;i++) + rows_now = 0; + for (i = 0; i < 15; i++) if (use_buffer->row_used[i]) rows_now++; - if (rows_now>keep_lines) + if (rows_now > keep_lines) hb_log ("Bug in roll_up, should have %d lines but I have %d.\n", keep_lines, rows_now); } @@ -1613,7 +1058,7 @@ void erase_memory (struct s_write *wb, int displayed) clear_eia608_cc_buffer (buf); } -int is_current_row_empty (struct s_write *wb) +static int is_current_row_empty (struct s_write *wb) { struct eia608_screen *use_buffer; int i; @@ -1628,7 +1073,8 @@ int is_current_row_empty (struct s_write *wb) } /* Process GLOBAL CODES */ -void handle_command (/*const */ unsigned char c1, const unsigned char c2, struct s_write *wb) +static void handle_command(unsigned char c1, const unsigned char c2, + struct s_write *wb) { // Handle channel change wb->data608->channel=wb->new_channel; @@ -1674,7 +1120,7 @@ void handle_command (/*const */ unsigned char c1, const unsigned char c2, struct if (wb->data608->cursor_column>0) { wb->data608->cursor_column--; - get_writing_buffer(wb)->characters[wb->data608->cursor_row][wb->data608->cursor_column]=' '; + get_writing_buffer(wb)->characters[wb->data608->cursor_row][wb->data608->cursor_column] = ' '; } break; case COM_TABOFFSET1: @@ -1693,11 +1139,11 @@ void handle_command (/*const */ unsigned char c1, const unsigned char c2, struct break; case COM_RESUMECAPTIONLOADING: wb->data608->mode=MODE_POPUP; - wb->data608->current_visible_start_ms = get_fts(wb); + wb->data608->current_visible_start_ms = get_last_pts(wb); break; case COM_RESUMETEXTDISPLAY: wb->data608->mode=MODE_TEXT; - wb->data608->current_visible_start_ms = get_fts(wb); + wb->data608->current_visible_start_ms = get_last_pts(wb); break; case COM_ROLLUP2: if (wb->data608->mode==MODE_POPUP) @@ -1714,11 +1160,11 @@ void handle_command (/*const */ unsigned char c1, const unsigned char c2, struct handle_command(0x14, 0x2D, wb); wb->rollup_cr = 1; } - wb->data608->current_visible_start_ms = get_fts(wb); + wb->data608->current_visible_start_ms = get_last_pts(wb); wb->data608->mode=MODE_ROLLUP_2; erase_memory (wb, 0); - wb->data608->cursor_column=0; - wb->data608->cursor_row=wb->data608->rollup_base_row; + wb->data608->cursor_column = 0; + wb->data608->cursor_row = wb->data608->rollup_base_row; break; case COM_ROLLUP3: if (wb->data608->mode==MODE_POPUP) @@ -1734,11 +1180,11 @@ void handle_command (/*const */ unsigned char c1, const unsigned char c2, struct handle_command(0x14, 0x2D, wb); wb->rollup_cr = 1; } - wb->data608->current_visible_start_ms = get_fts(wb); + wb->data608->current_visible_start_ms = get_last_pts(wb); wb->data608->mode=MODE_ROLLUP_3; erase_memory (wb, 0); - wb->data608->cursor_column=0; - wb->data608->cursor_row=wb->data608->rollup_base_row; + wb->data608->cursor_column = 0; + wb->data608->cursor_row = wb->data608->rollup_base_row; break; case COM_ROLLUP4: if (wb->data608->mode==MODE_POPUP) @@ -1754,10 +1200,10 @@ void handle_command (/*const */ unsigned char c1, const unsigned char c2, struct handle_command(0x14, 0x2D, wb); wb->rollup_cr = 1; } - wb->data608->current_visible_start_ms = get_fts(wb); - wb->data608->mode=MODE_ROLLUP_4; - wb->data608->cursor_column=0; - wb->data608->cursor_row=wb->data608->rollup_base_row; + wb->data608->current_visible_start_ms = get_last_pts(wb); + wb->data608->mode = MODE_ROLLUP_4; + wb->data608->cursor_column = 0; + wb->data608->cursor_row = wb->data608->rollup_base_row; erase_memory (wb, 0); break; case COM_CARRIAGERETURN: @@ -1768,17 +1214,16 @@ void handle_command (/*const */ unsigned char c1, const unsigned char c2, struct if (wb->rollup_cr && is_current_row_empty(wb)) { wb->rollup_cr = 0; - wb->data608->current_visible_start_ms = get_fts(wb); + wb->data608->current_visible_start_ms = get_last_pts(wb); break; } - if (norollup) delete_all_lines_but_current(get_current_visible_buffer(wb), wb->data608->cursor_row); if (write_cc_buffer(wb)) wb->data608->screenfuls_counter++; roll_up(wb); - wb->data608->cursor_column=0; - wb->data608->current_visible_start_ms = get_fts(wb); + wb->data608->cursor_column = 0; + wb->data608->current_visible_start_ms = get_last_pts(wb); break; case COM_ERASENONDISPLAYEDMEMORY: erase_memory (wb,0); @@ -1791,7 +1236,7 @@ void handle_command (/*const */ unsigned char c1, const unsigned char c2, struct { // If popup, the last pts is the time to remove the // popup from the screen - wb->data608->current_visible_start_ms = get_fts(wb); + wb->data608->current_visible_start_ms = get_last_pts(wb); } // Write "clear" subtitle if necessary write_cc_buffer(wb); @@ -1802,15 +1247,15 @@ void handle_command (/*const */ unsigned char c1, const unsigned char c2, struct if (wb->data608->mode == MODE_POPUP) { swap_visible_buffer(wb); - wb->data608->current_visible_start_ms = get_fts(wb); + wb->data608->current_visible_start_ms = get_last_pts(wb); } if (write_cc_buffer(wb)) wb->data608->screenfuls_counter++; if (wb->data608->mode != MODE_POPUP) swap_visible_buffer(wb); - wb->data608->cursor_column=0; - wb->data608->cursor_row=0; + wb->data608->cursor_column = 0; + wb->data608->cursor_row = 0; wb->data608->color=default_color; wb->data608->font=FONT_REGULAR; break; @@ -1823,14 +1268,15 @@ void handle_command (/*const */ unsigned char c1, const unsigned char c2, struct } } -void handle_end_of_data (struct s_write *wb) +static void handle_end_of_data(struct s_write *wb) { // We issue a EraseDisplayedMemory here so if there's any captions pending // they get written to file. handle_command (0x14, 0x2c, wb); // EDM } -void handle_double (const unsigned char c1, const unsigned char c2, struct s_write *wb) +static void handle_double(const unsigned char c1, const unsigned char c2, + struct s_write *wb) { unsigned char c; if (wb->data608->channel!=cc_channel) @@ -1845,7 +1291,8 @@ void handle_double (const unsigned char c1, const unsigned char c2, struct s_wri } /* Process EXTENDED CHARACTERS */ -unsigned char handle_extended (unsigned char hi, unsigned char lo, struct s_write *wb) +static unsigned char handle_extended(unsigned char hi, unsigned char lo, + struct s_write *wb) { // Handle channel change if (wb->new_channel > 2) @@ -1886,7 +1333,7 @@ unsigned char handle_extended (unsigned char hi, unsigned char lo, struct s_writ } /* Process PREAMBLE ACCESS CODES (PAC) */ -void handle_pac (unsigned char c1, unsigned char c2, struct s_write *wb) +static void handle_pac(unsigned char c1, unsigned char c2, struct s_write *wb) { // Handle channel change if (wb->new_channel > 2) @@ -1926,19 +1373,19 @@ void handle_pac (unsigned char c1, unsigned char c2, struct s_write *wb) int indent=pac2_attribs[c2][2]; if (debug_608) hb_log (" -- Position: %d:%d, color: %s, font: %s\n",row, - indent,color_text[color][0],font_text[font]); - if (wb->data608->mode!=MODE_TEXT) + indent,color_text[color][0],font_text[font]); + if (wb->data608->mode != MODE_TEXT) { // According to Robson, row info is discarded in text mode // but column is accepted - wb->data608->cursor_row=row-1 ; // Since the array is 0 based + wb->data608->cursor_row = row - 1 ; // Since the array is 0 based } - wb->data608->rollup_base_row=row-1; - wb->data608->cursor_column=indent; + wb->data608->rollup_base_row = row - 1; + wb->data608->cursor_column = indent; } -void handle_single (const unsigned char c1, struct s_write *wb) +static void handle_single(const unsigned char c1, struct s_write *wb) { if (c1<0x20 || wb->data608->channel!=cc_channel) return; // We don't allow special stuff here @@ -1950,7 +1397,7 @@ void handle_single (const unsigned char c1, struct s_write *wb) write_char (c1,wb); } -int check_channel (unsigned char c1, struct s_write *wb) +static int check_channel(unsigned char c1, struct s_write *wb) { if (c1==0x14) { @@ -1984,7 +1431,7 @@ int check_channel (unsigned char c1, struct s_write *wb) /* Handle Command, special char or attribute and also check for * channel changes. * Returns 1 if something was written to screen, 0 otherwise */ -int disCommand (unsigned char hi, unsigned char lo, struct s_write *wb) +static int disCommand(unsigned char hi, unsigned char lo, struct s_write *wb) { int wrote_to_screen=0; @@ -2050,7 +1497,8 @@ int disCommand (unsigned char hi, unsigned char lo, struct s_write *wb) return wrote_to_screen; } -void process608 (const unsigned char *data, int length, struct s_write *wb) +static void process608(const unsigned char *data, int length, + struct s_write *wb) { static int textprinted = 0; int i; @@ -2125,7 +1573,7 @@ void process608 (const unsigned char *data, int length, struct s_write *wb) if ( debug_608 && !textprinted && wb->data608->channel==cc_channel ) { // Current FTS information after the characters are shown - //hb_log("Current FTS: %s\n", print_mstime(get_fts())); + //hb_log("Current FTS: %s\n", print_mstime(get_last_pts())); } if (wrote_to_screen && direct_rollup && // If direct_rollup is enabled and @@ -2135,55 +1583,19 @@ void process608 (const unsigned char *data, int length, struct s_write *wb) { // We don't increase screenfuls_counter here. write_cc_buffer(wb); - wb->data608->current_visible_start_ms = get_fts(wb); + wb->data608->current_visible_start_ms = get_last_pts(wb); } } } } - -/* Return a pointer to a string that holds the printable characters - * of the caption data block. FOR DEBUG PURPOSES ONLY! */ -unsigned char *debug_608toASC (unsigned char *cc_data, int channel) -{ - static unsigned char output[3]; - - unsigned char cc_valid = (cc_data[0] & 4) >>2; - unsigned char cc_type = cc_data[0] & 3; - unsigned char hi, lo; - - output[0]=' '; - output[1]=' '; - output[2]='\x00'; - - if (cc_valid && cc_type==channel) - { - hi = cc_data[1] & 0x7F; // Get rid of parity bit - lo = cc_data[2] & 0x7F; // Get rid of parity bit - if (hi>=0x20) - { - output[0]=hi; - output[1]=(lo>=20 ? lo : '.'); - output[2]='\x00'; - } - else - { - output[0]='<'; - output[1]='>'; - output[2]='\x00'; - } - } - return output; -} - - struct hb_work_private_s { hb_job_t * job; struct s_write * cc608; }; -int decccInit( hb_work_object_t * w, hb_job_t * job ) +static int decccInit( hb_work_object_t * w, hb_job_t * job ) { int retval = 1; hb_work_private_t * pv; @@ -2199,6 +1611,9 @@ int decccInit( hb_work_object_t * w, hb_job_t * job ) if( pv->cc608 ) { + pv->cc608->width = job->title->width; + pv->cc608->height = job->title->height; + memcpy(pv->cc608->crop, job->crop, sizeof(int[4])); retval = general_608_init(pv->cc608); if( !retval ) { @@ -2211,10 +1626,17 @@ int decccInit( hb_work_object_t * w, hb_job_t * job ) } } } + if (!retval) + { + // Generate generic SSA Script Info. + int height = job->title->height - job->crop[0] - job->crop[1]; + int width = job->title->width - job->crop[2] - job->crop[3]; + hb_subtitle_add_ssa_header(w->subtitle, width, height); + } return retval; } -int decccWork( hb_work_object_t * w, hb_buffer_t ** buf_in, +static int decccWork( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_buffer_t ** buf_out ) { hb_work_private_t * pv = w->private_data; @@ -2254,7 +1676,7 @@ int decccWork( hb_work_object_t * w, hb_buffer_t ** buf_in, return HB_WORK_OK; } -void decccClose( hb_work_object_t * w ) +static void decccClose( hb_work_object_t * w ) { hb_work_private_t * pv = w->private_data; general_608_close( pv->cc608 ); |