3 Copyright (c) 2003-2015 HandBrake Team
4 This file is part of the HandBrake source code
5 Homepage: <http://handbrake.fr/>.
6 It may be used under the terms of the GNU General Public License v2.
7 For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
11 * From ccextractor, leave this file as intact and close to the original as possible so that
12 * it is easy to patch in fixes - even though this file contains code that we don't need.
14 * Note that the SRT sub generation from CC could be useful for mkv subs.
17 #include "deccc608sub.h"
19 #define SSA_PREAMBLE_LEN 24
21 * ccextractor static configuration variables.
23 static int debug_608
= 0;
24 static int cc_channel
= 1;
25 static int subs_delay
= 0;
28 * Get the time of the last buffer that we have received.
30 static int64_t get_last_pts(struct s_write
*wb
)
35 #define fatal(N, ...) // N
37 int rowdata
[] = {11,-1,1,2,3,4,12,13,14,15,5,6,7,8,9,10};
38 // Relationship between the first PAC byte and the row number
40 // The following enc_buffer is not used at the moment, if it does get used
41 // we need to bring it into the swrite struct. Same for "str".
42 #define INITIAL_ENC_BUFFER_CAPACITY 2048
44 static const unsigned char pac2_attribs
[][3]= // Color, font, ident
46 {COL_WHITE
, FONT_REGULAR
, 0}, // 0x40 || 0x60
47 {COL_WHITE
, FONT_UNDERLINED
, 0}, // 0x41 || 0x61
48 {COL_GREEN
, FONT_REGULAR
, 0}, // 0x42 || 0x62
49 {COL_GREEN
, FONT_UNDERLINED
, 0}, // 0x43 || 0x63
50 {COL_BLUE
, FONT_REGULAR
, 0}, // 0x44 || 0x64
51 {COL_BLUE
, FONT_UNDERLINED
, 0}, // 0x45 || 0x65
52 {COL_CYAN
, FONT_REGULAR
, 0}, // 0x46 || 0x66
53 {COL_CYAN
, FONT_UNDERLINED
, 0}, // 0x47 || 0x67
54 {COL_RED
, FONT_REGULAR
, 0}, // 0x48 || 0x68
55 {COL_RED
, FONT_UNDERLINED
, 0}, // 0x49 || 0x69
56 {COL_YELLOW
, FONT_REGULAR
, 0}, // 0x4a || 0x6a
57 {COL_YELLOW
, FONT_UNDERLINED
, 0}, // 0x4b || 0x6b
58 {COL_MAGENTA
, FONT_REGULAR
, 0}, // 0x4c || 0x6c
59 {COL_MAGENTA
, FONT_UNDERLINED
, 0}, // 0x4d || 0x6d
60 {COL_WHITE
, FONT_ITALICS
, 0}, // 0x4e || 0x6e
61 {COL_WHITE
, FONT_UNDERLINED_ITALICS
, 0}, // 0x4f || 0x6f
62 {COL_WHITE
, FONT_REGULAR
, 0}, // 0x50 || 0x70
63 {COL_WHITE
, FONT_UNDERLINED
, 0}, // 0x51 || 0x71
64 {COL_WHITE
, FONT_REGULAR
, 4}, // 0x52 || 0x72
65 {COL_WHITE
, FONT_UNDERLINED
, 4}, // 0x53 || 0x73
66 {COL_WHITE
, FONT_REGULAR
, 8}, // 0x54 || 0x74
67 {COL_WHITE
, FONT_UNDERLINED
, 8}, // 0x55 || 0x75
68 {COL_WHITE
, FONT_REGULAR
, 12}, // 0x56 || 0x76
69 {COL_WHITE
, FONT_UNDERLINED
, 12}, // 0x57 || 0x77
70 {COL_WHITE
, FONT_REGULAR
, 16}, // 0x58 || 0x78
71 {COL_WHITE
, FONT_UNDERLINED
, 16}, // 0x59 || 0x79
72 {COL_WHITE
, FONT_REGULAR
, 20}, // 0x5a || 0x7a
73 {COL_WHITE
, FONT_UNDERLINED
, 20}, // 0x5b || 0x7b
74 {COL_WHITE
, FONT_REGULAR
, 24}, // 0x5c || 0x7c
75 {COL_WHITE
, FONT_UNDERLINED
, 24}, // 0x5d || 0x7d
76 {COL_WHITE
, FONT_REGULAR
, 28}, // 0x5e || 0x7e
77 {COL_WHITE
, FONT_UNDERLINED
, 28} // 0x5f || 0x7f
81 static enum color_code default_color
=COL_WHITE
;
83 static const char *command_type
[] =
86 "EDM - EraseDisplayedMemory",
87 "RCL - ResumeCaptionLoading",
88 "EOC - End Of Caption",
89 "TO1 - Tab Offset, 1 column",
90 "TO2 - Tab Offset, 2 column",
91 "TO3 - Tab Offset, 3 column",
92 "RU2 - Roll up 2 rows",
93 "RU3 - Roll up 3 rows",
94 "RU4 - Roll up 4 rows",
95 "CR - Carriage Return",
96 "ENM - Erase non-displayed memory",
98 "RTD - Resume Text Display"
101 static const char *font_text
[]=
109 static const char *color_text
[][2]=
111 {"white", "&HFFFFFF&"},
112 {"green", "&H00FF00&"},
113 {"blue", "&HFF0000&"},
114 {"cyan", "&HFFFF00&"},
115 {"red", "&H0000FF&"},
116 {"yellow", "&H00FFFF&"},
117 {"magenta", "&HFF00FF&"},
118 {"userdefined", "&HFFFFFF&"}
121 static int general_608_init (struct s_write
*wb
)
123 if( !wb
->enc_buffer
)
125 wb
->enc_buffer
=(unsigned char *) malloc (INITIAL_ENC_BUFFER_CAPACITY
);
126 if (wb
->enc_buffer
==NULL
)
128 wb
->enc_buffer_capacity
=INITIAL_ENC_BUFFER_CAPACITY
;
132 wb
->subline
= malloc(2048);
140 wb
->new_sentence
= 1;
144 wb
->hb_buffer
= NULL
;
145 wb
->hb_last_buffer
= NULL
;
151 * Free up CC memory - don't call this from HB just yet since it will cause
152 * parallel encodes to fail - to be honest they will be stuffed anyway since
153 * the CC's may be overwriting the buffers.
155 static void general_608_close (struct s_write
*wb
)
157 if( wb
->enc_buffer
) {
158 free(wb
->enc_buffer
);
159 wb
->enc_buffer_capacity
= 0;
160 wb
->enc_buffer_used
= 0;
166 if( wb
->hb_buffer
) {
167 hb_buffer_close( &wb
->hb_buffer
);
174 // Returns number of bytes used
175 static int get_char_in_utf8(unsigned char *buffer
, unsigned char c
)
180 // Regular line-21 character set, mostly ASCII except these exceptions
185 case 0x2a: // lowercase a, acute accent
189 case 0x5c: // lowercase e, acute accent
193 case 0x5e: // lowercase i, acute accent
197 case 0x5f: // lowercase o, acute accent
201 case 0x60: // lowercase u, acute accent
205 case 0x7b: // lowercase c with cedilla
209 case 0x7c: // division symbol
213 case 0x7d: // uppercase N tilde
217 case 0x7e: // lowercase n tilde
228 // THIS BLOCK INCLUDES THE 16 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
229 // THAT COME FROM HI BYTE = 0x11 AND LOW BETWEEN 0x30 AND 0x3F
230 case 0x80: // Registered symbol (R)
234 case 0x81: // degree sign
238 case 0x82: // 1/2 symbol
242 case 0x83: // Inverted (open) question mark
246 case 0x84: // Trademark symbol (TM)
251 case 0x85: // Cents symbol
255 case 0x86: // Pounds sterling
259 case 0x87: // Music note
264 case 0x88: // lowercase a, grave accent
268 case 0x89: // transparent space, we make it regular
271 case 0x8a: // lowercase e, grave accent
275 case 0x8b: // lowercase a, circumflex accent
279 case 0x8c: // lowercase e, circumflex accent
283 case 0x8d: // lowercase i, circumflex accent
287 case 0x8e: // lowercase o, circumflex accent
291 case 0x8f: // lowercase u, circumflex accent
295 // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
296 // THAT COME FROM HI BYTE = 0x12 AND LOW BETWEEN 0x20 AND 0x3F
297 case 0x90: // capital letter A with acute
301 case 0x91: // capital letter E with acute
305 case 0x92: // capital letter O with acute
309 case 0x93: // capital letter U with acute
313 case 0x94: // capital letter U with diaresis
317 case 0x95: // lowercase letter U with diaeresis
321 case 0x96: // apostrophe
324 case 0x97: // inverted exclamation mark
328 case 0x98: // asterisk
331 case 0x99: // apostrophe (yes, duped). See CCADI source code.
334 case 0x9a: // hyphen-minus
337 case 0x9b: // copyright sign
341 case 0x9c: // Service mark
346 case 0x9d: // Full stop (.)
349 case 0x9e: // Quoatation mark
352 case 0x9f: // Quoatation mark
355 case 0xa0: // uppercase A, grave accent
359 case 0xa1: // uppercase A, circumflex
363 case 0xa2: // uppercase C with cedilla
367 case 0xa3: // uppercase E, grave accent
371 case 0xa4: // uppercase E, circumflex
375 case 0xa5: // capital letter E with diaresis
379 case 0xa6: // lowercase letter e with diaresis
383 case 0xa7: // uppercase I, circumflex
387 case 0xa8: // uppercase I, with diaresis
391 case 0xa9: // lowercase i, with diaresis
395 case 0xaa: // uppercase O, circumflex
399 case 0xab: // uppercase U, grave accent
403 case 0xac: // lowercase u, grave accent
407 case 0xad: // uppercase U, circumflex
411 case 0xae: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
415 case 0xaf: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
419 // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
420 // THAT COME FROM HI BYTE = 0x13 AND LOW BETWEEN 0x20 AND 0x3F
421 case 0xb0: // Uppercase A, tilde
425 case 0xb1: // Lowercase a, tilde
429 case 0xb2: // Uppercase I, acute accent
433 case 0xb3: // Uppercase I, grave accent
437 case 0xb4: // Lowercase i, grave accent
441 case 0xb5: // Uppercase O, grave accent
445 case 0xb6: // Lowercase o, grave accent
449 case 0xb7: // Uppercase O, tilde
453 case 0xb8: // Lowercase o, tilde
457 case 0xb9: // Open curly brace
460 case 0xba: // Closing curly brace
463 case 0xbb: // Backslash
469 case 0xbd: // Underscore
472 case 0xbe: // Pipe (broken bar)
477 *buffer
= 0x7e; // Not sure
479 case 0xc0: // Uppercase A, umlaut
483 case 0xc1: // Lowercase A, umlaut
487 case 0xc2: // Uppercase O, umlaut
491 case 0xc3: // Lowercase o, umlaut
495 case 0xc4: // Esszett (sharp S)
499 case 0xc5: // Yen symbol
503 case 0xc6: // Currency symbol
507 case 0xc7: // Vertical bar
510 case 0xc8: // Uppercase A, ring
514 case 0xc9: // Lowercase A, ring
518 case 0xca: // Uppercase O, slash
522 case 0xcb: // Lowercase o, slash
526 case 0xcc: // Upper left corner
531 case 0xcd: // Upper right corner
536 case 0xce: // Lower left corner
541 case 0xcf: // Lower right corner
547 *buffer
= '?'; // I'll do it eventually, I promise
548 return 1; // This are weird chars anyway
552 // Encodes a generic string. Note that since we use the encoders for closed
553 // caption data, text would have to be encoded as CCs... so using special
554 // characters here it's a bad idea.
555 static unsigned encode_line(unsigned char *buffer
, unsigned char *text
)
566 static unsigned stuff_space(unsigned char *buffer
, int space
)
569 for (ii
= 0; ii
< space
; ii
++)
577 static void find_limit_characters(unsigned char *line
, int *first_non_blank
,
582 *last_non_blank
= -1;
583 *first_non_blank
= -1;
584 for (i
= 0; i
< CC608_SCREEN_WIDTH
; i
++)
586 unsigned char c
= line
[i
];
587 if (c
!= ' ' && c
!= 0x89)
589 if (*first_non_blank
== -1)
590 *first_non_blank
= i
;
596 static unsigned get_decoder_line_encoded(struct s_write
*wb
,
597 unsigned char *buffer
, int line_num
,
598 struct eia608_screen
*data
)
604 unsigned char *line
= data
->characters
[line_num
];
605 unsigned char *orig
= buffer
; // Keep for debugging
606 int first
= 0, last
= 31;
608 find_limit_characters(line
, &first
, &last
);
609 for (i
= first
; i
<= last
; i
++)
612 font_color
= data
->colors
[line_num
][i
];
613 font_style
= data
->fonts
[line_num
][i
];
615 // Handle reset to defaults
616 if ((font_style
& FONT_STYLE_MASK
) == 0 && font_color
== COL_WHITE
)
618 if (((font_style
^ wb
->prev_font_style
) & FONT_STYLE_MASK
) ||
619 (font_color
!= wb
->prev_font_color
))
621 buffer
+= encode_line(buffer
, (uint8_t*)"{\\r}");
627 if (((font_style
^ wb
->prev_font_style
) & FONT_STYLE_MASK
) ||
628 (font_color
!= wb
->prev_font_color
))
631 buffer
+= encode_line(buffer
, (uint8_t*)"{");
635 if ((font_style
^ wb
->prev_font_style
) & FONT_UNDERLINED
)
637 int enable
= !!(font_style
& FONT_UNDERLINED
);
638 buffer
+= encode_line(buffer
, (uint8_t*)"\\u");
639 *buffer
++ = enable
+ 0x30;
643 if ((font_style
^ wb
->prev_font_style
) & FONT_ITALICS
)
645 int enable
= !!(font_style
& FONT_ITALICS
);
646 buffer
+= encode_line(buffer
, (uint8_t*)"\\i");
647 *buffer
++ = enable
+ 0x30;
651 if (font_color
!= wb
->prev_font_color
)
653 buffer
+= encode_line(buffer
, (uint8_t*)"\\1c");
654 buffer
+= encode_line(buffer
,
655 (uint8_t*)color_text
[font_color
][1]);
659 if (((font_style
^ wb
->prev_font_style
) & FONT_STYLE_MASK
) ||
660 (font_color
!= wb
->prev_font_color
))
663 buffer
+= encode_line(buffer
, (uint8_t*)"}");
666 wb
->prev_font_style
= font_style
;
667 wb
->prev_font_color
= font_color
;
670 bytes
= get_char_in_utf8(buffer
, line
[i
]);
674 return (unsigned) (buffer
- orig
); // Return length
678 static void clear_eia608_cc_buffer (struct eia608_screen
*data
)
684 memset(data
->characters
[i
],' ',CC608_SCREEN_WIDTH
);
685 data
->characters
[i
][CC608_SCREEN_WIDTH
]=0;
686 memset (data
->colors
[i
],default_color
,CC608_SCREEN_WIDTH
+1);
687 memset (data
->fonts
[i
],FONT_REGULAR
,CC608_SCREEN_WIDTH
+1);
693 static void init_eia608 (struct eia608
*data
)
695 data
->cursor_column
= 0;
696 data
->cursor_row
= 0;
697 clear_eia608_cc_buffer (&data
->buffer1
);
698 clear_eia608_cc_buffer (&data
->buffer2
);
699 data
->visible_buffer
= 1;
702 data
->mode
= MODE_POPUP
;
703 data
->current_visible_start_ms
= 0;
704 data
->ssa_counter
= 0;
705 data
->screenfuls_counter
= 0;
707 data
->color
= default_color
;
708 data
->font
= FONT_REGULAR
;
709 data
->rollup_base_row
= 14;
712 static struct eia608_screen
*get_current_hidden_buffer(struct s_write
*wb
)
714 struct eia608_screen
*data
;
715 if (wb
->data608
->visible_buffer
== 1)
716 data
= &wb
->data608
->buffer2
;
718 data
= &wb
->data608
->buffer1
;
722 static struct eia608_screen
*get_current_visible_buffer(struct s_write
*wb
)
724 struct eia608_screen
*data
;
725 if (wb
->data608
->visible_buffer
== 1)
726 data
= &wb
->data608
->buffer1
;
728 data
= &wb
->data608
->buffer2
;
732 static void swap_visible_buffer(struct s_write
*wb
)
734 wb
->data608
->visible_buffer
= (wb
->data608
->visible_buffer
== 1) ? 2 : 1;
737 static struct eia608_screen
*get_writing_buffer(struct s_write
*wb
)
739 struct eia608_screen
*use_buffer
=NULL
;
740 switch (wb
->data608
->mode
)
742 case MODE_POPUP
: // Write on the non-visible buffer
743 use_buffer
= get_current_hidden_buffer(wb
);
745 case MODE_ROLLUP_2
: // Write directly to screen
748 use_buffer
= get_current_visible_buffer(wb
);
751 fatal (EXIT_BUG_BUG
, "Caption mode has an illegal value at get_writing_buffer(), this is a bug.\n");
756 static void write_char(const unsigned char c
, struct s_write
*wb
)
758 if (wb
->data608
->mode
!= MODE_TEXT
)
760 struct eia608_screen
* use_buffer
= get_writing_buffer(wb
);
761 /* hb_log ("\rWriting char [%c] at %s:%d:%d\n",c,
762 use_buffer == &wb->data608->buffer1?"B1":"B2",
763 wb->data608->cursor_row,wb->data608->cursor_column); */
764 use_buffer
->characters
[wb
->data608
->cursor_row
][wb
->data608
->cursor_column
] = c
;
765 use_buffer
->colors
[wb
->data608
->cursor_row
][wb
->data608
->cursor_column
] = wb
->data608
->color
;
766 use_buffer
->fonts
[wb
->data608
->cursor_row
][wb
->data608
->cursor_column
] = wb
->data608
->font
;
767 use_buffer
->row_used
[wb
->data608
->cursor_row
] = 1;
768 use_buffer
->empty
= 0;
769 if (wb
->data608
->cursor_column
< 31)
770 wb
->data608
->cursor_column
++;
771 use_buffer
->dirty
= 1;
776 /* Handle MID-ROW CODES. */
777 static void handle_text_attr(const unsigned char c1
, const unsigned char c2
,
780 // Handle channel change
781 wb
->data608
->channel
=wb
->new_channel
;
782 if (wb
->data608
->channel
!=cc_channel
)
785 hb_log ("\r608: text_attr: %02X %02X",c1
,c2
);
786 if ( ((c1
!=0x11 && c1
!=0x19) ||
787 (c2
<0x20 || c2
>0x2f)) && debug_608
)
789 hb_log ("\rThis is not a text attribute!\n");
794 wb
->data608
->color
=pac2_attribs
[i
][0];
795 wb
->data608
->font
=pac2_attribs
[i
][1];
797 hb_log(" -- Color: %s, font: %s\n",
798 color_text
[wb
->data608
->color
][0],
799 font_text
[wb
->data608
->font
]);
800 if (wb
->data608
->cursor_column
<31)
801 wb
->data608
->cursor_column
++;
805 static int write_cc_buffer_as_ssa(struct eia608_screen
*data
,
808 int wrote_something
= 0;
810 int64_t ms_start
= wb
->data608
->current_visible_start_ms
;
811 //int64_t ms_end = get_last_pts(wb) + subs_delay;
813 ms_start
+= subs_delay
;
814 if (ms_start
<0) // Drop screens that because of subs_delay start too early
820 wb
->data608
->ssa_counter
++;
821 sprintf (timeline
,"%u\r\n",wb
->data608
->ssa_counter
);
823 hb_log ("\n- - - SSA caption - - -\n");
824 hb_log ("%s", timeline
);
828 * Write all the lines into enc_buffer, and then write that out at the end
829 * ensure that we only have two lines, insert a newline after the first one,
830 * and have a big bottom line (strip spaces from any joined lines).
832 int rows
= 0, columns
= 0;
833 int min_row
= 15, max_row
= 0;
834 int min_col
= 41, max_col
= 0;
835 for (i
= 0; i
< 15; i
++)
837 if (data
->row_used
[i
])
842 find_limit_characters(data
->characters
[i
], &first
, &last
);
843 if (last
- first
+ 1 > columns
)
844 columns
= last
- first
+ 1;
856 wb
->prev_font_style
= FONT_REGULAR
;
857 wb
->prev_font_color
= COL_WHITE
;
858 wb
->enc_buffer_used
= 0;
860 int cropped_width
, cropped_height
, font_size
;
861 int cell_width
, cell_height
;
863 int min_safe_x
, min_safe_y
;
866 cropped_height
= wb
->height
- wb
->crop
[0] - wb
->crop
[1];
867 cropped_width
= wb
->width
- wb
->crop
[2] - wb
->crop
[3];
868 aspect
= (double)wb
->width
* wb
->par
.num
/
869 (wb
->height
* wb
->par
.den
);
871 // CC grid is 16 rows by 32 colums (for 4:3 video)
872 // Our SSA resolution is the title resolution
873 // Tranlate CC grid to SSA coordinates
874 // The numbers are tweaked to keep things off the very
875 // edges of the screen and in the "safe" zone
876 int screen_columns
= 32;
879 // If the display aspect is close to or greater than 16:9
880 // then width of screen is 42 columns (see CEA-708)
883 font_size
= wb
->height
* .8 * .08;
885 safe_x
= 0.1 * wb
->width
;
886 safe_y
= 0.1 * wb
->height
;
887 min_safe_x
= 0.025 * cropped_width
;
888 min_safe_y
= 0.025 * cropped_height
;
889 cell_height
= (wb
->height
- 2 * safe_y
) / 16;
890 cell_width
= (wb
->width
- 2 * safe_x
) / screen_columns
;
897 // If the display aspect is close to or greater than 16:9
898 // center the CC in about a 4:3 region
901 y
= cell_height
* (min_row
+ 1 + rows
) + safe_y
- wb
->crop
[0];
902 x
= cell_width
* col
+ safe_x
- wb
->crop
[2];
903 top
= y
- rows
* font_size
;
905 if (top
< min_safe_y
)
906 y
= (rows
* font_size
) + min_safe_y
;
907 if (y
> cropped_height
- min_safe_y
)
908 y
= cropped_height
- min_safe_y
;
909 if (x
+ columns
* cell_width
> cropped_width
- min_safe_x
)
910 x
= cropped_width
- columns
* cell_width
- min_safe_x
;
913 pos
= hb_strdup_printf("{\\an1\\pos(%d,%d)}", x
, y
);
916 for (i
= 0; i
< 15; i
++)
918 if (data
->row_used
[i
])
921 // Get position for this CC
922 find_limit_characters(data
->characters
[i
], &first
, &last
);
925 * The intention was to use a newline but QT doesn't like it,
926 * old code still here just in case..
928 int space
= first
- min_col
;
930 wb
->enc_buffer_used
+= encode_line(
931 wb
->enc_buffer
+ wb
->enc_buffer_used
, (uint8_t*)pos
);
932 wb
->enc_buffer_used
+= stuff_space(
933 wb
->enc_buffer
+ wb
->enc_buffer_used
, space
);
934 wb
->enc_buffer_used
+= get_decoder_line_encoded(wb
,
935 wb
->enc_buffer
+ wb
->enc_buffer_used
, i
, data
);
938 wb
->enc_buffer_used
+= encode_line(
939 wb
->enc_buffer
+ wb
->enc_buffer_used
, (uint8_t*)"\\N");
940 wb
->enc_buffer_used
+= stuff_space(
941 wb
->enc_buffer
+ wb
->enc_buffer_used
, space
);
942 wb
->enc_buffer_used
+= get_decoder_line_encoded(wb
,
943 wb
->enc_buffer
+ wb
->enc_buffer_used
, i
, data
);
948 if (wb
->enc_buffer_used
&& wb
->enc_buffer
[0] != 0 && data
->dirty
)
953 // bump past null terminator
954 wb
->enc_buffer_used
++;
955 buffer
= hb_buffer_init(wb
->enc_buffer_used
+ SSA_PREAMBLE_LEN
);
956 buffer
->s
.frametype
= HB_FRAME_SUBTITLE
;
957 buffer
->s
.start
= ms_start
;
958 buffer
->s
.stop
= AV_NOPTS_VALUE
;
959 sprintf((char*)buffer
->data
, "%d,,Default,,0,0,0,,", ++wb
->line
);
960 len
= strlen((char*)buffer
->data
);
961 memcpy(buffer
->data
+ len
, wb
->enc_buffer
, wb
->enc_buffer_used
);
962 if (wb
->hb_last_buffer
)
964 wb
->hb_last_buffer
->next
= buffer
;
968 wb
->hb_buffer
= buffer
;
970 wb
->hb_last_buffer
= buffer
;
972 wb
->clear_sub_needed
= 1;
974 else if (wb
->clear_sub_needed
)
976 hb_buffer_t
*buffer
= hb_buffer_init(1);
977 buffer
->s
.frametype
= HB_FRAME_SUBTITLE
;
978 buffer
->s
.start
= ms_start
;
979 buffer
->s
.stop
= ms_start
;
981 if (wb
->hb_last_buffer
!= NULL
)
983 wb
->hb_last_buffer
->next
= buffer
;
987 wb
->hb_buffer
= buffer
;
989 wb
->hb_last_buffer
= buffer
;
990 wb
->clear_sub_needed
= 0;
994 hb_log ("- - - - - - - - - - - -\r\n");
996 return wrote_something
;
999 static int write_cc_buffer(struct s_write
*wb
)
1001 struct eia608_screen
*data
;
1002 int wrote_something
=0;
1004 data
= get_current_visible_buffer(wb
);
1008 wrote_something
= write_cc_buffer_as_ssa(data
, wb
);
1010 return wrote_something
;
1013 static void move_roll_up(struct s_write
*wb
, int row
)
1015 struct eia608_screen
*use_buffer
;
1016 int ii
, src
, dst
, keep_lines
;
1018 switch (wb
->data608
->mode
)
1030 // Not rollup mode, nothing to do
1034 if (row
== wb
->data608
->rollup_base_row
)
1036 // base row didn't change, nothing to do
1040 use_buffer
= get_current_visible_buffer(wb
);
1041 if (row
< wb
->data608
->rollup_base_row
)
1043 src
= wb
->data608
->rollup_base_row
- keep_lines
+ 1;
1044 dst
= row
- keep_lines
+ 1;
1045 for (ii
= 0; ii
< keep_lines
; ii
++)
1047 memcpy(use_buffer
->characters
[dst
], use_buffer
->characters
[src
], CC608_SCREEN_WIDTH
+1);
1048 memcpy(use_buffer
->colors
[dst
], use_buffer
->colors
[src
], CC608_SCREEN_WIDTH
+1);
1049 memcpy(use_buffer
->fonts
[dst
], use_buffer
->fonts
[src
], CC608_SCREEN_WIDTH
+1);
1050 use_buffer
->row_used
[dst
] = use_buffer
->row_used
[src
];
1052 memset(use_buffer
->characters
[src
], ' ', CC608_SCREEN_WIDTH
);
1053 memset(use_buffer
->colors
[src
], COL_WHITE
, CC608_SCREEN_WIDTH
);
1054 memset(use_buffer
->fonts
[src
], FONT_REGULAR
, CC608_SCREEN_WIDTH
);
1055 use_buffer
->characters
[src
][CC608_SCREEN_WIDTH
] = 0;
1056 use_buffer
->row_used
[src
] = 0;
1064 src
= wb
->data608
->rollup_base_row
;
1066 for (ii
= 0; ii
< keep_lines
; ii
++)
1068 memcpy(use_buffer
->characters
[dst
], use_buffer
->characters
[src
], CC608_SCREEN_WIDTH
+1);
1069 memcpy(use_buffer
->colors
[dst
], use_buffer
->colors
[src
], CC608_SCREEN_WIDTH
+1);
1070 memcpy(use_buffer
->fonts
[dst
], use_buffer
->fonts
[src
], CC608_SCREEN_WIDTH
+1);
1071 use_buffer
->row_used
[dst
] = use_buffer
->row_used
[src
];
1073 memset(use_buffer
->characters
[src
], ' ', CC608_SCREEN_WIDTH
);
1074 memset(use_buffer
->colors
[src
], COL_WHITE
, CC608_SCREEN_WIDTH
);
1075 memset(use_buffer
->fonts
[src
], FONT_REGULAR
, CC608_SCREEN_WIDTH
);
1076 use_buffer
->characters
[src
][CC608_SCREEN_WIDTH
] = 0;
1077 use_buffer
->row_used
[src
] = 0;
1083 use_buffer
->dirty
= 1;
1086 static void roll_up(struct s_write
*wb
)
1088 struct eia608_screen
*use_buffer
;
1091 use_buffer
= get_current_visible_buffer(wb
);
1093 switch (wb
->data608
->mode
)
1104 default: // Shouldn't happen
1108 int firstrow
= -1, lastrow
= -1;
1109 // Look for the last line used
1110 int rows_now
= 0; // Number of rows in use right now
1111 for (i
= 0; i
< 15; i
++)
1113 if (use_buffer
->row_used
[i
])
1123 hb_log ("\rIn roll-up: %d lines used, first: %d, last: %d\n", rows_now
, firstrow
, lastrow
);
1125 if (lastrow
==-1) // Empty screen, nothing to rollup
1128 for (j
= lastrow
- keep_lines
+ 1; j
< lastrow
; j
++)
1132 memcpy(use_buffer
->characters
[j
], use_buffer
->characters
[j
+1], CC608_SCREEN_WIDTH
+1);
1133 memcpy(use_buffer
->colors
[j
], use_buffer
->colors
[j
+1], CC608_SCREEN_WIDTH
+1);
1134 memcpy(use_buffer
->fonts
[j
], use_buffer
->fonts
[j
+1], CC608_SCREEN_WIDTH
+1);
1135 use_buffer
->row_used
[j
] = use_buffer
->row_used
[j
+1];
1138 for (j
= 0; j
< (1 + wb
->data608
->cursor_row
- keep_lines
); j
++)
1140 memset(use_buffer
->characters
[j
], ' ', CC608_SCREEN_WIDTH
);
1141 memset(use_buffer
->colors
[j
], COL_WHITE
, CC608_SCREEN_WIDTH
);
1142 memset(use_buffer
->fonts
[j
], FONT_REGULAR
, CC608_SCREEN_WIDTH
);
1143 use_buffer
->characters
[j
][CC608_SCREEN_WIDTH
] = 0;
1144 use_buffer
->row_used
[j
] = 0;
1146 memset(use_buffer
->characters
[lastrow
], ' ', CC608_SCREEN_WIDTH
);
1147 memset(use_buffer
->colors
[lastrow
], COL_WHITE
, CC608_SCREEN_WIDTH
);
1148 memset(use_buffer
->fonts
[lastrow
], FONT_REGULAR
, CC608_SCREEN_WIDTH
);
1150 use_buffer
->characters
[lastrow
][CC608_SCREEN_WIDTH
] = 0;
1151 use_buffer
->row_used
[lastrow
] = 0;
1155 for (i
= 0; i
< 15; i
++)
1156 if (use_buffer
->row_used
[i
])
1158 if (rows_now
> keep_lines
)
1159 hb_log ("Bug in roll_up, should have %d lines but I have %d.\n",
1160 keep_lines
, rows_now
);
1161 use_buffer
->dirty
= 1;
1164 void erase_memory (struct s_write
*wb
, int displayed
)
1166 struct eia608_screen
*buf
;
1169 buf
= get_current_visible_buffer(wb
);
1173 buf
= get_current_hidden_buffer(wb
);
1175 clear_eia608_cc_buffer (buf
);
1178 static int is_current_row_empty (struct s_write
*wb
)
1180 struct eia608_screen
*use_buffer
;
1183 use_buffer
= get_current_visible_buffer(wb
);
1184 for (i
=0;i
<CC608_SCREEN_WIDTH
;i
++)
1186 if (use_buffer
->characters
[wb
->data608
->rollup_base_row
][i
]!=' ')
1192 /* Process GLOBAL CODES */
1193 static void handle_command(unsigned char c1
, const unsigned char c2
,
1196 // Handle channel change
1197 wb
->data608
->channel
=wb
->new_channel
;
1198 if (wb
->data608
->channel
!=cc_channel
)
1201 enum command_code command
= COM_UNKNOWN
;
1204 if ((c1
==0x14 || c1
==0x1C) && c2
==0x2C)
1205 command
= COM_ERASEDISPLAYEDMEMORY
;
1206 if ((c1
==0x14 || c1
==0x1C) && c2
==0x20)
1207 command
= COM_RESUMECAPTIONLOADING
;
1208 if ((c1
==0x14 || c1
==0x1C) && c2
==0x2F)
1209 command
= COM_ENDOFCAPTION
;
1210 if ((c1
==0x17 || c1
==0x1F) && c2
==0x21)
1211 command
= COM_TABOFFSET1
;
1212 if ((c1
==0x17 || c1
==0x1F) && c2
==0x22)
1213 command
= COM_TABOFFSET2
;
1214 if ((c1
==0x17 || c1
==0x1F) && c2
==0x23)
1215 command
= COM_TABOFFSET3
;
1216 if ((c1
==0x14 || c1
==0x1C) && c2
==0x25)
1217 command
= COM_ROLLUP2
;
1218 if ((c1
==0x14 || c1
==0x1C) && c2
==0x26)
1219 command
= COM_ROLLUP3
;
1220 if ((c1
==0x14 || c1
==0x1C) && c2
==0x27)
1221 command
= COM_ROLLUP4
;
1222 if ((c1
==0x14 || c1
==0x1C) && c2
==0x2D)
1223 command
= COM_CARRIAGERETURN
;
1224 if ((c1
==0x14 || c1
==0x1C) && c2
==0x2E)
1225 command
= COM_ERASENONDISPLAYEDMEMORY
;
1226 if ((c1
==0x14 || c1
==0x1C) && c2
==0x21)
1227 command
= COM_BACKSPACE
;
1228 if ((c1
==0x14 || c1
==0x1C) && c2
==0x2b)
1229 command
= COM_RESUMETEXTDISPLAY
;
1232 hb_log ("\rCommand: %02X %02X (%s)\n",c1
,c2
,command_type
[command
]);
1237 if (wb
->data608
->cursor_column
>0)
1239 struct eia608_screen
*data
;
1240 data
= get_writing_buffer(wb
);
1241 wb
->data608
->cursor_column
--;
1242 data
->characters
[wb
->data608
->cursor_row
][wb
->data608
->cursor_column
] = ' ';
1246 case COM_TABOFFSET1
:
1247 if (wb
->data608
->cursor_column
<31)
1248 wb
->data608
->cursor_column
++;
1250 case COM_TABOFFSET2
:
1251 wb
->data608
->cursor_column
+=2;
1252 if (wb
->data608
->cursor_column
>31)
1253 wb
->data608
->cursor_column
=31;
1255 case COM_TABOFFSET3
:
1256 wb
->data608
->cursor_column
+=3;
1257 if (wb
->data608
->cursor_column
>31)
1258 wb
->data608
->cursor_column
=31;
1260 case COM_RESUMECAPTIONLOADING
:
1261 wb
->data608
->mode
=MODE_POPUP
;
1262 wb
->data608
->current_visible_start_ms
= get_last_pts(wb
);
1264 case COM_RESUMETEXTDISPLAY
:
1265 wb
->data608
->mode
=MODE_TEXT
;
1266 wb
->data608
->current_visible_start_ms
= get_last_pts(wb
);
1269 if (wb
->data608
->rollup_base_row
+ 1 < 2)
1271 move_roll_up(wb
, 1);
1272 wb
->data608
->rollup_base_row
= 1;
1274 if (wb
->data608
->mode
==MODE_POPUP
)
1276 swap_visible_buffer(wb
);
1277 if (write_cc_buffer(wb
))
1278 wb
->data608
->screenfuls_counter
++;
1279 erase_memory (wb
, 1);
1281 wb
->data608
->color
=default_color
;
1282 wb
->data608
->font
=FONT_REGULAR
;
1283 if (wb
->data608
->mode
==MODE_ROLLUP_2
&& !is_current_row_empty(wb
))
1286 hb_log ("Two RU2, current line not empty. Simulating a CR\n");
1287 handle_command(0x14, 0x2D, wb
);
1290 wb
->data608
->current_visible_start_ms
= get_last_pts(wb
);
1291 wb
->data608
->mode
=MODE_ROLLUP_2
;
1292 erase_memory (wb
, 0);
1293 wb
->data608
->cursor_column
= 0;
1294 wb
->data608
->cursor_row
= wb
->data608
->rollup_base_row
;
1297 if (wb
->data608
->rollup_base_row
+ 1 < 3)
1299 move_roll_up(wb
, 2);
1300 wb
->data608
->rollup_base_row
= 2;
1302 if (wb
->data608
->mode
==MODE_POPUP
)
1304 if (write_cc_buffer(wb
))
1305 wb
->data608
->screenfuls_counter
++;
1306 erase_memory (wb
, 1);
1308 wb
->data608
->color
=default_color
;
1309 wb
->data608
->font
=FONT_REGULAR
;
1310 if (wb
->data608
->mode
==MODE_ROLLUP_3
&& !is_current_row_empty(wb
))
1313 hb_log ("Two RU3, current line not empty. Simulating a CR\n");
1314 handle_command(0x14, 0x2D, wb
);
1317 wb
->data608
->current_visible_start_ms
= get_last_pts(wb
);
1318 wb
->data608
->mode
=MODE_ROLLUP_3
;
1319 erase_memory (wb
, 0);
1320 wb
->data608
->cursor_column
= 0;
1321 wb
->data608
->cursor_row
= wb
->data608
->rollup_base_row
;
1324 if (wb
->data608
->rollup_base_row
+ 1 < 4)
1326 move_roll_up(wb
, 3);
1327 wb
->data608
->rollup_base_row
= 3;
1329 if (wb
->data608
->mode
==MODE_POPUP
)
1331 if (write_cc_buffer(wb
))
1332 wb
->data608
->screenfuls_counter
++;
1333 erase_memory (wb
, 1);
1335 wb
->data608
->color
=default_color
;
1336 wb
->data608
->font
=FONT_REGULAR
;
1337 if (wb
->data608
->mode
==MODE_ROLLUP_4
&& !is_current_row_empty(wb
))
1340 hb_log ("Two RU4, current line not empty. Simulating a CR\n");
1341 handle_command(0x14, 0x2D, wb
);
1344 wb
->data608
->current_visible_start_ms
= get_last_pts(wb
);
1345 wb
->data608
->mode
= MODE_ROLLUP_4
;
1346 wb
->data608
->cursor_column
= 0;
1347 wb
->data608
->cursor_row
= wb
->data608
->rollup_base_row
;
1348 erase_memory (wb
, 0);
1350 case COM_CARRIAGERETURN
:
1351 // In transcript mode, CR doesn't write the whole screen, to avoid
1354 // Skip initial CR if rollup has already done it
1355 if (wb
->rollup_cr
&& is_current_row_empty(wb
))
1358 wb
->data608
->current_visible_start_ms
= get_last_pts(wb
);
1361 if (write_cc_buffer(wb
))
1362 wb
->data608
->screenfuls_counter
++;
1364 wb
->data608
->cursor_column
= 0;
1365 wb
->data608
->current_visible_start_ms
= get_last_pts(wb
);
1367 case COM_ERASENONDISPLAYEDMEMORY
:
1368 erase_memory (wb
,0);
1370 case COM_ERASEDISPLAYEDMEMORY
:
1371 // There may be "displayed" rollup data that has not been
1372 // written to a buffer yet.
1373 if (wb
->data608
->mode
== MODE_ROLLUP_2
||
1374 wb
->data608
->mode
== MODE_ROLLUP_3
||
1375 wb
->data608
->mode
== MODE_ROLLUP_4
)
1377 write_cc_buffer(wb
);
1379 erase_memory (wb
,1);
1381 // the last pts is the time to remove the previously
1382 // displayed CC from the display
1383 wb
->data608
->current_visible_start_ms
= get_last_pts(wb
);
1385 // Write "clear" subtitle if necessary
1386 struct eia608_screen
*data
;
1387 data
= get_current_visible_buffer(wb
);
1389 write_cc_buffer(wb
);
1391 case COM_ENDOFCAPTION
: // Switch buffers
1392 // The currently *visible* buffer is leaving, so now we know it's ending
1393 // time. Time to actually write it to file.
1394 if (wb
->data608
->mode
== MODE_POPUP
)
1396 swap_visible_buffer(wb
);
1397 wb
->data608
->current_visible_start_ms
= get_last_pts(wb
);
1399 if (write_cc_buffer(wb
))
1400 wb
->data608
->screenfuls_counter
++;
1402 if (wb
->data608
->mode
!= MODE_POPUP
)
1403 swap_visible_buffer(wb
);
1404 wb
->data608
->cursor_column
= 0;
1405 wb
->data608
->cursor_row
= 0;
1406 wb
->data608
->color
=default_color
;
1407 wb
->data608
->font
=FONT_REGULAR
;
1412 hb_log ("\rNot yet implemented.\n");
1418 static void handle_end_of_data(struct s_write
*wb
)
1420 // We issue a EraseDisplayedMemory here so if there's any captions pending
1421 // they get written to file.
1422 handle_command (0x14, 0x2c, wb
); // EDM
1425 static void handle_double(const unsigned char c1
, const unsigned char c2
,
1429 if (wb
->data608
->channel
!=cc_channel
)
1431 if (c2
>=0x30 && c2
<=0x3f)
1433 c
=c2
+ 0x50; // So if c>=0x80 && c<=0x8f, it comes from here
1435 hb_log ("\rDouble: %02X %02X --> %c\n",c1
,c2
,c
);
1440 /* Process EXTENDED CHARACTERS */
1441 static unsigned char handle_extended(unsigned char hi
, unsigned char lo
,
1444 // Handle channel change
1445 if (wb
->new_channel
> 2)
1447 wb
->new_channel
-= 2;
1449 hb_log ("\nChannel correction, now %d\n", wb
->new_channel
);
1451 wb
->data608
->channel
=wb
->new_channel
;
1452 if (wb
->data608
->channel
!=cc_channel
)
1455 // For lo values between 0x20-0x3f
1459 hb_log ("\rExtended: %02X %02X\n",hi
,lo
);
1460 if (lo
>=0x20 && lo
<=0x3f && (hi
==0x12 || hi
==0x13))
1465 c
=lo
+0x70; // So if c>=0x90 && c<=0xaf it comes from here
1468 c
=lo
+0x90; // So if c>=0xb0 && c<=0xcf it comes from here
1471 // This column change is because extended characters replace
1472 // the previous character (which is sent for basic decoders
1473 // to show something similar to the real char)
1474 if (wb
->data608
->cursor_column
>0)
1475 wb
->data608
->cursor_column
--;
1482 /* Process PREAMBLE ACCESS CODES (PAC) */
1483 static void handle_pac(unsigned char c1
, unsigned char c2
, struct s_write
*wb
)
1485 // Handle channel change
1486 if (wb
->new_channel
> 2)
1488 wb
->new_channel
-= 2;
1490 hb_log ("\nChannel correction, now %d\n", wb
->new_channel
);
1492 wb
->data608
->channel
=wb
->new_channel
;
1493 if (wb
->data608
->channel
!=cc_channel
)
1496 int row
=rowdata
[((c1
<<1)&14)|((c2
>>5)&1)];
1499 hb_log ("\rPAC: %02X %02X",c1
,c2
);
1501 if (c2
>=0x40 && c2
<=0x5f)
1507 if (c2
>=0x60 && c2
<=0x7f)
1514 hb_log ("\rThis is not a PAC!!!!!\n");
1518 wb
->data608
->color
=pac2_attribs
[c2
][0];
1519 wb
->data608
->font
=pac2_attribs
[c2
][1];
1520 int indent
=pac2_attribs
[c2
][2];
1522 hb_log (" -- Position: %d:%d, color: %s, font: %s\n", row
, indent
,
1523 color_text
[wb
->data608
->color
][0],
1524 font_text
[wb
->data608
->font
]);
1526 // CC spec says to the preferred method to handle a roll-up base row
1527 // that causes the display to scroll off the top of the screen is to
1528 // adjust the base row down.
1530 switch (wb
->data608
->mode
)
1542 // Not rollup mode, all rows ok
1546 if (row
< keep_lines
)
1550 if (wb
->data608
->mode
!= MODE_TEXT
)
1552 // According to Robson, row info is discarded in text mode
1553 // but column is accepted
1555 // CC-608 spec says current rollup display must move to the
1556 // new position when the cursor row changes
1557 move_roll_up(wb
, row
- 1);
1558 wb
->data608
->cursor_row
= row
- 1 ; // Since the array is 0 based
1560 wb
->data608
->rollup_base_row
= row
- 1;
1561 wb
->data608
->cursor_column
= indent
;
1565 static void handle_single(const unsigned char c1
, struct s_write
*wb
)
1567 if (c1
<0x20 || wb
->data608
->channel
!=cc_channel
)
1568 return; // We don't allow special stuff here
1573 hb_log ("Character: %02X (%c) -> %02X (%c)\n",c1,c1,c,c); */
1577 static int check_channel(unsigned char c1
, struct s_write
*wb
)
1581 if (debug_608
&& wb
->data608
->channel
!=1)
1582 hb_log ("\nChannel change, now 1\n");
1587 if (debug_608
&& wb
->data608
->channel
!=2)
1588 hb_log ("\nChannel change, now 2\n");
1593 if (debug_608
&& wb
->data608
->channel
!=3)
1594 hb_log ("\nChannel change, now 3\n");
1599 if (debug_608
&& wb
->data608
->channel
!=4)
1600 hb_log ("\nChannel change, now 4\n");
1604 // Otherwise keep the current channel
1605 return wb
->data608
->channel
;
1608 /* Handle Command, special char or attribute and also check for
1610 * Returns 1 if something was written to screen, 0 otherwise */
1611 static int disCommand(unsigned char hi
, unsigned char lo
, struct s_write
*wb
)
1613 int wrote_to_screen
=0;
1615 /* Full channel changes are only allowed for "GLOBAL CODES",
1616 * "OTHER POSITIONING CODES", "BACKGROUND COLOR CODES",
1618 * "PREAMBLE ACCESS CODES", "BACKGROUND COLOR CODES" and
1619 * SPECIAL/SPECIAL CHARACTERS allow only switching
1620 * between 1&3 or 2&4. */
1621 wb
->new_channel
= check_channel (hi
,wb
);
1622 //if (wb->data608->channel!=cc_channel)
1625 if (hi
>=0x18 && hi
<=0x1f)
1631 if (lo
>=0x40 && lo
<=0x5f)
1632 handle_pac (hi
,lo
,wb
);
1635 if (lo
>=0x20 && lo
<=0x2f)
1636 handle_text_attr (hi
,lo
,wb
);
1637 if (lo
>=0x30 && lo
<=0x3f)
1640 handle_double (hi
,lo
,wb
);
1642 if (lo
>=0x40 && lo
<=0x7f)
1643 handle_pac (hi
,lo
,wb
);
1647 if (lo
>=0x20 && lo
<=0x3f)
1649 wrote_to_screen
=handle_extended (hi
,lo
,wb
);
1651 if (lo
>=0x40 && lo
<=0x7f)
1652 handle_pac (hi
,lo
,wb
);
1656 if (lo
>=0x20 && lo
<=0x2f)
1657 handle_command (hi
,lo
,wb
);
1658 if (lo
>=0x40 && lo
<=0x7f)
1659 handle_pac (hi
,lo
,wb
);
1662 if (lo
>=0x40 && lo
<=0x7f)
1663 handle_pac (hi
,lo
,wb
);
1666 if (lo
>=0x21 && lo
<=0x23)
1667 handle_command (hi
,lo
,wb
);
1668 if (lo
>=0x2e && lo
<=0x2f)
1669 handle_text_attr (hi
,lo
,wb
);
1670 if (lo
>=0x40 && lo
<=0x7f)
1671 handle_pac (hi
,lo
,wb
);
1674 return wrote_to_screen
;
1677 static void process608(const unsigned char *data
, int length
,
1680 static int textprinted
= 0;
1685 for (i
=0;i
<length
;i
=i
+2)
1687 unsigned char hi
, lo
;
1688 hi
= data
[i
] & 0x7F; // Get rid of parity bit
1689 lo
= data
[i
+1] & 0x7F; // Get rid of parity bit
1691 if (hi
==0 && lo
==0) // Just padding
1693 if (hi
>=0x01 && hi
<=0x0E)
1695 // XDS crap - mode. Would be nice to support it eventually
1696 // wb->data608->last_c1=0;
1697 // wb->data608->last_c2=0;
1698 wb
->data608
->channel
=3; // Always channel 3
1701 if (hi
==0x0F) // End of XDS block
1706 if (hi
>=0x10 && hi
<0x1F) // Non-character code or special/extended char
1707 // http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/CC_CODES.HTML
1708 // http://www.geocities.com/mcpoodle43/SCC_TOOLS/DOCS/CC_CHARS.HTML
1710 // We were writing characters before, start a new line for
1711 // diagnostic output from disCommand()
1712 if (debug_608
&& textprinted
== 1 )
1718 wb
->in_xds_mode
=0; // Back to normal
1719 if (wb
->data608
->last_c1
==hi
&& wb
->data608
->last_c2
==lo
)
1721 // Duplicate dual code, discard
1724 wb
->data608
->last_c1
=hi
;
1725 wb
->data608
->last_c2
=lo
;
1726 disCommand (hi
,lo
,wb
);
1728 if (hi
>=0x20) // Standard characters (always in pairs)
1730 // Only print if the channel is active
1731 if (wb
->data608
->channel
!=cc_channel
)
1736 if( textprinted
== 0 )
1743 handle_single(hi
,wb
);
1744 handle_single(lo
,wb
);
1745 wb
->data608
->last_c1
=0;
1746 wb
->data608
->last_c2
=0;
1749 if ( debug_608
&& !textprinted
&& wb
->data608
->channel
==cc_channel
)
1750 { // Current FTS information after the characters are shown
1751 //hb_log("Current FTS: %s\n", print_mstime(get_last_pts()));
1754 if ((wb
->data608
->mode
== MODE_ROLLUP_2
||
1755 wb
->data608
->mode
== MODE_ROLLUP_3
||
1756 wb
->data608
->mode
== MODE_ROLLUP_4
) &&
1759 // If we are showing rollup on the fly (direct_rollup)
1760 // write a buffer now
1761 write_cc_buffer(wb
);
1762 wb
->data608
->current_visible_start_ms
= get_last_pts(wb
);
1768 struct hb_work_private_s
1771 struct s_write
* cc608
;
1774 static int decccInit( hb_work_object_t
* w
, hb_job_t
* job
)
1777 hb_work_private_t
* pv
;
1779 pv
= calloc( 1, sizeof( hb_work_private_t
) );
1782 w
->private_data
= pv
;
1786 pv
->cc608
= calloc(1, sizeof(struct s_write
));
1790 pv
->cc608
->width
= job
->title
->geometry
.width
;
1791 pv
->cc608
->height
= job
->title
->geometry
.height
;
1792 memcpy(pv
->cc608
->crop
, job
->crop
, sizeof(int[4]));
1793 pv
->cc608
->par
= job
->title
->geometry
.par
;
1794 retval
= general_608_init(pv
->cc608
);
1797 pv
->cc608
->data608
= calloc(1, sizeof(struct eia608
));
1798 if( !pv
->cc608
->data608
)
1802 init_eia608(pv
->cc608
->data608
);
1808 // Generate generic SSA Script Info.
1809 int height
= job
->title
->geometry
.height
- job
->crop
[0] - job
->crop
[1];
1810 int width
= job
->title
->geometry
.width
- job
->crop
[2] - job
->crop
[3];
1811 int safe_height
= 0.8 * job
->title
->geometry
.height
;
1812 hb_subtitle_add_ssa_header(w
->subtitle
, "Courier New",
1813 .08 * safe_height
, width
, height
);
1815 // When rendering subs, we need to push rollup subtitles out
1816 // asap (instead of waiting for a completed line) so that we
1817 // do not miss the frame that they should be rendered over.
1818 pv
->cc608
->direct_rollup
= w
->subtitle
->config
.dest
== RENDERSUB
;
1822 static int decccWork( hb_work_object_t
* w
, hb_buffer_t
** buf_in
,
1823 hb_buffer_t
** buf_out
)
1825 hb_work_private_t
* pv
= w
->private_data
;
1826 hb_buffer_t
* in
= *buf_in
;
1828 if (in
->s
.flags
& HB_BUF_FLAG_EOF
)
1830 /* EOF on input stream - send it downstream & say that we're done */
1831 handle_end_of_data(pv
->cc608
);
1833 * Grab any pending buffer and output them with the EOF on the end
1835 if (pv
->cc608
->hb_last_buffer
) {
1836 pv
->cc608
->hb_last_buffer
->next
= in
;
1837 *buf_out
= pv
->cc608
->hb_buffer
;
1839 pv
->cc608
->hb_buffer
= NULL
;
1840 pv
->cc608
->hb_last_buffer
= NULL
;
1845 return HB_WORK_DONE
;
1848 pv
->cc608
->last_pts
= in
->s
.start
;
1849 process608(in
->data
, in
->size
, pv
->cc608
);
1852 * If there is one waiting then pass it on
1854 *buf_out
= pv
->cc608
->hb_buffer
;
1856 pv
->cc608
->hb_buffer
= NULL
;
1857 pv
->cc608
->hb_last_buffer
= NULL
;
1862 static void decccClose( hb_work_object_t
* w
)
1864 hb_work_private_t
* pv
= w
->private_data
;
1865 general_608_close( pv
->cc608
);
1866 free( pv
->cc608
->data608
);
1868 free( w
->private_data
);
1871 hb_work_object_t hb_deccc608
=
1874 "Closed Caption (608) decoder",