blob: 8fec64b3e61366c0df0be60eb6fe8cd80e0b4390
1 | #ifndef _DTVCC_H_ |
2 | #define _DTVCC_H_ |
3 | |
4 | #include <assert.h> |
5 | #include <ctype.h> |
6 | #include <dirent.h> |
7 | #include <errno.h> |
8 | #include <fcntl.h> |
9 | #include <inttypes.h> |
10 | #include <limits.h> |
11 | #include <locale.h> |
12 | #include <malloc.h> |
13 | #include <math.h> |
14 | #include <pthread.h> |
15 | #include <signal.h> |
16 | #include <stdarg.h> |
17 | #include <stdio.h> |
18 | #include <stdlib.h> |
19 | #include <string.h> |
20 | #include <sys/ioctl.h> |
21 | #include <sys/mman.h> |
22 | #include <sys/stat.h> |
23 | #include <sys/statvfs.h> |
24 | #include <sys/wait.h> |
25 | #include <time.h> |
26 | #include <unistd.h> |
27 | #include "libzvbi.h" |
28 | |
29 | enum field_num { |
30 | FIELD_1 = 0, |
31 | FIELD_2, |
32 | MAX_FIELDS |
33 | }; |
34 | |
35 | enum cc_mode { |
36 | CC_MODE_UNKNOWN, |
37 | CC_MODE_ROLL_UP, |
38 | CC_MODE_POP_ON, |
39 | CC_MODE_PAINT_ON, |
40 | CC_MODE_TEXT |
41 | }; |
42 | |
43 | /* EIA 608-B Section 4.1. */ |
44 | #define VBI_CAPTION_CC1 1 /* primary synchronous caption service (F1) */ |
45 | #define VBI_CAPTION_CC2 2 /* special non-synchronous use captions (F1) */ |
46 | #define VBI_CAPTION_CC3 3 /* secondary synchronous caption service (F2) */ |
47 | #define VBI_CAPTION_CC4 4 /* special non-synchronous use captions (F2) */ |
48 | |
49 | #define VBI_CAPTION_T1 5 /* first text service (F1) */ |
50 | #define VBI_CAPTION_T2 6 /* second text service (F1) */ |
51 | #define VBI_CAPTION_T3 7 /* third text service (F2) */ |
52 | #define VBI_CAPTION_T4 8 /* fourth text service (F2) */ |
53 | |
54 | #define UNKNOWN_CC_CHANNEL 0 |
55 | #define MAX_CC_CHANNELS 8 |
56 | |
57 | /* 47 CFR 15.119 (d) Screen format. */ |
58 | #define CC_FIRST_ROW 0 |
59 | #define CC_LAST_ROW 14 |
60 | #define CC_MAX_ROWS 15 |
61 | |
62 | #define CC_FIRST_COLUMN 1 |
63 | #define CC_LAST_COLUMN 32 |
64 | #define CC_MAX_COLUMNS 32 |
65 | |
66 | #define CC_ALL_ROWS_MASK ((1 << CC_MAX_ROWS) - 1) |
67 | |
68 | #define VBI_TRANSLUCENT VBI_SEMI_TRANSPARENT |
69 | |
70 | struct cc_timestamp { |
71 | /* System time when the event occured, zero if no event occured yet. */ |
72 | struct timeval sys; |
73 | |
74 | /* Presentation time stamp of the event. Only the 33 least |
75 | significant bits are valid. < 0 if no event occured yet. */ |
76 | int64_t pts; |
77 | }; |
78 | |
79 | struct cc_channel { |
80 | /** |
81 | * [0] and [1] are the displayed and non-displayed buffer as |
82 | * defined in 47 CFR 15.119, and selected by displayed_buffer |
83 | * below. [2] is a snapshot of the displayed buffer at the |
84 | * last stream event. |
85 | * |
86 | * XXX Text channels don't need buffer[2] and buffer[3], we're |
87 | * wasting memory. |
88 | */ |
89 | uint16_t buffer[3][CC_MAX_ROWS][1 + CC_MAX_COLUMNS]; |
90 | |
91 | /** |
92 | * For buffer[0 ... 2], if bit 1 << row is set this row |
93 | * contains displayable characters, spacing or non-spacing |
94 | * attributes. (Special character 0x1139 "transparent space" |
95 | * is not a displayable character.) This information is |
96 | * intended to speed up copying, erasing and formatting. |
97 | */ |
98 | unsigned int dirty[3]; |
99 | |
100 | /** Index of displayed buffer, 0 or 1. */ |
101 | unsigned int displayed_buffer; |
102 | |
103 | /** |
104 | * Cursor position: FIRST_ROW ... LAST_ROW and |
105 | * FIRST_COLUMN ... LAST_COLUMN. |
106 | */ |
107 | unsigned int curr_row; |
108 | unsigned int curr_column; |
109 | |
110 | /** |
111 | * Text window height in CC_MODE_ROLL_UP. The first row of the |
112 | * window is curr_row - window_rows + 1, the last row is |
113 | * curr_row. |
114 | * |
115 | * Note: curr_row - window_rows + 1 may be < FIRST_ROW, this |
116 | * must be clipped before using window_rows: |
117 | * |
118 | * actual_rows = MIN (curr_row - FIRST_ROW + 1, window_rows); |
119 | * |
120 | * We won't do that at the RUx command because usually a PAC |
121 | * follows which may change curr_row. |
122 | */ |
123 | unsigned int window_rows; |
124 | |
125 | /* Most recently received PAC command. */ |
126 | unsigned int last_pac; |
127 | |
128 | /** |
129 | * This variable counts successive transmissions of the |
130 | * letters A to Z. It is reset to zero on reception of any |
131 | * letter a to z. |
132 | * |
133 | * Some stations do not transmit EIA 608-B extended characters |
134 | * and except for N with tilde the standard and special |
135 | * character sets contain only lower case accented |
136 | * characters. We force these characters to upper case if this |
137 | * variable indicates live caption, which is usually all upper |
138 | * case. |
139 | */ |
140 | unsigned int uppercase_predictor; |
141 | |
142 | /** Current caption mode or CC_MODE_UNKNOWN. */ |
143 | enum cc_mode mode; |
144 | |
145 | /** |
146 | * The time when we last received data for this |
147 | * channel. Intended to detect if this caption channel is |
148 | * active. |
149 | */ |
150 | struct cc_timestamp timestamp; |
151 | |
152 | /** |
153 | * The time when we received the first (but not necessarily |
154 | * leftmost) character in the current row. Unless the mode is |
155 | * CC_MODE_POP_ON the next stream event will carry this |
156 | * timestamp. |
157 | */ |
158 | struct cc_timestamp timestamp_c0; |
159 | }; |
160 | |
161 | struct cc_decoder { |
162 | /** |
163 | * Decoder state. We decode all channels in parallel, this way |
164 | * clients can switch between channels without data loss, or |
165 | * capture multiple channels with a single decoder instance. |
166 | * |
167 | * Also 47 CFR 15.119 and EIA 608-C require us to remember the |
168 | * cursor position on each channel. |
169 | */ |
170 | struct cc_channel channel[MAX_CC_CHANNELS]; |
171 | |
172 | /** |
173 | * Current channel, switched by caption control codes. Can be |
174 | * one of @c VBI_CAPTION_CC1 ... @c VBI_CAPTION_CC4 or @c |
175 | * VBI_CAPTION_T1 ... @c VBI_CAPTION_T4 or @c |
176 | * UNKNOWN_CC_CHANNEL if no channel number was received yet. |
177 | */ |
178 | vbi_pgno curr_ch_num[MAX_FIELDS]; |
179 | |
180 | /** |
181 | * Caption control codes (two bytes) may repeat once for error |
182 | * correction. -1 if no repeated control code can be expected. |
183 | */ |
184 | int expect_ctrl[MAX_FIELDS][2]; |
185 | |
186 | /** Receiving XDS data, as opposed to caption / ITV data. */ |
187 | vbi_bool in_xds[MAX_FIELDS]; |
188 | |
189 | /** |
190 | * Pointer into the channel[] array if a display update event |
191 | * shall be sent at the end of this iteration, %c NULL |
192 | * otherwise. Purpose is to suppress an event for the first of |
193 | * two displayable characters in a caption byte pair. |
194 | */ |
195 | struct cc_channel * event_pending; |
196 | |
197 | /** |
198 | * Remembers past parity errors: One bit for each call of |
199 | * cc_feed(), most recent result in lsb. The idea is to |
200 | * disable the decoder if we detect too many errors. |
201 | */ |
202 | unsigned int error_history; |
203 | |
204 | /** |
205 | * The time when we last received data, including NUL bytes. |
206 | * Intended to detect if the station transmits any data on |
207 | * line 21 or 284 at all. |
208 | */ |
209 | struct cc_timestamp timestamp; |
210 | }; |
211 | |
212 | /* CEA 708-C decoder. */ |
213 | |
214 | enum justify { |
215 | JUSTIFY_LEFT = 0, |
216 | JUSTIFY_RIGHT, |
217 | JUSTIFY_CENTER, |
218 | JUSTIFY_FULL |
219 | }; |
220 | |
221 | enum direction { |
222 | DIR_LEFT_RIGHT = 0, |
223 | DIR_RIGHT_LEFT, |
224 | DIR_TOP_BOTTOM, |
225 | DIR_BOTTOM_TOP |
226 | }; |
227 | |
228 | enum display_effect { |
229 | DISPLAY_EFFECT_SNAP = 0, |
230 | DISPLAY_EFFECT_FADE, |
231 | DISPLAY_EFFECT_WIPE |
232 | }; |
233 | |
234 | enum opacity { |
235 | OPACITY_SOLID = 0, |
236 | OPACITY_FLASH, |
237 | OPACITY_TRANSLUCENT, |
238 | OPACITY_TRANSPARENT |
239 | }; |
240 | |
241 | enum edge { |
242 | EDGE_NONE = 0, |
243 | EDGE_RAISED, |
244 | EDGE_DEPRESSED, |
245 | EDGE_UNIFORM, |
246 | EDGE_SHADOW_LEFT, |
247 | EDGE_SHADOW_RIGHT |
248 | }; |
249 | |
250 | enum pen_size { |
251 | PEN_SIZE_SMALL = 0, |
252 | PEN_SIZE_STANDARD, |
253 | PEN_SIZE_LARGE |
254 | }; |
255 | |
256 | enum font_style { |
257 | FONT_STYLE_DEFAULT = 0, |
258 | FONT_STYLE_MONO_SERIF, |
259 | FONT_STYLE_PROP_SERIF, |
260 | FONT_STYLE_MONO_SANS, |
261 | FONT_STYLE_PROP_SANS, |
262 | FONT_STYLE_CASUAL, |
263 | FONT_STYLE_CURSIVE, |
264 | FONT_STYLE_SMALL_CAPS |
265 | }; |
266 | |
267 | enum text_tag { |
268 | TEXT_TAG_DIALOG = 0, |
269 | TEXT_TAG_SOURCE_ID, |
270 | TEXT_TAG_DEVICE, |
271 | TEXT_TAG_DIALOG_2, |
272 | TEXT_TAG_VOICEOVER, |
273 | TEXT_TAG_AUDIBLE_TRANSL, |
274 | TEXT_TAG_SUBTITLE_TRANSL, |
275 | TEXT_TAG_VOICE_DESCR, |
276 | TEXT_TAG_LYRICS, |
277 | TEXT_TAG_EFFECT_DESCR, |
278 | TEXT_TAG_SCORE_DESCR, |
279 | TEXT_TAG_EXPLETIVE, |
280 | TEXT_TAG_NOT_DISPLAYABLE = 15 |
281 | }; |
282 | |
283 | enum offset { |
284 | OFFSET_SUBSCRIPT = 0, |
285 | OFFSET_NORMAL, |
286 | OFFSET_SUPERSCRIPT |
287 | }; |
288 | |
289 | /* RGB 2:2:2 (lsb = B). */ |
290 | typedef uint8_t dtvcc_color; |
291 | |
292 | /* Lsb = window 0, msb = window 7. */ |
293 | typedef uint8_t dtvcc_window_map; |
294 | |
295 | struct dtvcc_pen_style { |
296 | enum pen_size pen_size; |
297 | enum font_style font_style; |
298 | enum offset offset; |
299 | vbi_bool italics; |
300 | vbi_bool underline; |
301 | |
302 | enum edge edge_type; |
303 | |
304 | dtvcc_color fg_color; |
305 | enum opacity fg_opacity; |
306 | |
307 | dtvcc_color bg_color; |
308 | enum opacity bg_opacity; |
309 | |
310 | dtvcc_color edge_color; |
311 | vbi_bool fg_flash; |
312 | vbi_bool bg_flash; |
313 | }; |
314 | |
315 | struct dtvcc_pen { |
316 | enum text_tag text_tag; |
317 | struct dtvcc_pen_style style; |
318 | }; |
319 | |
320 | struct dtvcc_window_style { |
321 | enum justify justify; |
322 | enum direction print_direction; |
323 | enum direction scroll_direction; |
324 | vbi_bool wordwrap; |
325 | |
326 | enum display_effect display_effect; |
327 | enum direction effect_direction; |
328 | unsigned int effect_speed; /* 1/10 sec */ |
329 | |
330 | dtvcc_color fill_color; |
331 | enum opacity fill_opacity; |
332 | vbi_bool window_flash; |
333 | |
334 | enum edge border_type; |
335 | dtvcc_color border_color; |
336 | }; |
337 | |
338 | struct dtvcc_window { |
339 | /* EIA 708-C window state. */ |
340 | |
341 | uint16_t buffer[16][42]; |
342 | struct dtvcc_pen_style pen[16][42]; |
343 | int row_start[16]; |
344 | |
345 | vbi_bool visible; |
346 | |
347 | /* 0 = highest ... 7 = lowest. */ |
348 | unsigned int priority; |
349 | |
350 | unsigned int anchor_point; |
351 | unsigned int anchor_horizontal; |
352 | unsigned int anchor_vertical; |
353 | vbi_bool anchor_relative; |
354 | |
355 | unsigned int row_count; |
356 | unsigned int column_count; |
357 | |
358 | vbi_bool row_lock; |
359 | vbi_bool column_lock; |
360 | |
361 | unsigned int curr_row; |
362 | unsigned int curr_column; |
363 | |
364 | struct dtvcc_pen curr_pen; |
365 | |
366 | struct dtvcc_window_style style; |
367 | |
368 | /* Our stuff. */ |
369 | |
370 | /** |
371 | * If bit 1 << row is set we already sent a stream event for |
372 | * this row. |
373 | */ |
374 | unsigned int streamed; |
375 | |
376 | /** |
377 | * The time when we received the first (but not necessarily |
378 | * leftmost) character in the current row. Unless a |
379 | * DisplayWindow or ToggleWindow command completed the line |
380 | * the next stream event will carry this timestamp. |
381 | */ |
382 | struct cc_timestamp timestamp_c0; |
383 | }; |
384 | |
385 | struct dtvcc_service { |
386 | /* Interpretation Layer. */ |
387 | |
388 | struct dtvcc_window window[8]; |
389 | struct dtvcc_window old_window[8]; |
390 | |
391 | int old_win_cnt; |
392 | int update; |
393 | |
394 | struct dtvcc_window * curr_window; |
395 | |
396 | dtvcc_window_map created; |
397 | |
398 | /* For debugging. */ |
399 | unsigned int error_line; |
400 | |
401 | /* Service Layer. */ |
402 | |
403 | uint8_t service_data[128]; |
404 | unsigned int service_data_in; |
405 | /* For 0x8D 0x8E delay command |
406 | if delay flag is set, decoder stop decoding |
407 | */ |
408 | struct timespec delay_timer; |
409 | int delay; |
410 | int delay_cancel; |
411 | |
412 | /** The time when we last received data for this service. */ |
413 | struct cc_timestamp timestamp; |
414 | }; |
415 | |
416 | struct dtvcc_decoder { |
417 | struct dtvcc_service service[6]; |
418 | |
419 | /* Packet Layer. */ |
420 | |
421 | uint8_t packet[128]; |
422 | unsigned int packet_size; |
423 | |
424 | /* Next expected DTVCC packet sequence_number. Only the two |
425 | most significant bits are valid. < 0 if no sequence_number |
426 | has been received yet. */ |
427 | int next_sequence_number; |
428 | |
429 | /** The time when we last received data. */ |
430 | struct cc_timestamp timestamp; |
431 | }; |
432 | |
433 | /* ATSC A/53 Part 4:2007 Closed Caption Data decoder. */ |
434 | |
435 | enum cc_type { |
436 | NTSC_F1 = 0, |
437 | NTSC_F2 = 1, |
438 | DTVCC_DATA = 2, |
439 | DTVCC_START = 3, |
440 | }; |
441 | |
442 | struct cc_data_decoder { |
443 | /* Test tap. */ |
444 | const char * option_cc_data_tap_file_name; |
445 | |
446 | FILE * cc_data_tap_fp; |
447 | |
448 | /* For debugging. */ |
449 | int64_t last_pts; |
450 | }; |
451 | |
452 | /* Caption recorder. */ |
453 | |
454 | enum cc_attr { |
455 | VBI_UNDERLINE = (1 << 0), |
456 | VBI_ITALIC = (1 << 2), |
457 | VBI_FLASH = (1 << 3) |
458 | }; |
459 | |
460 | struct cc_pen { |
461 | uint8_t attr; |
462 | |
463 | uint8_t fg_color; |
464 | uint8_t fg_opacity; |
465 | |
466 | uint8_t bg_color; |
467 | uint8_t bg_opacity; |
468 | |
469 | uint8_t edge_type; |
470 | uint8_t edge_color; |
471 | uint8_t edge_opacity; |
472 | |
473 | uint8_t pen_size; |
474 | uint8_t font_style; |
475 | |
476 | uint8_t reserved[6]; |
477 | }; |
478 | |
479 | enum caption_format { |
480 | FORMAT_PLAIN, |
481 | FORMAT_VT100, |
482 | FORMAT_NTSC_CC |
483 | }; |
484 | |
485 | struct tvcc_decoder { |
486 | pthread_mutex_t mutex; |
487 | struct vbi_decoder *vbi; |
488 | struct cc_decoder cc; |
489 | struct dtvcc_decoder dtvcc; |
490 | }; |
491 | unsigned int dtvcc_unicode (unsigned int c); |
492 | |
493 | extern void tvcc_init(struct tvcc_decoder *td); |
494 | |
495 | extern void tvcc_decode_data(struct tvcc_decoder *td, int64_t pts, const uint8_t *buf, unsigned int n_bytes); |
496 | |
497 | extern void tvcc_reset(struct tvcc_decoder *td); |
498 | |
499 | extern void tvcc_destroy(struct tvcc_decoder *td); |
500 | |
501 | extern void tvcc_fetch_page(struct tvcc_decoder *td, int pgno, int *cnt, struct vbi_page *sub_pages); |
502 | |
503 | static void dtvcc_init(struct dtvcc_decoder * dc); |
504 | |
505 | extern void dtvcc_decode_packet(struct dtvcc_decoder *dc, const struct timeval *tv, int64_t pts); |
506 | |
507 | extern void dtvcc_reset(struct dtvcc_decoder * dc); |
508 | |
509 | extern void cc_init(struct cc_decoder *cd); |
510 | |
511 | extern vbi_bool cc_feed(struct cc_decoder *cd, const uint8_t buffer[2], unsigned int line, const struct timeval * tv, int64_t pts); |
512 | |
513 | extern void cc_reset(struct cc_decoder *cd); |
514 | |
515 | extern void vbi_decode_caption(vbi_decoder *vbi, int line, const uint8_t *buf); |
516 | |
517 | extern int get_input_offset(); |
518 | |
519 | #endif |
520 | |
521 |