summaryrefslogtreecommitdiffstats
path: root/libhb/deccc608sub.c
diff options
context:
space:
mode:
Diffstat (limited to 'libhb/deccc608sub.c')
-rw-r--r--libhb/deccc608sub.c2403
1 files changed, 2403 insertions, 0 deletions
diff --git a/libhb/deccc608sub.c b/libhb/deccc608sub.c
new file mode 100644
index 000000000..2b0b199fa
--- /dev/null
+++ b/libhb/deccc608sub.c
@@ -0,0 +1,2403 @@
+/*
+ * From ccextractor, leave this file as intact and close to the original as possible so that
+ * it is easy to patch in fixes - even though this file contains code that we don't need.
+ *
+ * Note that the SRT sub generation from CC could be useful for mkv subs.
+ */
+#include "hb.h"
+#include "deccc608sub.h"
+
+/*
+ * ccextractor static configuration variables.
+ */
+static int debug_608 = 0;
+static int trim_subs = 0;
+static int nofontcolor = 0;
+static enum encoding_type encoding = ENC_UTF_8;
+static int cc_channel = 1;
+static enum output_format write_format = OF_TRANSCRIPT;
+static int sentence_cap = 1;
+static int subs_delay = 0;
+static LLONG screens_to_process = -1;
+static int processed_enough = 0;
+static int gui_mode_reports = 0;
+static int norollup = 1;
+static int direct_rollup = 0;
+
+static LLONG get_fts(void)
+{
+ return 0;
+}
+
+#define fatal(N, ...) // N
+#define XMLRPC_APPEND(N, ...) // N
+
+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 *enc_buffer=NULL; // Generic general purpose buffer
+unsigned char str[2048]; // Another generic general purpose buffer
+unsigned enc_buffer_used;
+unsigned enc_buffer_capacity;
+
+#define GUARANTEE(length) if (length>enc_buffer_capacity) \
+{enc_buffer_capacity*=2; enc_buffer=(unsigned char*) realloc (enc_buffer, enc_buffer_capacity); \
+ if (enc_buffer==NULL) { fatal (EXIT_NOT_ENOUGH_MEMORY, "Not enough memory, bailing out\n"); } \
+}
+
+const unsigned char pac2_attribs[][3]= // Color, font, ident
+{
+ {COL_WHITE, FONT_REGULAR, 0}, // 0x40 || 0x60
+ {COL_WHITE, FONT_UNDERLINED, 0}, // 0x41 || 0x61
+ {COL_GREEN, FONT_REGULAR, 0}, // 0x42 || 0x62
+ {COL_GREEN, FONT_UNDERLINED, 0}, // 0x43 || 0x63
+ {COL_BLUE, FONT_REGULAR, 0}, // 0x44 || 0x64
+ {COL_BLUE, FONT_UNDERLINED, 0}, // 0x45 || 0x65
+ {COL_CYAN, FONT_REGULAR, 0}, // 0x46 || 0x66
+ {COL_CYAN, FONT_UNDERLINED, 0}, // 0x47 || 0x67
+ {COL_RED, FONT_REGULAR, 0}, // 0x48 || 0x68
+ {COL_RED, FONT_UNDERLINED, 0}, // 0x49 || 0x69
+ {COL_YELLOW, FONT_REGULAR, 0}, // 0x4a || 0x6a
+ {COL_YELLOW, FONT_UNDERLINED, 0}, // 0x4b || 0x6b
+ {COL_MAGENTA, FONT_REGULAR, 0}, // 0x4c || 0x6c
+ {COL_MAGENTA, FONT_UNDERLINED, 0}, // 0x4d || 0x6d
+ {COL_WHITE, FONT_ITALICS, 0}, // 0x4e || 0x6e
+ {COL_WHITE, FONT_UNDERLINED_ITALICS, 0}, // 0x4f || 0x6f
+ {COL_WHITE, FONT_REGULAR, 0}, // 0x50 || 0x70
+ {COL_WHITE, FONT_UNDERLINED, 0}, // 0x51 || 0x71
+ {COL_WHITE, FONT_REGULAR, 4}, // 0x52 || 0x72
+ {COL_WHITE, FONT_UNDERLINED, 4}, // 0x53 || 0x73
+ {COL_WHITE, FONT_REGULAR, 8}, // 0x54 || 0x74
+ {COL_WHITE, FONT_UNDERLINED, 8}, // 0x55 || 0x75
+ {COL_WHITE, FONT_REGULAR, 12}, // 0x56 || 0x76
+ {COL_WHITE, FONT_UNDERLINED, 12}, // 0x57 || 0x77
+ {COL_WHITE, FONT_REGULAR, 16}, // 0x58 || 0x78
+ {COL_WHITE, FONT_UNDERLINED, 16}, // 0x59 || 0x79
+ {COL_WHITE, FONT_REGULAR, 20}, // 0x5a || 0x7a
+ {COL_WHITE, FONT_UNDERLINED, 20}, // 0x5b || 0x7b
+ {COL_WHITE, FONT_REGULAR, 24}, // 0x5c || 0x7c
+ {COL_WHITE, FONT_UNDERLINED, 24}, // 0x5d || 0x7d
+ {COL_WHITE, FONT_REGULAR, 28}, // 0x5e || 0x7e
+ {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;
+
+const char *sami_header= // TODO: Revise the <!-- comments
+"<SAMI>\n\
+<HEAD>\n\
+<STYLE TYPE=\"text/css\">\n\
+<!--\n\
+P {margin-left: 16pt; margin-right: 16pt; margin-bottom: 16pt; margin-top: 16pt;\n\
+text-align: center; font-size: 18pt; font-family: arial; font-weight: bold; color: #f0f0f0;}\n\
+.UNKNOWNCC {Name:Unknown; lang:en-US; SAMIType:CC;}\n\
+-->\n\
+</STYLE>\n\
+</HEAD>\n\n\
+<BODY>\n";
+
+const char *command_type[] =
+{
+ "Unknown",
+ "EDM - EraseDisplayedMemory",
+ "RCL - ResumeCaptionLoading",
+ "EOC - End Of Caption",
+ "TO1 - Tab Offset, 1 column",
+ "TO2 - Tab Offset, 2 column",
+ "TO3 - Tab Offset, 3 column",
+ "RU2 - Roll up 2 rows",
+ "RU3 - Roll up 3 rows",
+ "RU4 - Roll up 4 rows",
+ "CR - Carriage Return",
+ "ENM - Erase non-displayed memory",
+ "BS - Backspace",
+ "RTD - Resume Text Display"
+};
+
+const char *font_text[]=
+{
+ "regular",
+ "italics",
+ "underlined",
+ "underlined italics"
+};
+
+const char *cc_modes_text[]=
+{
+ "Pop-Up captions"
+};
+
+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=\""}
+};
+
+int general_608_init (struct s_write *wb)
+{
+ /*
+ * Not currently used.
+ *
+ if( !enc_buffer )
+ {
+ enc_buffer=(unsigned char *) malloc (INITIAL_ENC_BUFFER_CAPACITY);
+ if (enc_buffer==NULL)
+ return -1;
+ enc_buffer_capacity=INITIAL_ENC_BUFFER_CAPACITY;
+ }
+ */
+
+ if( !wb->subline) {
+ wb->subline = malloc(2048);
+
+ if (!wb->subline)
+ {
+ return -1;
+ }
+ }
+
+ wb->new_sentence = 1;
+ wb->new_channel = 1;
+ wb->in_xds_mode = 0;
+ return 0;
+}
+
+/*
+ * Free up CC memory - don't call this from HB just yet since it will cause
+ * 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)
+{
+ if( enc_buffer ) {
+ free(enc_buffer);
+ enc_buffer_capacity = 0;
+ enc_buffer_used = 0;
+ }
+ if( wb->subline ) {
+ free(wb->subline);
+ }
+}
+
+
+#include <ctype.h>
+
+void get_char_in_latin_1 (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<0x80) // Regular line-21 character set, mostly ASCII except these exceptions
+ {
+ switch (c)
+ {
+ case 0x2a: // lowercase a, acute accent
+ *buffer=0xc3;
+ *(buffer+1)=0xa1;
+ return 2;
+ case 0x5c: // lowercase e, acute accent
+ *buffer=0xc3;
+ *(buffer+1)=0xa9;
+ return 2;
+ case 0x5e: // lowercase i, acute accent
+ *buffer=0xc3;
+ *(buffer+1)=0xad;
+ return 2;
+ case 0x5f: // lowercase o, acute accent
+ *buffer=0xc3;
+ *(buffer+1)=0xb3;
+ return 2;
+ case 0x60: // lowercase u, acute accent
+ *buffer=0xc3;
+ *(buffer+1)=0xba;
+ return 2;
+ case 0x7b: // lowercase c with cedilla
+ *buffer=0xc3;
+ *(buffer+1)=0xa7;
+ return 2;
+ case 0x7c: // division symbol
+ *buffer=0xc3;
+ *(buffer+1)=0xb7;
+ return 2;
+ case 0x7d: // uppercase N tilde
+ *buffer=0xc3;
+ *(buffer+1)=0x91;
+ return 2;
+ case 0x7e: // lowercase n tilde
+ *buffer=0xc3;
+ *(buffer+1)=0xb1;
+ return 2;
+ default:
+ *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
+ case 0x80: // Registered symbol (R)
+ *buffer=0xc2;
+ *(buffer+1)=0xae;
+ return 2;
+ case 0x81: // degree sign
+ *buffer=0xc2;
+ *(buffer+1)=0xb0;
+ return 2;
+ case 0x82: // 1/2 symbol
+ *buffer=0xc2;
+ *(buffer+1)=0xbd;
+ return 2;
+ case 0x83: // Inverted (open) question mark
+ *buffer=0xc2;
+ *(buffer+1)=0xbf;
+ return 2;
+ case 0x84: // Trademark symbol (TM)
+ *buffer=0xe2;
+ *(buffer+1)=0x84;
+ *(buffer+2)=0xa2;
+ return 3;
+ case 0x85: // Cents symbol
+ *buffer=0xc2;
+ *(buffer+1)=0xa2;
+ return 2;
+ case 0x86: // Pounds sterling
+ *buffer=0xc2;
+ *(buffer+1)=0xa3;
+ return 2;
+ case 0x87: // Music note
+ *buffer=0xe2;
+ *(buffer+1)=0x99;
+ *(buffer+2)=0xaa;
+ return 3;
+ case 0x88: // lowercase a, grave accent
+ *buffer=0xc3;
+ *(buffer+1)=0xa0;
+ return 2;
+ case 0x89: // transparent space, we make it regular
+ *buffer=0x20;
+ return 1;
+ case 0x8a: // lowercase e, grave accent
+ *buffer=0xc3;
+ *(buffer+1)=0xa8;
+ return 2;
+ case 0x8b: // lowercase a, circumflex accent
+ *buffer=0xc3;
+ *(buffer+1)=0xa2;
+ return 2;
+ case 0x8c: // lowercase e, circumflex accent
+ *buffer=0xc3;
+ *(buffer+1)=0xaa;
+ return 2;
+ case 0x8d: // lowercase i, circumflex accent
+ *buffer=0xc3;
+ *(buffer+1)=0xae;
+ return 2;
+ case 0x8e: // lowercase o, circumflex accent
+ *buffer=0xc3;
+ *(buffer+1)=0xb4;
+ return 2;
+ case 0x8f: // lowercase u, circumflex accent
+ *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
+ case 0x90: // capital letter A with acute
+ *buffer=0xc3;
+ *(buffer+1)=0x81;
+ return 2;
+ case 0x91: // capital letter E with acute
+ *buffer=0xc3;
+ *(buffer+1)=0x89;
+ return 2;
+ case 0x92: // capital letter O with acute
+ *buffer=0xc3;
+ *(buffer+1)=0x93;
+ return 2;
+ case 0x93: // capital letter U with acute
+ *buffer=0xc3;
+ *(buffer+1)=0x9a;
+ return 2;
+ case 0x94: // capital letter U with diaresis
+ *buffer=0xc3;
+ *(buffer+1)=0x9c;
+ return 2;
+ case 0x95: // lowercase letter U with diaeresis
+ *buffer=0xc3;
+ *(buffer+1)=0xbc;
+ return 2;
+ case 0x96: // apostrophe
+ *buffer=0x27;
+ return 1;
+ case 0x97: // inverted exclamation mark
+ *buffer=0xc1;
+ *(buffer+1)=0xa1;
+ return 2;
+ case 0x98: // asterisk
+ *buffer=0x2a;
+ return 1;
+ case 0x99: // apostrophe (yes, duped). See CCADI source code.
+ *buffer=0x27;
+ return 1;
+ case 0x9a: // hyphen-minus
+ *buffer=0x2d;
+ return 1;
+ case 0x9b: // copyright sign
+ *buffer=0xc2;
+ *(buffer+1)=0xa9;
+ return 2;
+ case 0x9c: // Service mark
+ *buffer=0xe2;
+ *(buffer+1)=0x84;
+ *(buffer+2)=0xa0;
+ return 3;
+ case 0x9d: // Full stop (.)
+ *buffer=0x2e;
+ return 1;
+ case 0x9e: // Quoatation mark
+ *buffer=0x22;
+ return 1;
+ case 0x9f: // Quoatation mark
+ *buffer=0x22;
+ return 1;
+ case 0xa0: // uppercase A, grave accent
+ *buffer=0xc3;
+ *(buffer+1)=0x80;
+ return 2;
+ case 0xa1: // uppercase A, circumflex
+ *buffer=0xc3;
+ *(buffer+1)=0x82;
+ return 2;
+ case 0xa2: // uppercase C with cedilla
+ *buffer=0xc3;
+ *(buffer+1)=0x87;
+ return 2;
+ case 0xa3: // uppercase E, grave accent
+ *buffer=0xc3;
+ *(buffer+1)=0x88;
+ return 2;
+ case 0xa4: // uppercase E, circumflex
+ *buffer=0xc3;
+ *(buffer+1)=0x8a;
+ return 2;
+ case 0xa5: // capital letter E with diaresis
+ *buffer=0xc3;
+ *(buffer+1)=0x8b;
+ return 2;
+ case 0xa6: // lowercase letter e with diaresis
+ *buffer=0xc3;
+ *(buffer+1)=0xab;
+ return 2;
+ case 0xa7: // uppercase I, circumflex
+ *buffer=0xc3;
+ *(buffer+1)=0x8e;
+ return 2;
+ case 0xa8: // uppercase I, with diaresis
+ *buffer=0xc3;
+ *(buffer+1)=0x8f;
+ return 2;
+ case 0xa9: // lowercase i, with diaresis
+ *buffer=0xc3;
+ *(buffer+1)=0xaf;
+ return 2;
+ case 0xaa: // uppercase O, circumflex
+ *buffer=0xc3;
+ *(buffer+1)=0x94;
+ return 2;
+ case 0xab: // uppercase U, grave accent
+ *buffer=0xc3;
+ *(buffer+1)=0x99;
+ return 2;
+ case 0xac: // lowercase u, grave accent
+ *buffer=0xc3;
+ *(buffer+1)=0xb9;
+ return 2;
+ case 0xad: // uppercase U, circumflex
+ *buffer=0xc3;
+ *(buffer+1)=0x9b;
+ return 2;
+ case 0xae: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ *buffer=0xc2;
+ *(buffer+1)=0xab;
+ return 2;
+ case 0xaf: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ *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
+ case 0xb0: // Uppercase A, tilde
+ *buffer=0xc3;
+ *(buffer+1)=0x83;
+ return 2;
+ case 0xb1: // Lowercase a, tilde
+ *buffer=0xc3;
+ *(buffer+1)=0xa3;
+ return 2;
+ case 0xb2: // Uppercase I, acute accent
+ *buffer=0xc3;
+ *(buffer+1)=0x8d;
+ return 2;
+ case 0xb3: // Uppercase I, grave accent
+ *buffer=0xc3;
+ *(buffer+1)=0x8c;
+ return 2;
+ case 0xb4: // Lowercase i, grave accent
+ *buffer=0xc3;
+ *(buffer+1)=0xac;
+ return 2;
+ case 0xb5: // Uppercase O, grave accent
+ *buffer=0xc3;
+ *(buffer+1)=0x92;
+ return 2;
+ case 0xb6: // Lowercase o, grave accent
+ *buffer=0xc3;
+ *(buffer+1)=0xb2;
+ return 2;
+ case 0xb7: // Uppercase O, tilde
+ *buffer=0xc3;
+ *(buffer+1)=0x95;
+ return 2;
+ case 0xb8: // Lowercase o, tilde
+ *buffer=0xc3;
+ *(buffer+1)=0xb5;
+ return 2;
+ case 0xb9: // Open curly brace
+ *buffer=0x7b;
+ return 1;
+ case 0xba: // Closing curly brace
+ *buffer=0x7d;
+ return 1;
+ case 0xbb: // Backslash
+ *buffer=0x5c;
+ return 1;
+ case 0xbc: // Caret
+ *buffer=0x5e;
+ return 1;
+ case 0xbd: // Underscore
+ *buffer=0x5f;
+ return 1;
+ case 0xbe: // Pipe (broken bar)
+ *buffer=0xc2;
+ *(buffer+1)=0xa6;
+ return 1;
+ case 0xbf: // Tilde
+ *buffer=0x7e; // Not sure
+ return 1;
+ case 0xc0: // Uppercase A, umlaut
+ *buffer=0xc3;
+ *(buffer+1)=0x84;
+ return 2;
+ case 0xc1: // Lowercase A, umlaut
+ *buffer=0xc3;
+ *(buffer+1)=0xa4;
+ return 2;
+ case 0xc2: // Uppercase O, umlaut
+ *buffer=0xc3;
+ *(buffer+1)=0x96;
+ return 2;
+ case 0xc3: // Lowercase o, umlaut
+ *buffer=0xc3;
+ *(buffer+1)=0xb6;
+ return 2;
+ case 0xc4: // Esszett (sharp S)
+ *buffer=0xc3;
+ *(buffer+1)=0x9f;
+ return 2;
+ case 0xc5: // Yen symbol
+ *buffer=0xc2;
+ *(buffer+1)=0xa5;
+ return 2;
+ case 0xc6: // Currency symbol
+ *buffer=0xc2;
+ *(buffer+1)=0xa4;
+ return 2;
+ case 0xc7: // Vertical bar
+ *buffer=0x7c;
+ return 1;
+ case 0xc8: // Uppercase A, ring
+ *buffer=0xc3;
+ *(buffer+1)=0x85;
+ return 2;
+ case 0xc9: // Lowercase A, ring
+ *buffer=0xc3;
+ *(buffer+1)=0xa5;
+ return 2;
+ case 0xca: // Uppercase O, slash
+ *buffer=0xc3;
+ *(buffer+1)=0x98;
+ return 2;
+ case 0xcb: // Lowercase o, slash
+ *buffer=0xc3;
+ *(buffer+1)=0xb8;
+ return 2;
+ case 0xcc: // Upper left corner
+ *buffer=0xe2;
+ *(buffer+1)=0x8c;
+ *(buffer+2)=0x9c;
+ return 3;
+ case 0xcd: // Upper right corner
+ *buffer=0xe2;
+ *(buffer+1)=0x8c;
+ *(buffer+2)=0x9d;
+ return 3;
+ case 0xce: // Lower left corner
+ *buffer=0xe2;
+ *(buffer+1)=0x8c;
+ *(buffer+2)=0x9e;
+ return 3;
+ case 0xcf: // Lower right corner
+ *buffer=0xe2;
+ *(buffer+1)=0x8c;
+ *(buffer+2)=0x9f;
+ return 3;
+ default: //
+ *buffer='?'; // I'll do it eventually, I promise
+ return 1; // This are weird chars anyway
+ }
+}
+
+unsigned char cctolower (unsigned char c)
+{
+ 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;
+ 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++;
+ }
+ 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)
+{
+ int i;
+
+ for (i=0;i<CC608_SCREEN_WIDTH;i++)
+ {
+ switch (data->characters[line_num][i])
+ {
+ 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;
+ }
+ }
+}
+
+void find_limit_characters (unsigned char *line, int *first_non_blank, int *last_non_blank)
+{
+ 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);
+
+ if (first_non_blank==-1)
+ {
+ *buffer=0;
+ return 0;
+ }
+
+ int bytes=0;
+ for (i=first_non_blank;i<=last_non_blank;i++)
+ {
+ char c=line[i];
+ switch (encoding)
+ {
+ 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;
+ }
+ buffer+=bytes;
+ }
+ *buffer=0;
+ return (unsigned) (buffer-orig); // Return length
+}
+
+unsigned get_decoder_line_encoded_for_gui (unsigned char *buffer, int line_num, struct eia608_screen *data)
+{
+ unsigned char *line = data->characters[line_num];
+ unsigned char *orig=buffer; // Keep for debugging
+ int first=0, last=31;
+ int i;
+
+ find_limit_characters(line,&first,&last);
+ for (i=first;i<=last;i++)
+ {
+ get_char_in_latin_1 (buffer,line[i]);
+ buffer++;
+ }
+ *buffer=0;
+ return (unsigned) (buffer-orig); // Return length
+
+}
+
+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;
+
+ 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
+ {
+ buffer+= encode_line (buffer,(unsigned char *) "</font>");
+ }
+ // Add new font tag
+ buffer+=encode_line (buffer, (unsigned char*) color_text[its_col][1]);
+ if (its_col==COL_USERDEFINED)
+ {
+ // 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*) "\">");
+ }
+
+ 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;
+ }
+ 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>");
+ }
+ *buffer=0;
+ return (unsigned) (buffer-orig); // Return length
+}
+
+
+void delete_all_lines_but_current (struct eia608_screen *data, int row)
+{
+ int i;
+ for (i=0;i<15;i++)
+ {
+ if (i!=row)
+ {
+ memset(data->characters[i],' ',CC608_SCREEN_WIDTH);
+ data->characters[i][CC608_SCREEN_WIDTH]=0;
+ memset (data->colors[i],default_color,CC608_SCREEN_WIDTH+1);
+ memset (data->fonts[i],FONT_REGULAR,CC608_SCREEN_WIDTH+1);
+ data->row_used[i]=0;
+ }
+ }
+}
+
+void clear_eia608_cc_buffer (struct eia608_screen *data)
+{
+ int i;
+
+ for (i=0;i<15;i++)
+ {
+ memset(data->characters[i],' ',CC608_SCREEN_WIDTH);
+ data->characters[i][CC608_SCREEN_WIDTH]=0;
+ memset (data->colors[i],default_color,CC608_SCREEN_WIDTH+1);
+ memset (data->fonts[i],FONT_REGULAR,CC608_SCREEN_WIDTH+1);
+ data->row_used[i]=0;
+ }
+ data->empty=1;
+}
+
+void init_eia608 (struct eia608 *data)
+{
+ 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;
+}
+
+struct eia608_screen *get_writing_buffer (struct s_write *wb)
+{
+ struct eia608_screen *use_buffer=NULL;
+ switch (wb->data608->mode)
+ {
+ case MODE_POPUP: // Write on the non-visible buffer
+ if (wb->data608->visible_buffer==1)
+ use_buffer = &wb->data608->buffer2;
+ else
+ use_buffer = &wb->data608->buffer1;
+ break;
+ case MODE_ROLLUP_2: // Write directly to screen
+ case MODE_ROLLUP_3:
+ case MODE_ROLLUP_4:
+ if (wb->data608->visible_buffer==1)
+ use_buffer = &wb->data608->buffer1;
+ else
+ use_buffer = &wb->data608->buffer2;
+ break;
+ default:
+ fatal (EXIT_BUG_BUG, "Caption mode has an illegal value at get_writing_buffer(), this is a bug.\n");
+ }
+ return use_buffer;
+}
+
+void write_char (const unsigned char c, struct s_write *wb)
+{
+ if (wb->data608->mode!=MODE_TEXT)
+ {
+ 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)
+ wb->data608->cursor_column++;
+ }
+
+}
+
+/* Handle MID-ROW CODES. */
+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;
+ if (wb->data608->channel!=cc_channel)
+ return;
+ if (debug_608)
+ hb_log ("\r608: text_attr: %02X %02X",c1,c2);
+ if ( ((c1!=0x11 && c1!=0x19) ||
+ (c2<0x20 || c2>0x2f)) && debug_608)
+ {
+ hb_log ("\rThis is not a text attribute!\n");
+ }
+ else
+ {
+ int i = c2-0x20;
+ 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]);
+ if (wb->data608->cursor_column<31)
+ wb->data608->cursor_column++;
+ }
+}
+
+void mstotime (LLONG milli, unsigned *hours, unsigned *minutes,
+ unsigned *seconds, unsigned *ms)
+{
+ // LLONG milli = (LLONG) ((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 write_subtitle_file_footer (struct s_write *wb)
+{
+ switch (write_format)
+ {
+ case OF_SAMI:
+ sprintf ((char *) str,"</BODY></SAMI>\n");
+ if (debug_608 && encoding!=ENC_UNICODE)
+ {
+ hb_log ("\r%s\n", str);
+ }
+ enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
+ //fwrite (enc_buffer,enc_buffer_used,1,wb->fh);
+ XMLRPC_APPEND(enc_buffer,enc_buffer_used);
+ break;
+ default: // Nothing to do. Only SAMI has a footer
+ break;
+ }
+}
+
+void fhb_log_encoded (FILE *fh, const char *string)
+{
+ GUARANTEE(strlen (string)*3);
+ enc_buffer_used=encode_line (enc_buffer,(unsigned char *) string);
+ fwrite (enc_buffer,enc_buffer_used,1,fh);
+}
+
+void write_subtitle_file_header (struct s_write *wb)
+{
+ switch (write_format)
+ {
+ case OF_SRT: // Subrip subtitles have no header
+ break;
+ case OF_SAMI: // This header brought to you by McPoodle's CCASDI
+ //fhb_log_encoded (wb->fh, sami_header);
+ GUARANTEE(strlen (sami_header)*3);
+ enc_buffer_used=encode_line (enc_buffer,(unsigned char *) sami_header);
+ //fwrite (enc_buffer,enc_buffer_used,1,wb->fh);
+ XMLRPC_APPEND(enc_buffer,enc_buffer_used);
+ break;
+ case OF_RCWT: // Write header
+ //fwrite (rcwt_header, sizeof(rcwt_header),1,wb->fh);
+ break;
+ case OF_TRANSCRIPT: // No header. Fall thru
+ default:
+ break;
+ }
+}
+
+void write_cc_line_as_transcript (struct eia608_screen *data, struct s_write *wb, int line_number)
+{
+ hb_buffer_t *buffer;
+
+ if (sentence_cap)
+ {
+ capitalize(line_number,data, &wb->new_sentence);
+ correct_case(line_number,data);
+ }
+ int length = get_decoder_line_basic (wb->subline, line_number, data);
+ if (debug_608 && encoding!=ENC_UNICODE)
+ {
+ hb_log ("\r");
+ hb_log ("%s\n",wb->subline);
+ }
+ if (length>0)
+ {
+ //fwrite (wb->subline, 1, length, wb->fh);
+ /*
+ * Put this subtitle in a hb_buffer_t and shove it into the subtitle fifo
+ */
+ buffer = hb_buffer_init( strlen( wb->subline ) + 1 );
+ buffer->start = wb->last_pts;
+ buffer->stop = wb->last_pts+1;
+ strcpy( buffer->data, wb->subline );
+ //hb_log("CC %lld: %s", buffer->stop, wb->subline);
+
+ hb_fifo_push( wb->subtitle->fifo_raw, buffer );
+
+ XMLRPC_APPEND(wb->subline,length);
+ //fwrite (encoded_crlf, 1, encoded_crlf_length,wb->fh);
+ XMLRPC_APPEND(encoded_crlf,encoded_crlf_length);
+ }
+ // fhb_log (wb->fh,encoded_crlf);
+}
+
+int write_cc_buffer_as_transcript (struct eia608_screen *data, struct s_write *wb)
+{
+ int i;
+
+ int wrote_something = 0;
+ if (debug_608)
+ {
+ hb_log ("\n- - - TRANSCRIPT caption - - -\n");
+ }
+ for (i=0;i<15;i++)
+ {
+ if (data->row_used[i])
+ {
+ write_cc_line_as_transcript (data,wb, i);
+ }
+ wrote_something=1;
+ }
+ if (debug_608)
+ {
+ hb_log ("- - - - - - - - - - - -\r\n");
+ }
+ return wrote_something;
+}
+
+void write_cc_buffer_to_gui (struct eia608_screen *data, struct s_write *wb)
+{
+ unsigned h1,m1,s1,ms1;
+ unsigned h2,m2,s2,ms2;
+ int i;
+
+ LLONG ms_start= wb->data608->current_visible_start_ms;
+
+ ms_start+=subs_delay;
+ if (ms_start<0) // Drop screens that because of subs_delay start too early
+ return;
+ int time_reported=0;
+ for (i=0;i<15;i++)
+ {
+ if (data->row_used[i])
+ {
+ hb_log ("###SUBTITLE#");
+ if (!time_reported)
+ {
+ LLONG ms_end = get_fts()+subs_delay;
+ mstotime (ms_start,&h1,&m1,&s1,&ms1);
+ mstotime (ms_end-1,&h2,&m2,&s2,&ms2); // -1 To prevent overlapping with next line.
+ // Note, only MM:SS here as we need to save space in the preview window
+ hb_log ("%02u:%02u#%02u:%02u#",
+ h1*60+m1,s1, h2*60+m2,s2);
+ time_reported=1;
+ }
+ else
+ hb_log ("##");
+
+ // We don't capitalize here because whatever function that was used
+ // before to write to file already took care of it.
+ int length = get_decoder_line_encoded_for_gui (wb->subline, i, data);
+ fwrite (wb->subline, 1, length, stderr);
+ fwrite ("\n",1,1,stderr);
+ }
+ }
+ fflush (stderr);
+}
+
+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;
+ LLONG ms_start= wb->data608->current_visible_start_ms;
+ int i;
+
+ ms_start+=subs_delay;
+ if (ms_start<0) // Drop screens that because of subs_delay start too early
+ return 0;
+
+ LLONG ms_end = get_fts()+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);
+ enc_buffer_used=encode_line (enc_buffer,(unsigned char *) timeline);
+ fwrite (enc_buffer,enc_buffer_used,1,wb->fh);
+ XMLRPC_APPEND(enc_buffer,enc_buffer_used);
+ sprintf (timeline, "%02u:%02u:%02u,%03u --> %02u:%02u:%02u,%03u\r\n",
+ h1,m1,s1,ms1, h2,m2,s2,ms2);
+ enc_buffer_used=encode_line (enc_buffer,(unsigned char *) timeline);
+ if (debug_608)
+ {
+ hb_log ("\n- - - SRT caption - - -\n");
+ hb_log (timeline);
+ }
+ fwrite (enc_buffer,enc_buffer_used,1,wb->fh);
+ XMLRPC_APPEND(enc_buffer,enc_buffer_used);
+ for (i=0;i<15;i++)
+ {
+ if (data->row_used[i])
+ {
+ if (sentence_cap)
+ {
+ capitalize(i,data, &wb->new_sentence);
+ correct_case(i,data);
+ }
+ int length = get_decoder_line_encoded (wb->subline, i, data);
+ if (debug_608 && encoding!=ENC_UNICODE)
+ {
+ hb_log ("\r");
+ hb_log ("%s\n",wb->subline);
+ }
+ fwrite (wb->subline, 1, length, wb->fh);
+ XMLRPC_APPEND(wb->subline,length);
+ fwrite (encoded_crlf, 1, encoded_crlf_length,wb->fh);
+ XMLRPC_APPEND(encoded_crlf,encoded_crlf_length);
+ wrote_something=1;
+ // fhb_log (wb->fh,encoded_crlf);
+ }
+ }
+ if (debug_608)
+ {
+ hb_log ("- - - - - - - - - - - -\r\n");
+ }
+ // fhb_log (wb->fh, encoded_crlf);
+ fwrite (encoded_crlf, 1, encoded_crlf_length,wb->fh);
+ XMLRPC_APPEND(encoded_crlf,encoded_crlf_length);
+ return wrote_something;
+}
+
+int write_cc_buffer_as_sami (struct eia608_screen *data, struct s_write *wb)
+{
+ int wrote_something=0;
+ LLONG startms = wb->data608->current_visible_start_ms;
+ int i;
+
+ startms+=subs_delay;
+ if (startms<0) // Drop screens that because of subs_delay start too early
+ return 0;
+
+ LLONG endms = get_fts()+subs_delay;
+ endms--; // To prevent overlapping with next line.
+ sprintf ((char *) str,"<SYNC start=\"%llu\"><P class=\"UNKNOWNCC\">\r\n",startms);
+ if (debug_608 && encoding!=ENC_UNICODE)
+ {
+ hb_log ("\r%s\n", str);
+ }
+ enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
+ fwrite (enc_buffer,enc_buffer_used,1,wb->fh);
+ XMLRPC_APPEND(enc_buffer,enc_buffer_used);
+ for (i=0;i<15;i++)
+ {
+ if (data->row_used[i])
+ {
+ int length = get_decoder_line_encoded (wb->subline, i, data);
+ if (debug_608 && encoding!=ENC_UNICODE)
+ {
+ hb_log ("\r");
+ hb_log ("%s\n",wb->subline);
+ }
+ fwrite (wb->subline, 1, length, wb->fh);
+ XMLRPC_APPEND(wb->subline,length);
+ wrote_something=1;
+ if (i!=14)
+ {
+ fwrite (encoded_br, 1, encoded_br_length,wb->fh);
+ XMLRPC_APPEND(encoded_br, encoded_br_length);
+ }
+ fwrite (encoded_crlf, 1, encoded_crlf_length,wb->fh);
+ XMLRPC_APPEND(encoded_crlf, encoded_crlf_length);
+ }
+ }
+ sprintf ((char *) str,"</P></SYNC>\r\n");
+ if (debug_608 && encoding!=ENC_UNICODE)
+ {
+ hb_log ("\r%s\n", str);
+ }
+ enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
+ fwrite (enc_buffer,enc_buffer_used,1,wb->fh);
+ XMLRPC_APPEND(enc_buffer,enc_buffer_used);
+ sprintf ((char *) str,"<SYNC start=\"%llu\"><P class=\"UNKNOWNCC\">&nbsp;</P></SYNC>\r\n\r\n",endms);
+ if (debug_608 && encoding!=ENC_UNICODE)
+ {
+ hb_log ("\r%s\n", str);
+ }
+ enc_buffer_used=encode_line (enc_buffer,(unsigned char *) str);
+ fwrite (enc_buffer,enc_buffer_used,1,wb->fh);
+ XMLRPC_APPEND(enc_buffer,enc_buffer_used);
+ return wrote_something;
+}
+
+struct eia608_screen *get_current_visible_buffer (struct s_write *wb)
+{
+ struct eia608_screen *data;
+ if (wb->data608->visible_buffer==1)
+ data = &wb->data608->buffer1;
+ else
+ data = &wb->data608->buffer2;
+ return data;
+}
+
+
+int write_cc_buffer (struct s_write *wb)
+{
+ struct eia608_screen *data;
+ int wrote_something=0;
+ if (screens_to_process!=-1 && wb->data608->screenfuls_counter>=screens_to_process)
+ {
+ // We are done.
+ processed_enough=1;
+ return 0;
+ }
+ if (wb->data608->visible_buffer==1)
+ data = &wb->data608->buffer1;
+ else
+ data = &wb->data608->buffer2;
+
+ if (!data->empty)
+ {
+ wb->new_sentence=1;
+ switch (write_format)
+ {
+ case OF_SRT:
+ wrote_something = write_cc_buffer_as_srt (data, wb);
+ break;
+ case OF_SAMI:
+ wrote_something = write_cc_buffer_as_sami (data,wb);
+ break;
+ case OF_TRANSCRIPT:
+ wrote_something = write_cc_buffer_as_transcript (data,wb);
+ break;
+ default:
+ break;
+ }
+ if (wrote_something && gui_mode_reports)
+ write_cc_buffer_to_gui (data,wb);
+ }
+ return wrote_something;
+}
+
+void roll_up(struct s_write *wb)
+{
+ struct eia608_screen *use_buffer;
+ int i, j;
+
+ if (wb->data608->visible_buffer==1)
+ use_buffer = &wb->data608->buffer1;
+ else
+ use_buffer = &wb->data608->buffer2;
+ int keep_lines;
+ switch (wb->data608->mode)
+ {
+ case MODE_ROLLUP_2:
+ keep_lines=2;
+ break;
+ case MODE_ROLLUP_3:
+ keep_lines=3;
+ break;
+ case MODE_ROLLUP_4:
+ keep_lines=4;
+ break;
+ default: // Shouldn't happen
+ keep_lines=0;
+ break;
+ }
+ 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++)
+ {
+ if (use_buffer->row_used[i])
+ {
+ rows_now++;
+ if (firstrow==-1)
+ firstrow=i;
+ lastrow=i;
+ }
+ }
+
+ if (debug_608)
+ hb_log ("\rIn roll-up: %d lines used, first: %d, last: %d\n", rows_now, firstrow, lastrow);
+
+ if (lastrow==-1) // Empty screen, nothing to rollup
+ return;
+
+ for (j=lastrow-keep_lines+1;j<lastrow; j++)
+ {
+ 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];
+ }
+ }
+ 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[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;
+
+ // Sanity check
+ rows_now=0;
+ for (i=0;i<15;i++)
+ if (use_buffer->row_used[i])
+ rows_now++;
+ if (rows_now>keep_lines)
+ hb_log ("Bug in roll_up, should have %d lines but I have %d.\n",
+ keep_lines, rows_now);
+}
+
+void erase_memory (struct s_write *wb, int displayed)
+{
+ struct eia608_screen *buf;
+ if (displayed)
+ {
+ if (wb->data608->visible_buffer==1)
+ buf=&wb->data608->buffer1;
+ else
+ buf=&wb->data608->buffer2;
+ }
+ else
+ {
+ if (wb->data608->visible_buffer==1)
+ buf=&wb->data608->buffer2;
+ else
+ buf=&wb->data608->buffer1;
+ }
+ clear_eia608_cc_buffer (buf);
+}
+
+int is_current_row_empty (struct s_write *wb)
+{
+ struct eia608_screen *use_buffer;
+ int i;
+
+ if (wb->data608->visible_buffer==1)
+ use_buffer = &wb->data608->buffer1;
+ else
+ use_buffer = &wb->data608->buffer2;
+ for (i=0;i<CC608_SCREEN_WIDTH;i++)
+ {
+ if (use_buffer->characters[wb->data608->rollup_base_row][i]!=' ')
+ return 0;
+ }
+ return 1;
+}
+
+/* Process GLOBAL CODES */
+void handle_command (/*const */ unsigned char c1, const unsigned char c2, struct s_write *wb)
+{
+ // Handle channel change
+ wb->data608->channel=wb->new_channel;
+ if (wb->data608->channel!=cc_channel)
+ return;
+
+ enum command_code command = COM_UNKNOWN;
+ if (c1==0x15)
+ c1=0x14;
+ if ((c1==0x14 || c1==0x1C) && c2==0x2C)
+ command = COM_ERASEDISPLAYEDMEMORY;
+ if ((c1==0x14 || c1==0x1C) && c2==0x20)
+ command = COM_RESUMECAPTIONLOADING;
+ if ((c1==0x14 || c1==0x1C) && c2==0x2F)
+ command = COM_ENDOFCAPTION;
+ if ((c1==0x17 || c1==0x1F) && c2==0x21)
+ command = COM_TABOFFSET1;
+ if ((c1==0x17 || c1==0x1F) && c2==0x22)
+ command = COM_TABOFFSET2;
+ if ((c1==0x17 || c1==0x1F) && c2==0x23)
+ command = COM_TABOFFSET3;
+ if ((c1==0x14 || c1==0x1C) && c2==0x25)
+ command = COM_ROLLUP2;
+ if ((c1==0x14 || c1==0x1C) && c2==0x26)
+ command = COM_ROLLUP3;
+ if ((c1==0x14 || c1==0x1C) && c2==0x27)
+ command = COM_ROLLUP4;
+ if ((c1==0x14 || c1==0x1C) && c2==0x2D)
+ command = COM_CARRIAGERETURN;
+ if ((c1==0x14 || c1==0x1C) && c2==0x2E)
+ command = COM_ERASENONDISPLAYEDMEMORY;
+ if ((c1==0x14 || c1==0x1C) && c2==0x21)
+ command = COM_BACKSPACE;
+ if ((c1==0x14 || c1==0x1C) && c2==0x2b)
+ command = COM_RESUMETEXTDISPLAY;
+ if (debug_608)
+ {
+ hb_log ("\rCommand: %02X %02X (%s)\n",c1,c2,command_type[command]);
+ }
+ switch (command)
+ {
+ case COM_BACKSPACE:
+ if (wb->data608->cursor_column>0)
+ {
+ wb->data608->cursor_column--;
+ get_writing_buffer(wb)->characters[wb->data608->cursor_row][wb->data608->cursor_column]=' ';
+ }
+ break;
+ case COM_TABOFFSET1:
+ if (wb->data608->cursor_column<31)
+ wb->data608->cursor_column++;
+ break;
+ case COM_TABOFFSET2:
+ wb->data608->cursor_column+=2;
+ if (wb->data608->cursor_column>31)
+ wb->data608->cursor_column=31;
+ break;
+ case COM_TABOFFSET3:
+ wb->data608->cursor_column+=3;
+ if (wb->data608->cursor_column>31)
+ wb->data608->cursor_column=31;
+ break;
+ case COM_RESUMECAPTIONLOADING:
+ wb->data608->mode=MODE_POPUP;
+ break;
+ case COM_RESUMETEXTDISPLAY:
+ wb->data608->mode=MODE_TEXT;
+ break;
+ case COM_ROLLUP2:
+ if (wb->data608->mode==MODE_POPUP)
+ {
+ if (write_cc_buffer (wb))
+ wb->data608->screenfuls_counter++;
+ erase_memory (wb, 1);
+ }
+ if (wb->data608->mode==MODE_ROLLUP_2 && !is_current_row_empty(wb))
+ {
+ if (debug_608)
+ hb_log ("Two RU2, current line not empty. Simulating a CR\n");
+ handle_command(0x14, 0x2D, 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;
+ break;
+ case COM_ROLLUP3:
+ if (wb->data608->mode==MODE_POPUP)
+ {
+ if (write_cc_buffer (wb))
+ wb->data608->screenfuls_counter++;
+ erase_memory (wb, 1);
+ }
+ if (wb->data608->mode==MODE_ROLLUP_3 && !is_current_row_empty(wb))
+ {
+ if (debug_608)
+ hb_log ("Two RU3, current line not empty. Simulating a CR\n");
+ handle_command(0x14, 0x2D, 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;
+ break;
+ case COM_ROLLUP4:
+ if (wb->data608->mode==MODE_POPUP)
+ {
+ if (write_cc_buffer (wb))
+ wb->data608->screenfuls_counter++;
+ erase_memory (wb, 1);
+ }
+ if (wb->data608->mode==MODE_ROLLUP_4 && !is_current_row_empty(wb))
+ {
+ if (debug_608)
+ hb_log ("Two RU4, current line not empty. Simulating a CR\n");
+ handle_command(0x14, 0x2D, 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:
+ // In transcript mode, CR doesn't write the whole screen, to avoid
+ // repeated lines.
+ if (write_format==OF_TRANSCRIPT)
+ {
+ write_cc_line_as_transcript(get_current_visible_buffer (wb), wb, wb->data608->cursor_row);
+ }
+ else
+ {
+ 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->current_visible_start_ms=get_fts();
+ wb->data608->cursor_column=0;
+ break;
+ case COM_ERASENONDISPLAYEDMEMORY:
+ erase_memory (wb,0);
+ break;
+ case COM_ERASEDISPLAYEDMEMORY:
+ // Write it to disk before doing this, and make a note of the new
+ // time it became clear.
+ if (write_format==OF_TRANSCRIPT &&
+ (wb->data608->mode==MODE_ROLLUP_2 || wb->data608->mode==MODE_ROLLUP_3 ||
+ wb->data608->mode==MODE_ROLLUP_4))
+ {
+ // In transcript mode we just write the cursor line. The previous lines
+ // should have been written already, so writing everything produces
+ // duplicate lines.
+ write_cc_line_as_transcript(get_current_visible_buffer (wb), wb, wb->data608->cursor_row);
+ }
+ else
+ {
+ if (write_cc_buffer (wb))
+ wb->data608->screenfuls_counter++;
+ }
+ erase_memory (wb,1);
+ wb->data608->current_visible_start_ms=get_fts();
+ break;
+ case COM_ENDOFCAPTION: // Switch buffers
+ // The currently *visible* buffer is leaving, so now we know it's ending
+ // time. Time to actually write it to file.
+ if (write_cc_buffer (wb))
+ wb->data608->screenfuls_counter++;
+ wb->data608->visible_buffer = (wb->data608->visible_buffer==1) ? 2 : 1;
+ wb->data608->current_visible_start_ms=get_fts();
+ wb->data608->cursor_column=0;
+ wb->data608->cursor_row=0;
+ wb->data608->color=default_color;
+ wb->data608->font=FONT_REGULAR;
+ break;
+ default:
+ if (debug_608)
+ {
+ hb_log ("\rNot yet implemented.\n");
+ }
+ break;
+ }
+}
+
+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)
+{
+ unsigned char c;
+ if (wb->data608->channel!=cc_channel)
+ return;
+ if (c2>=0x30 && c2<=0x3f)
+ {
+ c=c2 + 0x50; // So if c>=0x80 && c<=0x8f, it comes from here
+ if (debug_608)
+ hb_log ("\rDouble: %02X %02X --> %c\n",c1,c2,c);
+ write_char(c,wb);
+ }
+}
+
+/* Process EXTENDED CHARACTERS */
+unsigned char handle_extended (unsigned char hi, unsigned char lo, struct s_write *wb)
+{
+ // Handle channel change
+ if (wb->new_channel > 2)
+ {
+ wb->new_channel -= 2;
+ if (debug_608)
+ hb_log ("\nChannel correction, now %d\n", wb->new_channel);
+ }
+ wb->data608->channel=wb->new_channel;
+ if (wb->data608->channel!=cc_channel)
+ return 0;
+
+ // For lo values between 0x20-0x3f
+ unsigned char c=0;
+
+ if (debug_608)
+ hb_log ("\rExtended: %02X %02X\n",hi,lo);
+ if (lo>=0x20 && lo<=0x3f && (hi==0x12 || hi==0x13))
+ {
+ switch (hi)
+ {
+ case 0x12:
+ c=lo+0x70; // So if c>=0x90 && c<=0xaf it comes from here
+ break;
+ case 0x13:
+ c=lo+0x90; // So if c>=0xb0 && c<=0xcf it comes from here
+ break;
+ }
+ // This column change is because extended characters replace
+ // the previous character (which is sent for basic decoders
+ // to show something similar to the real char)
+ if (wb->data608->cursor_column>0)
+ wb->data608->cursor_column--;
+
+ write_char (c,wb);
+ }
+ return 1;
+}
+
+/* Process PREAMBLE ACCESS CODES (PAC) */
+void handle_pac (unsigned char c1, unsigned char c2, struct s_write *wb)
+{
+ // Handle channel change
+ if (wb->new_channel > 2)
+ {
+ wb->new_channel -= 2;
+ if (debug_608)
+ hb_log ("\nChannel correction, now %d\n", wb->new_channel);
+ }
+ wb->data608->channel=wb->new_channel;
+ if (wb->data608->channel!=cc_channel)
+ return;
+
+ int row=rowdata[((c1<<1)&14)|((c2>>5)&1)];
+
+ if (debug_608)
+ hb_log ("\rPAC: %02X %02X",c1,c2);
+
+ if (c2>=0x40 && c2<=0x5f)
+ {
+ c2=c2-0x40;
+ }
+ else
+ {
+ if (c2>=0x60 && c2<=0x7f)
+ {
+ c2=c2-0x60;
+ }
+ else
+ {
+ if (debug_608)
+ hb_log ("\rThis is not a PAC!!!!!\n");
+ return;
+ }
+ }
+ int color=pac2_attribs[c2][0];
+ int font=pac2_attribs[c2][1];
+ 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)
+ {
+ // 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->rollup_base_row=row-1;
+ wb->data608->cursor_column=indent;
+}
+
+
+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
+ if (debug_608)
+ hb_log ("%c",c1);
+
+ /*if (debug_608)
+ hb_log ("Character: %02X (%c) -> %02X (%c)\n",c1,c1,c,c); */
+ write_char (c1,wb);
+}
+
+int check_channel (unsigned char c1, struct s_write *wb)
+{
+ if (c1==0x14)
+ {
+ if (debug_608 && wb->data608->channel!=1)
+ hb_log ("\nChannel change, now 1\n");
+ return 1;
+ }
+ if (c1==0x1c)
+ {
+ if (debug_608 && wb->data608->channel!=2)
+ hb_log ("\nChannel change, now 2\n");
+ return 2;
+ }
+ if (c1==0x15)
+ {
+ if (debug_608 && wb->data608->channel!=3)
+ hb_log ("\nChannel change, now 3\n");
+ return 3;
+ }
+ if (c1==0x1d)
+ {
+ if (debug_608 && wb->data608->channel!=4)
+ hb_log ("\nChannel change, now 4\n");
+ return 4;
+ }
+
+ // Otherwise keep the current channel
+ return wb->data608->channel;
+}
+
+/* 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)
+{
+ int wrote_to_screen=0;
+
+ /* Full channel changes are only allowed for "GLOBAL CODES",
+ * "OTHER POSITIONING CODES", "BACKGROUND COLOR CODES",
+ * "MID-ROW CODES".
+ * "PREAMBLE ACCESS CODES", "BACKGROUND COLOR CODES" and
+ * SPECIAL/SPECIAL CHARACTERS allow only switching
+ * between 1&3 or 2&4. */
+ wb->new_channel = check_channel (hi,wb);
+ //if (wb->data608->channel!=cc_channel)
+ // continue;
+
+ if (hi>=0x18 && hi<=0x1f)
+ hi=hi-8;
+
+ switch (hi)
+ {
+ case 0x10:
+ if (lo>=0x40 && lo<=0x5f)
+ handle_pac (hi,lo,wb);
+ break;
+ case 0x11:
+ if (lo>=0x20 && lo<=0x2f)
+ handle_text_attr (hi,lo,wb);
+ if (lo>=0x30 && lo<=0x3f)
+ {
+ wrote_to_screen=1;
+ handle_double (hi,lo,wb);
+ }
+ if (lo>=0x40 && lo<=0x7f)
+ handle_pac (hi,lo,wb);
+ break;
+ case 0x12:
+ case 0x13:
+ if (lo>=0x20 && lo<=0x3f)
+ {
+ wrote_to_screen=handle_extended (hi,lo,wb);
+ }
+ if (lo>=0x40 && lo<=0x7f)
+ handle_pac (hi,lo,wb);
+ break;
+ case 0x14:
+ case 0x15:
+ if (lo>=0x20 && lo<=0x2f)
+ handle_command (hi,lo,wb);
+ if (lo>=0x40 && lo<=0x7f)
+ handle_pac (hi,lo,wb);
+ break;
+ case 0x16:
+ if (lo>=0x40 && lo<=0x7f)
+ handle_pac (hi,lo,wb);
+ break;
+ case 0x17:
+ if (lo>=0x21 && lo<=0x22)
+ handle_command (hi,lo,wb);
+ if (lo>=0x2e && lo<=0x2f)
+ handle_text_attr (hi,lo,wb);
+ if (lo>=0x40 && lo<=0x7f)
+ handle_pac (hi,lo,wb);
+ break;
+ }
+ return wrote_to_screen;
+}
+
+void process608 (const unsigned char *data, int length, struct s_write *wb)
+{
+ static int textprinted = 0;
+ int i;
+
+ if (data!=NULL)
+ {
+ for (i=0;i<length;i=i+2)
+ {
+ unsigned char hi, lo;
+ int wrote_to_screen=0;
+ hi = data[i] & 0x7F; // Get rid of parity bit
+ lo = data[i+1] & 0x7F; // Get rid of parity bit
+
+ if (hi==0 && lo==0) // Just padding
+ continue;
+ // hb_log ("\r[%02X:%02X]\n",hi,lo);
+
+ if (hi>=0x01 && hi<=0x0E)
+ {
+ // XDS crap - mode. Would be nice to support it eventually
+ // wb->data608->last_c1=0;
+ // wb->data608->last_c2=0;
+ wb->data608->channel=3; // Always channel 3
+ wb->in_xds_mode=1;
+ }
+ if (hi==0x0F) // End of XDS block
+ {
+ wb->in_xds_mode=0;
+ continue;
+ }
+ if (hi>=0x10 && hi<0x1F) // Non-character code or special/extended char
+ // http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/CC_CODES.HTML
+ // http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/CC_CHARS.HTML
+ {
+ // We were writing characters before, start a new line for
+ // diagnostic output from disCommand()
+ if (debug_608 && textprinted == 1 )
+ {
+ hb_log("\n");
+ textprinted = 0;
+ }
+
+ wb->in_xds_mode=0; // Back to normal
+ if (wb->data608->last_c1==hi && wb->data608->last_c2==lo)
+ {
+ // Duplicate dual code, discard
+ continue;
+ }
+ wb->data608->last_c1=hi;
+ wb->data608->last_c2=lo;
+ wrote_to_screen=disCommand (hi,lo,wb);
+ }
+ if (hi>=0x20) // Standard characters (always in pairs)
+ {
+ // Only print if the channel is active
+ if (wb->data608->channel!=cc_channel)
+ continue;
+
+ if (debug_608)
+ {
+ if( textprinted == 0 )
+ {
+ hb_log("\n");
+ textprinted = 1;
+ }
+ }
+
+ handle_single(hi,wb);
+ handle_single(lo,wb);
+ wrote_to_screen=1;
+ wb->data608->last_c1=0;
+ wb->data608->last_c2=0;
+ }
+
+ 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()));
+ }
+
+ if (wrote_to_screen && direct_rollup && // If direct_rollup is enabled and
+ (wb->data608->mode==MODE_ROLLUP_2 || // we are in rollup mode, write now.
+ wb->data608->mode==MODE_ROLLUP_3 ||
+ wb->data608->mode==MODE_ROLLUP_4))
+ {
+ // We don't increase screenfuls_counter here.
+ write_cc_buffer (wb);
+ wb->data608->current_visible_start_ms=get_fts();
+ }
+ }
+ }
+}
+
+
+/* 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;
+}