1 /*
2 * atsc-cc -- ATSC Closed Caption decoder
3 *
4 * Copyright (C) 2008 Michael H. Schimek <mschimek@users.sf.net>
5 *
6 * Contains code from zvbi-ntsc-cc closed caption decoder written by
7 * <timecop@japan.co.jp>, Mike Baker <mbm@linux.com>,
8 * Mark K. Kim <dev@cbreak.org>.
9 *
10 * Thanks to Karol Zapolski for his support.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 * MA 02110-1301, USA.
26 */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #define _GNU_SOURCE 1
33
34
35 #include <assert.h>
36 #include <ctype.h>
37 #include <dirent.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <inttypes.h>
41 #include <limits.h>
42 #include <locale.h>
43 #include <malloc.h>
44 #include <math.h>
45 #include <pthread.h>
46 #include <signal.h>
47 #include <stdarg.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <sys/ioctl.h>
52 #include <sys/mman.h>
53 #include <sys/stat.h>
54 #include <sys/statvfs.h>
55 #include <sys/wait.h>
56 #include <time.h>
57 #include <unistd.h>
58
59 #ifdef HAVE_GETOPT_LONG
60 # include <getopt.h>
61 #endif
62
63 #include "src/libzvbi.h"
64
65 /* Linux DVB driver interface. */
66 #include "src/dvb/dmx.h"
67 #include "src/dvb/frontend.h"
68
69 #undef PROGRAM
70 #define PROGRAM "ATSC-CC"
71 #undef VERSION
72 #define VERSION "0.5"
73
74 #if __GNUC__ < 3
75 # define likely(expr) (expr)
76 # define unlikely(expr) (expr)
77 #else
78 # define likely(expr) __builtin_expect(expr, 1)
79 # define unlikely(expr) __builtin_expect(expr, 0)
80 #endif
81
82 #define N_ELEMENTS(array) (sizeof (array) / sizeof ((array)[0]))
83 #define CLEAR(var) memset (&(var), 0, sizeof (var))
84
85 /* FIXME __typeof__ is a GCC extension. */
86 #undef SWAP
87 #define SWAP(x, y) \
88 do { \
89 __typeof__ (x) _x = x; \
90 x = y; \
91 y = _x; \
92 } while (0)
93
94 #undef MIN
95 #define MIN(x, y) ({ \
96 __typeof__ (x) _x = (x); \
97 __typeof__ (y) _y = (y); \
98 (void)(&_x == &_y); /* warn if types do not match */ \
99 /* return */ (_x < _y) ? _x : _y; \
100 })
101
102 #undef MAX
103 #define MAX(x, y) ({ \
104 __typeof__ (x) _x = (x); \
105 __typeof__ (y) _y = (y); \
106 (void)(&_x == &_y); /* warn if types do not match */ \
107 /* return */ (_x > _y) ? _x : _y; \
108 })
109
110 #undef PARENT
111 #define PARENT(_ptr, _type, _member) ({ \
112 __typeof__ (&((_type *) 0)->_member) _p = (_ptr); \
113 (_p != 0) ? (_type *)(((char *) _p) - offsetof (_type, \
114 _member)) : (_type *) 0; \
115 })
116
117 /* These should be defined in inttypes.h. */
118 #ifndef PRId64
119 # define PRId64 "lld"
120 #endif
121 #ifndef PRIu64
122 # define PRIu64 "llu"
123 #endif
124 #ifndef PRIx64
125 # define PRIx64 "llx"
126 #endif
127
128 /* EIA 608-B decoder. */
129
130 enum field_num {
131 FIELD_1 = 0,
132 FIELD_2,
133 MAX_FIELDS
134 };
135
136 enum cc_mode {
137 CC_MODE_UNKNOWN,
138 CC_MODE_ROLL_UP,
139 CC_MODE_POP_ON,
140 CC_MODE_PAINT_ON,
141 CC_MODE_TEXT
142 };
143
144 /* EIA 608-B Section 4.1. */
145 #define VBI_CAPTION_CC1 1 /* primary synchronous caption service (F1) */
146 #define VBI_CAPTION_CC2 2 /* special non-synchronous use captions (F1) */
147 #define VBI_CAPTION_CC3 3 /* secondary synchronous caption service (F2) */
148 #define VBI_CAPTION_CC4 4 /* special non-synchronous use captions (F2) */
149
150 #define VBI_CAPTION_T1 5 /* first text service (F1) */
151 #define VBI_CAPTION_T2 6 /* second text service (F1) */
152 #define VBI_CAPTION_T3 7 /* third text service (F2) */
153 #define VBI_CAPTION_T4 8 /* fourth text service (F2) */
154
155 #define UNKNOWN_CC_CHANNEL 0
156 #define MAX_CC_CHANNELS 8
157
158 /* 47 CFR 15.119 (d) Screen format. */
159 #define CC_FIRST_ROW 0
160 #define CC_LAST_ROW 14
161 #define CC_MAX_ROWS 15
162
163 #define CC_FIRST_COLUMN 1
164 #define CC_LAST_COLUMN 32
165 #define CC_MAX_COLUMNS 32
166
167 #define CC_ALL_ROWS_MASK ((1 << CC_MAX_ROWS) - 1)
168
169 #define VBI_TRANSLUCENT VBI_SEMI_TRANSPARENT
170
171 struct cc_timestamp {
172 /* System time when the event occured, zero if no event
173 occured yet. */
174 struct timeval sys;
175
176 /* Presentation time stamp of the event. Only the 33 least
177 significant bits are valid. < 0 if no event occured yet. */
178 int64_t pts;
179 };
180
181 struct cc_channel {
182 /**
183 * [0] and [1] are the displayed and non-displayed buffer as
184 * defined in 47 CFR 15.119, and selected by displayed_buffer
185 * below. [2] is a snapshot of the displayed buffer at the
186 * last stream event.
187 *
188 * XXX Text channels don't need buffer[2] and buffer[3], we're
189 * wasting memory.
190 */
191 uint16_t buffer[3][CC_MAX_ROWS][1 + CC_MAX_COLUMNS];
192
193 /**
194 * For buffer[0 ... 2], if bit 1 << row is set this row
195 * contains displayable characters, spacing or non-spacing
196 * attributes. (Special character 0x1139 "transparent space"
197 * is not a displayable character.) This information is
198 * intended to speed up copying, erasing and formatting.
199 */
200 unsigned int dirty[3];
201
202 /** Index of displayed buffer, 0 or 1. */
203 unsigned int displayed_buffer;
204
205 /**
206 * Cursor position: FIRST_ROW ... LAST_ROW and
207 * FIRST_COLUMN ... LAST_COLUMN.
208 */
209 unsigned int curr_row;
210 unsigned int curr_column;
211
212 /**
213 * Text window height in CC_MODE_ROLL_UP. The first row of the
214 * window is curr_row - window_rows + 1, the last row is
215 * curr_row.
216 *
217 * Note: curr_row - window_rows + 1 may be < FIRST_ROW, this
218 * must be clipped before using window_rows:
219 *
220 * actual_rows = MIN (curr_row - FIRST_ROW + 1, window_rows);
221 *
222 * We won't do that at the RUx command because usually a PAC
223 * follows which may change curr_row.
224 */
225 unsigned int window_rows;
226
227 /* Most recently received PAC command. */
228 unsigned int last_pac;
229
230 /**
231 * This variable counts successive transmissions of the
232 * letters A to Z. It is reset to zero on reception of any
233 * letter a to z.
234 *
235 * Some stations do not transmit EIA 608-B extended characters
236 * and except for N with tilde the standard and special
237 * character sets contain only lower case accented
238 * characters. We force these characters to upper case if this
239 * variable indicates live caption, which is usually all upper
240 * case.
241 */
242 unsigned int uppercase_predictor;
243
244 /** Current caption mode or CC_MODE_UNKNOWN. */
245 enum cc_mode mode;
246
247 /**
248 * The time when we last received data for this
249 * channel. Intended to detect if this caption channel is
250 * active.
251 */
252 struct cc_timestamp timestamp;
253
254 /**
255 * The time when we received the first (but not necessarily
256 * leftmost) character in the current row. Unless the mode is
257 * CC_MODE_POP_ON the next stream event will carry this
258 * timestamp.
259 */
260 struct cc_timestamp timestamp_c0;
261 };
262
263 struct cc_decoder {
264 /**
265 * Decoder state. We decode all channels in parallel, this way
266 * clients can switch between channels without data loss, or
267 * capture multiple channels with a single decoder instance.
268 *
269 * Also 47 CFR 15.119 and EIA 608-C require us to remember the
270 * cursor position on each channel.
271 */
272 struct cc_channel channel[MAX_CC_CHANNELS];
273
274 /**
275 * Current channel, switched by caption control codes. Can be
276 * one of @c VBI_CAPTION_CC1 ... @c VBI_CAPTION_CC4 or @c
277 * VBI_CAPTION_T1 ... @c VBI_CAPTION_T4 or @c
278 * UNKNOWN_CC_CHANNEL if no channel number was received yet.
279 */
280 vbi_pgno curr_ch_num[MAX_FIELDS];
281
282 /**
283 * Caption control codes (two bytes) may repeat once for error
284 * correction. -1 if no repeated control code can be expected.
285 */
286 int expect_ctrl[MAX_FIELDS][2];
287
288 /** Receiving XDS data, as opposed to caption / ITV data. */
289 vbi_bool in_xds[MAX_FIELDS];
290
291 /**
292 * Pointer into the channel[] array if a display update event
293 * shall be sent at the end of this iteration, %c NULL
294 * otherwise. Purpose is to suppress an event for the first of
295 * two displayable characters in a caption byte pair.
296 */
297 struct cc_channel * event_pending;
298
299 /**
300 * Remembers past parity errors: One bit for each call of
301 * cc_feed(), most recent result in lsb. The idea is to
302 * disable the decoder if we detect too many errors.
303 */
304 unsigned int error_history;
305
306 /**
307 * The time when we last received data, including NUL bytes.
308 * Intended to detect if the station transmits any data on
309 * line 21 or 284 at all.
310 */
311 struct cc_timestamp timestamp;
312 };
313
314 /* CEA 708-C decoder. */
315
316 enum justify {
317 JUSTIFY_LEFT = 0,
318 JUSTIFY_RIGHT,
319 JUSTIFY_CENTER,
320 JUSTIFY_FULL
321 };
322
323 enum direction {
324 DIR_LEFT_RIGHT = 0,
325 DIR_RIGHT_LEFT,
326 DIR_TOP_BOTTOM,
327 DIR_BOTTOM_TOP
328 };
329
330 enum display_effect {
331 DISPLAY_EFFECT_SNAP = 0,
332 DISPLAY_EFFECT_FADE,
333 DISPLAY_EFFECT_WIPE
334 };
335
336 enum opacity {
337 OPACITY_SOLID = 0,
338 OPACITY_FLASH,
339 OPACITY_TRANSLUCENT,
340 OPACITY_TRANSPARENT
341 };
342
343 enum edge {
344 EDGE_NONE = 0,
345 EDGE_RAISED,
346 EDGE_DEPRESSED,
347 EDGE_UNIFORM,
348 EDGE_SHADOW_LEFT,
349 EDGE_SHADOW_RIGHT
350 };
351
352 enum pen_size {
353 PEN_SIZE_SMALL = 0,
354 PEN_SIZE_STANDARD,
355 PEN_SIZE_LARGE
356 };
357
358 enum font_style {
359 FONT_STYLE_DEFAULT = 0,
360 FONT_STYLE_MONO_SERIF,
361 FONT_STYLE_PROP_SERIF,
362 FONT_STYLE_MONO_SANS,
363 FONT_STYLE_PROP_SANS,
364 FONT_STYLE_CASUAL,
365 FONT_STYLE_CURSIVE,
366 FONT_STYLE_SMALL_CAPS
367 };
368
369 enum text_tag {
370 TEXT_TAG_DIALOG = 0,
371 TEXT_TAG_SOURCE_ID,
372 TEXT_TAG_DEVICE,
373 TEXT_TAG_DIALOG_2,
374 TEXT_TAG_VOICEOVER,
375 TEXT_TAG_AUDIBLE_TRANSL,
376 TEXT_TAG_SUBTITLE_TRANSL,
377 TEXT_TAG_VOICE_DESCR,
378 TEXT_TAG_LYRICS,
379 TEXT_TAG_EFFECT_DESCR,
380 TEXT_TAG_SCORE_DESCR,
381 TEXT_TAG_EXPLETIVE,
382 TEXT_TAG_NOT_DISPLAYABLE = 15
383 };
384
385 enum offset {
386 OFFSET_SUBSCRIPT = 0,
387 OFFSET_NORMAL,
388 OFFSET_SUPERSCRIPT
389 };
390
391 /* RGB 2:2:2 (lsb = B). */
392 typedef uint8_t dtvcc_color;
393
394 /* Lsb = window 0, msb = window 7. */
395 typedef uint8_t dtvcc_window_map;
396
397 struct dtvcc_pen_style {
398 enum pen_size pen_size;
399 enum font_style font_style;
400 enum offset offset;
401 vbi_bool italics;
402 vbi_bool underline;
403
404 enum edge edge_type;
405
406 dtvcc_color fg_color;
407 enum opacity fg_opacity;
408
409 dtvcc_color bg_color;
410 enum opacity bg_opacity;
411
412 dtvcc_color edge_color;
413 };
414
415 struct dtvcc_pen {
416 enum text_tag text_tag;
417 struct dtvcc_pen_style style;
418 };
419
420 struct dtvcc_window_style {
421 enum justify justify;
422 enum direction print_direction;
423 enum direction scroll_direction;
424 vbi_bool wordwrap;
425
426 enum display_effect display_effect;
427 enum direction effect_direction;
428 unsigned int effect_speed; /* 1/10 sec */
429
430 dtvcc_color fill_color;
431 enum opacity fill_opacity;
432
433 enum edge border_type;
434 dtvcc_color border_color;
435 };
436
437 struct dtvcc_window {
438 /* EIA 708-C window state. */
439
440 uint16_t buffer[16][42];
441
442 vbi_bool visible;
443
444 /* 0 = highest ... 7 = lowest. */
445 unsigned int priority;
446
447 unsigned int anchor_point;
448 unsigned int anchor_horizontal;
449 unsigned int anchor_vertical;
450 vbi_bool anchor_relative;
451
452 unsigned int row_count;
453 unsigned int column_count;
454
455 vbi_bool row_lock;
456 vbi_bool column_lock;
457
458 unsigned int curr_row;
459 unsigned int curr_column;
460
461 struct dtvcc_pen curr_pen;
462
463 struct dtvcc_window_style style;
464
465 /* Our stuff. */
466
467 /**
468 * If bit 1 << row is set we already sent a stream event for
469 * this row.
470 */
471 unsigned int streamed;
472
473 /**
474 * The time when we received the first (but not necessarily
475 * leftmost) character in the current row. Unless a
476 * DisplayWindow or ToggleWindow command completed the line
477 * the next stream event will carry this timestamp.
478 */
479 struct cc_timestamp timestamp_c0;
480 };
481
482 struct dtvcc_service {
483 /* Interpretation Layer. */
484
485 struct dtvcc_window window[8];
486
487 struct dtvcc_window * curr_window;
488
489 dtvcc_window_map created;
490
491 /* For debugging. */
492 unsigned int error_line;
493
494 /* Service Layer. */
495
496 uint8_t service_data[128];
497 unsigned int service_data_in;
498
499 /** The time when we last received data for this service. */
500 struct cc_timestamp timestamp;
501 };
502
503 struct dtvcc_decoder {
504 struct dtvcc_service service[2];
505
506 /* Packet Layer. */
507
508 uint8_t packet[128];
509 unsigned int packet_size;
510
511 /* Next expected DTVCC packet sequence_number. Only the two
512 most significant bits are valid. < 0 if no sequence_number
513 has been received yet. */
514 int next_sequence_number;
515
516 /** The time when we last received data. */
517 struct cc_timestamp timestamp;
518 };
519
520 /* ATSC A/53 Part 4:2007 Closed Caption Data decoder. */
521
522 enum cc_type {
523 NTSC_F1 = 0,
524 NTSC_F2 = 1,
525 DTVCC_DATA = 2,
526 DTVCC_START = 3,
527 };
528
529 struct cc_data_decoder {
530 /* Test tap. */
531 const char * option_cc_data_tap_file_name;
532
533 FILE * cc_data_tap_fp;
534
535 /* For debugging. */
536 int64_t last_pts;
537 };
538
539 /* Caption recorder. */
540
541 enum cc_attr {
542 VBI_UNDERLINE = (1 << 0),
543 VBI_ITALIC = (1 << 2),
544 VBI_FLASH = (1 << 3)
545 };
546
547 struct cc_pen {
548 uint8_t attr;
549
550 uint8_t fg_color;
551 uint8_t fg_opacity;
552
553 uint8_t bg_color;
554 uint8_t bg_opacity;
555
556 uint8_t edge_type;
557 uint8_t edge_color;
558 uint8_t edge_opacity;
559
560 uint8_t pen_size;
561 uint8_t font_style;
562
563 uint8_t reserved[6];
564 };
565
566 enum caption_format {
567 FORMAT_PLAIN,
568 FORMAT_VT100,
569 FORMAT_NTSC_CC
570 };
571
572 struct caption_recorder {
573 /* Caption stream filter:
574 NTSC CC1 ... CC4 (1 << 0 ... 1 << 3),
575 NTSC T1 ... T4 (1 << 4 ... 1 << 7),
576 ATSC Service 1 ... 2 (1 << 8 ... 1 << 9). */
577 unsigned int option_caption_mask;
578
579 /* Output file name for caption stream. */
580 const char * option_caption_file_name[10];
581
582 /* Output file name for XDS data. */
583 const char * option_xds_output_file_name;
584
585 vbi_bool option_caption_timestamps;
586
587 enum caption_format option_caption_format;
588
589 /* old options */
590 char usexds;
591 char usecc;
592 char usesen;
593 char usewebtv;
594
595 struct cc_data_decoder ccd;
596
597 struct cc_decoder cc;
598
599 struct dtvcc_decoder dtvcc;
600
601 //XDSdecode
602 unsigned int field;
603 struct {
604 char packet[34];
605 uint8_t length;
606 int print : 1;
607 } info[2][8][25];
608 char newinfo[2][8][25][34];
609 char *infoptr;
610 int mode,type;
611 char infochecksum;
612 const char * xds_info_prefix;
613 const char * xds_info_suffix;
614 FILE * xds_fp;
615
616 uint16_t * ucs_buffer;
617 unsigned int ucs_buffer_length;
618 unsigned int ucs_buffer_capacity;
619
620 FILE * caption_fp[10];
621
622 int minicut_min[10];
623 };
624
625 /* Video recorder. */
626
627 enum start_code {
628 PICTURE_START_CODE = 0x00,
629 /* 0x01 ... 0xAF slice_start_code */
630 /* 0xB0 reserved */
631 /* 0xB1 reserved */
632 USER_DATA_START_CODE = 0xB2,
633 SEQUENCE_HEADER_CODE = 0xB3,
634 SEQUENCE_ERROR_CODE = 0xB4,
635 EXTENSION_START_CODE = 0xB5,
636 /* 0xB6 reserved */
637 SEQUENCE_END_CODE = 0xB7,
638 GROUP_START_CODE = 0xB8,
639 /* 0xB9 ... 0xFF system start codes */
640 PRIVATE_STREAM_1 = 0xBD,
641 PADDING_STREAM = 0xBE,
642 PRIVATE_STREAM_2 = 0xBF,
643 AUDIO_STREAM_0 = 0xC0,
644 AUDIO_STREAM_31 = 0xDF,
645 VIDEO_STREAM_0 = 0xE0,
646 VIDEO_STREAM_15 = 0xEF,
647 };
648
649 enum extension_start_code_identifier {
650 /* 0x0 reserved */
651 SEQUENCE_EXTENSION_ID = 0x1,
652 SEQUENCE_DISPLAY_EXTENSION_ID = 0x2,
653 QUANT_MATRIX_EXTENSION_ID = 0x3,
654 COPYRIGHT_EXTENSION_ID = 0x4,
655 SEQUENCE_SCALABLE_EXTENSION_ID = 0x5,
656 /* 0x6 reserved */
657 PICTURE_DISPLAY_EXTENSION_ID = 0x7,
658 PICTURE_CODING_EXTENSION_ID = 0x8,
659 PICTURE_SPATIAL_SCALABLE_EXTENSION_ID = 0x9,
660 PICTURE_TEMPORAL_SCALABLE_EXTENSION_ID = 0xA,
661 /* 0xB ... 0xF reserved */
662 };
663
664 enum picture_coding_type {
665 /* 0 forbidden */
666 I_TYPE = 1,
667 P_TYPE = 2,
668 B_TYPE = 3,
669 D_TYPE = 4,
670 /* 5 ... 7 reserved */
671 };
672
673 enum picture_structure {
674 /* 0 reserved */
675 TOP_FIELD = 1,
676 BOTTOM_FIELD = 2,
677 FRAME_PICTURE = 3
678 };
679
680 /* PTSs and DTSs are 33 bits wide. */
681 #define TIMESTAMP_MASK (((int64_t) 1 << 33) - 1)
682
683 struct packet {
684 /* Offset in bytes from the buffer start. */
685 unsigned int offset;
686
687 /* Packet and payload size in bytes. */
688 unsigned int size;
689 unsigned int payload;
690
691 /* Decoding and presentation time stamp and display duration
692 of this packet. */
693 int64_t dts;
694 int64_t pts;
695 int64_t duration;
696
697 /* Cut the stream at this packet. */
698 vbi_bool splice;
699
700 /* Data is missing before this packet but the producer will
701 correct that later. */
702 vbi_bool data_lost;
703 };
704
705 struct buffer {
706 uint8_t * base;
707
708 /* Capacity of the buffer in bytes. */
709 unsigned int capacity;
710
711 /* Offset in bytes from base where the next data will be
712 stored. */
713 unsigned int in;
714
715 /* Offset in bytes from base where the next data will be
716 removed. */
717 unsigned int out;
718 };
719
720 #define MAX_PACKETS 64
721
722 struct pes_buffer {
723 uint8_t * base;
724
725 /* Capacity of the buffer in bytes. */
726 unsigned int capacity;
727
728 /* Offset in bytes from base where the next data will be stored. */
729 unsigned int in;
730
731 /* Information about the packets in the buffer.
732 packet[0].offset is the offset in bytes from base
733 where the next data will be removed. */
734 struct packet packet[MAX_PACKETS];
735
736 /* Number of packets in the packet[] array. packet[0] must not
737 be removed unless n_packets >= 2. */
738 unsigned int n_packets;
739 };
740
741 struct pes_multiplexer {
742 vbi_bool new_file;
743 unsigned int b_state;
744
745 time_t minicut_end;
746
747 FILE * minicut_fp;
748 };
749
750 struct audio_es_packetizer {
751 /* Test tap. */
752 const char * option_audio_es_tap_file_name;
753 FILE * audio_es_tap_fp;
754
755 struct buffer ac3_buffer;
756 struct pes_buffer pes_buffer;
757
758 /* Number of bytes we want to examine at pes_buffer.in. */
759 unsigned int need;
760
761 /* Estimated PTS of the next/current AC3 frame (pts or
762 pes_packet_pts plus previous frame duration), -1 if no PTS
763 was received yet. */
764 int64_t pts;
765
766 /* Next/current AC3 frame is the first received frame. */
767 vbi_bool first_frame;
768
769 /* Data may have been lost between the previous and
770 next/current AC3 frame. */
771 vbi_bool data_lost;
772
773 uint64_t pes_audio_bit_rate;
774 };
775
776 struct video_es_packetizer {
777 struct pes_buffer pes_buffer;
778 int sequence_header_offset;
779 unsigned int packet_filled;
780 uint8_t pes_packet_header_6;
781 uint64_t pes_video_bit_rate;
782 vbi_bool aligned;
783 };
784
785 struct audio_pes_decoder {
786 struct buffer buffer;
787
788 unsigned int need;
789 unsigned int look_ahead;
790 };
791
792 struct video_recorder {
793 struct audio_pes_decoder apesd;
794
795 struct video_es_packetizer vesp;
796
797 struct audio_es_packetizer aesp;
798
799 struct pes_multiplexer pm;
800
801 /* TS recorder */
802
803 unsigned int pat_cc;
804 unsigned int pmt_cc;
805
806 time_t minicut_end;
807 FILE * minicut_fp;
808 };
809
810 enum received_blocks {
811 RECEIVED_PES_PACKET = (1 << 0),
812 RECEIVED_PICTURE = (1 << 1),
813 RECEIVED_PICTURE_EXT = (1 << 2),
814 RECEIVED_MPEG_CC_DATA = (1 << 3)
815 };
816
817 struct video_es_decoder {
818 /* Test tap. */
819 const char * option_video_es_all_tap_file_name;
820 const char * option_video_es_tap_file_name;
821
822 FILE * video_es_tap_fp;
823
824 /* Video elementary stream buffer. */
825 struct buffer buffer;
826
827 unsigned int min_bytes_valid;
828
829 /* Number of bytes after buffer.out which have already
830 been scanned for a start code prefix. */
831 unsigned int skip;
832
833 /* Last received start code, < 0 if none. If valid
834 buffer.out points at the first start code prefix
835 byte. */
836 enum start_code last_start_code;
837
838 /* The decoding and presentation time stamp of the
839 current picture. Only the lowest 33 bits are
840 valid. < 0 if no PTS or DTS was received or the PES
841 packet header was malformed. */
842 int64_t pts;
843 int64_t dts;
844
845 /* For debugging. */
846 uint64_t n_pictures_received;
847
848 /* Parameters of the current picture. */
849 enum picture_coding_type picture_coding_type;
850 enum picture_structure picture_structure;
851 unsigned int picture_temporal_reference;
852
853 /* Set of the data blocks we received so far. */
854 enum received_blocks received_blocks;
855
856 /* Describes the contents of the reorder_buffer[]:
857 Bit 0 - a top field in reorder_buffer[0],
858 Bit 1 - a bottom field in reorder_buffer[1],
859 Bit 2 - a frame in reorder_buffer[0]. Only the
860 combinations 0, 1, 2, 3, 4 are valid. */
861 unsigned int reorder_pictures;
862
863 /* The PTS (as above) of the data in the reorder_buffer. */
864 int64_t reorder_pts[2];
865
866 unsigned int reorder_n_bytes[2];
867
868 /* Buffer to convert picture user data from coded
869 order to display order, for the top and bottom
870 field. Maximum size required: 11 + cc_count * 3,
871 where cc_count = 0 ... 31. */
872 uint8_t reorder_buffer[2][128];
873 };
874
875 struct ts_decoder {
876 /* TS PID of the video [0] and audio [1] stream. */
877 unsigned int pid[2];
878
879 /* Next expected video and audio TS packet continuity
880 counter. Only the lowest four bits are valid. < 0
881 if no continuity counter has been received yet. */
882 int next_ts_cc[2];
883
884 /* One or more TS packets were lost. */
885 vbi_bool data_lost;
886 } tsd;
887
888 struct program {
889 const char * option_station_name;
890
891 /* Convert the captured video and audio data to PES format,
892 cut the stream into one minute long fragments and save them
893 with file name
894 <option_minicut_dir_name>/yyyymmddhh0000/yyyymmddhhmm00.mpg
895 One minute is measured in real time, yyyymmddhhmm is the
896 system time in the UTC zone when the data was received and
897 decoded. */
898 const char * option_minicut_dir_name;
899
900 struct timeval now;
901
902 int64_t first_dts;
903
904 struct ts_decoder tsd;
905
906 struct video_es_decoder vesd;
907
908 struct video_recorder vr;
909
910 struct caption_recorder cr;
911 };
912
913 struct station {
914 struct station * next;
915 char * name;
916 enum fe_type type;
917 unsigned long frequency;
918 unsigned int video_pid;
919 unsigned int audio_pid;
920 union {
921 struct {
922 enum fe_modulation modulation;
923 } atsc;
924 struct {
925 enum fe_spectral_inversion inversion;
926 enum fe_bandwidth bandwidth;
927 enum fe_code_rate code_rate_HP;
928 enum fe_code_rate code_rate_LP;
929 enum fe_modulation constellation;
930 enum fe_transmit_mode transm_mode;
931 enum fe_guard_interval guard_interval;
932 enum fe_hierarchy hierarchy;
933 } dvb_t;
934 } u;
935 };
936
937 enum debug {
938 DEBUG_VESD_START_CODE = (1 << 0),
939 DEBUG_VESD_PES_PACKET = (1 << 1),
940 DEBUG_VESD_PIC_HDR = (1 << 2),
941 DEBUG_VESD_PIC_EXT = (1 << 3),
942 DEBUG_VESD_USER_DATA = (1 << 5),
943 DEBUG_VESD_CC_DATA = (1 << 6),
944 DEBUG_CC_DATA = (1 << 7),
945 DEBUG_CC_F1 = (1 << 8),
946 DEBUG_CC_F2 = (1 << 9),
947 DEBUG_CC_DECODER = (1 << 10),
948 DEBUG_DTVCC_PACKET = (1 << 11),
949 DEBUG_DTVCC_SE = (1 << 12),
950 DEBUG_DTVCC_PUT_CHAR = (1 << 13),
951 DEBUG_DTVCC_STREAM_EVENT = (1 << 14),
952 DEBUG_CONFIG = (1 << 15)
953 };
954
955 enum source {
956 SOURCE_DVB_DEVICE = 1,
957 SOURCE_STDIN_TS,
958
959 /* Not implemented yet. */
960 SOURCE_STDIN_PES,
961
962 /* For tests only. */
963 SOURCE_STDIN_VIDEO_ES,
964 SOURCE_STDIN_CC_DATA
965 };
966
967 static const char * my_name;
968
969 static unsigned int option_verbosity;
970 static unsigned int option_debug;
971
972 /* Input. */
973
974 static enum source option_source;
975
976 /* DVB device. */
977
978 static enum fe_type option_dvb_type;
979 static unsigned long option_dvb_adapter_num;
980 static unsigned long option_dvb_frontend_id;
981 static unsigned long option_dvb_demux_id;
982 static unsigned long option_dvb_dvr_id;
983
984 static const char * option_channel_conf_file_name;
985
986 /* Test taps. */
987 const char * option_ts_all_tap_file_name;
988 const char * option_ts_tap_file_name;
989
990 static vbi_bool option_minicut_test;
991
992 static const char * locale_codeset;
993
994 /* DVB devices. */
995 static int fe_fd; /* frontend */
996 static int dvr_fd; /* data stream */
997 static int dmx_fd; /* demultiplexer */
998
999 /* Capture thread. */
1000
1001 static pthread_t capture_thread_id;
1002
1003 /* The read buffer of the capture thread. */
1004 static uint8_t * ct_buffer;
1005 static unsigned int ct_buffer_capacity;
1006
1007 /* For debugging. */
1008 static uint64_t ct_n_bytes_in;
1009
1010 /* Transport stream decoder. */
1011
1012 /* static pthread_t demux_thread_id; */
1013
1014 /* Transport stream buffer. The capture thread stores TS packets at
1015 ts_buffer_in, the TS decoder removes packets from ts_buffer_out,
1016 and increments the respective pointer by the number of bytes
1017 transferred. The input and output pointers jump back to the start
1018 of the buffer before they would exceed ts_buffer_capacity (wraps at
1019 packet, not byte granularity). The buffer is empty if ts_buffer_in
1020 equals ts_buffer_out. */
1021 static uint8_t * ts_buffer;
1022 static unsigned int ts_buffer_capacity;
1023 static volatile unsigned int ts_buffer_in;
1024 static volatile unsigned int ts_buffer_out;
1025
1026 static uint8_t ts_error;
1027
1028 /* For debugging. */
1029 static uint64_t ts_n_packets_in;
1030
1031 /* Test tap into the transport stream. */
1032 static FILE * ts_tap_fp;
1033
1034 /* Notifies the TS decoder when data is available in the ts_buffer. */
1035 static pthread_mutex_t dx_mutex;
1036 static pthread_cond_t dx_cond;
1037
1038 /* If pid_map[].program < 0, no TS packet with PID n is needed and the
1039 capture thread will drop the packet. Otherwise pid_map[].program is
1040 an index into the programs[] table. This information is used by the
1041 TS decoder to separate multiple video streams. */
1042 static struct {
1043 int8_t program;
1044 } pid_map[0x2000];
1045
1046 /* The programs we want to record. */
1047 static struct program program_table[12];
1048 static unsigned int n_programs;
1049
1050 /* A list of stations found in the channel.conf file. */
1051 static struct station * station_list;
1052
1053 /* Any station on the selected transponder. */
1054 static struct station * station;
1055
1056 static void
1057 list_stations (void);
1058 static void
1059 init_cc_decoder (struct cc_decoder * cd);
1060 static void
1061 init_dtvcc_decoder (struct dtvcc_decoder * dc);
1062 static void
1063 init_cc_data_decoder (struct cc_data_decoder *cd);
1064
1065 #define CASE(x) case x: return #x;
1066
1067 static const char *
picture_coding_type_name(enum picture_coding_type t)1068 picture_coding_type_name (enum picture_coding_type t)
1069 {
1070 switch (t) {
1071 CASE (I_TYPE)
1072 CASE (P_TYPE)
1073 CASE (B_TYPE)
1074 CASE (D_TYPE)
1075 }
1076
1077 return "invalid";
1078 }
1079
1080 static const char *
picture_structure_name(enum picture_structure t)1081 picture_structure_name (enum picture_structure t)
1082 {
1083 switch (t) {
1084 CASE (TOP_FIELD)
1085 CASE (BOTTOM_FIELD)
1086 CASE (FRAME_PICTURE)
1087 }
1088
1089 return "invalid";
1090 }
1091
1092 static const char *
cc_type_name(enum cc_type t)1093 cc_type_name (enum cc_type t)
1094 {
1095 switch (t) {
1096 CASE (NTSC_F1)
1097 CASE (NTSC_F2)
1098 CASE (DTVCC_DATA)
1099 CASE (DTVCC_START)
1100 }
1101
1102 return "invalid";
1103 }
1104
1105 #undef CASE
1106
1107 static int
printable(int c)1108 printable (int c)
1109 {
1110 if ((c & 0x7F) < 0x20)
1111 return '.';
1112 else
1113 return c & 0x7F;
1114 }
1115
1116 static void
1117 dump (FILE * fp,
1118 const uint8_t * buf,
1119 unsigned int n_bytes)
1120 _vbi_unused;
1121
1122 static void
dump(FILE * fp,const uint8_t * buf,unsigned int n_bytes)1123 dump (FILE * fp,
1124 const uint8_t * buf,
1125 unsigned int n_bytes)
1126 {
1127 const unsigned int width = 16;
1128 unsigned int i;
1129
1130 for (i = 0; i < n_bytes; i += width) {
1131 unsigned int end;
1132 unsigned int j;
1133
1134 end = MIN (i + width, n_bytes);
1135 for (j = i; j < end; ++j)
1136 fprintf (fp, "%02x ", buf[j]);
1137 for (; j < i + width; ++j)
1138 fputs (" ", fp);
1139 fputc (' ', fp);
1140 for (j = i; j < end; ++j) {
1141 int c = buf[j];
1142 fputc (printable (c), fp);
1143 }
1144 fputc ('\n', fp);
1145 }
1146 }
1147
1148 #define log(verb, templ, args...) \
1149 log_message (verb, /* print_errno */ FALSE, templ , ##args)
1150
1151 #define log_errno(verb, templ, args...) \
1152 log_message (verb, /* print_errno */ TRUE, templ , ##args)
1153
1154 #define bug(templ, args...) \
1155 log_message (1, /* print_errno */ FALSE, "BUG: " templ , ##args)
1156
1157 static void
1158 log_message (unsigned int verbosity,
1159 vbi_bool print_errno,
1160 const char * templ,
1161 ...)
1162 _vbi_format ((printf, 3, 4));
1163
1164 static void
log_message(unsigned int verbosity,vbi_bool print_errno,const char * templ,...)1165 log_message (unsigned int verbosity,
1166 vbi_bool print_errno,
1167 const char * templ,
1168 ...)
1169 {
1170 if (verbosity <= option_verbosity) {
1171 va_list ap;
1172
1173 va_start (ap, templ);
1174
1175 fprintf (stderr, "%s: ", my_name);
1176 vfprintf (stderr, templ, ap);
1177
1178 if (print_errno) {
1179 fprintf (stderr, ": %s.\n",
1180 strerror (errno));
1181 }
1182
1183 va_end (ap);
1184 }
1185 }
1186
1187 #define error_exit(templ, args...) \
1188 error_message_exit (/* print_errno */ FALSE, templ , ##args)
1189
1190 #define errno_exit(templ, args...) \
1191 error_message_exit (/* print_errno */ TRUE, templ , ##args)
1192
1193 static void
1194 error_message_exit (vbi_bool print_errno,
1195 const char * templ,
1196 ...)
1197 _vbi_format ((printf, 2, 3));
1198
1199 static void
error_message_exit(vbi_bool print_errno,const char * templ,...)1200 error_message_exit (vbi_bool print_errno,
1201 const char * templ,
1202 ...)
1203 {
1204 if (option_verbosity > 0) {
1205 va_list ap;
1206
1207 va_start (ap, templ);
1208
1209 fprintf (stderr, "%s: ", my_name);
1210 vfprintf (stderr, templ, ap);
1211
1212 if (print_errno) {
1213 fprintf (stderr, ": %s.\n",
1214 strerror (errno));
1215 }
1216
1217 va_end (ap);
1218 }
1219
1220 exit (EXIT_FAILURE);
1221 }
1222
1223 static void
no_mem_exit(void)1224 no_mem_exit (void)
1225 {
1226 error_exit ("Out of memory.");
1227 }
1228
1229 static void *
xmalloc(size_t size)1230 xmalloc (size_t size)
1231 {
1232 void *p;
1233
1234 p = malloc (size);
1235 if (NULL == p) {
1236 no_mem_exit ();
1237 }
1238
1239 return p;
1240 }
1241
1242 static char *
1243 xasprintf (const char * templ,
1244 ...)
1245 _vbi_format ((printf, 1, 2));
1246
1247 static char *
xasprintf(const char * templ,...)1248 xasprintf (const char * templ,
1249 ...)
1250 {
1251 va_list ap;
1252 char *s;
1253 int r;
1254
1255 va_start (ap, templ);
1256
1257 r = vasprintf (&s, templ, ap);
1258 if (r < 0 || NULL == s) {
1259 no_mem_exit ();
1260 }
1261
1262 va_end (ap);
1263
1264 return s;
1265 }
1266
1267 static int
xioctl_may_fail(int fd,int request,void * arg)1268 xioctl_may_fail (int fd,
1269 int request,
1270 void * arg)
1271 {
1272 int r;
1273
1274 do r = ioctl (fd, request, arg);
1275 while (-1 == r && EINTR == errno);
1276
1277 return r;
1278 }
1279
1280 #define xioctl(fd, request, arg) \
1281 do { \
1282 int r; \
1283 \
1284 r = xioctl_may_fail (fd, request, arg); \
1285 if (-1 == r) { \
1286 errno_exit (#request " failed"); \
1287 } \
1288 } while (0)
1289
1290 static FILE *
open_output_file(const char * name)1291 open_output_file (const char * name)
1292 {
1293 FILE *fp;
1294
1295 if (NULL == name || 0 == strcmp (name, "-")) {
1296 fp = stdout;
1297 } else {
1298 fp = fopen (name, "a");
1299 if (NULL == fp) {
1300 errno_exit ("Cannot open output file '%s'",
1301 name);
1302 }
1303 }
1304
1305 return fp;
1306 }
1307
1308 static FILE *
open_test_file(const char * name)1309 open_test_file (const char * name)
1310 {
1311 FILE *fp;
1312
1313 if (NULL == name || 0 == strcmp (name, "-")) {
1314 fp = stdin;
1315 } else {
1316 fp = fopen (name, "r");
1317 if (NULL == fp) {
1318 errno_exit ("Cannot open test file '%s'",
1319 name);
1320 }
1321 }
1322
1323 return fp;
1324 }
1325
1326 static FILE *
open_minicut_file(struct program * pr,const struct tm * tm,const char * file_name,const char * extension)1327 open_minicut_file (struct program * pr,
1328 const struct tm * tm,
1329 const char * file_name,
1330 const char * extension)
1331 {
1332 char dir_name[32];
1333 size_t base_len;
1334 size_t dir_len;
1335 char *buf;
1336 struct stat st;
1337 unsigned int i;
1338 FILE *fp;
1339
1340 base_len = strlen (pr->option_minicut_dir_name);
1341
1342 dir_len = snprintf (dir_name, sizeof (dir_name),
1343 "/%04u%02u%02u%02u0000",
1344 tm->tm_year + 1900,
1345 tm->tm_mon + 1,
1346 tm->tm_mday,
1347 tm->tm_hour);
1348
1349 buf = xmalloc (base_len + dir_len
1350 + strlen (file_name) + 2
1351 + strlen (extension) + 1);
1352
1353 strcpy (buf, pr->option_minicut_dir_name);
1354 if (0 != stat (buf, &st)) {
1355 errno_exit ("Cannot open '%s'", buf);
1356 } else if (!S_ISDIR(st.st_mode)) {
1357 error_exit ("'%s' is not a directory.\n", buf);
1358 }
1359
1360 strcpy (buf + base_len, dir_name);
1361 if (0 != stat (buf, &st)) {
1362 if (ENOENT != errno)
1363 errno_exit ("Cannot open '%s'", buf);
1364 if (-1 == mkdir (buf, /* mode */ 0777))
1365 errno_exit ("Cannot create '%s'", buf);
1366 } else if (!S_ISDIR(st.st_mode)) {
1367 error_exit ("'%s' is not a directory.\n", buf);
1368 }
1369
1370 for (i = 0; i < 100; ++i) {
1371 int fd;
1372
1373 if (0 == i) {
1374 sprintf (buf + base_len + dir_len,
1375 "%s%s",
1376 file_name, extension);
1377 } else {
1378 sprintf (buf + base_len + dir_len,
1379 "%s-%u%s",
1380 file_name, i, extension);
1381 }
1382
1383 fd = open64 (buf, (O_CREAT | O_EXCL |
1384 O_LARGEFILE | O_WRONLY), 0666);
1385 if (fd >= 0) {
1386 fp = fdopen (fd, "w");
1387 if (NULL == fp)
1388 goto failed;
1389
1390 log (2, "Opened '%s'.\n", buf);
1391
1392 free (buf);
1393
1394 return fp;
1395 }
1396
1397 if (EEXIST == errno)
1398 continue;
1399 if (ENOSPC == errno)
1400 break;
1401
1402 failed:
1403 errno_exit ("Cannot open output file '%s'", buf);
1404 }
1405
1406 free (buf);
1407
1408 /* Will try again later. */
1409 log_errno (1, "Cannot open output file '%s'", buf);
1410
1411 return NULL;
1412 }
1413
1414 static unsigned int
station_num(struct program * pr)1415 station_num (struct program * pr)
1416 {
1417 return (pr - program_table) + 1;
1418 }
1419
1420 /* Caption recorder */
1421
1422 static const char *
1423 cr_file_name_suffix [10] = {
1424 "-cc1", "-cc2", "-cc3", "-cc4",
1425 "-t1", "-t2", "-t3", "-t4",
1426 "-s1", "-s2"
1427 };
1428
1429 static void
cr_grow_buffer(struct caption_recorder * cr,unsigned int n_chars)1430 cr_grow_buffer (struct caption_recorder *cr,
1431 unsigned int n_chars)
1432 {
1433 uint16_t *new_buffer;
1434 size_t min_size;
1435 size_t new_size;
1436
1437 if (likely (cr->ucs_buffer_length + n_chars
1438 <= cr->ucs_buffer_capacity))
1439 return;
1440
1441 min_size = (cr->ucs_buffer_length + n_chars) * 2;
1442 min_size = MAX ((size_t) 64, min_size);
1443 new_size = MAX (min_size, (size_t) cr->ucs_buffer_capacity * 4);
1444
1445 new_buffer = realloc (cr->ucs_buffer, new_size);
1446 if (NULL == new_buffer)
1447 no_mem_exit ();
1448
1449 cr->ucs_buffer = new_buffer;
1450 cr->ucs_buffer_capacity = new_size / 2;
1451 }
1452
1453 static void
cr_putuc(struct caption_recorder * cr,uint16_t uc)1454 cr_putuc (struct caption_recorder *cr,
1455 uint16_t uc)
1456 {
1457 cr_grow_buffer (cr, 1);
1458 cr->ucs_buffer[cr->ucs_buffer_length++] = uc;
1459 }
1460
1461 static void
cr_puts(struct caption_recorder * cr,const char * s)1462 cr_puts (struct caption_recorder *cr,
1463 const char * s)
1464 {
1465 while (0 != *s)
1466 cr_putuc (cr, *s++);
1467 }
1468
1469 _vbi_inline void
vbi_char_copy_attr(struct vbi_char * cp1,struct vbi_char * cp2,unsigned int attr)1470 vbi_char_copy_attr (struct vbi_char * cp1,
1471 struct vbi_char * cp2,
1472 unsigned int attr)
1473 {
1474 if (attr & VBI_UNDERLINE)
1475 cp1->underline = cp2->underline;
1476 if (attr & VBI_ITALIC)
1477 cp1->italic = cp2->italic;
1478 if (attr & VBI_FLASH)
1479 cp1->flash = cp2->flash;
1480 }
1481
1482 _vbi_inline void
vbi_char_clear_attr(struct vbi_char * cp,unsigned int attr)1483 vbi_char_clear_attr (struct vbi_char * cp,
1484 unsigned int attr)
1485 {
1486 if (attr & VBI_UNDERLINE)
1487 cp->underline = 0;
1488 if (attr & VBI_ITALIC)
1489 cp->italic = 0;
1490 if (attr & VBI_FLASH)
1491 cp->flash = 0;
1492 }
1493
1494 _vbi_inline void
vbi_char_set_attr(struct vbi_char * cp,unsigned int attr)1495 vbi_char_set_attr (struct vbi_char * cp,
1496 unsigned int attr)
1497 {
1498 if (attr & VBI_UNDERLINE)
1499 cp->underline = 1;
1500 if (attr & VBI_ITALIC)
1501 cp->italic = 1;
1502 if (attr & VBI_FLASH)
1503 cp->flash = 1;
1504 }
1505
1506 _vbi_inline unsigned int
vbi_char_has_attr(struct vbi_char * cp,unsigned int attr)1507 vbi_char_has_attr (struct vbi_char * cp,
1508 unsigned int attr)
1509 {
1510 attr &= (VBI_UNDERLINE | VBI_ITALIC | VBI_FLASH);
1511
1512 if (0 == cp->underline)
1513 attr &= ~VBI_UNDERLINE;
1514 if (0 == cp->italic)
1515 attr &= ~VBI_ITALIC;
1516 if (0 == cp->flash)
1517 attr &= ~VBI_FLASH;
1518
1519 return attr;
1520 }
1521
1522 _vbi_inline unsigned int
vbi_char_xor_attr(struct vbi_char * cp1,struct vbi_char * cp2,unsigned int attr)1523 vbi_char_xor_attr (struct vbi_char * cp1,
1524 struct vbi_char * cp2,
1525 unsigned int attr)
1526 {
1527 attr &= (VBI_UNDERLINE | VBI_ITALIC | VBI_FLASH);
1528
1529 if (0 == (cp1->underline ^ cp2->underline))
1530 attr &= ~VBI_UNDERLINE;
1531 if (0 == (cp1->italic ^ cp2->italic))
1532 attr &= ~VBI_ITALIC;
1533 if (0 == (cp1->flash ^ cp2->flash))
1534 attr &= ~VBI_FLASH;
1535
1536 return attr;
1537 }
1538
1539 static vbi_bool
cr_put_attr(struct caption_recorder * cr,vbi_char * prev,vbi_char curr)1540 cr_put_attr (struct caption_recorder *cr,
1541 vbi_char * prev,
1542 vbi_char curr)
1543 {
1544 uint16_t *d;
1545
1546 switch (cr->option_caption_format) {
1547 case FORMAT_PLAIN:
1548 return TRUE;
1549
1550 case FORMAT_NTSC_CC:
1551 /* Same output as the [zvbi-]ntsc-cc app. */
1552
1553 curr.opacity = VBI_OPAQUE;
1554
1555 /* Use the default foreground and background color of
1556 the terminal. */
1557 curr.foreground = -1;
1558 curr.background = -1;
1559
1560 if (vbi_char_has_attr (&curr, VBI_ITALIC))
1561 curr.foreground = VBI_CYAN;
1562
1563 vbi_char_clear_attr (&curr, VBI_ITALIC | VBI_FLASH);
1564
1565 break;
1566
1567 case FORMAT_VT100:
1568 break;
1569 }
1570
1571 cr_grow_buffer (cr, 32);
1572
1573 d = cr->ucs_buffer + cr->ucs_buffer_length;
1574
1575 /* Control sequences based on ECMA-48,
1576 http://www.ecma-international.org/ */
1577
1578 /* SGR sequence */
1579
1580 d[0] = 27; /* CSI */
1581 d[1] = '[';
1582 d += 2;
1583
1584 switch (curr.opacity) {
1585 case VBI_TRANSPARENT_SPACE:
1586 vbi_char_clear_attr (&curr, -1);
1587 curr.foreground = -1;
1588 curr.background = -1;
1589 break;
1590
1591 case VBI_TRANSPARENT_FULL:
1592 curr.background = -1;
1593 break;
1594
1595 case VBI_SEMI_TRANSPARENT:
1596 case VBI_OPAQUE:
1597 break;
1598 }
1599
1600 if ((prev->foreground != curr.foreground
1601 && (uint8_t) -1 == curr.foreground)
1602 || (prev->background != curr.background
1603 && (uint8_t) -1 == curr.background)) {
1604 *d++ = ';'; /* "[0m;" reset */
1605 vbi_char_clear_attr (prev, -1);
1606 prev->foreground = -1;
1607 prev->background = -1;
1608 }
1609
1610 if (vbi_char_xor_attr (prev, &curr, VBI_ITALIC)) {
1611 if (!vbi_char_has_attr (&curr, VBI_ITALIC))
1612 *d++ = '2'; /* off */
1613 d[0] = '3'; /* italic */
1614 d[1] = ';';
1615 d += 2;
1616 }
1617
1618 if (vbi_char_xor_attr (prev, &curr, VBI_UNDERLINE)) {
1619 if (!vbi_char_has_attr (&curr, VBI_UNDERLINE))
1620 *d++ = '2'; /* off */
1621 d[0] = '4'; /* underline */
1622 d[1] = ';';
1623 d += 2;
1624 }
1625
1626 if (vbi_char_xor_attr (prev, &curr, VBI_FLASH)) {
1627 if (!vbi_char_has_attr (&curr, VBI_FLASH))
1628 *d++ = '2'; /* steady */
1629 d[0] = '5'; /* slowly blinking */
1630 d[1] = ';';
1631 d += 2;
1632 }
1633
1634 if (prev->foreground != curr.foreground) {
1635 d[0] = '3';
1636 d[1] = curr.foreground + '0';
1637 d[2] = ';';
1638 d += 3;
1639 }
1640
1641 if (prev->background != curr.background) {
1642 d[0] = '4';
1643 d[1] = curr.background + '0';
1644 d[2] = ';';
1645 d += 3;
1646 }
1647
1648 vbi_char_copy_attr (prev, &curr, -1);
1649 prev->foreground = curr.foreground;
1650 prev->background = curr.background;
1651
1652 if ('[' == d[-1])
1653 d -= 2; /* no change, remove CSI */
1654 else
1655 d[-1] = 'm'; /* replace last semicolon */
1656
1657 cr->ucs_buffer_length = d - cr->ucs_buffer;
1658
1659 return TRUE;
1660 }
1661
1662 static void
cr_timestamp(struct caption_recorder * cr,struct tm * tm,time_t t)1663 cr_timestamp (struct caption_recorder *cr,
1664 struct tm * tm,
1665 time_t t)
1666 {
1667 char time_str[32];
1668
1669 if (!cr->option_caption_timestamps)
1670 return;
1671
1672 if (tm->tm_mday <= 0) {
1673 if (NULL == gmtime_r (&t, tm)) {
1674 /* Should not happen. */
1675 error_exit ("System time invalid.\n");
1676 }
1677 }
1678
1679 snprintf (time_str, sizeof (time_str),
1680 "%04u%02u%02u%02u%02u%02u|",
1681 tm->tm_year + 1900, tm->tm_mon + 1,
1682 tm->tm_mday, tm->tm_hour,
1683 tm->tm_min, tm->tm_sec);
1684
1685 cr_puts (cr, time_str);
1686 }
1687
1688 static void
cr_minicut(struct caption_recorder * cr,struct tm * tm,time_t t,vbi_pgno channel)1689 cr_minicut (struct caption_recorder *cr,
1690 struct tm * tm,
1691 time_t t,
1692 vbi_pgno channel)
1693 {
1694 struct program *pr = PARENT (cr, struct program, cr);
1695
1696 if (NULL == pr->option_minicut_dir_name)
1697 return;
1698
1699 if (NULL != cr->option_caption_file_name[channel - 1])
1700 return;
1701
1702 if (tm->tm_mday <= 0) {
1703 if (NULL == gmtime_r (&t, tm)) {
1704 /* Should not happen. */
1705 error_exit ("System time invalid.\n");
1706 }
1707 }
1708
1709 if (tm->tm_min != cr->minicut_min[channel - 1]) {
1710 char file_name[32];
1711 FILE *fp;
1712
1713 fp = cr->caption_fp[channel - 1];
1714 if (NULL != fp) {
1715 if (0 != fclose (fp)) {
1716 log_errno (1, "Station %u CC file "
1717 "write error",
1718 station_num (pr));
1719 }
1720 }
1721
1722 snprintf (file_name, sizeof (file_name),
1723 "/%04u%02u%02u%02u%02u00%s",
1724 tm->tm_year + 1900, tm->tm_mon + 1,
1725 tm->tm_mday, tm->tm_hour, tm->tm_min,
1726 cr_file_name_suffix [channel - 1]);
1727
1728 /* Note: May be NULL. */
1729 cr->caption_fp[channel - 1] =
1730 open_minicut_file (pr, tm, file_name, ".txt");
1731
1732 cr->minicut_min[channel - 1] = tm->tm_min;
1733 }
1734 }
1735
1736 static void
cr_new_line(struct caption_recorder * cr,struct cc_timestamp * ts,vbi_pgno channel,const vbi_char text[42],unsigned int length)1737 cr_new_line (struct caption_recorder *cr,
1738 struct cc_timestamp * ts,
1739 vbi_pgno channel,
1740 const vbi_char text[42],
1741 unsigned int length)
1742 {
1743 FILE *fp;
1744
1745 if (0 == (ts->sys.tv_sec | ts->sys.tv_usec)
1746 || channel >= 10 || length < 32)
1747 return;
1748
1749 if (0 == (cr->option_caption_mask & (1 << (channel - 1))))
1750 return;
1751
1752 cr->ucs_buffer_length = 0;
1753
1754 if (cr->usesen) {
1755 unsigned int uc[3];
1756 unsigned int column;
1757 unsigned int end;
1758 unsigned int separator;
1759
1760 end = length;
1761
1762 /* Eat trailing spaces. */
1763 while (end > 0 && ' ' == text[end - 1].unicode)
1764 --end;
1765
1766 uc[2] = ' ';
1767 separator = 0;
1768
1769 for (column = 0; column < end + 1; ++column) {
1770 uc[0] = uc[1];
1771 uc[1] = uc[2];
1772 uc[2] = 0;
1773 if (column < end)
1774 uc[2] = text[column].unicode;
1775
1776 if (0 == separator && ' ' == uc[1])
1777 continue;
1778 cr_putuc (cr, uc[1]);
1779 separator = ' ';
1780
1781 switch (uc[1]) {
1782 case '"':
1783 if ('.' != uc[0] && '!' != uc[0]
1784 && '?' != uc[0])
1785 continue;
1786 break;
1787
1788 case '.':
1789 if ('.' == uc[0] || '.' == uc[2])
1790 continue;
1791 /* fall through */
1792
1793 case '!':
1794 case '?':
1795 if ('"' == uc[2])
1796 continue;
1797 if (0 != uc[2] && ' ' != uc[2])
1798 continue;
1799 break;
1800
1801 default:
1802 continue;
1803 }
1804
1805 cr_putuc (cr, '\n');
1806 separator = 0;
1807 }
1808
1809 if (0 != separator)
1810 cr_putuc (cr, separator);
1811 } else {
1812 struct tm tm;
1813 vbi_char prev_char;
1814 unsigned int column;
1815
1816 tm.tm_mday = 0;
1817 cr_minicut (cr, &tm, (time_t) ts->sys.tv_sec, channel);
1818 cr_timestamp (cr, &tm, (time_t) ts->sys.tv_sec);
1819
1820 vbi_char_clear_attr (&prev_char, -1);
1821 prev_char.foreground = -1;
1822 prev_char.background = -1;
1823
1824 for (column = 0; column < length; ++column) {
1825 cr_put_attr (cr, &prev_char, text[column]);
1826 cr_putuc (cr, text[column].unicode);
1827 }
1828
1829 if (0 != vbi_char_has_attr (&prev_char, -1)
1830 || (uint8_t) -1 != prev_char.foreground
1831 || (uint8_t) -1 != prev_char.background) {
1832 static const char end_seq[] = {
1833 27, '[', 'm', '\n', 0
1834 };
1835
1836 cr_puts (cr, end_seq);
1837 } else {
1838 cr_putuc (cr, '\n');
1839 }
1840 }
1841
1842 fp = cr->caption_fp[channel - 1];
1843
1844 /* May be NULL due to a bug or a temporary failure of
1845 open_minicut_file(). */
1846 if (NULL != fp) {
1847 vbi_fputs_iconv_ucs2 (fp, locale_codeset,
1848 cr->ucs_buffer,
1849 cr->ucs_buffer_length,
1850 /* repl_char */ '?');
1851 }
1852 }
1853
1854 static void
init_caption_recorder(struct caption_recorder * cr)1855 init_caption_recorder (struct caption_recorder *cr)
1856 {
1857 CLEAR (*cr);
1858
1859 cr->option_xds_output_file_name = "-";
1860
1861 init_cc_data_decoder (&cr->ccd);
1862 init_cc_decoder (&cr->cc);
1863 init_dtvcc_decoder (&cr->dtvcc);
1864
1865 cr->infoptr = cr->newinfo[0][0][0];
1866 cr->xds_info_prefix = "\33[33m% ";
1867 cr->xds_info_suffix = "\33[0m\n";
1868 cr->usewebtv = 1;
1869
1870 memset (cr->minicut_min, -1, sizeof (cr->minicut_min));
1871 }
1872
1873 /* EIA 608-B Closed Caption decoder. */
1874
1875 static void
cc_timestamp_reset(struct cc_timestamp * ts)1876 cc_timestamp_reset (struct cc_timestamp * ts)
1877 {
1878 CLEAR (ts->sys);
1879 ts->pts = -1;
1880 }
1881
1882 static vbi_bool
cc_timestamp_isset(struct cc_timestamp * ts)1883 cc_timestamp_isset (struct cc_timestamp * ts)
1884 {
1885 return (ts->pts >= 0 || 0 != (ts->sys.tv_sec | ts->sys.tv_usec));
1886 }
1887
1888 static const vbi_color
1889 cc_color_map [8] = {
1890 VBI_WHITE, VBI_GREEN, VBI_BLUE, VBI_CYAN,
1891 VBI_RED, VBI_YELLOW, VBI_MAGENTA, VBI_BLACK
1892 };
1893
1894 static const int8_t
1895 cc_pac_row_map [16] = {
1896 /* 0 */ 10, /* 0x1040 */
1897 /* 1 */ -1, /* no function */
1898 /* 2 */ 0, 1, 2, 3, /* 0x1140 ... 0x1260 */
1899 /* 6 */ 11, 12, 13, 14, /* 0x1340 ... 0x1460 */
1900 /* 10 */ 4, 5, 6, 7, 8, 9 /* 0x1540 ... 0x1760 */
1901 };
1902
1903 static void
dump_cc(FILE * fp,unsigned int index,unsigned int cc_count,unsigned int cc_valid,unsigned int cc_type,unsigned int c1,unsigned int c2)1904 dump_cc (FILE * fp,
1905 unsigned int index,
1906 unsigned int cc_count,
1907 unsigned int cc_valid,
1908 unsigned int cc_type,
1909 unsigned int c1,
1910 unsigned int c2)
1911 {
1912 uint16_t ucs2_str[2];
1913 unsigned int ch;
1914 unsigned int a7;
1915 unsigned int f;
1916 unsigned int b7;
1917 unsigned int u;
1918
1919 fprintf (fp,
1920 "%s%u/%u %d %s %02X%02X %02X%c%02X%c",
1921 (NTSC_F2 == cc_type) ? "\t\t\t\t\t\t\t\t" : "",
1922 index, cc_count, !!cc_valid,
1923 cc_type_name (cc_type), c1, c2,
1924 c1 & 0x7F, vbi_unpar8 (c1) < 0 ? '*' : ' ',
1925 c2 & 0x7F, vbi_unpar8 (c2) < 0 ? '*' : ' ');
1926
1927 c1 &= 0x7F;
1928 c2 &= 0x7F;
1929
1930 if (0 == c1) {
1931 fputs (" null\n", fp);
1932 return;
1933 } else if (c1 < 0x10) {
1934 fputc ('\n', fp);
1935 return;
1936 } else if (c1 >= 0x20) {
1937 fputs (" '", fp);
1938 ucs2_str[0] = vbi_caption_unicode (c1, /* to_upper */ FALSE);
1939 ucs2_str[1] = vbi_caption_unicode (c2, /* to_upper */ FALSE);
1940 vbi_fputs_iconv_ucs2 (fp, locale_codeset,
1941 ucs2_str, 2,
1942 /* repl_char */ '?');
1943 fputs ("'\n", fp);
1944 return;
1945 } else if (c2 < 0x20) {
1946 fputs (" INVALID\n", fp);
1947 return;
1948 }
1949
1950 /* Some common bit groups. */
1951
1952 ch = (c1 >> 3) & 1; /* channel */
1953 a7 = c1 & 7;
1954 f = c1 & 1; /* field */
1955 b7 = (c2 >> 1) & 7;
1956 u = c2 & 1; /* underline */
1957
1958 if (c2 >= 0x40) {
1959 unsigned int row;
1960
1961 /* Preamble Address Codes -- 001 crrr 1ri bbbu */
1962
1963 row = cc_pac_row_map [a7 * 2 + ((c2 >> 5) & 1)];
1964 if (c2 & 0x10)
1965 fprintf (fp, " PAC ch=%u row=%d column=%u u=%u\n",
1966 ch, row, b7 * 4, u);
1967 else
1968 fprintf (fp, " PAC ch=%u row=%d color=%u u=%u\n",
1969 ch, row, b7, u);
1970 return;
1971 }
1972
1973 /* Control codes -- 001 caaa 01x bbbu */
1974
1975 switch (a7) {
1976 case 0:
1977 if (c2 < 0x30) {
1978 static const char mnemo [16 * 4] =
1979 "BWO\0BWS\0BGO\0BGS\0"
1980 "BBO\0BBS\0BCO\0BCS\0"
1981 "BRO\0BRS\0BYO\0BYS\0"
1982 "BMO\0BMS\0BAO\0BAS";
1983
1984 fprintf (fp, " %s ch=%u\n",
1985 mnemo + (c2 & 0xF) * 4, ch);
1986 return;
1987 }
1988 break;
1989
1990 case 1:
1991 if (c2 < 0x30) {
1992 fprintf (fp, " mid-row ch=%u color=%u u=%u\n",
1993 ch, b7, u);
1994 } else {
1995 fprintf (fp, " special character ch=%u '", ch);
1996 ucs2_str[0] = vbi_caption_unicode
1997 (0x1100 | c2, /* to_upper */ FALSE);
1998 vbi_fputs_iconv_ucs2 (fp, locale_codeset,
1999 ucs2_str, 1,
2000 /* repl_char */ '?');
2001 fputs ("'\n", fp);
2002 }
2003 return;
2004
2005 case 2: /* first group */
2006 case 3: /* second group */
2007 fprintf (fp, " extended character ch=%u '", ch);
2008 ucs2_str[0] = vbi_caption_unicode
2009 (c1 * 256 + c2, /* to_upper */ FALSE);
2010 vbi_fputs_iconv_ucs2 (fp, locale_codeset,
2011 ucs2_str, 1,
2012 /* repl_char */ '?');
2013 fputs ("'\n", fp);
2014 return;
2015
2016 case 4: /* f=0 */
2017 case 5: /* f=1 */
2018 if (c2 < 0x30) {
2019 static const char mnemo [16 * 4] =
2020 "RCL\0BS \0AOF\0AON\0"
2021 "DER\0RU2\0RU3\0RU4\0"
2022 "FON\0RDC\0TR \0RTD\0"
2023 "EDM\0CR \0ENM\0EOC";
2024
2025 fprintf (fp, " %s ch=%u f=%u\n",
2026 mnemo + (c2 & 0xF) * 4, ch, f);
2027 return;
2028 }
2029 break;
2030
2031 case 6:
2032 fprintf (fp, " reserved\n");
2033 return;
2034
2035 case 7:
2036 switch (c2) {
2037 case 0x21 ... 0x23:
2038 fprintf (fp, " TO%u ch=%u\n", c2 - 0x20, ch);
2039 return;
2040
2041 case 0x2D:
2042 fprintf (fp, " BT ch=%u\n", ch);
2043 return;
2044
2045 case 0x2E:
2046 fprintf (fp, " FA ch=%u\n", ch);
2047 return;
2048
2049 case 0x2F:
2050 fprintf (fp, " FAU ch=%u\n", ch);
2051 return;
2052
2053 default:
2054 break;
2055 }
2056 break;
2057 }
2058
2059 fprintf (fp, " unknown\n");
2060 }
2061
2062 static void
2063 cc_reset (struct cc_decoder * cd);
2064
2065 static vbi_pgno
cc_channel_num(struct cc_decoder * cd,struct cc_channel * ch)2066 cc_channel_num (struct cc_decoder * cd,
2067 struct cc_channel * ch)
2068 {
2069 return (ch - cd->channel) + 1;
2070 }
2071
2072 /* Note 47 CFR 15.119 (h) Character Attributes: "(1) Transmission of
2073 Attributes. A character may be transmitted with any or all of four
2074 attributes: Color, italics, underline, and flash. All of these
2075 attributes are set by control codes included in the received
2076 data. An attribute will remain in effect until changed by another
2077 control code or until the end of the row is reached. Each row
2078 begins with a control code which sets the color and underline
2079 attributes. (White non-underlined is the default display attribute
2080 if no Preamble Address Code is received before the first character
2081 on an empty row.) Attributes are not affected by transparent spaces
2082 within a row. (i) All Mid-Row Codes and the Flash On command are
2083 spacing attributes which appear in the display just as if a
2084 standard space (20h) had been received. Preamble Address Codes are
2085 non-spacing and will not alter any attributes when used to position
2086 the cursor in the midst of a row of characters. (ii) The color
2087 attribute has the highest priority and can only be changed by the
2088 Mid-Row Code of another color. Italics has the next highest
2089 priority. If characters with both color and italics are desired,
2090 the italics Mid-Row Code must follow the color assignment. Any
2091 color Mid-Row Code will turn off italics. If the least significant
2092 bit of a Preamble Address Code or of a color or italics Mid-Row
2093 Code is a 1 (high), underlining is turned on. If that bit is a 0
2094 (low), underlining is off. (iii) The flash attribute is transmitted
2095 as a Miscellaneous Control Code. The Flash On command will not
2096 alter the status of the color, italics, or underline
2097 attributes. However, any coloror italics Mid-Row Code will turn off
2098 flash. (iv) Thus, for example, if a red, italicized, underlined,
2099 flashing character is desired, the attributes must be received in
2100 the following order: a red Mid-Row or Preamble Address Code, an
2101 italics Mid-Row Code with underline bit, and the Flash On
2102 command. The character will then be preceded by three spaces (two
2103 if red was assigned via a Preamble Address Code)."
2104
2105 EIA 608-B Annex C.7 Preamble Address Codes and Tab Offsets
2106 (Regulatory/Preferred): "In general, Preamble Address Codes (PACs)
2107 have no immediate effect on the display. A major exception is the
2108 receipt of a PAC during roll-up captioning. In that case, if the
2109 base row designated in the PAC is not the same as the current base
2110 row, the display shall be moved immediately to the new base
2111 row. [...] An indenting PAC carries the attributes of white,
2112 non-italicized, and it sets underlining on or off. Tab Offset
2113 commands do not change these attributes. If an indenting PAC with
2114 underline ON is received followed by a Tab Offset and by text, the
2115 text shall be underlined (except as noted below). When a
2116 displayable character is received, it is deposited at the current
2117 cursor position. If there is already a displayable character in the
2118 column immediately to the left, the new character assumes the
2119 attributes of that character. The new character may be arriving as
2120 the result of an indenting PAC (with or without a Tab Offset), and
2121 that PAC may designate other attributes, but the new character is
2122 forced to assume the attributes of the character immediately to its
2123 left, and the PAC's attributes are ignored. If, when a displayable
2124 character is received, it overwrites an existing PAC or mid-row
2125 code, and there are already characters to the right of the new
2126 character, these existing characters shall assume the same
2127 attributes as the new character. This adoption can result in a
2128 whole caption row suddenly changing color, underline, italics,
2129 and/or flash attributes."
2130
2131 EIA 608-B Annex C.14 Special Cases Regarding Attributes
2132 (Normative): "In most cases, Preamble Address Codes shall set
2133 attributes for the caption elements they address. It is
2134 theoretically possible for a service provider to use an indenting
2135 PAC to start a row at Column 5 or greater, and then to use
2136 Backspace to move the cursor to the left of the PAC into an area to
2137 which no attributes have been assigned. It is also possible for a
2138 roll-up row, having been created by a Carriage Return, to receive
2139 characters with no PAC used to set attributes. In these cases, and
2140 in any other case where no explicit attributes have been assigned,
2141 the display shall be white, non-underlined, non-italicized, and
2142 non-flashing. In case new displayable characters are received
2143 immediately after a Delete to End of Row (DER), the display
2144 attributes of the first deleted character shall remain in effect if
2145 there is a displayable character to the left of the cursor;
2146 otherwise, the most recently received PAC shall set the display
2147 attributes."
2148
2149 47 CFR 15.119 (n) Glossary of terms: "(6) Displayable character:
2150 Any letter, number or symbol which is defined for on-screen
2151 display, plus the 20h space. [...] (13) Special characters:
2152 Displayable characters (except for "transparent space") [...]" */
2153
2154 static void
cc_format_row(struct cc_decoder * cd,struct vbi_char * cp,struct cc_channel * ch,unsigned int buffer,unsigned int row,vbi_bool to_upper,vbi_bool padding)2155 cc_format_row (struct cc_decoder * cd,
2156 struct vbi_char * cp,
2157 struct cc_channel * ch,
2158 unsigned int buffer,
2159 unsigned int row,
2160 vbi_bool to_upper,
2161 vbi_bool padding)
2162 {
2163 struct vbi_char ac;
2164 unsigned int i;
2165
2166 cd = cd; /* unused */
2167
2168 /* 47 CFR 15.119 (h)(1). EIA 608-B Section 6.4. */
2169 CLEAR (ac);
2170 ac.foreground = VBI_WHITE;
2171 ac.background = VBI_BLACK;
2172
2173 /* Shortcut. */
2174 if (0 == (ch->dirty[buffer] & (1 << row))) {
2175 vbi_char *end;
2176
2177 ac.unicode = 0x20;
2178 ac.opacity = VBI_TRANSPARENT_SPACE;
2179
2180 end = cp + CC_MAX_COLUMNS;
2181 if (padding)
2182 end += 2;
2183
2184 while (cp < end)
2185 *cp++ = ac;
2186
2187 return;
2188 }
2189
2190 if (padding) {
2191 ac.unicode = 0x20;
2192 ac.opacity = VBI_TRANSPARENT_SPACE;
2193 *cp++ = ac;
2194 }
2195
2196 /* EIA 608-B Section 6.4. */
2197 ac.opacity = VBI_OPAQUE;
2198
2199 for (i = CC_FIRST_COLUMN - 1; i <= CC_LAST_COLUMN; ++i) {
2200 unsigned int color;
2201 unsigned int c;
2202
2203 ac.unicode = 0x20;
2204
2205 c = ch->buffer[buffer][row][i];
2206 if (0 == c) {
2207 if (padding
2208 && VBI_TRANSPARENT_SPACE != cp[-1].opacity
2209 && 0x20 != cp[-1].unicode) {
2210 /* Append a space with the same colors
2211 and opacity (opaque or
2212 transp. backgr.) as the text to the
2213 left of it. */
2214 *cp++ = ac;
2215 /* We don't underline spaces, see
2216 below. */
2217 vbi_char_clear_attr (cp - 1, -1);
2218 } else if (i > 0) {
2219 *cp++ = ac;
2220 cp[-1].opacity = VBI_TRANSPARENT_SPACE;
2221 }
2222
2223 continue;
2224 } else if (c < 0x1040) {
2225 if (padding
2226 && VBI_TRANSPARENT_SPACE == cp[-1].opacity) {
2227 /* Prepend a space with the same
2228 colors and opacity (opaque or
2229 transp. backgr.) as the text to the
2230 right of it. */
2231 cp[-1] = ac;
2232 /* We don't underline spaces, see
2233 below. */
2234 vbi_char_clear_attr (cp - 1, -1);
2235 }
2236
2237 if ((c >= 'a' && c <= 'z')
2238 || 0x7E == c /* n with tilde */) {
2239 /* We do not force these characters to
2240 upper case because the standard
2241 character set includes upper case
2242 versions of these characters and
2243 lower case was probably
2244 deliberately transmitted. */
2245 ac.unicode = vbi_caption_unicode
2246 (c, /* to_upper */ FALSE);
2247 } else {
2248 ac.unicode = vbi_caption_unicode
2249 (c, to_upper);
2250 }
2251 } else if (c < 0x1120) {
2252 /* Preamble Address Codes -- 001 crrr 1ri xxxu */
2253
2254 /* PAC is a non-spacing attribute and only
2255 stored in the buffer at the addressed
2256 column minus one if it replaces a
2257 transparent space (EIA 608-B Annex C.7,
2258 C.14). There's always a transparent space
2259 to the left of the first column but we show
2260 this zeroth column only if padding is
2261 enabled. */
2262 if (padding
2263 && VBI_TRANSPARENT_SPACE != cp[-1].opacity
2264 && 0x20 != cp[-1].unicode) {
2265 /* See 0 == c. */
2266 *cp++ = ac;
2267 vbi_char_clear_attr (cp - 1, -1);
2268 } else if (i > 0) {
2269 *cp++ = ac;
2270 cp[-1].opacity = VBI_TRANSPARENT_SPACE;
2271 }
2272
2273 vbi_char_clear_attr (&ac, VBI_UNDERLINE | VBI_ITALIC);
2274 if (c & 0x0001)
2275 vbi_char_set_attr (&ac, VBI_UNDERLINE);
2276 if (c & 0x0010) {
2277 ac.foreground = VBI_WHITE;
2278 } else {
2279 color = (c >> 1) & 7;
2280 if (7 == color) {
2281 ac.foreground = VBI_WHITE;
2282 vbi_char_set_attr (&ac, VBI_ITALIC);
2283 } else {
2284 ac.foreground = cc_color_map[color];
2285 }
2286 }
2287
2288 continue;
2289 } else if (c < 0x1130) {
2290 /* Mid-Row Codes -- 001 c001 010 xxxu */
2291 /* 47 CFR 15.119 Mid-Row Codes table,
2292 (h)(1)(ii), (h)(1)(iii). */
2293
2294 /* 47 CFR 15.119 (h)(1)(i), EIA 608-B Section
2295 6.2: Mid-Row codes, FON, BT, FA and FAU are
2296 set-at spacing attributes. */
2297
2298 vbi_char_clear_attr (&ac, -1);
2299 if (c & 0x0001)
2300 vbi_char_set_attr (&ac, VBI_UNDERLINE);
2301 color = (c >> 1) & 7;
2302 if (7 == color) {
2303 vbi_char_set_attr (&ac, VBI_ITALIC);
2304 } else {
2305 ac.foreground = cc_color_map[color];
2306 }
2307 } else if (c < 0x1220) {
2308 /* Special Characters -- 001 c001 011 xxxx */
2309 /* 47 CFR 15.119 Character Set Table. */
2310
2311 if (padding
2312 && VBI_TRANSPARENT_SPACE == cp[-1].opacity) {
2313 cp[-1] = ac;
2314 vbi_char_clear_attr (cp - 1, -1);
2315 }
2316
2317 /* Note we already stored 0 instead of 0x1139
2318 (transparent space) in the ch->buffer. */
2319 ac.unicode = vbi_caption_unicode (c, to_upper);
2320 } else if (c < 0x1428) {
2321 /* Extended Character Set -- 001 c01x 01x xxxx */
2322 /* EIA 608-B Section 6.4.2 */
2323
2324 if (padding
2325 && VBI_TRANSPARENT_SPACE == cp[-1].opacity) {
2326 cp[-1] = ac;
2327 vbi_char_clear_attr (cp - 1, -1);
2328 }
2329
2330 /* We do not force these characters to upper
2331 case because the extended character set
2332 includes upper case versions of all letters
2333 and lower case was probably deliberately
2334 transmitted. */
2335 ac.unicode = vbi_caption_unicode
2336 (c, /* to_upper */ FALSE);
2337 } else if (c < 0x172D) {
2338 /* FON Flash On -- 001 c10f 010 1000 */
2339 /* 47 CFR 15.119 (h)(1)(iii). */
2340
2341 vbi_char_set_attr (&ac, VBI_FLASH);
2342 } else if (c < 0x172E) {
2343 /* BT Background Transparent -- 001 c111 010 1101 */
2344 /* EIA 608-B Section 6.4. */
2345
2346 ac.opacity = VBI_TRANSPARENT_FULL;
2347 } else if (c <= 0x172F) {
2348 /* FA Foreground Black -- 001 c111 010 111u */
2349 /* EIA 608-B Section 6.4. */
2350
2351 if (c & 0x0001)
2352 vbi_char_set_attr (&ac, VBI_UNDERLINE);
2353 ac.foreground = VBI_BLACK;
2354 }
2355
2356 *cp++ = ac;
2357
2358 /* 47 CFR 15.119 and EIA 608-B are silent about
2359 underlined spaces, but considering the example in
2360 47 CFR (h)(1)(iv) which would produce something
2361 ugly like "__text" I suppose we should not
2362 underline them. For good measure we also clear the
2363 invisible italic and flash attribute. */
2364 if (0x20 == ac.unicode)
2365 vbi_char_clear_attr (cp - 1, -1);
2366 }
2367
2368 if (padding) {
2369 ac.unicode = 0x20;
2370 vbi_char_clear_attr (&ac, -1);
2371
2372 if (VBI_TRANSPARENT_SPACE != cp[-1].opacity
2373 && 0x20 != cp[-1].unicode) {
2374 *cp = ac;
2375 } else {
2376 ac.opacity = VBI_TRANSPARENT_SPACE;
2377 *cp = ac;
2378 }
2379 }
2380 }
2381
2382 typedef enum {
2383 /**
2384 * 47 CFR Section 15.119 requires caption decoders to roll
2385 * caption smoothly: Nominally each character cell has a
2386 * height of 13 field lines. When this flag is set the current
2387 * caption should be displayed with a vertical offset of 12
2388 * field lines, and after every 1001 / 30000 seconds the
2389 * caption overlay should move up by one field line until the
2390 * offset is zero. The roll rate should be no more than 0.433
2391 * seconds/row for other character cell heights.
2392 *
2393 * The flag may be set again before the offset returned to
2394 * zero. The caption overlay should jump to offset 12 in this
2395 * case regardless.
2396 */
2397 VBI_START_ROLLING = (1 << 0)
2398 } vbi_cc_page_flags;
2399
2400 static void
cc_display_event(struct cc_decoder * cd,struct cc_channel * ch,vbi_cc_page_flags flags)2401 cc_display_event (struct cc_decoder * cd,
2402 struct cc_channel * ch,
2403 vbi_cc_page_flags flags)
2404 {
2405 cd = cd; /* unused */
2406 ch = ch;
2407 flags = flags;
2408 }
2409
2410 /* This decoder is mainly designed to overlay caption onto live video,
2411 but to create transcripts we also offer an event every time a line
2412 of caption is complete. The event occurs when certain control codes
2413 are received.
2414
2415 In POP_ON mode we send the event upon reception of EOC, which swaps
2416 the displayed and non-displayed memory.
2417
2418 In ROLL_UP and TEXT mode captioners are not expected to display new
2419 text by erasing and overwriting a row with PAC, TOx, BS and DER so
2420 we ignore these codes. In ROLL_UP mode CR, EDM, EOC, RCL and RDC
2421 complete a line. CR moves the cursor to a new row, EDM erases the
2422 displayed memory. The remaining codes switch to POP_ON or PAINT_ON
2423 mode. In TEXT mode CR and TR are our line completion indicators. CR
2424 works as above and TR erases the displayed memory. EDM, EOC, RDC,
2425 RCL and RUx have no effect on TEXT buffers.
2426
2427 In PAINT_ON mode RDC never erases the displayed memory and CR has
2428 no function. Instead captioners can freely position the cursor and
2429 erase or overwrite (parts of) rows with PAC, TOx, BS and DER, or
2430 erase all rows with EDM. We send an event on PAC, EDM, EOC, RCL and
2431 RUx, provided the characters (including spacing attributes) in the
2432 current row changed since the last event. PAC is the only control
2433 code which can move the cursor to the left and/or to a new row, and
2434 likely to introduce a new line. EOC, RCL and RUx switch to POP_ON
2435 or ROLL_UP mode. */
2436
2437 static void
cc_stream_event(struct cc_decoder * cd,struct cc_channel * ch,unsigned int first_row,unsigned int last_row)2438 cc_stream_event (struct cc_decoder * cd,
2439 struct cc_channel * ch,
2440 unsigned int first_row,
2441 unsigned int last_row)
2442 {
2443 vbi_pgno channel;
2444 unsigned int row;
2445
2446 channel = cc_channel_num (cd, ch);
2447
2448 for (row = first_row; row <= last_row; ++row) {
2449 struct vbi_char text[36];
2450 unsigned int end;
2451
2452 cc_format_row (cd, text, ch,
2453 ch->displayed_buffer,
2454 row, /* to_upper */ FALSE,
2455 /* padding */ FALSE);
2456
2457 for (end = 32; end > 0; --end) {
2458 if (VBI_TRANSPARENT_SPACE != text[end - 1].opacity)
2459 break;
2460 }
2461
2462 if (0 == end)
2463 continue;
2464
2465 {
2466 struct program *pr;
2467
2468 pr = PARENT (cd, struct program, cr.cc);
2469 cr_new_line (&pr->cr, &ch->timestamp_c0,
2470 channel, text, /* length */ 32);
2471 }
2472 }
2473
2474 cc_timestamp_reset (&ch->timestamp_c0);
2475 }
2476
2477 static void
cc_put_char(struct cc_decoder * cd,struct cc_channel * ch,int c,vbi_bool displayable,vbi_bool backspace)2478 cc_put_char (struct cc_decoder * cd,
2479 struct cc_channel * ch,
2480 int c,
2481 vbi_bool displayable,
2482 vbi_bool backspace)
2483 {
2484 uint16_t *text;
2485 unsigned int curr_buffer;
2486 unsigned int row;
2487 unsigned int column;
2488
2489 /* 47 CFR Section 15.119 (f)(1), (f)(2), (f)(3). */
2490 curr_buffer = ch->displayed_buffer
2491 ^ (CC_MODE_POP_ON == ch->mode);
2492
2493 row = ch->curr_row;
2494 column = ch->curr_column;
2495
2496 if (unlikely (backspace)) {
2497 /* 47 CFR 15.119 (f)(1)(vi), (f)(2)(ii),
2498 (f)(3)(i). EIA 608-B Section 6.4.2, 7.4. */
2499 if (column > CC_FIRST_COLUMN)
2500 --column;
2501 } else {
2502 /* 47 CFR 15.119 (f)(1)(v), (f)(1)(vi), (f)(2)(ii),
2503 (f)(3)(i). EIA 608-B Section 7.4. */
2504 if (column < CC_LAST_COLUMN)
2505 ch->curr_column = column + 1;
2506 }
2507
2508 text = &ch->buffer[curr_buffer][row][0];
2509 text[column] = c;
2510
2511 /* Send a display update event when the displayed buffer of
2512 the current channel changed, but no more than once for each
2513 pair of Closed Caption bytes. */
2514 /* XXX This may not be a visible change, but such cases are
2515 rare and we'd need something close to format_row() to be
2516 sure. */
2517 if (CC_MODE_POP_ON != ch->mode) {
2518 cd->event_pending = ch;
2519 }
2520
2521 if (likely (displayable)) {
2522 /* Note EIA 608-B Annex C.7, C.14. */
2523 if (CC_FIRST_COLUMN == column
2524 || 0 == text[column - 1]) {
2525 /* Note last_pac may be 0 as well. */
2526 text[column - 1] = ch->last_pac;
2527 }
2528
2529 if (c >= 'a' && c <= 'z') {
2530 ch->uppercase_predictor = 0;
2531 } else if (c >= 'A' && c <= 'Z') {
2532 unsigned int up;
2533
2534 up = ch->uppercase_predictor + 1;
2535 if (up > 0)
2536 ch->uppercase_predictor = up;
2537 }
2538 } else if (unlikely (0 == c)) {
2539 unsigned int i;
2540
2541 /* This is Special Character "Transparent space". */
2542
2543 for (i = CC_FIRST_COLUMN; i <= CC_LAST_COLUMN; ++i)
2544 c |= ch->buffer[curr_buffer][row][i];
2545
2546 ch->dirty[curr_buffer] &= ~((0 == c) << row);
2547
2548 return;
2549 }
2550
2551 assert (sizeof (ch->dirty[0]) * 8 - 1 >= CC_MAX_ROWS);
2552 ch->dirty[curr_buffer] |= 1 << row;
2553
2554 if (ch->timestamp_c0.pts < 0
2555 && 0 == (ch->timestamp_c0.sys.tv_sec
2556 | ch->timestamp_c0.sys.tv_usec)) {
2557 ch->timestamp_c0 = cd->timestamp;
2558 }
2559 }
2560
2561 static void
cc_ext_control_code(struct cc_decoder * cd,struct cc_channel * ch,unsigned int c2)2562 cc_ext_control_code (struct cc_decoder * cd,
2563 struct cc_channel * ch,
2564 unsigned int c2)
2565 {
2566 unsigned int column;
2567
2568 switch (c2) {
2569 case 0x21: /* TO1 */
2570 case 0x22: /* TO2 */
2571 case 0x23: /* TO3 Tab Offset -- 001 c111 010 00xx */
2572 /* 47 CFR 15.119 (e)(1)(ii). EIA 608-B Section 7.4,
2573 Annex C.7. */
2574 column = ch->curr_column + (c2 & 3);
2575 ch->curr_column = MIN (column,
2576 (unsigned int) CC_LAST_COLUMN);
2577 break;
2578
2579 case 0x24: /* Select standard character set in normal size */
2580 case 0x25: /* Select standard character set in double size */
2581 case 0x26: /* Select first private character set */
2582 case 0x27: /* Select second private character set */
2583 case 0x28: /* Select character set GB 2312-80 (Chinese) */
2584 case 0x29: /* Select character set KSC 5601-1987 (Korean) */
2585 case 0x2A: /* Select first registered character set. */
2586 /* EIA 608-B Section 6.3 Closed Group Extensions. */
2587 break;
2588
2589 case 0x2D: /* BT Background Transparent -- 001 c111 010 1101 */
2590 case 0x2E: /* FA Foreground Black -- 001 c111 010 1110 */
2591 case 0x2F: /* FAU Foregr. Black Underl. -- 001 c111 010 1111 */
2592 /* EIA 608-B Section 6.2. */
2593 cc_put_char (cd, ch, 0x1700 | c2,
2594 /* displayable */ FALSE,
2595 /* backspace */ TRUE);
2596 break;
2597
2598 default:
2599 /* 47 CFR Section 15.119 (j): Ignore. */
2600 break;
2601 }
2602 }
2603
2604 /* Send a stream event if the current row has changed since the last
2605 stream event. This is necessary in paint-on mode where CR has no
2606 function and captioners can freely position the cursor to erase or
2607 overwrite (parts of) rows. */
2608 static void
cc_stream_event_if_changed(struct cc_decoder * cd,struct cc_channel * ch)2609 cc_stream_event_if_changed (struct cc_decoder * cd,
2610 struct cc_channel * ch)
2611 {
2612 unsigned int curr_buffer;
2613 unsigned int row;
2614 unsigned int i;
2615
2616 curr_buffer = ch->displayed_buffer;
2617 row = ch->curr_row;
2618
2619 if (0 == (ch->dirty[curr_buffer] & (1 << row)))
2620 return;
2621
2622 for (i = CC_FIRST_COLUMN; i <= CC_LAST_COLUMN; ++i) {
2623 unsigned int c1;
2624 unsigned int c2;
2625
2626 c1 = ch->buffer[curr_buffer][row][i];
2627 if (c1 >= 0x1040) {
2628 if (c1 < 0x1120) {
2629 c1 = 0; /* PAC -- non-spacing */
2630 } else if (c1 < 0x1130 || c1 >= 0x1428) {
2631 /* MR, FON, BT, FA, FAU -- spacing */
2632 c1 = 0x20;
2633 }
2634 }
2635
2636 c2 = ch->buffer[2][row][i];
2637 if (c2 >= 0x1040) {
2638 if (c2 < 0x1120) {
2639 c2 = 0;
2640 } else if (c2 < 0x1130 || c2 >= 0x1428) {
2641 c1 = 0x20;
2642 }
2643 }
2644
2645 if (c1 != c2) {
2646 cc_stream_event (cd, ch, row, row);
2647
2648 memcpy (ch->buffer[2][row],
2649 ch->buffer[curr_buffer][row],
2650 sizeof (ch->buffer[0][0]));
2651
2652 ch->dirty[2] = ch->dirty[curr_buffer];
2653
2654 return;
2655 }
2656 }
2657 }
2658
2659 static void
cc_end_of_caption(struct cc_decoder * cd,struct cc_channel * ch)2660 cc_end_of_caption (struct cc_decoder * cd,
2661 struct cc_channel * ch)
2662 {
2663 unsigned int curr_buffer;
2664 unsigned int row;
2665
2666 /* EOC End Of Caption -- 001 c10f 010 1111 */
2667
2668 curr_buffer = ch->displayed_buffer;
2669
2670 switch (ch->mode) {
2671 case CC_MODE_UNKNOWN:
2672 case CC_MODE_POP_ON:
2673 break;
2674
2675 case CC_MODE_ROLL_UP:
2676 row = ch->curr_row;
2677 if (0 != (ch->dirty[curr_buffer] & (1 << row)))
2678 cc_stream_event (cd, ch, row, row);
2679 break;
2680
2681 case CC_MODE_PAINT_ON:
2682 cc_stream_event_if_changed (cd, ch);
2683 break;
2684
2685 case CC_MODE_TEXT:
2686 /* Not reached. (ch is a caption channel.) */
2687 return;
2688 }
2689
2690 ch->displayed_buffer = curr_buffer ^= 1;
2691
2692 /* 47 CFR Section 15.119 (f)(2). */
2693 ch->mode = CC_MODE_POP_ON;
2694
2695 if (0 != ch->dirty[curr_buffer]) {
2696 ch->timestamp_c0 = cd->timestamp;
2697
2698 cc_stream_event (cd, ch,
2699 CC_FIRST_ROW,
2700 CC_LAST_ROW);
2701
2702 cc_display_event (cd, ch, 0);
2703 }
2704 }
2705
2706 static void
cc_carriage_return(struct cc_decoder * cd,struct cc_channel * ch)2707 cc_carriage_return (struct cc_decoder * cd,
2708 struct cc_channel * ch)
2709 {
2710 unsigned int curr_buffer;
2711 unsigned int row;
2712 unsigned int window_rows;
2713 unsigned int first_row;
2714
2715 /* CR Carriage Return -- 001 c10f 010 1101 */
2716
2717 curr_buffer = ch->displayed_buffer;
2718 row = ch->curr_row;
2719
2720 switch (ch->mode) {
2721 case CC_MODE_UNKNOWN:
2722 return;
2723
2724 case CC_MODE_ROLL_UP:
2725 /* 47 CFR Section 15.119 (f)(1)(iii). */
2726 ch->curr_column = CC_FIRST_COLUMN;
2727
2728 /* 47 CFR 15.119 (f)(1): "The cursor always remains on
2729 the base row." */
2730
2731 /* XXX Spec? */
2732 ch->last_pac = 0;
2733
2734 /* No event if the buffer contains only
2735 TRANSPARENT_SPACEs. */
2736 if (0 == ch->dirty[curr_buffer])
2737 return;
2738
2739 window_rows = MIN (row + 1 - CC_FIRST_ROW,
2740 ch->window_rows);
2741 break;
2742
2743 case CC_MODE_POP_ON:
2744 case CC_MODE_PAINT_ON:
2745 /* 47 CFR 15.119 (f)(2)(i), (f)(3)(i): No effect. */
2746 return;
2747
2748 case CC_MODE_TEXT:
2749 /* 47 CFR Section 15.119 (f)(1)(iii). */
2750 ch->curr_column = CC_FIRST_COLUMN;
2751
2752 /* XXX Spec? */
2753 ch->last_pac = 0;
2754
2755 /* EIA 608-B Section 7.4: "When Text Mode has
2756 initially been selected and the specified Text
2757 memory is empty, the cursor starts at the topmost
2758 row, Column 1, and moves down to Column 1 on the
2759 next row each time a Carriage Return is received
2760 until the last available row is reached. A variety
2761 of methods may be used to accomplish the scrolling,
2762 provided that the text is legible while moving. For
2763 example, as soon as all of the available rows of
2764 text are on the screen, Text Mode switches to the
2765 standard roll-up type of presentation." */
2766
2767 if (CC_LAST_ROW != row) {
2768 if (0 != (ch->dirty[curr_buffer] & (1 << row))) {
2769 cc_stream_event (cd, ch, row, row);
2770 }
2771
2772 ch->curr_row = row + 1;
2773
2774 return;
2775 }
2776
2777 /* No event if the buffer contains all
2778 TRANSPARENT_SPACEs. */
2779 if (0 == ch->dirty[curr_buffer])
2780 return;
2781
2782 window_rows = CC_MAX_ROWS;
2783
2784 break;
2785 }
2786
2787 /* 47 CFR Section 15.119 (f)(1)(iii). In roll-up mode: "Each
2788 time a Carriage Return is received, the text in the top row
2789 of the window is erased from memory and from the display or
2790 scrolled off the top of the window. The remaining rows of
2791 text are each rolled up into the next highest row in the
2792 window, leaving the base row blank and ready to accept new
2793 text." */
2794
2795 if (0 != (ch->dirty[curr_buffer] & (1 << row))) {
2796 cc_stream_event (cd, ch, row, row);
2797 }
2798
2799 first_row = row + 1 - window_rows;
2800 memmove (ch->buffer[curr_buffer][first_row],
2801 ch->buffer[curr_buffer][first_row + 1],
2802 (window_rows - 1) * sizeof (ch->buffer[0][0]));
2803
2804 ch->dirty[curr_buffer] >>= 1;
2805
2806 memset (ch->buffer[curr_buffer][row], 0,
2807 sizeof (ch->buffer[0][0]));
2808
2809 cc_display_event (cd, ch, VBI_START_ROLLING);
2810 }
2811
2812 static void
cc_erase_memory(struct cc_decoder * cd,struct cc_channel * ch,unsigned int buffer)2813 cc_erase_memory (struct cc_decoder * cd,
2814 struct cc_channel * ch,
2815 unsigned int buffer)
2816 {
2817 if (0 != ch->dirty[buffer]) {
2818 CLEAR (ch->buffer[buffer]);
2819
2820 ch->dirty[buffer] = 0;
2821
2822 if (buffer == ch->displayed_buffer)
2823 cc_display_event (cd, ch, 0);
2824 }
2825 }
2826
2827 static void
cc_erase_displayed_memory(struct cc_decoder * cd,struct cc_channel * ch)2828 cc_erase_displayed_memory (struct cc_decoder * cd,
2829 struct cc_channel * ch)
2830 {
2831 unsigned int row;
2832
2833 /* EDM Erase Displayed Memory -- 001 c10f 010 1100 */
2834
2835 switch (ch->mode) {
2836 case CC_MODE_UNKNOWN:
2837 /* We have not received EOC, RCL, RDC or RUx yet, but
2838 ch is valid. */
2839 break;
2840
2841 case CC_MODE_ROLL_UP:
2842 row = ch->curr_row;
2843 if (0 != (ch->dirty[ch->displayed_buffer] & (1 << row)))
2844 cc_stream_event (cd, ch, row, row);
2845 break;
2846
2847 case CC_MODE_PAINT_ON:
2848 cc_stream_event_if_changed (cd, ch);
2849 break;
2850
2851 case CC_MODE_POP_ON:
2852 /* Nothing to do. */
2853 break;
2854
2855 case CC_MODE_TEXT:
2856 /* Not reached. (ch is a caption channel.) */
2857 return;
2858 }
2859
2860 /* May send a display event. */
2861 cc_erase_memory (cd, ch, ch->displayed_buffer);
2862 }
2863
2864 static void
cc_text_restart(struct cc_decoder * cd,struct cc_channel * ch)2865 cc_text_restart (struct cc_decoder * cd,
2866 struct cc_channel * ch)
2867 {
2868 unsigned int curr_buffer;
2869 unsigned int row;
2870
2871 /* TR Text Restart -- 001 c10f 010 1010 */
2872
2873 curr_buffer = ch->displayed_buffer;
2874 row = ch->curr_row;
2875
2876 /* ch->mode is invariably CC_MODE_TEXT. */
2877
2878 if (0 != (ch->dirty[curr_buffer] & (1 << row))) {
2879 cc_stream_event (cd, ch, row, row);
2880 }
2881
2882 /* EIA 608-B Section 7.4. */
2883 /* May send a display event. */
2884 cc_erase_memory (cd, ch, ch->displayed_buffer);
2885
2886 /* EIA 608-B Section 7.4. */
2887 ch->curr_row = CC_FIRST_ROW;
2888 ch->curr_column = CC_FIRST_COLUMN;
2889 }
2890
2891 static void
cc_resume_direct_captioning(struct cc_decoder * cd,struct cc_channel * ch)2892 cc_resume_direct_captioning (struct cc_decoder * cd,
2893 struct cc_channel * ch)
2894 {
2895 unsigned int curr_buffer;
2896 unsigned int row;
2897
2898 /* RDC Resume Direct Captioning -- 001 c10f 010 1001 */
2899
2900 /* 47 CFR 15.119 (f)(1)(x), (f)(2)(vi) and EIA 608-B Annex
2901 B.7: Does not erase memory, does not move the cursor when
2902 resuming after a Text transmission.
2903
2904 XXX If ch->mode is unknown, roll-up or pop-on, what shall
2905 we do if no PAC is received between RDC and the text? */
2906
2907 curr_buffer = ch->displayed_buffer;
2908 row = ch->curr_row;
2909
2910 switch (ch->mode) {
2911 case CC_MODE_ROLL_UP:
2912 if (0 != (ch->dirty[curr_buffer] & (1 << row)))
2913 cc_stream_event (cd, ch, row, row);
2914
2915 /* fall through */
2916
2917 case CC_MODE_UNKNOWN:
2918 case CC_MODE_POP_ON:
2919 /* No change since last stream_event(). */
2920 memcpy (ch->buffer[2], ch->buffer[curr_buffer],
2921 sizeof (ch->buffer[2]));
2922 break;
2923
2924 case CC_MODE_PAINT_ON:
2925 /* Mode continues. */
2926 break;
2927
2928 case CC_MODE_TEXT:
2929 /* Not reached. (ch is a caption channel.) */
2930 return;
2931 }
2932
2933 ch->mode = CC_MODE_PAINT_ON;
2934 }
2935
2936 static void
cc_resize_window(struct cc_decoder * cd,struct cc_channel * ch,unsigned int new_rows)2937 cc_resize_window (struct cc_decoder * cd,
2938 struct cc_channel * ch,
2939 unsigned int new_rows)
2940 {
2941 unsigned int curr_buffer;
2942 unsigned int max_rows;
2943 unsigned int old_rows;
2944 unsigned int row1;
2945
2946 curr_buffer = ch->displayed_buffer;
2947
2948 /* No event if the buffer contains all TRANSPARENT_SPACEs. */
2949 if (0 == ch->dirty[curr_buffer])
2950 return;
2951
2952 row1 = ch->curr_row + 1;
2953 max_rows = row1 - CC_FIRST_ROW;
2954 old_rows = MIN (ch->window_rows, max_rows);
2955 new_rows = MIN (new_rows, max_rows);
2956
2957 /* Nothing to do unless the window shrinks. */
2958 if (0 == new_rows || new_rows >= old_rows)
2959 return;
2960
2961 memset (&ch->buffer[curr_buffer][row1 - old_rows][0], 0,
2962 (old_rows - new_rows)
2963 * sizeof (ch->buffer[0][0]));
2964
2965 ch->dirty[curr_buffer] &= -1 << (row1 - new_rows);
2966
2967 cc_display_event (cd, ch, 0);
2968 }
2969
2970 static void
cc_roll_up_caption(struct cc_decoder * cd,struct cc_channel * ch,unsigned int c2)2971 cc_roll_up_caption (struct cc_decoder * cd,
2972 struct cc_channel * ch,
2973 unsigned int c2)
2974 {
2975 unsigned int window_rows;
2976
2977 /* Roll-Up Captions -- 001 c10f 010 01xx */
2978
2979 window_rows = (c2 & 7) - 3; /* 2, 3, 4 */
2980
2981 switch (ch->mode) {
2982 case CC_MODE_ROLL_UP:
2983 /* 47 CFR 15.119 (f)(1)(iv). */
2984 /* May send a display event. */
2985 cc_resize_window (cd, ch, window_rows);
2986
2987 /* fall through */
2988
2989 case CC_MODE_UNKNOWN:
2990 ch->mode = CC_MODE_ROLL_UP;
2991 ch->window_rows = window_rows;
2992
2993 /* 47 CFR 15.119 (f)(1)(ix): No cursor movements,
2994 no memory erasing. */
2995
2996 break;
2997
2998 case CC_MODE_PAINT_ON:
2999 cc_stream_event_if_changed (cd, ch);
3000
3001 /* fall through */
3002
3003 case CC_MODE_POP_ON:
3004 ch->mode = CC_MODE_ROLL_UP;
3005 ch->window_rows = window_rows;
3006
3007 /* 47 CFR 15.119 (f)(1)(ii). */
3008 ch->curr_row = CC_LAST_ROW;
3009 ch->curr_column = CC_FIRST_COLUMN;
3010
3011 /* 47 CFR 15.119 (f)(1)(x). */
3012 /* May send a display event. */
3013 cc_erase_memory (cd, ch, ch->displayed_buffer);
3014 cc_erase_memory (cd, ch, ch->displayed_buffer ^ 1);
3015
3016 break;
3017
3018 case CC_MODE_TEXT:
3019 /* Not reached. (ch is a caption channel.) */
3020 return;
3021 }
3022 }
3023
3024 static void
cc_delete_to_end_of_row(struct cc_decoder * cd,struct cc_channel * ch)3025 cc_delete_to_end_of_row (struct cc_decoder * cd,
3026 struct cc_channel * ch)
3027 {
3028 unsigned int curr_buffer;
3029 unsigned int row;
3030
3031 /* DER Delete To End Of Row -- 001 c10f 010 0100 */
3032
3033 /* 47 CFR 15.119 (f)(1)(vii), (f)(2)(iii), (f)(3)(ii) and EIA
3034 608-B Section 7.4: In all caption modes and Text mode
3035 "[the] Delete to End of Row command will erase from memory
3036 any characters or control codes starting at the current
3037 cursor location and in all columns to its right on the same
3038 row." */
3039
3040 curr_buffer = ch->displayed_buffer
3041 ^ (CC_MODE_POP_ON == ch->mode);
3042
3043 row = ch->curr_row;
3044
3045 /* No event if the row contains only TRANSPARENT_SPACEs. */
3046 if (0 != (ch->dirty[curr_buffer] & (1 << row))) {
3047 unsigned int column;
3048 unsigned int i;
3049 uint16_t c;
3050
3051 column = ch->curr_column;
3052
3053 memset (&ch->buffer[curr_buffer][row][column], 0,
3054 (CC_LAST_COLUMN - column + 1)
3055 * sizeof (ch->buffer[0][0][0]));
3056
3057 c = 0;
3058 for (i = CC_FIRST_COLUMN; i < column; ++i)
3059 c |= ch->buffer[curr_buffer][row][i];
3060
3061 ch->dirty[curr_buffer] &= ~((0 == c) << row);
3062
3063 cc_display_event (cd, ch, 0);
3064 }
3065 }
3066
3067 static void
cc_backspace(struct cc_decoder * cd,struct cc_channel * ch)3068 cc_backspace (struct cc_decoder * cd,
3069 struct cc_channel * ch)
3070 {
3071 unsigned int curr_buffer;
3072 unsigned int row;
3073 unsigned int column;
3074
3075 /* BS Backspace -- 001 c10f 010 0001 */
3076
3077 /* 47 CFR Section 15.119 (f)(1)(vi), (f)(2)(ii), (f)(3)(i) and
3078 EIA 608-B Section 7.4. */
3079 column = ch->curr_column;
3080 if (column <= CC_FIRST_COLUMN)
3081 return;
3082
3083 ch->curr_column = --column;
3084
3085 curr_buffer = ch->displayed_buffer
3086 ^ (CC_MODE_POP_ON == ch->mode);
3087
3088 row = ch->curr_row;
3089
3090 /* No event if there's no visible effect. */
3091 if (0 != ch->buffer[curr_buffer][row][column]) {
3092 unsigned int i;
3093 uint16_t c;
3094
3095 /* 47 CFR 15.119 (f), (f)(1)(vi), (f)(2)(ii) and EIA
3096 608-B Section 7.4. */
3097 ch->buffer[curr_buffer][row][column] = 0;
3098
3099 c = 0;
3100 for (i = CC_FIRST_COLUMN; i <= CC_LAST_COLUMN; ++i)
3101 c |= ch->buffer[curr_buffer][row][i];
3102
3103 ch->dirty[curr_buffer] &= ~((0 == c) << row);
3104
3105 cc_display_event (cd, ch, 0);
3106 }
3107 }
3108
3109 static void
cc_resume_caption_loading(struct cc_decoder * cd,struct cc_channel * ch)3110 cc_resume_caption_loading (struct cc_decoder * cd,
3111 struct cc_channel * ch)
3112 {
3113 unsigned int row;
3114
3115 /* RCL Resume Caption Loading -- 001 c10f 010 0000 */
3116
3117 switch (ch->mode) {
3118 case CC_MODE_UNKNOWN:
3119 case CC_MODE_POP_ON:
3120 break;
3121
3122 case CC_MODE_ROLL_UP:
3123 row = ch->curr_row;
3124 if (0 != (ch->dirty[ch->displayed_buffer] & (1 << row)))
3125 cc_stream_event (cd, ch, row, row);
3126 break;
3127
3128 case CC_MODE_PAINT_ON:
3129 cc_stream_event_if_changed (cd, ch);
3130 break;
3131
3132 case CC_MODE_TEXT:
3133 /* Not reached. (ch is a caption channel.) */
3134 return;
3135 }
3136
3137 /* 47 CFR 15.119 (f)(1)(x): Does not erase memory.
3138 (f)(2)(iv): Cursor position remains unchanged. */
3139
3140 ch->mode = CC_MODE_POP_ON;
3141 }
3142
3143
3144
3145 /* Note curr_ch is invalid if UNKNOWN_CC_CHANNEL == cd->cc.curr_ch_num. */
3146 static struct cc_channel *
cc_switch_channel(struct cc_decoder * cd,struct cc_channel * curr_ch,vbi_pgno new_ch_num,enum field_num f)3147 cc_switch_channel (struct cc_decoder * cd,
3148 struct cc_channel * curr_ch,
3149 vbi_pgno new_ch_num,
3150 enum field_num f)
3151 {
3152 struct cc_channel *new_ch;
3153
3154 if (UNKNOWN_CC_CHANNEL != cd->curr_ch_num[f]
3155 && CC_MODE_UNKNOWN != curr_ch->mode) {
3156 /* XXX Force a display update if we do not send events
3157 on every display change. */
3158 }
3159
3160 cd->curr_ch_num[f] = new_ch_num;
3161 new_ch = &cd->channel[new_ch_num - VBI_CAPTION_CC1];
3162
3163 return new_ch;
3164 }
3165
3166 /* Note ch is invalid if UNKNOWN_CC_CHANNEL == cd->cc.curr_ch_num[f]. */
3167 static void
cc_misc_control_code(struct cc_decoder * cd,struct cc_channel * ch,unsigned int c2,unsigned int ch_num0,enum field_num f)3168 cc_misc_control_code (struct cc_decoder * cd,
3169 struct cc_channel * ch,
3170 unsigned int c2,
3171 unsigned int ch_num0,
3172 enum field_num f)
3173 {
3174 unsigned int new_ch_num;
3175
3176 /* Misc Control Codes -- 001 c10f 010 xxxx */
3177
3178 /* c = channel (0 -> CC1/CC3/T1/T3, 1 -> CC2/CC4/T2/T4)
3179 -- 47 CFR Section 15.119, EIA 608-B Section 7.7.
3180 f = field (0 -> F1, 1 -> F2)
3181 -- EIA 608-B Section 8.4, 8.5. */
3182
3183 /* XXX The f flag is intended to detect accidential field
3184 swapping and we should use it for that purpose. */
3185
3186 switch (c2 & 15) {
3187 case 0: /* RCL Resume Caption Loading -- 001 c10f 010 0000 */
3188 /* 47 CFR 15.119 (f)(2) and EIA 608-B Section 7.7. */
3189 new_ch_num = VBI_CAPTION_CC1 + (ch_num0 & 3);
3190 ch = cc_switch_channel (cd, ch, new_ch_num, f);
3191 cc_resume_caption_loading (cd, ch);
3192 break;
3193
3194 case 1: /* BS Backspace -- 001 c10f 010 0001 */
3195 if (UNKNOWN_CC_CHANNEL == cd->curr_ch_num[f]
3196 || CC_MODE_UNKNOWN == ch->mode)
3197 break;
3198 cc_backspace (cd, ch);
3199 break;
3200
3201 case 2: /* reserved (formerly AOF Alarm Off) */
3202 case 3: /* reserved (formerly AON Alarm On) */
3203 break;
3204
3205 case 4: /* DER Delete To End Of Row -- 001 c10f 010 0100 */
3206 if (UNKNOWN_CC_CHANNEL == cd->curr_ch_num[f]
3207 || CC_MODE_UNKNOWN == ch->mode)
3208 break;
3209 cc_delete_to_end_of_row (cd, ch);
3210 break;
3211
3212 case 5: /* RU2 */
3213 case 6: /* RU3 */
3214 case 7: /* RU4 Roll-Up Captions -- 001 c10f 010 01xx */
3215 /* 47 CFR 15.119 (f)(1) and EIA 608-B Section 7.7. */
3216 new_ch_num = VBI_CAPTION_CC1 + (ch_num0 & 3);
3217 ch = cc_switch_channel (cd, ch, new_ch_num, f);
3218 cc_roll_up_caption (cd, ch, c2);
3219 break;
3220
3221 case 8: /* FON Flash On -- 001 c10f 010 1000 */
3222 if (UNKNOWN_CC_CHANNEL == cd->curr_ch_num[f]
3223 || CC_MODE_UNKNOWN == ch->mode)
3224 break;
3225
3226 /* 47 CFR 15.119 (h)(1)(i): Spacing attribute. */
3227 cc_put_char (cd, ch, 0x1428,
3228 /* displayable */ FALSE,
3229 /* backspace */ FALSE);
3230 break;
3231
3232 case 9: /* RDC Resume Direct Captioning -- 001 c10f 010 1001 */
3233 /* 47 CFR 15.119 (f)(3) and EIA 608-B Section 7.7. */
3234 new_ch_num = VBI_CAPTION_CC1 + (ch_num0 & 3);
3235 ch = cc_switch_channel (cd, ch, new_ch_num, f);
3236 cc_resume_direct_captioning (cd, ch);
3237 break;
3238
3239 case 10: /* TR Text Restart -- 001 c10f 010 1010 */
3240 /* EIA 608-B Section 7.4. */
3241 new_ch_num = VBI_CAPTION_T1 + (ch_num0 & 3);
3242 ch = cc_switch_channel (cd, ch, new_ch_num, f);
3243 cc_text_restart (cd, ch);
3244 break;
3245
3246 case 11: /* RTD Resume Text Display -- 001 c10f 010 1011 */
3247 /* EIA 608-B Section 7.4. */
3248 new_ch_num = VBI_CAPTION_T1 + (ch_num0 & 3);
3249 ch = cc_switch_channel (cd, ch, new_ch_num, f);
3250 /* ch->mode is invariably CC_MODE_TEXT. */
3251 break;
3252
3253 case 12: /* EDM Erase Displayed Memory -- 001 c10f 010 1100 */
3254 /* 47 CFR 15.119 (f). EIA 608-B Section 7.7 and Annex
3255 B.7: "[The] command shall be acted upon as
3256 appropriate for caption processing without
3257 terminating the Text Mode data stream." */
3258
3259 /* We need not check cd->curr_ch_num because bit 2 is
3260 implied, bit 1 is the known field number and bit 0
3261 is coded in the control code. */
3262 ch = &cd->channel[ch_num0 & 3];
3263
3264 cc_erase_displayed_memory (cd, ch);
3265
3266 break;
3267
3268 case 13: /* CR Carriage Return -- 001 c10f 010 1101 */
3269 if (UNKNOWN_CC_CHANNEL == cd->curr_ch_num[f])
3270 break;
3271 cc_carriage_return (cd, ch);
3272 break;
3273
3274 case 14: /* ENM Erase Non-Displayed Memory -- 001 c10f 010 1110 */
3275 /* 47 CFR 15.119 (f)(2)(v). EIA 608-B Section 7.7 and
3276 Annex B.7: "[The] command shall be acted upon as
3277 appropriate for caption processing without
3278 terminating the Text Mode data stream." */
3279
3280 /* See EDM. */
3281 ch = &cd->channel[ch_num0 & 3];
3282
3283 cc_erase_memory (cd, ch, ch->displayed_buffer ^ 1);
3284
3285 break;
3286
3287 case 15: /* EOC End Of Caption -- 001 c10f 010 1111 */
3288 /* 47 CFR 15.119 (f), (f)(2), (f)(3)(iv) and EIA 608-B
3289 Section 7.7, Annex C.11. */
3290 new_ch_num = VBI_CAPTION_CC1 + (ch_num0 & 3);
3291 ch = cc_switch_channel (cd, ch, new_ch_num, f);
3292 cc_end_of_caption (cd, ch);
3293 break;
3294 }
3295 }
3296
3297 static void
cc_move_window(struct cc_decoder * cd,struct cc_channel * ch,unsigned int new_base_row)3298 cc_move_window (struct cc_decoder * cd,
3299 struct cc_channel * ch,
3300 unsigned int new_base_row)
3301 {
3302 uint8_t *base;
3303 unsigned int curr_buffer;
3304 unsigned int bytes_per_row;
3305 unsigned int old_max_rows;
3306 unsigned int new_max_rows;
3307 unsigned int copy_bytes;
3308 unsigned int erase_begin;
3309 unsigned int erase_end;
3310
3311 curr_buffer = ch->displayed_buffer;
3312
3313 /* No event if we do not move the window or the buffer
3314 contains only TRANSPARENT_SPACEs. */
3315 if (new_base_row == ch->curr_row
3316 || 0 == ch->dirty[curr_buffer])
3317 return;
3318
3319 base = (void *) &ch->buffer[curr_buffer][CC_FIRST_ROW][0];
3320 bytes_per_row = sizeof (ch->buffer[0][0]);
3321
3322 old_max_rows = ch->curr_row + 1 - CC_FIRST_ROW;
3323 new_max_rows = new_base_row + 1 - CC_FIRST_ROW;
3324 copy_bytes = MIN (MIN (old_max_rows, new_max_rows),
3325 ch->window_rows) * bytes_per_row;
3326
3327 if (new_base_row < ch->curr_row) {
3328 erase_begin = (new_base_row + 1) * bytes_per_row;
3329 erase_end = (ch->curr_row + 1) * bytes_per_row;
3330
3331 memmove (base + erase_begin - copy_bytes,
3332 base + erase_end - copy_bytes, copy_bytes);
3333
3334 ch->dirty[curr_buffer] >>= ch->curr_row - new_base_row;
3335 } else {
3336 erase_begin = (ch->curr_row + 1) * bytes_per_row
3337 - copy_bytes;
3338 erase_end = (new_base_row + 1) * bytes_per_row
3339 - copy_bytes;
3340
3341 memmove (base + erase_end,
3342 base + erase_begin, copy_bytes);
3343
3344 ch->dirty[curr_buffer] <<= new_base_row - ch->curr_row;
3345 ch->dirty[curr_buffer] &= CC_ALL_ROWS_MASK;
3346 }
3347
3348 memset (base + erase_begin, 0, erase_end - erase_begin);
3349
3350 cc_display_event (cd, ch, 0);
3351 }
3352
3353 static void
cc_preamble_address_code(struct cc_decoder * cd,struct cc_channel * ch,unsigned int c1,unsigned int c2)3354 cc_preamble_address_code (struct cc_decoder * cd,
3355 struct cc_channel * ch,
3356 unsigned int c1,
3357 unsigned int c2)
3358 {
3359 unsigned int row;
3360
3361 /* PAC Preamble Address Codes -- 001 crrr 1ri xxxu */
3362
3363 row = cc_pac_row_map[(c1 & 7) * 2 + ((c2 >> 5) & 1)];
3364 if ((int) row < 0)
3365 return;
3366
3367 switch (ch->mode) {
3368 case CC_MODE_UNKNOWN:
3369 return;
3370
3371 case CC_MODE_ROLL_UP:
3372 /* EIA 608-B Annex C.4. */
3373 if (ch->window_rows > row + 1)
3374 row = ch->window_rows - 1;
3375
3376 /* 47 CFR Section 15.119 (f)(1)(ii). */
3377 /* May send a display event. */
3378 cc_move_window (cd, ch, row);
3379
3380 ch->curr_row = row;
3381
3382 break;
3383
3384 case CC_MODE_PAINT_ON:
3385 cc_stream_event_if_changed (cd, ch);
3386
3387 /* fall through */
3388
3389 case CC_MODE_POP_ON:
3390 /* XXX 47 CFR 15.119 (f)(2)(i), (f)(3)(i): In Pop-on
3391 and paint-on mode "Preamble Address Codes can be
3392 used to move the cursor around the screen in random
3393 order to place captions on Rows 1 to 15." We do not
3394 have a limit on the number of displayable rows, but
3395 as EIA 608-B Annex C.6 points out, if more than
3396 four rows must be displayed they were probably
3397 received in error and we should respond
3398 accordingly. */
3399
3400 /* 47 CFR Section 15.119 (d)(1)(i) and EIA 608-B Annex
3401 C.7. */
3402 ch->curr_row = row;
3403
3404 break;
3405
3406 case CC_MODE_TEXT:
3407 /* 47 CFR 15.119 (e)(1) and EIA 608-B Section 7.4:
3408 Does not change the cursor row. */
3409 break;
3410 }
3411
3412 if (c2 & 0x10) {
3413 /* 47 CFR 15.119 (e)(1)(i) and EIA 608-B Table 71. */
3414 ch->curr_column = CC_FIRST_COLUMN + (c2 & 0x0E) * 2;
3415 }
3416
3417 /* PAC is a non-spacing attribute for the next character, see
3418 cc_put_char(). */
3419 ch->last_pac = 0x1000 | c2;
3420 }
3421
3422 static void
cc_control_code(struct cc_decoder * cd,unsigned int c1,unsigned int c2,enum field_num f)3423 cc_control_code (struct cc_decoder * cd,
3424 unsigned int c1,
3425 unsigned int c2,
3426 enum field_num f)
3427 {
3428 struct cc_channel *ch;
3429 unsigned int ch_num0;
3430
3431 if (option_debug & DEBUG_CC_DECODER) {
3432 fprintf (stderr, "%s %02x %02x %d\n",
3433 __FUNCTION__, c1, c2, f);
3434 }
3435
3436 /* Caption / text, field 1 / 2, primary / secondary channel. */
3437 ch_num0 = (((cd->curr_ch_num[f] - VBI_CAPTION_CC1) & 4)
3438 + f * 2
3439 + ((c1 >> 3) & 1));
3440
3441 /* Note ch is invalid if UNKNOWN_CC_CHANNEL ==
3442 cd->curr_ch_num[f]. */
3443 ch = &cd->channel[ch_num0];
3444
3445 if (c2 >= 0x40) {
3446 /* Preamble Address Codes -- 001 crrr 1ri xxxu */
3447 if (UNKNOWN_CC_CHANNEL != cd->curr_ch_num[f])
3448 cc_preamble_address_code (cd, ch, c1, c2);
3449 return;
3450 }
3451
3452 switch (c1 & 7) {
3453 case 0:
3454 if (UNKNOWN_CC_CHANNEL == cd->curr_ch_num[f]
3455 || CC_MODE_UNKNOWN == ch->mode)
3456 break;
3457
3458 if (c2 < 0x30) {
3459 /* Backgr. Attr. Codes -- 001 c000 010 xxxt */
3460 /* EIA 608-B Section 6.2. */
3461 cc_put_char (cd, ch, 0x1000 | c2,
3462 /* displayable */ FALSE,
3463 /* backspace */ TRUE);
3464 } else {
3465 /* Undefined. */
3466 }
3467
3468 break;
3469
3470 case 1:
3471 if (UNKNOWN_CC_CHANNEL == cd->curr_ch_num[f]
3472 || CC_MODE_UNKNOWN == ch->mode)
3473 break;
3474
3475 if (c2 < 0x30) {
3476 /* Mid-Row Codes -- 001 c001 010 xxxu */
3477 /* 47 CFR 15.119 (h)(1)(i): Spacing attribute. */
3478 cc_put_char (cd, ch, 0x1100 | c2,
3479 /* displayable */ FALSE,
3480 /* backspace */ FALSE);
3481 } else {
3482 /* Special Characters -- 001 c001 011 xxxx */
3483 if (0x39 == c2) {
3484 /* Transparent space. */
3485 cc_put_char (cd, ch, 0,
3486 /* displayable */ FALSE,
3487 /* backspace */ FALSE);
3488 } else {
3489 cc_put_char (cd, ch, 0x1100 | c2,
3490 /* displayable */ TRUE,
3491 /* backspace */ FALSE);
3492 }
3493 }
3494
3495 break;
3496
3497 case 2:
3498 case 3: /* Extended Character Set -- 001 c01x 01x xxxx */
3499 if (UNKNOWN_CC_CHANNEL == cd->curr_ch_num[f]
3500 || CC_MODE_UNKNOWN == ch->mode)
3501 break;
3502
3503 /* EIA 608-B Section 6.4.2. */
3504 cc_put_char (cd, ch, (c1 * 256 + c2) & 0x777F,
3505 /* displayable */ TRUE,
3506 /* backspace */ TRUE);
3507 break;
3508
3509 case 4:
3510 case 5:
3511 if (c2 < 0x30) {
3512 /* Misc. Control Codes -- 001 c10f 010 xxxx */
3513 cc_misc_control_code (cd, ch, c2, ch_num0, f);
3514 } else {
3515 /* Undefined. */
3516 }
3517
3518 break;
3519
3520 case 6: /* reserved */
3521 break;
3522
3523 case 7: /* Extended control codes -- 001 c111 01x xxxx */
3524 if (UNKNOWN_CC_CHANNEL == cd->curr_ch_num[f]
3525 || CC_MODE_UNKNOWN == ch->mode)
3526 break;
3527
3528 cc_ext_control_code (cd, ch, c2);
3529
3530 break;
3531 }
3532 }
3533
3534 static vbi_bool
cc_characters(struct cc_decoder * cd,struct cc_channel * ch,int c)3535 cc_characters (struct cc_decoder * cd,
3536 struct cc_channel * ch,
3537 int c)
3538 {
3539 if (option_debug & DEBUG_CC_DECODER) {
3540 fprintf (stderr, "%s %02x '%c'\n",
3541 __FUNCTION__, c, printable (c));
3542 }
3543
3544 if (0 == c) {
3545 if (CC_MODE_UNKNOWN == ch->mode)
3546 return TRUE;
3547
3548 /* XXX After x NUL characters (presumably a caption
3549 pause), force a display update if we do not send
3550 events on every display change. */
3551
3552 return TRUE;
3553 }
3554
3555 if (c < 0x20) {
3556 /* Parity error or invalid data. */
3557
3558 if (c < 0 && CC_MODE_UNKNOWN != ch->mode) {
3559 /* 47 CFR Section 15.119 (j)(1). */
3560 cc_put_char (cd, ch, 0x7F,
3561 /* displayable */ TRUE,
3562 /* backspace */ FALSE);
3563 }
3564
3565 return FALSE;
3566 }
3567
3568 if (CC_MODE_UNKNOWN != ch->mode) {
3569 cc_put_char (cd, ch, c,
3570 /* displayable */ TRUE,
3571 /* backspace */ FALSE);
3572 }
3573
3574 return TRUE;
3575 }
3576
3577 static vbi_bool
cc_feed(struct cc_decoder * cd,const uint8_t buffer[2],unsigned int line,const struct timeval * tv,int64_t pts)3578 cc_feed (struct cc_decoder * cd,
3579 const uint8_t buffer[2],
3580 unsigned int line,
3581 const struct timeval * tv,
3582 int64_t pts)
3583 {
3584 int c1, c2;
3585 enum field_num f;
3586 vbi_bool all_successful;
3587
3588 assert (NULL != cd);
3589
3590 if (option_debug & DEBUG_CC_DECODER) {
3591 fprintf (stderr, "%s %02x %02x '%c%c' "
3592 "%3d %f %" PRId64 "\n",
3593 __FUNCTION__,
3594 buffer[0] & 0x7F,
3595 buffer[1] & 0x7F,
3596 printable (buffer[0]),
3597 printable (buffer[1]),
3598 line,
3599 tv->tv_sec + tv->tv_usec * (1 / 1e6),
3600 pts);
3601 }
3602
3603 f = FIELD_1;
3604
3605 switch (line) {
3606 case 21: /* NTSC */
3607 case 22: /* PAL/SECAM */
3608 break;
3609
3610 case 284: /* NTSC */
3611 f = FIELD_2;
3612 break;
3613
3614 default:
3615 return FALSE;
3616 }
3617
3618 cd->timestamp.sys = *tv;
3619 cd->timestamp.pts = pts;
3620
3621 /* FIXME deferred reset here */
3622
3623 c1 = vbi_unpar8 (buffer[0]);
3624 c2 = vbi_unpar8 (buffer[1]);
3625
3626 all_successful = TRUE;
3627
3628 /* 47 CFR 15.119 (2)(i)(4): "If the first transmission of a
3629 control code pair passes parity, it is acted upon within
3630 one video frame. If the next frame contains a perfect
3631 repeat of the same pair, the redundant code is ignored. If,
3632 however, the next frame contains a different but also valid
3633 control code pair, this pair, too, will be acted upon (and
3634 the receiver will expect a repeat of this second pair in
3635 the next frame). If the first byte of the expected
3636 redundant control code pair fails the parity check and the
3637 second byte is identical to the second byte in the
3638 immediately preceding pair, then the expected redundant
3639 code is ignored. If there are printing characters in place
3640 of the redundant code, they will be processed normally."
3641
3642 EIA 608-B Section 8.3: Caption control codes on field 2 may
3643 repeat as on field 1. Section 8.6.2: XDS control codes
3644 shall not repeat. */
3645
3646 if (unlikely (c1 < 0)) {
3647 goto parity_error;
3648 } else if (c1 == cd->expect_ctrl[f][0]
3649 && c2 == cd->expect_ctrl[f][1]) {
3650 /* Already acted upon. */
3651 cd->expect_ctrl[f][0] = -1;
3652 goto finish;
3653 }
3654
3655 if (c1 >= 0x10 && c1 < 0x20) {
3656 /* Caption control code. */
3657
3658 /* There's no XDS on field 1, we just
3659 use an array to save a branch. */
3660 cd->in_xds[f] = FALSE;
3661
3662 /* 47 CFR Section 15.119 (i)(1), (i)(2). */
3663 if (c2 < 0x20) {
3664 /* Parity error or invalid control code.
3665 Let's hope it repeats. */
3666 goto parity_error;
3667 }
3668
3669 cc_control_code (cd, c1, c2, f);
3670
3671 if (cd->event_pending) {
3672 cc_display_event (cd, cd->event_pending, 0);
3673 cd->event_pending = NULL;
3674 }
3675
3676 cd->expect_ctrl[f][0] = c1;
3677 cd->expect_ctrl[f][1] = c2;
3678 } else {
3679 cd->expect_ctrl[f][0] = -1;
3680
3681 if (c1 < 0x10) {
3682 if (FIELD_1 == f) {
3683 /* 47 CFR Section 15.119 (i)(1): "If the
3684 non-printing character in the pair is
3685 in the range 00h to 0Fh, that character
3686 alone will be ignored and the second
3687 character will be treated normally." */
3688 c1 = 0;
3689 } else if (0x0F == c1) {
3690 /* XDS packet terminator. */
3691 cd->in_xds[FIELD_2] = FALSE;
3692 goto finish;
3693 } else if (c1 >= 0x01) {
3694 /* XDS packet start or continuation.
3695 EIA 608-B Section 7.7, 8.5: Also
3696 interrupts a Text mode
3697 transmission. */
3698 cd->in_xds[FIELD_2] = TRUE;
3699 goto finish;
3700 }
3701 }
3702
3703 {
3704 struct cc_channel *ch;
3705 vbi_pgno ch_num;
3706
3707 ch_num = cd->curr_ch_num[f];
3708 if (UNKNOWN_CC_CHANNEL == ch_num)
3709 goto finish;
3710
3711 ch_num = ((ch_num - VBI_CAPTION_CC1) & 5) + f * 2;
3712 ch = &cd->channel[ch_num];
3713
3714 all_successful &= cc_characters (cd, ch, c1);
3715 all_successful &= cc_characters (cd, ch, c2);
3716
3717 if (cd->event_pending) {
3718 cc_display_event (cd, cd->event_pending, 0);
3719 cd->event_pending = NULL;
3720 }
3721 }
3722 }
3723
3724 finish:
3725 cd->error_history = cd->error_history * 2 + all_successful;
3726
3727 return all_successful;
3728
3729 parity_error:
3730 cd->expect_ctrl[f][0] = -1;
3731
3732 /* XXX Some networks stupidly transmit 0x0000 instead of
3733 0x8080 as filler. Perhaps we shouldn't take that as a
3734 serious parity error. */
3735 cd->error_history *= 2;
3736
3737 return FALSE;
3738 }
3739
3740 static void
cc_reset(struct cc_decoder * cd)3741 cc_reset (struct cc_decoder * cd)
3742 {
3743 unsigned int ch_num;
3744
3745 assert (NULL != cd);
3746
3747 if (option_debug & DEBUG_CC_DECODER) {
3748 fprintf (stderr, "%s\n", __FUNCTION__);
3749 }
3750
3751 for (ch_num = 0; ch_num < MAX_CC_CHANNELS; ++ch_num) {
3752 struct cc_channel *ch;
3753
3754 ch = &cd->channel[ch_num];
3755
3756 if (ch_num <= 3) {
3757 ch->mode = CC_MODE_UNKNOWN;
3758
3759 /* Something suitable for roll-up mode. */
3760 ch->curr_row = CC_LAST_ROW;
3761 ch->curr_column = CC_FIRST_COLUMN;
3762 ch->window_rows = 4;
3763 } else {
3764 ch->mode = CC_MODE_TEXT; /* invariable */
3765
3766 /* EIA 608-B Section 7.4: "When Text Mode has
3767 initially been selected and the specified
3768 Text memory is empty, the cursor starts at
3769 the topmost row, Column 1." */
3770 ch->curr_row = CC_FIRST_ROW;
3771 ch->curr_column = CC_FIRST_COLUMN;
3772 ch->window_rows = 0; /* n/a */
3773 }
3774
3775 ch->displayed_buffer = 0;
3776
3777 ch->last_pac = 0;
3778
3779 CLEAR (ch->buffer);
3780 CLEAR (ch->dirty);
3781
3782 cc_timestamp_reset (&ch->timestamp);
3783 cc_timestamp_reset (&ch->timestamp_c0);
3784 }
3785
3786 cd->curr_ch_num[0] = UNKNOWN_CC_CHANNEL;
3787 cd->curr_ch_num[1] = UNKNOWN_CC_CHANNEL;
3788
3789 memset (cd->expect_ctrl, -1, sizeof (cd->expect_ctrl));
3790
3791 CLEAR (cd->in_xds);
3792
3793 cd->event_pending = NULL;
3794 }
3795
3796 static void
init_cc_decoder(struct cc_decoder * cd)3797 init_cc_decoder (struct cc_decoder * cd)
3798 {
3799 cc_reset (cd);
3800
3801 cd->error_history = 0;
3802
3803 cc_timestamp_reset (&cd->timestamp);
3804 }
3805
3806 /* Some code left over from ntsc-cc, to be replaced. */
3807
3808 const char * const ratings[] = {
3809 "(NOT RATED)","TV-Y","TV-Y7","TV-G",
3810 "TV-PG","TV-14","TV-MA","(NOT RATED)"};
3811 const char * const modes[]={
3812 "current","future","channel","miscellaneous","public service",
3813 "reserved","invalid","invalid","invalid","invalid"};
3814
3815 static void
print_xds_info(struct caption_recorder * cr,unsigned int mode,unsigned int type)3816 print_xds_info (struct caption_recorder *cr,
3817 unsigned int mode,
3818 unsigned int type)
3819 {
3820 const char *infoptr;
3821
3822 if (!cr->info[0][mode][type].print)
3823 return;
3824
3825 infoptr = cr->info[cr->field][mode][type].packet;
3826
3827 switch ((mode << 8) + type) {
3828 case 0x0101:
3829 fprintf (cr->xds_fp,
3830 "%sTIMECODE: %d/%02d %d:%02d%s",
3831 cr->xds_info_prefix,
3832 infoptr[3]&0x0f,infoptr[2]&0x1f,
3833 infoptr[1]&0x1f,infoptr[0]&0x3f,
3834 cr->xds_info_suffix);
3835 case 0x0102:
3836 if ((infoptr[1]&0x3f)>5)
3837 break;
3838 fprintf (cr->xds_fp,
3839 "%s LENGTH: %d:%02d:%02d of %d:%02d:00%s",
3840 cr->xds_info_prefix,
3841 infoptr[3]&0x3f,infoptr[2]&0x3f,
3842 infoptr[4]&0x3f,infoptr[1]&0x3f,
3843 infoptr[0]&0x3f,
3844 cr->xds_info_suffix);
3845 break;
3846 case 0x0103:
3847 fprintf (cr->xds_fp,
3848 "%s TITLE: %s%s",
3849 cr->xds_info_prefix,
3850 infoptr,
3851 cr->xds_info_suffix);
3852 break;
3853 case 0x0105:
3854 fprintf (cr->xds_fp,
3855 "%s RATING: %s (%d)",
3856 cr->xds_info_prefix,
3857 ratings[infoptr[0]&0x07],infoptr[0]);
3858 if ((infoptr[0]&0x07)>0) {
3859 if (infoptr[0]&0x20) fputs (" VIOLENCE", cr->xds_fp);
3860 if (infoptr[0]&0x10) fputs (" SEXUAL", cr->xds_fp);
3861 if (infoptr[0]&0x08) fputs (" LANGUAGE", cr->xds_fp);
3862 }
3863 fputs (cr->xds_info_suffix, cr->xds_fp);
3864 break;
3865 case 0x0501:
3866 fprintf (cr->xds_fp,
3867 "%s NETWORK: %s%s",
3868 cr->xds_info_prefix,
3869 infoptr,
3870 cr->xds_info_suffix);
3871 break;
3872 case 0x0502:
3873 fprintf (cr->xds_fp,
3874 "%s CALL: %s%s",
3875 cr->xds_info_prefix,
3876 infoptr,
3877 cr->xds_info_suffix);
3878 break;
3879 case 0x0701:
3880 fprintf (cr->xds_fp,
3881 "%sCUR.TIME: %d:%02d %d/%02d/%04d UTC%s",
3882 cr->xds_info_prefix,
3883 infoptr[1]&0x1F,infoptr[0]&0x3f,
3884 infoptr[3]&0x0f,infoptr[2]&0x1f,
3885 (infoptr[5]&0x3f)+1990,
3886 cr->xds_info_suffix);
3887 break;
3888 case 0x0704: //timezone
3889 fprintf (cr->xds_fp,
3890 "%sTIMEZONE: UTC-%d%s",
3891 cr->xds_info_prefix,
3892 infoptr[0]&0x1f,
3893 cr->xds_info_suffix);
3894 break;
3895 case 0x0104: //program genere
3896 break;
3897 case 0x0110:
3898 case 0x0111:
3899 case 0x0112:
3900 case 0x0113:
3901 case 0x0114:
3902 case 0x0115:
3903 case 0x0116:
3904 case 0x0117:
3905 fprintf (cr->xds_fp,
3906 "%s DESC: %s%s",
3907 cr->xds_info_prefix,
3908 infoptr,
3909 cr->xds_info_suffix);
3910 break;
3911 }
3912
3913 fflush (cr->xds_fp);
3914 }
3915
XDSdecode(struct caption_recorder * cr,int data)3916 static int XDSdecode(struct caption_recorder *cr, int data)
3917 {
3918 static vbi_bool in_xds[2];
3919 int b1, b2, length;
3920
3921 if (data == -1)
3922 return -1;
3923
3924 b1 = data & 0x7F;
3925 b2 = (data>>8) & 0x7F;
3926
3927 if (0 == b1) {
3928 /* Filler, discard. */
3929 return -1;
3930 }
3931 else if (b1 < 15) // start packet
3932 {
3933 cr->mode = b1;
3934 cr->type = b2;
3935 cr->infochecksum = b1 + b2 + 15;
3936 if (cr->mode > 8 || cr->type > 20)
3937 {
3938 // printf("%% Unsupported mode %s(%d) [%d]\n",modes[(mode-1)>>1],mode,type);
3939 cr->mode=0; cr->type=0;
3940 }
3941 cr->infoptr = cr->newinfo[cr->field][cr->mode][cr->type];
3942 in_xds[cr->field] = TRUE;
3943 }
3944 else if (b1 == 15) // eof (next byte is checksum)
3945 {
3946 #if 0 //debug
3947 if (mode == 0)
3948 {
3949 length=infoptr - newinfo[cr->field][0][0];
3950 infoptr[1]=0;
3951 printf("LEN: %d\n",length);
3952 for (y=0;y<length;y++)
3953 printf(" %03d",newinfo[cr->field][0][0][y]);
3954 printf(" --- %s\n",newinfo[cr->field][0][0]);
3955 }
3956 #endif
3957 if (cr->mode == 0) return 0;
3958 if (b2 != 128-((cr->infochecksum%128)&0x7F)) return 0;
3959
3960 length = cr->infoptr - cr->newinfo[cr->field][cr->mode][cr->type];
3961
3962 //don't bug the user with repeated data
3963 //only parse it if it's different
3964 if (cr->info[cr->field][cr->mode][cr->type].length != length
3965 || 0 != memcmp (cr->info[cr->field][cr->mode][cr->type].packet,
3966 cr->newinfo[cr->field][cr->mode][cr->type],
3967 length))
3968 {
3969 memcpy (cr->info[cr->field][cr->mode][cr->type].packet,
3970 cr->newinfo[cr->field][cr->mode][cr->type], 32);
3971 cr->info[cr->field][cr->mode][cr->type].packet[length] = 0;
3972 cr->info[cr->field][cr->mode][cr->type].length = length;
3973 if (0)
3974 fprintf (stderr, "XDS %d %d %d %d %d\n",
3975 cr->field, cr->mode, cr->type, length,
3976 cr->info[0][cr->mode][cr->type].print);
3977 print_xds_info (cr, cr->mode, cr->type);
3978 }
3979 cr->mode = 0; cr->type = 0;
3980 in_xds[cr->field] = FALSE;
3981 } else if (b1 <= 31) {
3982 /* Caption control code. */
3983 in_xds[cr->field] = FALSE;
3984 } else if (in_xds[cr->field]) {
3985 if (cr->infoptr >= &cr->newinfo[cr->field][cr->mode][cr->type][32]) {
3986 /* Bad packet. */
3987 cr->mode = 0;
3988 cr->type = 0;
3989 in_xds[cr->field] = 0;
3990 } else {
3991 cr->infoptr[0] = b1; cr->infoptr++;
3992 cr->infoptr[0] = b2; cr->infoptr++;
3993 cr->infochecksum += b1 + b2;
3994 }
3995 }
3996 return 0;
3997 }
3998
3999 #if 0 /* to be replaced */
4000
4001 static int webtv_check(struct caption_recorder *cr, char * buf,int len)
4002 {
4003 unsigned long sum;
4004 unsigned long nwords;
4005 unsigned short csum=0;
4006 char temp[9];
4007 int nbytes=0;
4008
4009 while (buf[0]!='<' && len > 6) //search for the start
4010 {
4011 buf++; len--;
4012 }
4013
4014 if (len == 6) //failure to find start
4015 return 0;
4016
4017
4018 while (nbytes+6 <= len)
4019 {
4020 //look for end of object checksum, it's enclosed in []'s and there shouldn't be any [' after
4021 if (buf[nbytes] == '[' && buf[nbytes+5] == ']' && buf[nbytes+6] != '[')
4022 break;
4023 else
4024 nbytes++;
4025 }
4026 if (nbytes+6>len) //failure to find end
4027 return 0;
4028
4029 nwords = nbytes >> 1; sum = 0;
4030
4031 //add up all two byte words
4032 while (nwords-- > 0) {
4033 sum += *buf++ << 8;
4034 sum += *buf++;
4035 }
4036 if (nbytes & 1) {
4037 sum += *buf << 8;
4038 }
4039 csum = (unsigned short)(sum >> 16);
4040 while(csum !=0) {
4041 sum = csum + (sum & 0xffff);
4042 csum = (unsigned short)(sum >> 16);
4043 }
4044 sprintf(temp,"%04X\n",(int)~sum&0xffff);
4045 buf++;
4046 if(!strncmp(buf,temp,4))
4047 {
4048 buf[5]=0;
4049 if (cr->cur_ch[cr->field] >= 0 && cr->cc_fp[cr->cur_ch[cr->field]]) {
4050 if (!cr->plain)
4051 fprintf(cr->cc_fp[cr->cur_ch[cr->field]], "\33[35mWEBTV: %s\33[0m\n",buf-nbytes-1);
4052 else
4053 fprintf(cr->cc_fp[cr->cur_ch[cr->field]], "WEBTV: %s\n",buf-nbytes-1);
4054 fflush (cr->cc_fp[cr->cur_ch[cr->field]]);
4055 }
4056 }
4057 return 0;
4058 }
4059
4060 #endif /* 0 */
4061
4062 static void
xds_filter_option(struct caption_recorder * cr,const char * optarg)4063 xds_filter_option (struct caption_recorder *cr,
4064 const char * optarg)
4065 {
4066 const char *s;
4067
4068 /* Attention: may be called repeatedly. */
4069
4070 if (NULL == optarg
4071 || 0 == strcasecmp (optarg, "all")) {
4072 unsigned int i;
4073
4074 for (i = 0; i < (N_ELEMENTS (cr->info[0])
4075 * N_ELEMENTS (cr->info[0][0])); ++i) {
4076 cr->info[0][0][i].print = TRUE;
4077 }
4078
4079 return;
4080 }
4081
4082 s = optarg;
4083
4084 while (0 != *s) {
4085 char buf[16];
4086 unsigned int len;
4087
4088 for (;;) {
4089 if (0 == *s)
4090 return;
4091 if (isalnum (*s))
4092 break;
4093 ++s;
4094 }
4095
4096 for (len = 0; len < N_ELEMENTS (buf) - 1; ++len) {
4097 if (!isalnum (*s))
4098 break;
4099 buf[len] = *s++;
4100 }
4101
4102 buf[len] = 0;
4103
4104 if (0 == strcasecmp (buf, "timecode")) {
4105 cr->info[0][1][1].print = TRUE;
4106 } else if (0 == strcasecmp (buf, "length")) {
4107 cr->info[0][1][2].print = TRUE;
4108 } else if (0 == strcasecmp (buf, "title")) {
4109 cr->info[0][1][3].print = TRUE;
4110 } else if (0 == strcasecmp (buf, "rating")) {
4111 cr->info[0][1][5].print = TRUE;
4112 } else if (0 == strcasecmp (buf, "network")) {
4113 cr->info[0][5][1].print = TRUE;
4114 } else if (0 == strcasecmp (buf, "call")) {
4115 cr->info[0][5][2].print = TRUE;
4116 } else if (0 == strcasecmp (buf, "time")) {
4117 cr->info[0][7][1].print = TRUE;
4118 } else if (0 == strcasecmp (buf, "timezone")) {
4119 cr->info[0][7][4].print = TRUE;
4120 } else if (0 == strcasecmp (buf, "desc")) {
4121 cr->info[0][1][0x10].print = TRUE;
4122 cr->info[0][1][0x11].print = TRUE;
4123 cr->info[0][1][0x12].print = TRUE;
4124 cr->info[0][1][0x13].print = TRUE;
4125 cr->info[0][1][0x14].print = TRUE;
4126 cr->info[0][1][0x15].print = TRUE;
4127 cr->info[0][1][0x16].print = TRUE;
4128 cr->info[0][1][0x17].print = TRUE;
4129 } else {
4130 fprintf (stderr, "Unknown XDS info '%s'\n", buf);
4131 }
4132 }
4133 }
4134
4135 /* CEA 708-C Digital TV Closed Caption decoder. */
4136
4137 static const uint8_t
4138 dtvcc_c0_length [4] = {
4139 1, 1, 2, 3
4140 };
4141
4142 static const uint8_t
4143 dtvcc_c1_length [32] = {
4144 /* 0x80 CW0 ... CW7 */ 1, 1, 1, 1, 1, 1, 1, 1,
4145 /* 0x88 CLW */ 2,
4146 /* 0x89 DSW */ 2,
4147 /* 0x8A HDW */ 2,
4148 /* 0x8B TGW */ 2,
4149
4150 /* 0x8C DLW */ 2,
4151 /* 0x8D DLY */ 2,
4152 /* 0x8E DLC */ 1,
4153 /* 0x8F RST */ 1,
4154
4155 /* 0x90 SPA */ 3,
4156 /* 0x91 SPC */ 4,
4157 /* 0x92 SPL */ 3,
4158 /* CEA 708-C Section 7.1.5.1: 0x93 ... 0x96 are
4159 reserved one byte codes. */ 1, 1, 1, 1,
4160 /* 0x97 SWA */ 5,
4161 /* 0x98 DF0 ... DF7 */ 7, 7, 7, 7, 7, 7, 7, 7
4162 };
4163
4164 static const uint16_t
4165 dtvcc_g2 [96] = {
4166 /* Note Unicode defines no transparent spaces. */
4167 0x0020, /* 0x1020 Transparent space */
4168 0x00A0, /* 0x1021 Non-breaking transparent space */
4169
4170 0, /* 0x1022 reserved */
4171 0,
4172 0,
4173 0x2026, /* 0x1025 Horizontal ellipsis */
4174 0,
4175 0,
4176 0,
4177 0,
4178 0x0160, /* 0x102A S with caron */
4179 0,
4180 0x0152, /* 0x102C Ligature OE */
4181 0,
4182 0,
4183 0,
4184
4185 /* CEA 708-C Section 7.1.8: "The character (0x30) is a solid
4186 block which fills the entire character position with the
4187 text foreground color." */
4188 0x2588, /* 0x1030 Full block */
4189
4190 0x2018, /* 0x1031 Left single quotation mark */
4191 0x2019, /* 0x1032 Right single quotation mark */
4192 0x201C, /* 0x1033 Left double quotation mark */
4193 0x201D, /* 0x1034 Right double quotation mark */
4194 0,
4195 0,
4196 0,
4197 0x2122, /* 0x1039 Trademark sign */
4198 0x0161, /* 0x103A s with caron */
4199 0,
4200 0x0153, /* 0x103C Ligature oe */
4201 0x2120, /* 0x103D Service mark */
4202 0,
4203 0x0178, /* 0x103F Y with diaeresis */
4204
4205 /* Code points 0x1040 ... 0x106F reserved. */
4206 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4207 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4208 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4209
4210 0, /* 0x1070 reserved */
4211 0,
4212 0,
4213 0,
4214 0,
4215 0,
4216 0x215B, /* 0x1076 1/8 */
4217 0x215C, /* 0x1077 3/8 */
4218 0x215D, /* 0x1078 5/8 */
4219 0x215E, /* 0x1079 7/8 */
4220 0x2502, /* 0x107A Box drawings vertical */
4221 0x2510, /* 0x107B Box drawings down and left */
4222 0x2514, /* 0x107C Box drawings up and right */
4223 0x2500, /* 0x107D Box drawings horizontal */
4224 0x2518, /* 0x107E Box drawings up and left */
4225 0x250C /* 0x107F Box drawings down and right */
4226 };
4227
4228 static unsigned int
dtvcc_unicode(unsigned int c)4229 dtvcc_unicode (unsigned int c)
4230 {
4231 if (unlikely (0 == (c & 0x60))) {
4232 /* C0, C1, C2, C3 */
4233 return 0;
4234 } else if (likely (c < 0x100)) {
4235 /* G0, G1 */
4236 if (unlikely (0x7F == c))
4237 return 0x266A; /* music note */
4238 else
4239 return c;
4240 } else if (c < 0x1080) {
4241 if (unlikely (c < 0x1020))
4242 return 0;
4243 else
4244 return dtvcc_g2[c - 0x1020];
4245 } else if (0x10A0 == c) {
4246 /* We map all G2/G3 characters which are not
4247 representable in Unicode to private code U+E900
4248 ... U+E9FF. */
4249 return 0xE9A0; /* caption icon */
4250 }
4251
4252 return 0;
4253 }
4254
4255 static void
dump_dtvcc_se(FILE * fp,const uint8_t * buf,unsigned int n_bytes)4256 dump_dtvcc_se (FILE * fp,
4257 const uint8_t * buf,
4258 unsigned int n_bytes)
4259 {
4260 uint16_t ucs2_str[1];
4261 unsigned int se_length;
4262 unsigned int c;
4263 unsigned int i;
4264
4265 if (0 == n_bytes)
4266 return;
4267
4268 c = buf[0];
4269 if (0 != (c & 0x60)) {
4270 ucs2_str[0] = dtvcc_unicode (c);
4271 fprintf (fp, "G0/G1 0x%02X U+%04X '",
4272 c, ucs2_str[0]);
4273 vbi_fputs_iconv_ucs2 (fp, locale_codeset,
4274 ucs2_str, 1,
4275 /* repl_char */ '?');
4276 fputs ("'\n", fp);
4277 return;
4278 } else if ((int8_t) c < 0) {
4279 static const char *mnemo [32] = {
4280 "CW0", "CW1", "CW2", "CW3",
4281 "CW4", "CW5", "CW6", "CW7",
4282 "CLW", "DSW", "HDW", "TGW",
4283 "DLW", "DLY", "DLC", "RST",
4284 "SPA", "SPC", "SPL", "93",
4285 "reserved", "reserved",
4286 "reserved", "SWA",
4287 "DF0", "DF1", "DF2", "DF3",
4288 "DF4", "DF5", "DF6", "DF7"
4289 };
4290 static const char *opacity_name [4] = {
4291 "Solid", "Flash", "Transl", "Transp"
4292 };
4293 static const char *edge_name [8] = {
4294 "None", "Raised", "Depressed",
4295 "Uniform", "ShadowL", "ShadowR",
4296 "INVALID", "INVALID"
4297 };
4298
4299 fprintf (fp, "C1 0x%02X %s", c, mnemo[c & 31]);
4300
4301 se_length = dtvcc_c1_length[c - 0x80];
4302 if (n_bytes < se_length) {
4303 fputs (" incomplete\n", fp);
4304 return;
4305 }
4306
4307 switch (c) {
4308 case 0x80 ... 0x87: /* CWx */
4309 case 0x8E: /* DLC */
4310 case 0x8F: /* RST */
4311 case 0x93 ... 0x96: /* reserved */
4312 fputc ('\n', fp);
4313 return;
4314
4315 case 0x88: /* CLW */
4316 case 0x89: /* DSW */
4317 case 0x8A: /* HDW */
4318 case 0x8B: /* TGW */
4319 case 0x8C: /* DLW */
4320 fputs (" 0b", fp);
4321 for (i = 0; i < 8; ++i) {
4322 unsigned int bit;
4323
4324 bit = !!(buf[1] & (0x80 >> i));
4325 fputc ('0' + bit, fp);
4326 }
4327 fputc ('\n', fp);
4328 return;
4329
4330 case 0x8D: /* DLY */
4331 fprintf (fp, " t=%u\n", buf[1]);
4332 return;
4333
4334 case 0x90: /* SPA */
4335 {
4336 static const char *s_name [4] = {
4337 "Small", "Std", "Large", "INVALID"
4338 };
4339 static const char *fs_name [8] = {
4340 "Default", "MonoSerif", "PropSerif",
4341 "MonoSans", "PropSans", "Casual",
4342 "Cursive", "SmallCaps"
4343 };
4344 static const char *tt_name [16] = {
4345 "Dialog", "SourceID", "Device",
4346 "Dialog2", "Voiceover", "AudTransl",
4347 "SubTransl", "VoiceDescr", "Lyrics",
4348 "EffectDescr", "ScoreDescr",
4349 "Expletive", "INVALID", "INVALID",
4350 "INVALID", "NotDisplayable"
4351 };
4352 static const char *o_name [4] = {
4353 "Sub", "Normal", "Super", "INVALID"
4354 };
4355
4356 fprintf (fp, " s=%s fs=%s tt=%s o=%s i=%u "
4357 "u=%u et=%s\n",
4358 s_name[buf[1] & 3],
4359 fs_name[buf[2] & 7],
4360 tt_name[(buf[1] >> 4) & 15],
4361 o_name[(buf[1] >> 2) & 3],
4362 !!(buf[2] & 0x80),
4363 !!(buf[2] & 0x40),
4364 edge_name[(buf[2] >> 3) & 7]);
4365 return;
4366 }
4367
4368 case 0x91: /* SPC */
4369 {
4370 fprintf (fp, " fg=%u%u%u fo=%s bg=%u%u%u bo=%s "
4371 "edge=%u%u%u\n",
4372 (buf[1] >> 4) & 3, (buf[1] >> 2) & 3,
4373 buf[1] & 3,
4374 opacity_name[(buf[1] >> 6) & 3],
4375 (buf[2] >> 4) & 3, (buf[2] >> 2) & 3,
4376 buf[2] & 3,
4377 opacity_name[(buf[2] >> 6) & 3],
4378 (buf[3] >> 4) & 3, (buf[3] >> 2) & 3,
4379 buf[3] & 3);
4380 return;
4381 }
4382
4383 case 0x92: /* SPL */
4384 fprintf (fp, " r=%u c=%u\n",
4385 buf[1] & 0x0F,
4386 buf[2] & 0x3F);
4387 return;
4388
4389 case 0x97: /* SWA */
4390 {
4391 static const char *j_name [4] = {
4392 "L", "R", "C", "F"
4393 };
4394 static const char *pd_sd_ed_name [4] = {
4395 "LR", "RL", "TB", "BT"
4396 };
4397 static const char *de_name [4] = {
4398 "Snap", "Fade", "Wipe", "INVALID"
4399 };
4400
4401 fprintf (fp, " j=%s pd=%s sd=%s ww=%u de=%s "
4402 "ed=%s es=%u fill=%u%u%u fo=%s "
4403 "bt=%s border=%u%u%u\n",
4404 j_name [buf[3] & 3],
4405 pd_sd_ed_name [(buf[3] >> 4) & 3],
4406 pd_sd_ed_name [(buf[3] >> 2) & 3],
4407 !!(buf[3] & 0x40),
4408 de_name [buf[4] & 3],
4409 pd_sd_ed_name [(buf[4] >> 2) & 3],
4410 (buf[4] >> 4) & 15,
4411 (buf[1] >> 4) & 3, (buf[1] >> 2) & 3,
4412 buf[1] & 3,
4413 opacity_name[(buf[1] >> 6) & 3],
4414 edge_name[(buf[2] >> 6) & 3],
4415 (buf[2] >> 4) & 3, (buf[2] >> 2) & 3,
4416 buf[2] & 3);
4417 return;
4418 }
4419
4420 case 0x98 ... 0x9F: /* DFx */
4421 {
4422 static const char *ap_name [16] = {
4423 "TL", "TC", "TR",
4424 "CL", "C", "CR",
4425 "BL", "BC", "BR",
4426 "INVALID", "INVALID", "INVALID",
4427 "INVALID", "INVALID", "INVALID",
4428 "INVALID"
4429 };
4430 static const char *ws_name [8] = {
4431 "0", "PopUp", "TranspPopUp",
4432 "CentPopUp", "RollUp", "TranspRollUp",
4433 "CentRollUp", "Ticker"
4434 };
4435 static const char *ps_name [8] = {
4436 "0", "NTSC", "NTSCMonoSerif",
4437 "NTSCPropSerif", "NTSCMonoSans",
4438 "NTSCPropSans", "MonoSans",
4439 "PropSans"
4440 };
4441
4442 fprintf (fp, " p=%u ap=%s rp=%u av=%u ah=%u "
4443 "rc=%u cc=%u rl=%u cl=%u v=%u "
4444 "ws=%s ps=%s\n",
4445 buf[1] & 7,
4446 ap_name[(buf[4] >> 4) & 15],
4447 !!(buf[2] & 0x80),
4448 buf[2] & 0x7F,
4449 buf[3],
4450 buf[4] & 0x0F,
4451 buf[5] & 0x3F,
4452 !!(buf[1] & 0x10),
4453 !!(buf[1] & 0x08),
4454 !!(buf[1] & 0x20),
4455 ws_name [(buf[6] >> 3) & 7],
4456 ps_name [buf[6] & 7]);
4457 return;
4458 }
4459
4460 } /* switch */
4461 } else {
4462 static const char *mnemo [32] = {
4463 "NUL", "reserved", "reserved",
4464 "ETX", "reserved", "reserved",
4465 "reserved", "reserved",
4466 "BS", "reserved", "reserved",
4467 "reserved", "FF", "CR", "HCR",
4468 "reserved", "EXT1", "reserved",
4469 "reserved", "reserved", "reserved",
4470 "reserved", "reserved", "reserved",
4471 "P16", "reserved", "reserved",
4472 "reserved", "reserved", "reserved",
4473 "reserved", "reserved"
4474 };
4475
4476 /* C0 code. */
4477
4478 fprintf (fp, "C0 0x%02X %s", c, mnemo [c]);
4479
4480 se_length = dtvcc_c0_length[c >> 3];
4481 if (n_bytes < se_length) {
4482 fputs (" incomplete\n", fp);
4483 return;
4484 }
4485
4486 if (0x10 != c) {
4487 if (se_length > 1)
4488 fprintf (fp, " 0x%02X", buf[1]);
4489 if (se_length > 2)
4490 fprintf (fp, " 0x%02X", buf[2]);
4491 fputc ('\n', fp);
4492 return;
4493 }
4494 }
4495
4496 /* Two-byte codes. */
4497
4498 c = buf[1];
4499 if (0 != (c & 0x60)) {
4500 ucs2_str[0] = dtvcc_unicode (0x1000 | c);
4501 fprintf (fp, "G2/G3 0x10%02X U+%04X '",
4502 c, ucs2_str[0]);
4503 vbi_fputs_iconv_ucs2 (fp, locale_codeset,
4504 ucs2_str, 1,
4505 /* repl_char */ '?');
4506 fputs ("'\n", fp);
4507 return;
4508 } else if ((int8_t) c >= 0) {
4509 /* C2 code. */
4510
4511 se_length = (c >> 3) + 2;
4512 fprintf (fp, "C2 0x10%02X reserved", c);
4513 } else if (c < 0x90) {
4514 /* C3 Fixed Length Commands. */
4515
4516 se_length = (c >> 3) - 10;
4517 fprintf (fp, "C3 0x10%02X reserved", c);
4518 } else {
4519 /* C3 Variable Length Commands. */
4520
4521 if (n_bytes < 3) {
4522 fprintf (fp, "C3 0x10%02X incomplete\n", c);
4523 return;
4524 }
4525
4526 /* type [2], zero_bit [1],
4527 length [5] */
4528 se_length = (buf[2] & 0x1F) + 3;
4529
4530 fprintf (fp, "C3 0x10%02X%02X reserved",
4531 c, buf[2]);
4532 }
4533
4534 for (i = 2; i < se_length; ++i)
4535 fprintf (fp, " 0x%02X", buf[i]);
4536
4537 fputc ('\n', fp);
4538 }
4539
4540 static void
dump_dtvcc_buffer(FILE * fp,struct dtvcc_window * dw)4541 dump_dtvcc_buffer (FILE * fp,
4542 struct dtvcc_window * dw)
4543 {
4544 unsigned int row;
4545 unsigned int column;
4546
4547 for (row = 0; row < dw->row_count; ++row) {
4548 uint16_t ucs2_str[42];
4549
4550 fprintf (fp, "%02u '", row);
4551
4552 for (column = 0; column < dw->column_count; ++column) {
4553 unsigned int c;
4554
4555 c = dw->buffer[row][column];
4556 if (0 == c) {
4557 ucs2_str[column] = 0x20;
4558 continue;
4559 }
4560 c = dtvcc_unicode (c);
4561 if (0 == c) {
4562 ucs2_str[column] = '?';
4563 continue;
4564 }
4565 ucs2_str[column] = c;
4566 }
4567
4568 vbi_fputs_iconv_ucs2 (fp, locale_codeset,
4569 ucs2_str, dw->column_count,
4570 /* repl_char */ '?');
4571 fputs ("'\n", fp);
4572 }
4573 }
4574
4575 static void
4576 dtvcc_reset (struct dtvcc_decoder * cd);
4577 static void
4578 dtvcc_reset_service (struct dtvcc_service * ds);
4579
4580 static unsigned int
dtvcc_window_id(struct dtvcc_service * ds,struct dtvcc_window * dw)4581 dtvcc_window_id (struct dtvcc_service * ds,
4582 struct dtvcc_window * dw)
4583 {
4584 return dw - ds->window;
4585 }
4586
4587 static unsigned int
dtvcc_service_num(struct dtvcc_decoder * dc,struct dtvcc_service * ds)4588 dtvcc_service_num (struct dtvcc_decoder * dc,
4589 struct dtvcc_service * ds)
4590 {
4591 return ds - dc->service + 1;
4592 }
4593
4594 /* Up to eight windows can be visible at once, so which one displays
4595 the caption? Let's take a guess. */
4596 static struct dtvcc_window *
dtvcc_caption_window(struct dtvcc_service * ds)4597 dtvcc_caption_window (struct dtvcc_service * ds)
4598 {
4599 struct dtvcc_window *dw;
4600 unsigned int max_priority;
4601 unsigned int window_id;
4602
4603 dw = NULL;
4604 max_priority = 8;
4605
4606 for (window_id = 0; window_id < 8; ++window_id) {
4607 if (0 == (ds->created & (1 << window_id)))
4608 continue;
4609 if (!ds->window[window_id].visible)
4610 continue;
4611 if (DIR_BOTTOM_TOP
4612 != ds->window[window_id].style.scroll_direction)
4613 continue;
4614 if (ds->window[window_id].priority < max_priority) {
4615 dw = &ds->window[window_id];
4616 max_priority = ds->window[window_id].priority;
4617 }
4618 }
4619
4620 return dw;
4621 }
4622
4623 static void
dtvcc_stream_event(struct dtvcc_decoder * dc,struct dtvcc_service * ds,struct dtvcc_window * dw,unsigned int row)4624 dtvcc_stream_event (struct dtvcc_decoder * dc,
4625 struct dtvcc_service * ds,
4626 struct dtvcc_window * dw,
4627 unsigned int row)
4628 {
4629 vbi_char text[48];
4630 vbi_char ac;
4631 unsigned int column;
4632
4633 if (NULL == dw || dw != dtvcc_caption_window (ds))
4634 return;
4635
4636 if (option_debug & DEBUG_DTVCC_STREAM_EVENT) {
4637 fprintf (stderr, "%s row=%u streamed=%08x\n",
4638 __FUNCTION__, row, dw->streamed);
4639 dump_dtvcc_buffer (stderr, dw);
4640 }
4641
4642 /* Note we only stream windows with scroll direction
4643 upwards. */
4644 if (0 != (dw->streamed & (1 << row))
4645 || !cc_timestamp_isset (&dw->timestamp_c0))
4646 return;
4647
4648 dw->streamed |= 1 << row;
4649
4650 for (column = 0; column < dw->column_count; ++column) {
4651 if (0 != dw->buffer[row][column])
4652 break;
4653 }
4654
4655 /* Row contains only transparent spaces. */
4656 if (column >= dw->column_count)
4657 return;
4658
4659 /* TO DO. */
4660 CLEAR (ac);
4661 ac.foreground = VBI_WHITE;
4662 ac.background = VBI_BLACK;
4663 ac.opacity = VBI_OPAQUE;
4664
4665 for (column = 0; column < dw->column_count; ++column) {
4666 unsigned int c;
4667
4668 c = dw->buffer[row][column];
4669 if (0 == c) {
4670 ac.unicode = 0x20;
4671 } else {
4672 ac.unicode = dtvcc_unicode (c);
4673 if (0 == ac.unicode) {
4674 ac.unicode = 0x20;
4675 }
4676 }
4677 text[column] = ac;
4678 }
4679
4680 {
4681 struct program *pr;
4682
4683 pr = PARENT (dc, struct program, cr.dtvcc);
4684 cr_new_line (&pr->cr, &dw->timestamp_c0,
4685 /* channel */ dtvcc_service_num (dc, ds) + 8,
4686 text, /* length */ dw->column_count);
4687 }
4688
4689 cc_timestamp_reset (&dw->timestamp_c0);
4690 }
4691
4692 static vbi_bool
dtvcc_put_char(struct dtvcc_decoder * dc,struct dtvcc_service * ds,unsigned int c)4693 dtvcc_put_char (struct dtvcc_decoder * dc,
4694 struct dtvcc_service * ds,
4695 unsigned int c)
4696 {
4697 struct dtvcc_window *dw;
4698 unsigned int row;
4699 unsigned int column;
4700
4701 dc = dc; /* unused */
4702
4703 dw = ds->curr_window;
4704 if (NULL == dw) {
4705 ds->error_line = __LINE__;
4706 return FALSE;
4707 }
4708
4709 row = dw->curr_row;
4710 column = dw->curr_column;
4711
4712 /* FIXME how should we handle TEXT_TAG_NOT_DISPLAYABLE? */
4713
4714 dw->buffer[row][column] = c;
4715
4716 if (option_debug & DEBUG_DTVCC_PUT_CHAR) {
4717 fprintf (stderr, "%s row=%u/%u column=%u/%u\n",
4718 __FUNCTION__,
4719 row, dw->row_count,
4720 column, dw->column_count);
4721 dump_dtvcc_buffer (stderr, dw);
4722 }
4723
4724 switch (dw->style.print_direction) {
4725 case DIR_LEFT_RIGHT:
4726 dw->streamed &= ~(1 << row);
4727 if (!cc_timestamp_isset (&dw->timestamp_c0))
4728 dw->timestamp_c0 = ds->timestamp;
4729 if (++column >= dw->column_count)
4730 return TRUE;
4731 break;
4732
4733 case DIR_RIGHT_LEFT:
4734 dw->streamed &= ~(1 << row);
4735 if (!cc_timestamp_isset (&dw->timestamp_c0))
4736 dw->timestamp_c0 = ds->timestamp;
4737 if (column-- <= 0)
4738 return TRUE;
4739 break;
4740
4741 case DIR_TOP_BOTTOM:
4742 dw->streamed &= ~(1 << column);
4743 if (!cc_timestamp_isset (&dw->timestamp_c0))
4744 dw->timestamp_c0 = ds->timestamp;
4745 if (++row >= dw->row_count)
4746 return TRUE;
4747 break;
4748
4749 case DIR_BOTTOM_TOP:
4750 dw->streamed &= ~(1 << column);
4751 if (!cc_timestamp_isset (&dw->timestamp_c0))
4752 dw->timestamp_c0 = ds->timestamp;
4753 if (row-- <= 0)
4754 return TRUE;
4755 break;
4756 }
4757
4758 dw->curr_row = row;
4759 dw->curr_column = column;
4760
4761 return TRUE;
4762 }
4763
4764 static vbi_bool
dtvcc_set_pen_location(struct dtvcc_decoder * dc,struct dtvcc_service * ds,const uint8_t * buf)4765 dtvcc_set_pen_location (struct dtvcc_decoder * dc,
4766 struct dtvcc_service * ds,
4767 const uint8_t * buf)
4768 {
4769 struct dtvcc_window *dw;
4770 unsigned int row;
4771 unsigned int column;
4772
4773 dw = ds->curr_window;
4774 if (NULL == dw) {
4775 ds->error_line = __LINE__;
4776 return FALSE;
4777 }
4778
4779 row = buf[1];
4780 /* We check the top four zero bits. */
4781 if (row >= 16) {
4782 ds->error_line = __LINE__;
4783 return FALSE;
4784 }
4785
4786 column = buf[2];
4787 /* We also check the top two zero bits. */
4788 if (column >= 42) {
4789 ds->error_line = __LINE__;
4790 return FALSE;
4791 }
4792
4793 if (row > dw->row_count)
4794 row = dw->row_count - 1;
4795 if (column > dw->column_count)
4796 column = dw->column_count - 1;
4797
4798 if (row != dw->curr_row) {
4799 dtvcc_stream_event (dc, ds, dw, dw->curr_row);
4800 }
4801
4802 /* FIXME there's more. */
4803 dw->curr_row = row;
4804 dw->curr_column = column;
4805
4806 return TRUE;
4807 }
4808
4809 static vbi_bool
dtvcc_set_pen_color(struct dtvcc_service * ds,const uint8_t * buf)4810 dtvcc_set_pen_color (struct dtvcc_service * ds,
4811 const uint8_t * buf)
4812 {
4813 struct dtvcc_window *dw;
4814 unsigned int c;
4815
4816 dw = ds->curr_window;
4817 if (NULL == dw) {
4818 ds->error_line = __LINE__;
4819 return FALSE;
4820 }
4821
4822 c = buf[3];
4823 if (0 != (c & 0xC0)) {
4824 ds->error_line = __LINE__;
4825 return FALSE;
4826 }
4827
4828 dw->curr_pen.style.edge_color = c;
4829 c = buf[1];
4830 dw->curr_pen.style.fg_opacity = c >> 6;
4831 dw->curr_pen.style.fg_color = c & 0x3F;
4832 c = buf[2];
4833 dw->curr_pen.style.bg_opacity = c >> 6;
4834 dw->curr_pen.style.bg_color = c & 0x3F;
4835
4836 return TRUE;
4837 }
4838
4839 static vbi_bool
dtvcc_set_pen_attributes(struct dtvcc_service * ds,const uint8_t * buf)4840 dtvcc_set_pen_attributes (struct dtvcc_service * ds,
4841 const uint8_t * buf)
4842 {
4843 struct dtvcc_window *dw;
4844 unsigned int c;
4845 enum pen_size pen_size;
4846 enum offset offset;
4847 enum edge edge_type;
4848
4849 dw = ds->curr_window;
4850 if (NULL == dw) {
4851 ds->error_line = __LINE__;
4852 return FALSE;
4853 }
4854
4855 c = buf[1];
4856 offset = (c >> 2) & 3;
4857 pen_size = c & 3;
4858 if ((offset | pen_size) >= 3) {
4859 ds->error_line = __LINE__;
4860 return FALSE;
4861 }
4862
4863 c = buf[2];
4864 edge_type = (c >> 3) & 7;
4865 if (edge_type >= 6) {
4866 ds->error_line = __LINE__;
4867 return FALSE;
4868 }
4869
4870 c = buf[1];
4871 dw->curr_pen.text_tag = c >> 4;
4872 dw->curr_pen.style.offset = offset;
4873 dw->curr_pen.style.pen_size = pen_size;
4874 c = buf[2];
4875 dw->curr_pen.style.italics = c >> 7;
4876 dw->curr_pen.style.underline = (c >> 6) & 1;
4877 dw->curr_pen.style.edge_type = edge_type;
4878 dw->curr_pen.style.font_style = c & 7;
4879
4880 return TRUE;
4881 }
4882
4883 static vbi_bool
dtvcc_set_window_attributes(struct dtvcc_service * ds,const uint8_t * buf)4884 dtvcc_set_window_attributes (struct dtvcc_service * ds,
4885 const uint8_t * buf)
4886 {
4887 struct dtvcc_window *dw;
4888 unsigned int c;
4889 enum edge border_type;
4890 enum display_effect display_effect;
4891
4892 dw = ds->curr_window;
4893 if (NULL == dw)
4894 return FALSE;
4895
4896 c = buf[2];
4897 border_type = ((buf[3] >> 5) & 0x04) | (c >> 6);
4898 if (border_type >= 6)
4899 return FALSE;
4900
4901 c = buf[4];
4902 display_effect = c & 3;
4903 if (display_effect >= 3)
4904 return FALSE;
4905
4906 c = buf[1];
4907 dw->style.fill_opacity = c >> 6;
4908 dw->style.fill_color = c & 0x3F;
4909 c = buf[2];
4910 dw->style.border_type = border_type;
4911 dw->style.border_color = c & 0x3F;
4912 c = buf[3];
4913 dw->style.wordwrap = (c >> 6) & 1;
4914 dw->style.print_direction = (c >> 4) & 3;
4915 dw->style.scroll_direction = (c >> 2) & 3;
4916 dw->style.justify = c & 3;
4917 c = buf[4];
4918 dw->style.effect_speed = c >> 4;
4919 dw->style.effect_direction = (c >> 2) & 3;
4920 dw->style.display_effect = display_effect;
4921
4922 return TRUE;
4923 }
4924
4925 static vbi_bool
dtvcc_clear_windows(struct dtvcc_decoder * dc,struct dtvcc_service * ds,dtvcc_window_map window_map)4926 dtvcc_clear_windows (struct dtvcc_decoder * dc,
4927 struct dtvcc_service * ds,
4928 dtvcc_window_map window_map)
4929 {
4930 unsigned int i;
4931
4932 window_map &= ds->created;
4933
4934 for (i = 0; i < 8; ++i) {
4935 struct dtvcc_window *dw;
4936
4937 if (0 == (window_map & (1 << i)))
4938 continue;
4939
4940 dw = &ds->window[i];
4941
4942 dtvcc_stream_event (dc, ds, dw, dw->curr_row);
4943
4944 memset (dw->buffer, 0, sizeof (dw->buffer));
4945
4946 dw->streamed = 0;
4947
4948 /* FIXME CEA 708-C Section 7.1.4 (Form Feed)
4949 and 8.10.5.3 confuse me. */
4950 if (0) {
4951 dw->curr_column = 0;
4952 dw->curr_row = 0;
4953 }
4954 }
4955
4956 return TRUE;
4957 }
4958
4959 static vbi_bool
dtvcc_define_window(struct dtvcc_decoder * dc,struct dtvcc_service * ds,uint8_t * buf)4960 dtvcc_define_window (struct dtvcc_decoder * dc,
4961 struct dtvcc_service * ds,
4962 uint8_t * buf)
4963 {
4964 static const struct dtvcc_window_style window_styles [7] = {
4965 {
4966 JUSTIFY_LEFT, DIR_LEFT_RIGHT, DIR_BOTTOM_TOP,
4967 FALSE, DISPLAY_EFFECT_SNAP, 0, 0, 0,
4968 OPACITY_SOLID, EDGE_NONE, 0
4969 }, {
4970 JUSTIFY_LEFT, DIR_LEFT_RIGHT, DIR_BOTTOM_TOP,
4971 FALSE, DISPLAY_EFFECT_SNAP, 0, 0, 0,
4972 OPACITY_TRANSPARENT, EDGE_NONE, 0
4973 }, {
4974 JUSTIFY_CENTER, DIR_LEFT_RIGHT, DIR_BOTTOM_TOP,
4975 FALSE, DISPLAY_EFFECT_SNAP, 0, 0, 0,
4976 OPACITY_SOLID, EDGE_NONE, 0
4977 }, {
4978 JUSTIFY_LEFT, DIR_LEFT_RIGHT, DIR_BOTTOM_TOP,
4979 TRUE, DISPLAY_EFFECT_SNAP, 0, 0, 0,
4980 OPACITY_SOLID, EDGE_NONE, 0
4981 }, {
4982 JUSTIFY_LEFT, DIR_LEFT_RIGHT, DIR_BOTTOM_TOP,
4983 TRUE, DISPLAY_EFFECT_SNAP, 0, 0, 0,
4984 OPACITY_TRANSPARENT, EDGE_NONE, 0
4985 }, {
4986 JUSTIFY_CENTER, DIR_LEFT_RIGHT, DIR_BOTTOM_TOP,
4987 TRUE, DISPLAY_EFFECT_SNAP, 0, 0, 0,
4988 OPACITY_SOLID, EDGE_NONE, 0
4989 }, {
4990 JUSTIFY_LEFT, DIR_TOP_BOTTOM, DIR_RIGHT_LEFT,
4991 FALSE, DISPLAY_EFFECT_SNAP, 0, 0, 0,
4992 OPACITY_SOLID, EDGE_NONE, 0
4993 }
4994 };
4995 static const struct dtvcc_pen_style pen_styles [7] = {
4996 {
4997 PEN_SIZE_STANDARD, 0, OFFSET_NORMAL, FALSE,
4998 FALSE, EDGE_NONE, 0x3F, OPACITY_SOLID,
4999 0x00, OPACITY_SOLID, 0
5000 }, {
5001 PEN_SIZE_STANDARD, 1, OFFSET_NORMAL, FALSE,
5002 FALSE, EDGE_NONE, 0x3F, OPACITY_SOLID,
5003 0x00, OPACITY_SOLID, 0
5004 }, {
5005 PEN_SIZE_STANDARD, 2, OFFSET_NORMAL, FALSE,
5006 FALSE, EDGE_NONE, 0x3F, OPACITY_SOLID,
5007 0x00, OPACITY_SOLID, 0
5008 }, {
5009 PEN_SIZE_STANDARD, 3, OFFSET_NORMAL, FALSE,
5010 FALSE, EDGE_NONE, 0x3F, OPACITY_SOLID,
5011 0x00, OPACITY_SOLID, 0
5012 }, {
5013 PEN_SIZE_STANDARD, 4, OFFSET_NORMAL, FALSE,
5014 FALSE, EDGE_NONE, 0x3F, OPACITY_SOLID,
5015 0x00, OPACITY_SOLID, 0
5016 }, {
5017 PEN_SIZE_STANDARD, 3, OFFSET_NORMAL, FALSE,
5018 FALSE, EDGE_UNIFORM, 0x3F, OPACITY_SOLID,
5019 0, OPACITY_TRANSPARENT, 0x00
5020 }, {
5021 PEN_SIZE_STANDARD, 4, OFFSET_NORMAL, FALSE,
5022 FALSE, EDGE_UNIFORM, 0x3F, OPACITY_SOLID,
5023 0, OPACITY_TRANSPARENT, 0x00
5024 }
5025 };
5026 struct dtvcc_window *dw;
5027 dtvcc_window_map window_map;
5028 vbi_bool anchor_relative;
5029 unsigned int anchor_vertical;
5030 unsigned int anchor_horizontal;
5031 unsigned int anchor_point;
5032 unsigned int column_count_m1;
5033 unsigned int window_id;
5034 unsigned int window_style_id;
5035 unsigned int pen_style_id;
5036 unsigned int c;
5037
5038 if (0 != ((buf[1] | buf[6]) & 0xC0)) {
5039 ds->error_line = __LINE__;
5040 return FALSE;
5041 }
5042
5043 c = buf[2];
5044 anchor_relative = (c >> 7) & 1;
5045 anchor_vertical = c & 0x7F;
5046 anchor_horizontal = buf[3];
5047 if (0 == anchor_relative) {
5048 if (unlikely (anchor_vertical >= 75
5049 || anchor_horizontal >= 210)) {
5050 ds->error_line = __LINE__;
5051 return FALSE;
5052 }
5053 } else {
5054 if (unlikely (anchor_vertical >= 100
5055 || anchor_horizontal >= 100)) {
5056 ds->error_line = __LINE__;
5057 return FALSE;
5058 }
5059 }
5060
5061 c = buf[4];
5062 anchor_point = c >> 4;
5063 if (unlikely (anchor_point >= 9)) {
5064 ds->error_line = __LINE__;
5065 return FALSE;
5066 }
5067
5068 column_count_m1 = buf[5];
5069 /* We also check the top two zero bits. */
5070 if (unlikely (column_count_m1 >= 41)) {
5071 ds->error_line = __LINE__;
5072 return FALSE;
5073 }
5074
5075 window_id = buf[0] & 7;
5076 dw = &ds->window[window_id];
5077 window_map = 1 << window_id;
5078
5079 ds->curr_window = dw;
5080
5081 c = buf[1];
5082 dw->visible = (c >> 5) & 1;
5083 dw->row_lock = (c >> 4) & 1;
5084 dw->column_lock = (c >> 4) & 1;
5085 dw->priority = c & 7;
5086
5087 dw->anchor_relative = anchor_relative;
5088 dw->anchor_vertical = anchor_vertical;
5089 dw->anchor_horizontal = anchor_horizontal;
5090 dw->anchor_point = anchor_point;
5091
5092 c = buf[4];
5093 dw->row_count = (c & 15) + 1;
5094 dw->column_count = column_count_m1 + 1;
5095
5096 c = buf[6];
5097 window_style_id = (c >> 3) & 7;
5098 pen_style_id = c & 7;
5099
5100 if (window_style_id > 0) {
5101 dw->style = window_styles[window_style_id];
5102 } else if (0 == (ds->created & window_map)) {
5103 dw->style = window_styles[1];
5104 }
5105
5106 if (pen_style_id > 0) {
5107 dw->curr_pen.style = pen_styles[pen_style_id];
5108 } else if (0 == (ds->created & window_map)) {
5109 dw->curr_pen.style = pen_styles[1];
5110 }
5111
5112 if (0 != (ds->created & window_map))
5113 return TRUE;
5114
5115 /* Has to be something, no? */
5116 dw->curr_pen.text_tag = TEXT_TAG_NOT_DISPLAYABLE;
5117
5118 dw->curr_column = 0;
5119 dw->curr_row = 0;
5120
5121 dw->streamed = 0;
5122
5123 cc_timestamp_reset (&dw->timestamp_c0);
5124
5125 ds->created |= window_map;
5126
5127 return dtvcc_clear_windows (dc, ds, window_map);
5128 }
5129
5130 static vbi_bool
dtvcc_display_windows(struct dtvcc_decoder * dc,struct dtvcc_service * ds,unsigned int c,dtvcc_window_map window_map)5131 dtvcc_display_windows (struct dtvcc_decoder * dc,
5132 struct dtvcc_service * ds,
5133 unsigned int c,
5134 dtvcc_window_map window_map)
5135 {
5136 unsigned int i;
5137
5138 window_map &= ds->created;
5139
5140 for (i = 0; i < 8; ++i) {
5141 struct dtvcc_window *dw;
5142 vbi_bool was_visible;
5143
5144 if (0 == (window_map & (1 << i)))
5145 continue;
5146
5147 dw = &ds->window[i];
5148 was_visible = dw->visible;
5149
5150 switch (c) {
5151 case 0x89: /* DSW DisplayWindows */
5152 dw->visible = TRUE;
5153 break;
5154
5155 case 0x8A: /* HDW HideWindows */
5156 dw->visible = FALSE;
5157 break;
5158
5159 case 0x8B: /* TGW ToggleWindows */
5160 dw->visible = was_visible ^ TRUE;
5161 break;
5162 }
5163
5164 if (!was_visible) {
5165 unsigned int row;
5166
5167 dw->timestamp_c0 = ds->timestamp;
5168 for (row = 0; row < dw->row_count; ++row) {
5169 dtvcc_stream_event (dc, ds, dw, row);
5170 }
5171 }
5172 }
5173
5174 return TRUE;
5175 }
5176
5177 static vbi_bool
dtvcc_carriage_return(struct dtvcc_decoder * dc,struct dtvcc_service * ds)5178 dtvcc_carriage_return (struct dtvcc_decoder * dc,
5179 struct dtvcc_service * ds)
5180 {
5181 struct dtvcc_window *dw;
5182 unsigned int row;
5183 unsigned int column;
5184
5185 dw = ds->curr_window;
5186 if (NULL == dw) {
5187 ds->error_line = __LINE__;
5188 return FALSE;
5189 }
5190
5191 dtvcc_stream_event (dc, ds, dw, dw->curr_row);
5192
5193 row = dw->curr_row;
5194 column = dw->curr_column;
5195
5196 switch (dw->style.scroll_direction) {
5197 case DIR_LEFT_RIGHT:
5198 dw->curr_row = 0;
5199 if (column > 0) {
5200 dw->curr_column = column - 1;
5201 break;
5202 }
5203 dw->streamed = (dw->streamed << 1)
5204 & ~(1 << dw->column_count);
5205 for (row = 0; row < dw->row_count; ++row) {
5206 for (column = dw->column_count - 1;
5207 column > 0; --column) {
5208 dw->buffer[row][column] =
5209 dw->buffer[row][column - 1];
5210 }
5211 dw->buffer[row][column] = 0;
5212 }
5213 break;
5214
5215 case DIR_RIGHT_LEFT:
5216 dw->curr_row = 0;
5217 if (column + 1 < dw->row_count) {
5218 dw->curr_column = column + 1;
5219 break;
5220 }
5221 dw->streamed >>= 1;
5222 for (row = 0; row < dw->row_count; ++row) {
5223 for (column = 0;
5224 column < dw->column_count - 1; ++column) {
5225 dw->buffer[row][column] =
5226 dw->buffer[row][column + 1];
5227 }
5228 dw->buffer[row][column] = 0;
5229 }
5230 break;
5231
5232 case DIR_TOP_BOTTOM:
5233 dw->curr_column = 0;
5234 if (row > 0) {
5235 dw->curr_row = row - 1;
5236 break;
5237 }
5238 dw->streamed = (dw->streamed << 1)
5239 & ~(1 << dw->row_count);
5240 memmove (&dw->buffer[1], &dw->buffer[0],
5241 sizeof (dw->buffer[0]) * (dw->row_count - 1));
5242 memset (&dw->buffer[0], 0, sizeof (dw->buffer[0]));
5243 break;
5244
5245 case DIR_BOTTOM_TOP:
5246 dw->curr_column = 0;
5247 if (row + 1 < dw->row_count) {
5248 dw->curr_row = row + 1;
5249 break;
5250 }
5251 dw->streamed >>= 1;
5252 memmove (&dw->buffer[0], &dw->buffer[1],
5253 sizeof (dw->buffer[0]) * (dw->row_count - 1));
5254 memset (&dw->buffer[row], 0, sizeof (dw->buffer[0]));
5255 break;
5256 }
5257
5258 return TRUE;
5259 }
5260
5261 static vbi_bool
dtvcc_form_feed(struct dtvcc_decoder * dc,struct dtvcc_service * ds)5262 dtvcc_form_feed (struct dtvcc_decoder * dc,
5263 struct dtvcc_service * ds)
5264 {
5265 struct dtvcc_window *dw;
5266 dtvcc_window_map window_map;
5267
5268 dw = ds->curr_window;
5269 if (NULL == dw) {
5270 ds->error_line = __LINE__;
5271 return FALSE;
5272 }
5273
5274 window_map = 1 << dtvcc_window_id (ds, dw);
5275
5276 if (!dtvcc_clear_windows (dc, ds, window_map))
5277 return FALSE;
5278
5279 dw->curr_row = 0;
5280 dw->curr_column = 0;
5281
5282 return TRUE;
5283 }
5284
5285 static vbi_bool
dtvcc_backspace(struct dtvcc_decoder * dc,struct dtvcc_service * ds)5286 dtvcc_backspace (struct dtvcc_decoder * dc,
5287 struct dtvcc_service * ds)
5288 {
5289 struct dtvcc_window *dw;
5290 unsigned int row;
5291 unsigned int column;
5292 unsigned int mask;
5293
5294 dc = dc; /* unused */
5295
5296 dw = ds->curr_window;
5297 if (NULL == dw) {
5298 ds->error_line = __LINE__;
5299 return FALSE;
5300 }
5301
5302 row = dw->curr_row;
5303 column = dw->curr_column;
5304
5305 switch (dw->style.print_direction) {
5306 case DIR_LEFT_RIGHT:
5307 mask = 1 << row;
5308 if (column-- <= 0)
5309 return TRUE;
5310 break;
5311
5312 case DIR_RIGHT_LEFT:
5313 mask = 1 << row;
5314 if (++column >= dw->column_count)
5315 return TRUE;
5316 break;
5317
5318 case DIR_TOP_BOTTOM:
5319 mask = 1 << column;
5320 if (row-- <= 0)
5321 return TRUE;
5322 break;
5323
5324 case DIR_BOTTOM_TOP:
5325 mask = 1 << column;
5326 if (++row >= dw->row_count)
5327 return TRUE;
5328 break;
5329 }
5330
5331 if (0 != dw->buffer[row][column]) {
5332 dw->streamed &= ~mask;
5333 dw->buffer[row][column] = 0;
5334 }
5335
5336 dw->curr_row = row;
5337 dw->curr_column = column;
5338
5339 return TRUE;
5340 }
5341
5342 static vbi_bool
dtvcc_hor_carriage_return(struct dtvcc_decoder * dc,struct dtvcc_service * ds)5343 dtvcc_hor_carriage_return (struct dtvcc_decoder * dc,
5344 struct dtvcc_service * ds)
5345 {
5346 struct dtvcc_window *dw;
5347 unsigned int row;
5348 unsigned int column;
5349 unsigned int mask;
5350
5351 dc = dc; /* unused */
5352
5353 dw = ds->curr_window;
5354 if (NULL == dw) {
5355 ds->error_line = __LINE__;
5356 return FALSE;
5357 }
5358
5359 row = dw->curr_row;
5360 column = dw->curr_column;
5361
5362 switch (dw->style.print_direction) {
5363 case DIR_LEFT_RIGHT:
5364 case DIR_RIGHT_LEFT:
5365 mask = 1 << row;
5366 memset (&dw->buffer[row][0], 0,
5367 sizeof (dw->buffer[0]));
5368 if (DIR_LEFT_RIGHT == dw->style.print_direction)
5369 dw->curr_column = 0;
5370 else
5371 dw->curr_column = dw->column_count - 1;
5372 break;
5373
5374 case DIR_TOP_BOTTOM:
5375 case DIR_BOTTOM_TOP:
5376 mask = 1 << column;
5377 for (row = 0; row < dw->column_count; ++row)
5378 dw->buffer[row][column] = 0;
5379 if (DIR_TOP_BOTTOM == dw->style.print_direction)
5380 dw->curr_row = 0;
5381 else
5382 dw->curr_row = dw->row_count - 1;
5383 break;
5384 }
5385
5386 dw->streamed &= ~mask;
5387
5388 return TRUE;
5389 }
5390
5391 static vbi_bool
dtvcc_delete_windows(struct dtvcc_decoder * dc,struct dtvcc_service * ds,dtvcc_window_map window_map)5392 dtvcc_delete_windows (struct dtvcc_decoder * dc,
5393 struct dtvcc_service * ds,
5394 dtvcc_window_map window_map)
5395 {
5396 struct dtvcc_window *dw;
5397
5398 dw = ds->curr_window;
5399 if (NULL != dw) {
5400 unsigned int window_id;
5401
5402 window_id = dtvcc_window_id (ds, dw);
5403 if (0 != (window_map & (1 << window_id))) {
5404 dtvcc_stream_event (dc, ds, dw, dw->curr_row);
5405 ds->curr_window = NULL;
5406 }
5407 }
5408
5409 ds->created &= ~window_map;
5410
5411 return TRUE;
5412 }
5413
5414 static vbi_bool
dtvcc_command(struct dtvcc_decoder * dc,struct dtvcc_service * ds,unsigned int * se_length,uint8_t * buf,unsigned int n_bytes)5415 dtvcc_command (struct dtvcc_decoder * dc,
5416 struct dtvcc_service * ds,
5417 unsigned int * se_length,
5418 uint8_t * buf,
5419 unsigned int n_bytes)
5420 {
5421 unsigned int c;
5422 unsigned int window_id;
5423
5424 c = buf[0];
5425 if ((int8_t) c < 0) {
5426 *se_length = dtvcc_c1_length[c - 0x80];
5427 } else {
5428 *se_length = dtvcc_c0_length[c >> 3];
5429 }
5430
5431 if (*se_length > n_bytes) {
5432 ds->error_line = __LINE__;
5433 return FALSE;
5434 }
5435
5436 switch (c) {
5437 case 0x08: /* BS Backspace */
5438 return dtvcc_backspace (dc, ds);
5439
5440 case 0x0C: /* FF Form Feed */
5441 return dtvcc_form_feed (dc, ds);
5442
5443 case 0x0D: /* CR Carriage Return */
5444 return dtvcc_carriage_return (dc, ds);
5445
5446 case 0x0E: /* HCR Horizontal Carriage Return */
5447 return dtvcc_hor_carriage_return (dc, ds);
5448
5449 case 0x80 ... 0x87: /* CWx SetCurrentWindow */
5450 window_id = c & 7;
5451 if (0 == (ds->created & (1 << window_id))) {
5452 ds->error_line = __LINE__;
5453 return FALSE;
5454 }
5455 ds->curr_window = &ds->window[window_id];
5456 return TRUE;
5457
5458 case 0x88: /* CLW ClearWindows */
5459 return dtvcc_clear_windows (dc, ds, buf[1]);
5460
5461 case 0x89: /* DSW DisplayWindows */
5462 return dtvcc_display_windows (dc, ds, c, buf[1]);
5463
5464 case 0x8A: /* HDW HideWindows */
5465 return dtvcc_display_windows (dc, ds, c, buf[1]);
5466
5467 case 0x8B: /* TGW ToggleWindows */
5468 return dtvcc_display_windows (dc, ds, c, buf[1]);
5469
5470 case 0x8C: /* DLW DeleteWindows */
5471 return dtvcc_delete_windows (dc, ds, buf[1]);
5472
5473 case 0x8F: /* RST Reset */
5474 dtvcc_reset_service (ds);
5475 return TRUE;
5476
5477 case 0x90: /* SPA SetPenAttributes */
5478 return dtvcc_set_pen_attributes (ds, buf);
5479
5480 case 0x91: /* SPC SetPenColor */
5481 return dtvcc_set_pen_color (ds, buf);
5482
5483 case 0x92: /* SPL SetPenLocation */
5484 return dtvcc_set_pen_location (dc, ds, buf);
5485
5486 case 0x97: /* SWA SetWindowAttributes */
5487 return dtvcc_set_window_attributes (ds, buf);
5488
5489 case 0x98 ... 0x9F: /* DFx DefineWindow */
5490 return dtvcc_define_window (dc, ds, buf);
5491
5492 default:
5493 return TRUE;
5494 }
5495 }
5496
5497 static vbi_bool
dtvcc_decode_se(struct dtvcc_decoder * dc,struct dtvcc_service * ds,unsigned int * se_length,uint8_t * buf,unsigned int n_bytes)5498 dtvcc_decode_se (struct dtvcc_decoder * dc,
5499 struct dtvcc_service * ds,
5500 unsigned int * se_length,
5501 uint8_t * buf,
5502 unsigned int n_bytes)
5503 {
5504 unsigned int c;
5505
5506 c = buf[0];
5507 if (likely (0 != (c & 0x60))) {
5508 /* G0/G1 character. */
5509 *se_length = 1;
5510 return dtvcc_put_char (dc, ds, c);
5511 }
5512
5513 if (0x10 != c) {
5514 /* C0/C1 control code. */
5515 return dtvcc_command (dc, ds, se_length,
5516 buf, n_bytes);
5517 }
5518
5519 if (unlikely (n_bytes < 2)) {
5520 ds->error_line = __LINE__;
5521 return FALSE;
5522 }
5523
5524 c = buf[1];
5525 if (likely (0 != (c & 0x60))) {
5526 /* G2/G3 character. */
5527 *se_length = 2;
5528 return dtvcc_put_char (dc, ds, 0x1000 | c);
5529 }
5530
5531 /* CEA 708-C defines no C2 or C3 commands. */
5532
5533 if ((int8_t) c >= 0) {
5534 /* C2 code. */
5535 *se_length = (c >> 3) + 2;
5536 } else if (c < 0x90) {
5537 /* C3 Fixed Length Commands. */
5538 *se_length = (c >> 3) - 10;
5539 } else {
5540 /* C3 Variable Length Commands. */
5541
5542 if (unlikely (n_bytes < 3)) {
5543 ds->error_line = __LINE__;
5544 return FALSE;
5545 }
5546
5547 /* type [2], zero_bit [1],
5548 length [5] */
5549 *se_length = (buf[2] & 0x1F) + 3;
5550 }
5551
5552 if (unlikely (n_bytes < *se_length)) {
5553 ds->error_line = __LINE__;
5554 return FALSE;
5555 }
5556
5557 return TRUE;
5558 }
5559
5560 static vbi_bool
dtvcc_decode_syntactic_elements(struct dtvcc_decoder * dc,struct dtvcc_service * ds,uint8_t * buf,unsigned int n_bytes)5561 dtvcc_decode_syntactic_elements (struct dtvcc_decoder * dc,
5562 struct dtvcc_service * ds,
5563 uint8_t * buf,
5564 unsigned int n_bytes)
5565 {
5566 ds->timestamp = dc->timestamp;
5567
5568 while (n_bytes > 0) {
5569 unsigned int se_length;
5570
5571 if (option_debug & DEBUG_DTVCC_SE) {
5572 fprintf (stderr, "S%u ",
5573 dtvcc_service_num (dc, ds));
5574 dump_dtvcc_se (stderr, buf, n_bytes);
5575 }
5576
5577 if (0x8D /* DLY */ == *buf
5578 || 0x8E /* DLC */ == *buf) {
5579 /* FIXME ignored for now. */
5580 ++buf;
5581 --n_bytes;
5582 continue;
5583 }
5584
5585 if (!dtvcc_decode_se (dc, ds,
5586 &se_length,
5587 buf, n_bytes)) {
5588 return FALSE;
5589 }
5590
5591 buf += se_length;
5592 n_bytes -= se_length;
5593 }
5594
5595 return TRUE;
5596 }
5597
5598 static void
dtvcc_decode_packet(struct dtvcc_decoder * dc,const struct timeval * tv,int64_t pts)5599 dtvcc_decode_packet (struct dtvcc_decoder * dc,
5600 const struct timeval * tv,
5601 int64_t pts)
5602 {
5603 unsigned int packet_size_code;
5604 unsigned int packet_size;
5605 unsigned int i;
5606
5607 dc->timestamp.sys = *tv;
5608 dc->timestamp.pts = pts;
5609
5610 /* Packet Layer. */
5611
5612 /* sequence_number [2], packet_size_code [6],
5613 packet_data [n * 8] */
5614
5615 if (dc->next_sequence_number >= 0
5616 && 0 != ((dc->packet[0] ^ dc->next_sequence_number) & 0xC0)) {
5617 struct program *pr;
5618
5619 pr = PARENT (dc, struct program, cr.dtvcc);
5620 log (4, "Station %u DTVCC packet lost.\n",
5621 station_num (pr));
5622 dtvcc_reset (dc);
5623 return;
5624 }
5625
5626 dc->next_sequence_number = dc->packet[0] + 0x40;
5627
5628 packet_size_code = dc->packet[0] & 0x3F;
5629 packet_size = 128;
5630 if (packet_size_code > 0)
5631 packet_size = packet_size_code * 2;
5632
5633 if (option_debug & DEBUG_DTVCC_PACKET) {
5634 unsigned int sequence_number;
5635
5636 sequence_number = (dc->packet[0] >> 6) & 3;
5637 fprintf (stderr, "DTVCC packet packet_size=%u "
5638 "(transmitted %u), sequence_number %u\n",
5639 packet_size, dc->packet_size,
5640 sequence_number);
5641 dump (stderr, dc->packet, dc->packet_size);
5642 }
5643
5644 /* CEA 708-C Section 5: Apparently packet_size need not be
5645 equal to the actually transmitted amount of data. */
5646 if (packet_size > dc->packet_size) {
5647 struct program *pr;
5648
5649 pr = PARENT (dc, struct program, cr.dtvcc);
5650 log (4, "Station %u DTVCC packet incomplete (%u/%u).\n",
5651 station_num (pr),
5652 dc->packet_size, packet_size);
5653 dtvcc_reset (dc);
5654 return;
5655 }
5656
5657 /* Service Layer. */
5658
5659 /* CEA 708-C Section 6.2.5, 6.3: Service Blocks and syntactic
5660 elements must not cross Caption Channel Packet
5661 boundaries. */
5662
5663 for (i = 1; i < packet_size;) {
5664 unsigned int service_number;
5665 unsigned int block_size;
5666 unsigned int header_size;
5667 unsigned int c;
5668
5669 header_size = 1;
5670
5671 /* service_number [3], block_size [5],
5672 (null_fill [2], extended_service_number [6]),
5673 (Block_data [n * 8]) */
5674
5675 c = dc->packet[i];
5676 service_number = (c & 0xE0) >> 5;
5677
5678 /* CEA 708-C Section 6.3: Ignore block_size if
5679 service_number is zero. */
5680 if (0 == service_number) {
5681 /* NULL Service Block Header, no more data in
5682 this Caption Channel Packet. */
5683 break;
5684 }
5685
5686 /* CEA 708-C Section 6.2.1: Apparently block_size zero
5687 is valid, although properly it should only occur in
5688 NULL Service Block Headers. */
5689 block_size = c & 0x1F;
5690
5691 if (7 == service_number) {
5692 if (i + 1 > packet_size)
5693 goto service_block_incomplete;
5694
5695 header_size = 2;
5696 c = dc->packet[i + 1];
5697
5698 /* We also check the null_fill bits. */
5699 if (c < 7 || c > 63)
5700 goto invalid_service_block;
5701
5702 service_number = c;
5703 }
5704
5705 if (i + header_size + block_size > packet_size)
5706 goto service_block_incomplete;
5707
5708 if (service_number <= 2) {
5709 struct dtvcc_service *ds;
5710 unsigned int in;
5711
5712 ds = &dc->service[service_number - 1];
5713 in = ds->service_data_in;
5714 memcpy (ds->service_data + in,
5715 dc->packet + i + header_size,
5716 block_size);
5717 ds->service_data_in = in + block_size;
5718 }
5719
5720 i += header_size + block_size;
5721 }
5722
5723 for (i = 0; i < 2; ++i) {
5724 struct dtvcc_service *ds;
5725 struct program *pr;
5726 vbi_bool success;
5727
5728 ds = &dc->service[i];
5729 if (0 == ds->service_data_in)
5730 continue;
5731
5732 success = dtvcc_decode_syntactic_elements
5733 (dc, ds, ds->service_data, ds->service_data_in);
5734
5735 ds->service_data_in = 0;
5736
5737 if (success)
5738 continue;
5739
5740 pr = PARENT (dc, struct program, cr.dtvcc);
5741 log (4, "Station %u DTVCC invalid "
5742 "syntactic element (%u).\n",
5743 station_num (pr), ds->error_line);
5744
5745 if (option_debug & DEBUG_DTVCC_PACKET) {
5746 fprintf (stderr, "Packet (%d/%d):\n",
5747 packet_size, dc->packet_size);
5748 dump (stderr, dc->packet, packet_size);
5749 fprintf (stderr, "Service Data:\n");
5750 dump (stderr, ds->service_data,
5751 ds->service_data_in);
5752 }
5753
5754 dtvcc_reset_service (ds);
5755 }
5756
5757 return;
5758
5759 invalid_service_block:
5760 {
5761 struct program *pr;
5762
5763 pr = PARENT (dc, struct program, cr.dtvcc);
5764 log (4, "Station %u DTVCC invalid "
5765 "service block (%u).\n",
5766 station_num (pr), i);
5767 if (option_debug & DEBUG_DTVCC_PACKET) {
5768 fprintf (stderr, "Packet (%d/%d):\n",
5769 packet_size, dc->packet_size);
5770 dump (stderr, dc->packet, packet_size);
5771 }
5772 dtvcc_reset (dc);
5773 return;
5774 }
5775
5776 service_block_incomplete:
5777 {
5778 struct program *pr;
5779
5780 pr = PARENT (dc, struct program, cr.dtvcc);
5781 log (4, "Station %u DTVCC incomplete "
5782 "service block (%u).\n",
5783 station_num (pr), i);
5784 if (option_debug & DEBUG_DTVCC_PACKET) {
5785 fprintf (stderr, "Packet (%d/%d):\n",
5786 packet_size, dc->packet_size);
5787 dump (stderr, dc->packet, packet_size);
5788 }
5789 dtvcc_reset (dc);
5790 return;
5791 }
5792
5793 }
5794
5795 static void
dtvcc_reset_service(struct dtvcc_service * ds)5796 dtvcc_reset_service (struct dtvcc_service * ds)
5797 {
5798 ds->curr_window = NULL;
5799 ds->created = 0;
5800
5801 cc_timestamp_reset (&ds->timestamp);
5802 }
5803
5804 static void
dtvcc_reset(struct dtvcc_decoder * dc)5805 dtvcc_reset (struct dtvcc_decoder * dc)
5806 {
5807 dtvcc_reset_service (&dc->service[0]);
5808 dtvcc_reset_service (&dc->service[1]);
5809
5810 dc->packet_size = 0;
5811 dc->next_sequence_number = -1;
5812 }
5813
5814 static void
init_dtvcc_decoder(struct dtvcc_decoder * dc)5815 init_dtvcc_decoder (struct dtvcc_decoder * dc)
5816 {
5817 dtvcc_reset (dc);
5818
5819 cc_timestamp_reset (&dc->timestamp);
5820 }
5821
5822 /* ATSC A/53 Part 4:2007 Closed Caption Data decoder */
5823
5824 static void
dump_cc_data_pair(FILE * fp,unsigned int index,const uint8_t buf[3])5825 dump_cc_data_pair (FILE * fp,
5826 unsigned int index,
5827 const uint8_t buf[3])
5828 {
5829 unsigned int one_bit;
5830 unsigned int reserved;
5831 unsigned int cc_valid;
5832 enum cc_type cc_type;
5833 unsigned int cc_data_1;
5834 unsigned int cc_data_2;
5835
5836 /* Was marker_bits: "11111". */
5837 one_bit = (buf[0] >> 7) & 1;
5838 reserved = (buf[0] >> 3) & 15;
5839
5840 cc_valid = (buf[0] >> 2) & 1;
5841 cc_type = (enum cc_type)(buf[0] & 3);
5842 cc_data_1 = buf[1];
5843 cc_data_2 = buf[2];
5844
5845 fprintf (fp, " %2u '1F'=%u%X%s valid=%u type=%s "
5846 "%02x %02x '%c%c'\n",
5847 index, one_bit, reserved,
5848 (1 != one_bit || 0xF != reserved) ? "*" : "",
5849 cc_valid, cc_type_name (cc_type),
5850 cc_data_1, cc_data_2,
5851 printable (cc_data_1), printable (cc_data_2));
5852 }
5853
5854 static void
dump_cc_data(FILE * fp,const uint8_t * buf,unsigned int n_bytes,int64_t pts,int64_t last_pts)5855 dump_cc_data (FILE * fp,
5856 const uint8_t * buf,
5857 unsigned int n_bytes,
5858 int64_t pts,
5859 int64_t last_pts)
5860 {
5861 unsigned int reserved1;
5862 unsigned int process_cc_data_flag;
5863 unsigned int zero_bit;
5864 unsigned int cc_count;
5865 unsigned int reserved2;
5866 unsigned int same;
5867 unsigned int marker_bits;
5868 unsigned int i;
5869
5870 /* Was process_em_data_flag: "This flag is set to
5871 indicate whether it is necessary to process the em_data. If
5872 it is set to 1, the em_data has to be parsed and its
5873 meaning has to be processed. When it is set to 0, the
5874 em_data can be discarded." */
5875 reserved1 = (buf[9] >> 7) & 1;
5876
5877 process_cc_data_flag = (buf[9] >> 6) & 1;
5878
5879 /* Was: additional_cc_data. */
5880 zero_bit = (buf[9] >> 5) & 1;
5881
5882 cc_count = buf[9] & 0x1F;
5883
5884 /* Was em_data: "Eight bits for representing emergency
5885 message." */
5886 reserved2 = buf[10];
5887
5888 fprintf (fp, "cc_data pts=%" PRId64 " (%+" PRId64 ") "
5889 "'1'=%u%s process_cc_data_flag=%u "
5890 "'0'=%u%s cc_count=%u 'FF'=0x%02X%s:\n",
5891 pts, pts - last_pts, reserved1,
5892 (1 != reserved1) ? "*" : "", process_cc_data_flag,
5893 zero_bit, (0 != zero_bit) ? "*" : "",
5894 cc_count, reserved2,
5895 (0xFF != reserved2) ? "*" : "");
5896
5897 same = 0;
5898 for (i = 0; i <= cc_count; ++i) {
5899 if (i > 0 && i < cc_count
5900 && 0 == memcmp (&buf[11 + i * 3],
5901 &buf[ 8 + i * 3], 3)) {
5902 ++same;
5903 } else {
5904 if (same > 1) {
5905 fprintf (fp, " %2u-%u as above\n",
5906 i - same, i - 1);
5907 } else if (same > 0) {
5908 dump_cc_data_pair (fp, i - 1, &buf[8 + i * 3]);
5909 }
5910 if (i < cc_count)
5911 dump_cc_data_pair (fp, i, &buf[11 + i * 3]);
5912 same = 0;
5913 }
5914 }
5915
5916 marker_bits = buf[11 + cc_count * 3];
5917
5918 fprintf (fp, " marker_bits=0x%02X%s\n",
5919 marker_bits, (0xFF != marker_bits) ? "*" : "");
5920
5921 if (n_bytes > 12 + cc_count * 3) {
5922 fprintf (fp, " extraneous");
5923 for (i = 12 + cc_count * 3; i < n_bytes; ++i)
5924 fprintf (stderr, " %02x", buf[i]);
5925 fputc ('\n', stderr);
5926 }
5927 }
5928
5929 /* Note pts may be < 0 if no PTS was received. */
5930 static void
decode_cc_data(struct program * pr,int64_t pts,const uint8_t * buf,unsigned int n_bytes)5931 decode_cc_data (struct program * pr,
5932 int64_t pts,
5933 const uint8_t * buf,
5934 unsigned int n_bytes)
5935 {
5936 unsigned int process_cc_data_flag;
5937 unsigned int cc_count;
5938 unsigned int i;
5939 vbi_bool dtvcc;
5940
5941 if (option_debug & DEBUG_CC_DATA) {
5942 static int64_t last_pts = 0; /* XXX */
5943
5944 dump_cc_data (stderr, buf, n_bytes, pts, last_pts);
5945 last_pts = pts;
5946 }
5947
5948 process_cc_data_flag = buf[9] & 0x40;
5949 if (!process_cc_data_flag)
5950 return;
5951
5952 cc_count = buf[9] & 0x1F;
5953 dtvcc = FALSE;
5954
5955 if (NULL != pr->cr.ccd.cc_data_tap_fp) {
5956 static uint8_t output_buffer [8 + 11 + 31 * 3];
5957 unsigned int in;
5958 unsigned int out;
5959 unsigned int n_bytes;
5960
5961 for (in = 0; in < 8; ++in)
5962 output_buffer[in] = pts >> (56 - in * 8);
5963 n_bytes = 11 + cc_count * 3;
5964 memcpy (output_buffer + in, buf, n_bytes);
5965 in += n_bytes;
5966 out = sizeof (output_buffer);
5967 memset (output_buffer + in, 0, out - in);
5968
5969 if (out != fwrite (output_buffer, 1, out,
5970 pr->cr.ccd.cc_data_tap_fp)) {
5971 errno_exit ("cc_data tap write error");
5972 }
5973 }
5974
5975 for (i = 0; i < cc_count; ++i) {
5976 unsigned int b0;
5977 unsigned int cc_valid;
5978 enum cc_type cc_type;
5979 unsigned int cc_data_1;
5980 unsigned int cc_data_2;
5981 unsigned int j;
5982
5983 b0 = buf[11 + i * 3];
5984 cc_valid = b0 & 4;
5985 cc_type = (enum cc_type)(b0 & 3);
5986 cc_data_1 = buf[12 + i * 3];
5987 cc_data_2 = buf[13 + i * 3];
5988
5989 switch (cc_type) {
5990 case NTSC_F1:
5991 case NTSC_F2:
5992 /* Note CEA 708-C Table 4: Only one NTSC pair
5993 will be present in field picture user_data
5994 or in progressive video pictures, and up to
5995 three can occur if the frame rate < 30 Hz
5996 or repeat_first_field = 1. */
5997 if (!cc_valid || i >= 3 || dtvcc) {
5998 /* Illegal, invalid or filler. */
5999 break;
6000 }
6001
6002 if (option_debug & (DEBUG_CC_F1 | DEBUG_CC_F2)) {
6003 if ((NTSC_F1 == cc_type
6004 && 0 != (option_debug & DEBUG_CC_F1))
6005 || (NTSC_F2 == cc_type
6006 && 0 != (option_debug & DEBUG_CC_F2)))
6007 dump_cc (stderr, i, cc_count,
6008 cc_valid, cc_type,
6009 cc_data_1, cc_data_2);
6010 }
6011
6012 cc_feed (&pr->cr.cc, &buf[12 + i * 3],
6013 /* line */ (NTSC_F1 == cc_type) ? 21 : 284,
6014 &pr->now, pts);
6015
6016 /* XXX replace me. */
6017 if (NTSC_F1 == cc_type) {
6018 pr->cr.field = 0;
6019 if (pr->cr.usexds) /* fields swapped? */
6020 XDSdecode(&pr->cr, cc_data_1
6021 + cc_data_2 * 256);
6022 } else {
6023 pr->cr.field = 1;
6024 if (pr->cr.usexds)
6025 XDSdecode(&pr->cr, cc_data_1
6026 + cc_data_2 * 256);
6027 }
6028
6029 break;
6030
6031 case DTVCC_DATA:
6032 j = pr->cr.dtvcc.packet_size;
6033 if (j <= 0) {
6034 /* Missed packet start. */
6035 break;
6036 } else if (!cc_valid) {
6037 /* End of DTVCC packet. */
6038 dtvcc_decode_packet (&pr->cr.dtvcc,
6039 &pr->now, pts);
6040 pr->cr.dtvcc.packet_size = 0;
6041 } else if (j >= 128) {
6042 /* Packet buffer overflow. */
6043 dtvcc_reset (&pr->cr.dtvcc);
6044 pr->cr.dtvcc.packet_size = 0;
6045 } else {
6046 pr->cr.dtvcc.packet[j] = cc_data_1;
6047 pr->cr.dtvcc.packet[j + 1] = cc_data_2;
6048 pr->cr.dtvcc.packet_size = j + 2;
6049 }
6050 break;
6051
6052 case DTVCC_START:
6053 dtvcc = TRUE;
6054 j = pr->cr.dtvcc.packet_size;
6055 if (j > 0) {
6056 /* End of DTVCC packet. */
6057 dtvcc_decode_packet (&pr->cr.dtvcc,
6058 &pr->now, pts);
6059 }
6060 if (!cc_valid) {
6061 /* No new data. */
6062 pr->cr.dtvcc.packet_size = 0;
6063 } else {
6064 pr->cr.dtvcc.packet[0] = cc_data_1;
6065 pr->cr.dtvcc.packet[1] = cc_data_2;
6066 pr->cr.dtvcc.packet_size = 2;
6067 }
6068 break;
6069 }
6070 }
6071 }
6072
6073 static void
init_cc_data_decoder(struct cc_data_decoder * cd)6074 init_cc_data_decoder (struct cc_data_decoder *cd)
6075 {
6076 CLEAR (*cd);
6077 }
6078
6079 static void
cc_data_test_loop(struct program * pr,const char * test_file_name)6080 cc_data_test_loop (struct program * pr,
6081 const char * test_file_name)
6082 {
6083 FILE *test_fp;
6084
6085 test_fp = open_test_file (test_file_name);
6086
6087 for (;;) {
6088 static uint8_t buffer[8 + 11 + 31 * 3];
6089 size_t todo;
6090 size_t actual;
6091
6092 todo = sizeof (buffer);
6093 actual = fread (buffer, 1, todo, test_fp);
6094 if (likely (actual == todo)) {
6095 int64_t pts;
6096 unsigned int i;
6097
6098 pts = 0;
6099 for (i = 0; i < 8; ++i) {
6100 pts |= buffer[i] << (56 - i * 8);
6101 }
6102 decode_cc_data (pr, pts, &buffer[8], actual);
6103 continue;
6104 }
6105
6106 if (ferror (test_fp)) {
6107 errno_exit ("CC data file read error");
6108 } else {
6109 log (1, "End of CC data file.\n");
6110 fclose (test_fp);
6111 return;
6112 }
6113 }
6114 }
6115
6116 /* DVB capture functions and transport stream decoding. */
6117
6118 static void
init_buffer(struct buffer * b,unsigned int capacity)6119 init_buffer (struct buffer * b,
6120 unsigned int capacity)
6121 {
6122 b->capacity = capacity;
6123 b->base = xmalloc (capacity);
6124 b->in = 0;
6125 b->out = 0;
6126 }
6127
6128 static void
6129 dump_pes_buffer (FILE * fp,
6130 const struct pes_buffer *b,
6131 const char * name)
6132 _vbi_unused;
6133
6134 static void
dump_pes_buffer(FILE * fp,const struct pes_buffer * b,const char * name)6135 dump_pes_buffer (FILE * fp,
6136 const struct pes_buffer *b,
6137 const char * name)
6138 {
6139 unsigned int i;
6140
6141 fprintf (fp, "%s PES buffer:\n", name);
6142
6143 for (i = 0; i < b->n_packets; ++i) {
6144 fprintf (fp, "%2u: offs=%5u size=%u/%u "
6145 "dts=%" PRId64 " (%+" PRId64 ") "
6146 "duration=%" PRId64 " splice=%d lost=%d\n",
6147 i,
6148 b->packet[i].offset,
6149 b->packet[i].payload,
6150 b->packet[i].size,
6151 b->packet[i].dts,
6152 (i > 0) ? (b->packet[i].dts
6153 - b->packet[i - 1].dts) : 0,
6154 b->packet[i].duration,
6155 b->packet[i].splice,
6156 b->packet[i].data_lost);
6157 }
6158 }
6159
6160
6161
6162 static vbi_bool
decode_time_stamp(int64_t * ts,const uint8_t * buf,unsigned int marker)6163 decode_time_stamp (int64_t * ts,
6164 const uint8_t * buf,
6165 unsigned int marker)
6166 {
6167 /* ISO 13818-1 Section 2.4.3.6 */
6168
6169 if (0 != ((marker ^ buf[0]) & 0xF1))
6170 return FALSE;
6171
6172 if (NULL != ts) {
6173 unsigned int a, b, c;
6174
6175 /* marker [4], TS [32..30], marker_bit,
6176 TS [29..15], marker_bit,
6177 TS [14..0], marker_bit */
6178 a = (buf[0] >> 1) & 0x7;
6179 b = (buf[1] * 256 + buf[2]) >> 1;
6180 c = (buf[3] * 256 + buf[4]) >> 1;
6181
6182 *ts = ((int64_t) a << 30) + (b << 15) + (c << 0);
6183 }
6184
6185 return TRUE;
6186 }
6187
6188
6189 static void
dump_pes_packet_header(FILE * fp,const uint8_t * buf)6190 dump_pes_packet_header (FILE * fp,
6191 const uint8_t * buf)
6192 {
6193 unsigned int packet_start_code_prefix;
6194 unsigned int stream_id;
6195 unsigned int PES_packet_length;
6196 unsigned int PES_scrambling_control;
6197 unsigned int PES_priority;
6198 unsigned int data_alignment_indicator;
6199 unsigned int copyright;
6200 unsigned int original_or_copy;
6201 unsigned int PTS_DTS_flags;
6202 unsigned int ESCR_flag;
6203 unsigned int ES_rate_flag;
6204 unsigned int DSM_trick_mode_flag;
6205 unsigned int additional_copy_info_flag;
6206 unsigned int PES_CRC_flag;
6207 unsigned int PES_extension_flag;
6208 unsigned int PES_header_data_length;
6209 int64_t ts;
6210
6211 /* ISO 13818-1 Section 2.4.3.6. */
6212
6213 packet_start_code_prefix = buf[0] * 65536 + buf[1] * 256 + buf[2];
6214 stream_id = buf[3];
6215 PES_packet_length = buf[4] * 256 + buf[5];
6216 /* '10' */
6217 PES_scrambling_control = (buf[6] & 0x30) >> 4;
6218 PES_priority = buf[6] & 0x08;
6219 data_alignment_indicator = buf[6] & 0x04;
6220 copyright = buf[6] & 0x02;
6221 original_or_copy = buf[6] & 0x01;
6222 PTS_DTS_flags = (buf[7] & 0xC0) >> 6;
6223 ESCR_flag = buf[7] & 0x20;
6224 ES_rate_flag = buf[7] & 0x10;
6225 DSM_trick_mode_flag = buf[7] & 0x08;
6226 additional_copy_info_flag = buf[7] & 0x04;
6227 PES_CRC_flag = buf[7] & 0x02;
6228 PES_extension_flag = buf[7] & 0x01;
6229 PES_header_data_length = buf[8];
6230
6231 fprintf (fp, "PES %06X%02X %5u "
6232 "%u%u%u%c%c%c%c%u%c%c%c%c%c%c %u",
6233 packet_start_code_prefix, stream_id,
6234 PES_packet_length,
6235 !!(buf[6] & 0x80),
6236 !!(buf[6] & 0x40),
6237 PES_scrambling_control,
6238 PES_priority ? 'P' : '-',
6239 data_alignment_indicator ? 'A' : '-',
6240 copyright ? 'C' : '-',
6241 original_or_copy ? 'O' : 'C',
6242 PTS_DTS_flags,
6243 ESCR_flag ? 'E' : '-',
6244 ES_rate_flag ? 'E' : '-',
6245 DSM_trick_mode_flag ? 'D' : '-',
6246 additional_copy_info_flag ? 'A' : '-',
6247 PES_CRC_flag ? 'C' : '-',
6248 PES_extension_flag ? 'X' : '-',
6249 PES_header_data_length);
6250
6251 switch (PTS_DTS_flags) {
6252 case 0: /* no timestamps */
6253 case 1: /* forbidden */
6254 fputc ('\n', fp);
6255 break;
6256
6257 case 2: /* PTS only */
6258 if (decode_time_stamp (&ts, &buf[9], 0x21))
6259 fprintf (fp, " %" PRId64 "\n", ts);
6260 else
6261 fputs (" PTS?\n", fp);
6262 break;
6263
6264 case 3: /* PTS and DTS */
6265 if (decode_time_stamp (&ts, &buf[9], 0x31))
6266 fprintf (fp, " %" PRId64, ts);
6267 else
6268 fputs (" PTS?", fp);
6269 if (decode_time_stamp (&ts, &buf[14], 0x11))
6270 fprintf (fp, " %" PRId64 "\n", ts);
6271 else
6272 fputs (" DTS?\n", fp);
6273 break;
6274 }
6275 }
6276
6277
6278 static void
close_ts_file(struct video_recorder * vr)6279 close_ts_file (struct video_recorder *vr)
6280 {
6281 if (NULL != vr->minicut_fp) {
6282 if (0 != fclose (vr->minicut_fp)) {
6283 struct program *pr;
6284
6285 pr = PARENT (vr, struct program, vr);
6286 log_errno (1, "TS stream %u close error",
6287 (unsigned int)(pr - program_table));
6288 }
6289
6290 vr->minicut_fp = NULL;
6291 }
6292 }
6293
6294 static unsigned int
mpeg2_crc(const uint8_t * buf,unsigned int n_bytes)6295 mpeg2_crc (const uint8_t * buf,
6296 unsigned int n_bytes)
6297 {
6298 static uint32_t crc_table[256];
6299 unsigned int crc;
6300 unsigned int i;
6301
6302 /* ISO 13818-1 Annex B. */
6303
6304 if (unlikely (0 == crc_table[255])) {
6305 const unsigned int poly =
6306 ((1 << 26) | (1 << 23) | (1 << 22) | (1 << 16) |
6307 (1 << 12) | (1 << 11) | (1 << 10) | (1 << 8) |
6308 (1 << 7) | (1 << 5) | (1 << 4) | (1 << 2) |
6309 (1 << 1) | 1);
6310 unsigned int c, j;
6311
6312 for (i = 0; i < 256; ++i) {
6313 c = i << 24;
6314 for (j = 0; j < 8; ++j) {
6315 if (c & (1 << 31))
6316 c = (c << 1) ^ poly;
6317 else
6318 c <<= 1;
6319 }
6320 crc_table[i] = c;
6321 }
6322 assert (0 != crc_table[255]);
6323 }
6324
6325 crc = -1;
6326 for (i = 0; i < n_bytes; ++i)
6327 crc = crc_table[(buf[i] ^ (crc >> 24)) & 0xFF] ^ (crc << 8);
6328
6329 return crc & 0xFFFFFFFFUL;
6330 }
6331
6332 static const unsigned int pmt_pid = 0x5A5;
6333
6334 static void
init_pmt(uint8_t buf[188],struct video_recorder * vr,const struct ts_decoder * td)6335 init_pmt (uint8_t buf[188],
6336 struct video_recorder *vr,
6337 const struct ts_decoder *td)
6338 {
6339 uint32_t CRC_32;
6340
6341 /* sync_byte [8], transport_error_indicator,
6342 payload_unit_start_indicator, transport_priority, PID [13],
6343 transport_scrambling_control [2], adaptation_field_control
6344 [2], continuity_counter [4] */
6345 buf[0] = 0x47;
6346 buf[1] = 0x40 | ((pmt_pid & 0x1FFF) >> 8);
6347 buf[2] = pmt_pid;
6348 buf[3] = 0x10 | (vr->pmt_cc & 0x0F);
6349 ++vr->pmt_cc;
6350
6351 /* pointer_field */
6352 buf[4] = 0x00;
6353
6354 /* table_id [8] */
6355 buf[5] = 0x02; /* TS_program_map_section */
6356
6357 /* section_syntax_indicator, '0', reserved [2], section_length
6358 [12] */
6359 buf[6] = 0xB0;
6360 buf[7] = 31 - 8;
6361
6362 /* program_number [16] */
6363 buf[8] = 0x00;
6364 buf[9] = 0x01;
6365
6366 /* reserved [2], version_number [5], current_next_indicator */
6367 buf[10] = 0xC1;
6368
6369 /* section_number [8], last_section_number [8] */
6370 buf[11] = 0x00;
6371 buf[12] = 0x00;
6372
6373 /* reserved [3], PCR_PID [13] */
6374 buf[13] = 0xE0 | (td->pid[0] >> 8);
6375 buf[14] = td->pid[0];
6376
6377 /* reserved [4], program_info_length [12] */
6378 buf[15] = 0xF0;
6379 buf[16] = 0x00;
6380
6381 /* stream_type [8], reserved [3], elementary_PID [13],
6382 reserved [4], ES_info_length [12] */
6383 buf[17] = 0x02; /* MPEG-2 video */
6384 buf[18] = 0xE0 | (td->pid[0] >> 8);
6385 buf[19] = td->pid[0];
6386 buf[20] = 0xF0;
6387 buf[21] = 0x00;
6388
6389 buf[22] = 0x81; /* AC3 audio */
6390 buf[23] = 0xE0 | (td->pid[1] >> 8);
6391 buf[24] = td->pid[1];
6392 buf[25] = 0xF0;
6393 buf[26] = 0x00;
6394
6395 CRC_32 = mpeg2_crc (buf + 5, 27 - 5);
6396 buf[27] = CRC_32 >> 24;
6397 buf[28] = CRC_32 >> 16;
6398 buf[29] = CRC_32 >> 8;
6399 buf[30] = CRC_32;
6400
6401 memset (buf + 31, -1, 188 - 31);
6402 }
6403
6404 static void
init_pat(uint8_t buf[188],struct video_recorder * vr)6405 init_pat (uint8_t buf[188],
6406 struct video_recorder *vr)
6407 {
6408 uint32_t CRC_32;
6409
6410 /* sync_byte [8], transport_error_indicator,
6411 payload_unit_start_indicator, transport_priority, PID [13],
6412 transport_scrambling_control [2], adaptation_field_control
6413 [2], continuity_counter [4] */
6414 buf[0] = 0x47;
6415 buf[1] = 0x40;
6416 buf[2] = 0x00;
6417 buf[3] = 0x10 | (vr->pat_cc & 0x0F);
6418 ++vr->pat_cc;
6419
6420 /* pointer_field [8] */
6421 buf[4] = 0x00;
6422
6423 /* table_id [8] */
6424 buf[5] = 0x00; /* program_association_section */
6425
6426 /* section_syntax_indicator, '0', reserved [2],
6427 section_length [12] */
6428 buf[6] = 0xB0;
6429 buf[7] = 21 - 8;
6430
6431 /* transport_stream_id [16] */
6432 buf[8] = 0x00;
6433 buf[9] = 0x01;
6434
6435 /* reserved [2], version_number [5], current_next_indicator */
6436 buf[10] = 0xC1;
6437
6438 /* section_number [8], last_section_number [8] */
6439 buf[11] = 0x00;
6440 buf[12] = 0x00;
6441
6442 /* program_number [16] */
6443 buf[13] = 0x00;
6444 buf[14] = 0x01;
6445
6446 /* reserved [3], program_map_PID [13] */
6447 buf[15] = 0xE0 | ((pmt_pid & 0x1FFF) >> 8);
6448 buf[16] = pmt_pid;
6449
6450 CRC_32 = mpeg2_crc (buf + 5, 17 - 5);
6451 buf[17] = CRC_32 >> 24;
6452 buf[18] = CRC_32 >> 16;
6453 buf[19] = CRC_32 >> 8;
6454 buf[20] = CRC_32;
6455
6456 memset (buf + 21, -1, 188 - 21);
6457 }
6458
6459 static void
video_recorder(struct video_recorder * vr,const uint8_t buf[188])6460 video_recorder (struct video_recorder *vr,
6461 const uint8_t buf[188])
6462 {
6463 struct program *pr = PARENT (vr, struct program, vr);
6464 size_t actual;
6465
6466 if (NULL == pr->option_minicut_dir_name)
6467 return; /* no video recording */
6468
6469 /* The TS packet rate is too high to call time() here. We do
6470 that when a picture arrives, some 24 to 60 times/second. */
6471 if (0 == (pr->now.tv_sec | pr->now.tv_usec))
6472 return; /* no picture received yet */
6473
6474 /* Note minicut_end is initially zero. */
6475 if (pr->now.tv_sec >= vr->minicut_end) {
6476 char file_name[32];
6477 struct tm tm;
6478 time_t t;
6479
6480 t = pr->now.tv_sec;
6481 if (NULL == gmtime_r (&t, &tm)) {
6482 /* Should not happen. */
6483 error_exit ("System time invalid.\n");
6484 }
6485
6486 vr->minicut_end = t + (60 - tm.tm_sec);
6487
6488 if (option_minicut_test) {
6489 tm.tm_sec = 0;
6490 } else if (1) {
6491 tm.tm_sec = 0;
6492 } else {
6493 if (0 != tm.tm_sec)
6494 return;
6495 }
6496
6497 close_ts_file (vr);
6498
6499 snprintf (file_name, sizeof (file_name),
6500 "/%04u%02u%02u%02u%02u%02u",
6501 tm.tm_year + 1900,
6502 tm.tm_mon + 1,
6503 tm.tm_mday,
6504 tm.tm_hour,
6505 tm.tm_min,
6506 tm.tm_sec);
6507
6508 vr->minicut_fp = open_minicut_file (pr, &tm, file_name, ".ts");
6509 if (NULL != vr->minicut_fp) {
6510 uint8_t buf[2 * 188];
6511
6512 init_pat (buf, vr);
6513 init_pmt (buf + 188, vr, &pr->tsd);
6514
6515 actual = fwrite (buf, 1, 2 * 188, vr->minicut_fp);
6516 if (2 * 188 != actual) {
6517 log_errno (1, "TS stream %u write error",
6518 station_num (pr));
6519 }
6520 }
6521 }
6522
6523 if (NULL == vr->minicut_fp)
6524 return;
6525
6526 actual = fwrite (buf, 1, 188, vr->minicut_fp);
6527 if (188 != actual) {
6528 log_errno (1, "TS stream %u write error",
6529 station_num (pr));
6530 }
6531 }
6532
6533
6534 static void
init_video_recorder(struct video_recorder * vr)6535 init_video_recorder (struct video_recorder *vr)
6536 {
6537
6538
6539
6540
6541
6542 vr->pat_cc = 0;
6543 vr->pmt_cc = 0;
6544
6545 vr->minicut_end = 0;
6546 vr->minicut_fp = NULL;
6547 }
6548
6549 /* Video elementary stream decoder. */
6550
6551 static void
vesd_reorder_decode_cc_data(struct video_es_decoder * vd,const uint8_t * buf,unsigned int n_bytes)6552 vesd_reorder_decode_cc_data (struct video_es_decoder *vd,
6553 const uint8_t * buf,
6554 unsigned int n_bytes)
6555 {
6556 struct program *pr = PARENT (vd, struct program, vesd);
6557
6558 n_bytes = MIN (n_bytes, (unsigned int)
6559 sizeof (vd->reorder_buffer[0]));
6560
6561 switch (vd->picture_structure) {
6562 case FRAME_PICTURE:
6563 if (0 != vd->reorder_pictures) {
6564 if (vd->reorder_pictures & 5) {
6565 /* Top field or top and bottom field. */
6566 decode_cc_data (pr, vd->reorder_pts[0],
6567 vd->reorder_buffer[0],
6568 vd->reorder_n_bytes[0]);
6569 }
6570 if (vd->reorder_pictures & 2) {
6571 /* Bottom field. */
6572 decode_cc_data (pr, vd->reorder_pts[1],
6573 vd->reorder_buffer[1],
6574 vd->reorder_n_bytes[1]);
6575 }
6576 }
6577
6578 memcpy (vd->reorder_buffer[0], buf, n_bytes);
6579 vd->reorder_n_bytes[0] = n_bytes;
6580 vd->reorder_pts[0] = vd->pts;
6581
6582 /* We have a frame. */
6583 vd->reorder_pictures = 4;
6584
6585 break;
6586
6587 case TOP_FIELD:
6588 if (vd->reorder_pictures >= 3) {
6589 /* Top field or top and bottom field. */
6590 decode_cc_data (pr, vd->reorder_pts[0],
6591 vd->reorder_buffer[0],
6592 vd->reorder_n_bytes[0]);
6593
6594 vd->reorder_pictures &= 2;
6595 } else if (1 == vd->reorder_pictures) {
6596 /* Apparently we missed a bottom field. */
6597 }
6598
6599 memcpy (vd->reorder_buffer[0], buf, n_bytes);
6600 vd->reorder_n_bytes[0] = n_bytes;
6601 vd->reorder_pts[0] = vd->pts;
6602
6603 /* We have a top field. */
6604 vd->reorder_pictures |= 1;
6605
6606 break;
6607
6608 case BOTTOM_FIELD:
6609 if (vd->reorder_pictures >= 3) {
6610 if (vd->reorder_pictures >= 4) {
6611 /* Top and bottom field. */
6612 decode_cc_data (pr, vd->reorder_pts[0],
6613 vd->reorder_buffer[0],
6614 vd->reorder_n_bytes[0]);
6615 } else {
6616 /* Bottom field. */
6617 decode_cc_data (pr, vd->reorder_pts[1],
6618 vd->reorder_buffer[1],
6619 vd->reorder_n_bytes[1]);
6620 }
6621
6622 vd->reorder_pictures &= 1;
6623 } else if (2 == vd->reorder_pictures) {
6624 /* Apparently we missed a top field. */
6625 }
6626
6627 memcpy (vd->reorder_buffer[1], buf, n_bytes);
6628 vd->reorder_n_bytes[1] = n_bytes;
6629 vd->reorder_pts[1] = vd->pts;
6630
6631 /* We have a bottom field. */
6632 vd->reorder_pictures |= 2;
6633
6634 break;
6635
6636 default: /* invalid */
6637 break;
6638 }
6639 }
6640
6641 static void
vesd_user_data(struct video_es_decoder * vd,const uint8_t * buf,unsigned int min_bytes_valid)6642 vesd_user_data (struct video_es_decoder *vd,
6643 const uint8_t * buf,
6644 unsigned int min_bytes_valid)
6645 {
6646 unsigned int ATSC_identifier;
6647 unsigned int user_data_type_code;
6648 unsigned int cc_count;
6649
6650 /* ATSC A/53 Part 4:2007 Section 6.2.2 */
6651
6652 if (unlikely (option_debug & DEBUG_VESD_USER_DATA)) {
6653 unsigned int i;
6654
6655 fprintf (stderr, "VES UD: %s %s ref=%u "
6656 "dts=%" PRId64 " pts=%" PRId64,
6657 picture_coding_type_name (vd->picture_coding_type),
6658 picture_structure_name (vd->picture_structure),
6659 vd->picture_temporal_reference,
6660 vd->dts, vd->pts);
6661 for (i = 0; i < min_bytes_valid; ++i)
6662 fprintf (stderr, " %02x", buf[i]);
6663 fputc (' ', stderr);
6664 for (i = 0; i < min_bytes_valid; ++i)
6665 fputc (printable (buf[i]), stderr);
6666 fputc ('\n', stderr);
6667 }
6668
6669 /* NB. the PES packet header is optional and we may receive
6670 more than one user_data structure. */
6671 if ((RECEIVED_PICTURE |
6672 RECEIVED_PICTURE_EXT)
6673 != (vd->received_blocks & (RECEIVED_PICTURE |
6674 RECEIVED_PICTURE_EXT))) {
6675 /* Either sequence or group user_data, or we missed
6676 the picture_header. */
6677 vd->received_blocks &= ~RECEIVED_PES_PACKET;
6678 return;
6679 }
6680
6681 if (NULL == buf) {
6682 /* No user_data received on this field or frame. */
6683
6684 if (option_debug & DEBUG_VESD_CC_DATA) {
6685 fprintf (stderr, "DTVCC coding=%s structure=%s "
6686 "pts=%" PRId64 " no data\n",
6687 picture_coding_type_name
6688 (vd->picture_coding_type),
6689 picture_structure_name
6690 (vd->picture_structure),
6691 vd->pts);
6692 }
6693 } else {
6694 /* start_code_prefix [24], start_code [8],
6695 ATSC_identifier [32], user_data_type_code [8] */
6696 if (min_bytes_valid < 9)
6697 return;
6698
6699 ATSC_identifier = ((buf[4] << 24) | (buf[5] << 16) |
6700 (buf[6] << 8) | buf[7]);
6701 if (0x47413934 != ATSC_identifier)
6702 return;
6703
6704 user_data_type_code = buf[8];
6705 if (0x03 != user_data_type_code)
6706 return;
6707
6708 /* ATSC A/53 Part 4:2007 Section 6.2.1: "No more than one
6709 user_data() structure using the same user_data_type_code
6710 [...] shall be present following any given picture
6711 header." */
6712 if (vd->received_blocks & RECEIVED_MPEG_CC_DATA) {
6713 /* Too much data lost. */
6714 return;
6715 }
6716
6717 vd->received_blocks |= RECEIVED_MPEG_CC_DATA;
6718
6719 /* reserved, process_cc_data_flag, zero_bit, cc_count [5],
6720 reserved [8] */
6721 if (min_bytes_valid < 11)
6722 return;
6723
6724 /* one_bit, reserved [4], cc_valid, cc_type [2],
6725 cc_data_1 [8], cc_data_2 [8] */
6726 cc_count = buf[9] & 0x1F;
6727
6728 /* CEA 708-C Section 4.4 permits padding, so we have to see
6729 all cc_data elements. */
6730 if (min_bytes_valid < 11 + cc_count * 3)
6731 return;
6732
6733 if (option_debug & DEBUG_VESD_CC_DATA) {
6734 char text[0x1F * 2 + 1];
6735 unsigned int i;
6736 vbi_bool ooo;
6737
6738 for (i = 0; i < cc_count; ++i) {
6739 text[i * 2 + 0] = printable (buf[12 + i * 3]);
6740 text[i * 2 + 1] = printable (buf[13 + i * 3]);
6741 }
6742 text[cc_count * 2] = 0;
6743
6744 ooo = (B_TYPE == vd->picture_coding_type
6745 && vd->reorder_pictures < 3);
6746
6747 fprintf (stderr, "DTVCC coding=%s structure=%s "
6748 "pts=%" PRId64 " cc_count=%u "
6749 "n_bytes=%u '%s'%s\n",
6750 picture_coding_type_name
6751 (vd->picture_coding_type),
6752 picture_structure_name
6753 (vd->picture_structure),
6754 vd->pts, cc_count, min_bytes_valid,
6755 text, ooo ? " (out of order)" : "");
6756 }
6757 }
6758
6759 /* CEA 708-C Section 4.4.1.1 */
6760
6761 switch (vd->picture_coding_type) {
6762 case I_TYPE:
6763 case P_TYPE:
6764 vesd_reorder_decode_cc_data (vd, buf, min_bytes_valid);
6765 break;
6766
6767 case B_TYPE:
6768 /* To prevent a gap in the caption stream we must not
6769 decode B pictures until we have buffered both
6770 fields of the temporally following I or P picture. */
6771 if (vd->reorder_pictures < 3) {
6772 vd->reorder_pictures = 0;
6773 break;
6774 }
6775
6776 /* To do: If a B picture appears to have a higher
6777 temporal_reference than the picture it forward
6778 references we lost that I or P picture. */
6779 {
6780 struct program *pr;
6781
6782 pr = PARENT (vd, struct program, vesd);
6783 decode_cc_data (pr, vd->pts, buf,
6784 min_bytes_valid);
6785 }
6786
6787 break;
6788
6789 default: /* invalid */
6790 break;
6791 }
6792 }
6793
6794 static void
vesd_extension(struct video_es_decoder * vd,const uint8_t * buf,unsigned int min_bytes_valid)6795 vesd_extension (struct video_es_decoder *vd,
6796 const uint8_t * buf,
6797 unsigned int min_bytes_valid)
6798 {
6799 enum extension_start_code_identifier extension_start_code_identifier;
6800
6801 /* extension_start_code [32],
6802 extension_start_code_identifier [4],
6803 f_code [4][4], intra_dc_precision [2],
6804 picture_structure [2], ... */
6805 if (min_bytes_valid < 7)
6806 return;
6807
6808 extension_start_code_identifier =
6809 (enum extension_start_code_identifier)(buf[4] >> 4);
6810 if (PICTURE_CODING_EXTENSION_ID
6811 != extension_start_code_identifier)
6812 return;
6813
6814 if (0 == (vd->received_blocks & RECEIVED_PICTURE)) {
6815 /* We missed the picture_header. */
6816 vd->received_blocks = 0;
6817 return;
6818 }
6819
6820 vd->picture_structure = (enum picture_structure)(buf[6] & 3);
6821
6822 if (option_debug & DEBUG_VESD_PIC_EXT) {
6823 fprintf (stderr, "VES PIC EXT structure=%s\n",
6824 picture_structure_name (vd->picture_structure));
6825 }
6826
6827 vd->received_blocks |= RECEIVED_PICTURE_EXT;
6828 }
6829
6830 static void
vesd_picture_header(struct video_es_decoder * vd,const uint8_t * buf,unsigned int min_bytes_valid)6831 vesd_picture_header (struct video_es_decoder *vd,
6832 const uint8_t * buf,
6833 unsigned int min_bytes_valid)
6834 {
6835 unsigned int c;
6836
6837 /* picture_start_code [32],
6838 picture_temporal_reference [10],
6839 picture_coding_type [3], ... */
6840 /* XXX consider estimating the PTS if none transmitted. */
6841 if (min_bytes_valid < 6
6842 /* || vd->received_blocks != RECEIVED_PES_PACKET */) {
6843 /* Too much data lost. */
6844 vd->received_blocks = 0;
6845 return;
6846 }
6847
6848 c = buf[4] * 256 + buf[5];
6849 vd->picture_temporal_reference = (c >> 6) & 0x3FF;
6850 vd->picture_coding_type = (enum picture_coding_type)((c >> 3) & 7);
6851
6852 if (option_debug & DEBUG_VESD_PIC_HDR) {
6853 fprintf (stderr, "VES PIC HDR ref=%d type=%ss\n",
6854 vd->picture_temporal_reference,
6855 picture_coding_type_name
6856 (vd->picture_coding_type));
6857 }
6858
6859 ++vd->n_pictures_received;
6860
6861 vd->received_blocks |= RECEIVED_PICTURE;
6862 }
6863
6864 static void
vesd_pes_packet_header(struct video_es_decoder * vd,const uint8_t * buf,unsigned int min_bytes_valid)6865 vesd_pes_packet_header (struct video_es_decoder *vd,
6866 const uint8_t * buf,
6867 unsigned int min_bytes_valid)
6868 {
6869 unsigned int PES_packet_length;
6870 unsigned int PTS_DTS_flags;
6871 int64_t pts;
6872
6873 if (unlikely (option_debug & DEBUG_VESD_PES_PACKET)) {
6874 dump_pes_packet_header (stderr, buf);
6875 }
6876
6877 vd->pts = -1;
6878 vd->dts = -1;
6879
6880 vd->received_blocks = 0;
6881
6882 /* packet_start_code_prefix [24], stream_id [8],
6883 PES_packet_length [16],
6884
6885 '10', PES_scrambling_control [2], PES_priority,
6886 data_alignment_indicator, copyright, original_or_copy,
6887
6888 PTS_DTS_flags [2], ESCR_flag, ES_rate_flag,
6889 DSM_trick_mode_flag, additional_copy_info_flag,
6890 PES_CRC_flag, PES_extension_flag,
6891
6892 PES_header_data_length [8] */
6893 if (min_bytes_valid < 9)
6894 return;
6895
6896 PES_packet_length = buf[4] * 256 + buf[5];
6897 PTS_DTS_flags = (buf[7] & 0xC0) >> 6;
6898
6899 /* ISO 13818-1 Section 2.4.3.7: In transport streams video PES
6900 packets do not carry data, they only contain the DTS/PTS of
6901 the following picture and PES_packet_length must be
6902 zero. */
6903 if (0 != PES_packet_length)
6904 return;
6905
6906 switch (PTS_DTS_flags) {
6907 case 0: /* no timestamps */
6908 return;
6909
6910 case 1: /* forbidden */
6911 return;
6912
6913 case 2: /* PTS only */
6914 if (min_bytes_valid < 14)
6915 return;
6916 if (!decode_time_stamp (&vd->pts, &buf[9], 0x21))
6917 return;
6918 break;
6919
6920 case 3: /* PTS and DTS */
6921 if (min_bytes_valid < 19)
6922 return;
6923 if (!decode_time_stamp (&pts, &buf[9], 0x31))
6924 return;
6925 if (!decode_time_stamp (&vd->dts, &buf[14], 0x11))
6926 return;
6927 vd->pts = pts;
6928 break;
6929 }
6930
6931 if (unlikely (option_minicut_test)) {
6932 struct program *pr;
6933 int64_t dts;
6934
6935 pr = PARENT (vd, struct program, vesd);
6936
6937 dts = vd->dts;
6938 if (dts < 0)
6939 dts = vd->pts;
6940
6941 if (pr->first_dts < 0) {
6942 pr->first_dts = dts;
6943 } else if (dts < pr->first_dts) {
6944 dts += TIMESTAMP_MASK + 1;
6945 }
6946
6947 pr->now.tv_sec = (dts - pr->first_dts) / 90000;
6948 pr->now.tv_usec = (dts - pr->first_dts) % 90000 * 100 / 9;
6949 } else {
6950 struct program *pr;
6951
6952 pr = PARENT (vd, struct program, vesd);
6953 gettimeofday (&pr->now, /* tz */ NULL);
6954 }
6955
6956 vd->received_blocks = RECEIVED_PES_PACKET;
6957 }
6958
6959 static void
vesd_decode_block(struct video_es_decoder * vd,unsigned int start_code,const uint8_t * buf,unsigned int n_bytes,unsigned int min_bytes_valid,vbi_bool data_lost)6960 vesd_decode_block (struct video_es_decoder *vd,
6961 unsigned int start_code,
6962 const uint8_t * buf,
6963 unsigned int n_bytes,
6964 unsigned int min_bytes_valid,
6965 vbi_bool data_lost)
6966 {
6967 if (unlikely (option_debug & DEBUG_VESD_START_CODE)) {
6968 fprintf (stderr, "VES 0x000001%02X %u %u\n",
6969 start_code, min_bytes_valid, n_bytes);
6970 }
6971
6972 /* The CEA 608-C and 708-C Close Caption data is encoded in
6973 picture user data fields. ISO 13818-2 requires the start
6974 code sequence 0x00, 0xB5/8, (0xB5?, 0xB2?)*. To properly
6975 convert from coded order to display order we also need the
6976 picture_coding_type and picture_structure fields. */
6977
6978 if (likely (start_code <= 0xAF)) {
6979 if (!data_lost
6980 && (vd->received_blocks == (RECEIVED_PICTURE |
6981 RECEIVED_PICTURE_EXT)
6982 || vd->received_blocks == (RECEIVED_PES_PACKET |
6983 RECEIVED_PICTURE |
6984 RECEIVED_PICTURE_EXT))) {
6985 /* No user data received for this picture. */
6986 vesd_user_data (vd, NULL, 0);
6987 }
6988
6989 if (unlikely (0x00 == start_code) && !data_lost) {
6990 vesd_picture_header (vd, buf, min_bytes_valid);
6991 } else {
6992 /* slice_start_code, or data lost in or after
6993 the picture_header. */
6994
6995 /* For all we care the picture data is just
6996 useless filler prior to the next PES packet
6997 header, and we need an uninterrupted
6998 sequence from there to the next picture
6999 user_data to ensure the PTS, DTS,
7000 picture_temporal_reference,
7001 picture_coding_type, picture_structure and
7002 cc_data belong together. */
7003
7004 vd->received_blocks = 0;
7005 vd->pts = -1;
7006 vd->dts = -1;
7007 }
7008 } else if (USER_DATA_START_CODE == start_code) {
7009 vesd_user_data (vd, buf, min_bytes_valid);
7010 } else if (data_lost) {
7011 /* Data lost in or after this block. */
7012 vd->received_blocks = 0;
7013 } else if (EXTENSION_START_CODE == start_code) {
7014 vesd_extension (vd, buf, min_bytes_valid);
7015 } else if (start_code >= VIDEO_STREAM_0
7016 && start_code <= VIDEO_STREAM_15) {
7017 if (!data_lost
7018 && (vd->received_blocks == (RECEIVED_PICTURE |
7019 RECEIVED_PICTURE_EXT)
7020 || vd->received_blocks == (RECEIVED_PES_PACKET |
7021 RECEIVED_PICTURE |
7022 RECEIVED_PICTURE_EXT))) {
7023 /* No user data received for previous picture. */
7024 vesd_user_data (vd, NULL, 0);
7025 }
7026
7027 /* Start of a new picture. */
7028 vesd_pes_packet_header (vd, buf, min_bytes_valid);
7029 } else {
7030 /* Should be a sequence_header or
7031 group_of_pictures_header. */
7032
7033 vd->received_blocks &= RECEIVED_PES_PACKET;
7034 }
7035
7036 /* Not all of this data is relevant for caption decoding but
7037 we may need it to debug the video ES decoder. Without the
7038 actual picture data it should be highly repetitive and
7039 compress rather well. */
7040 if (unlikely (NULL != vd->video_es_tap_fp)) {
7041 unsigned int n = n_bytes;
7042
7043 if (start_code >= 0x01 && start_code <= 0xAF) {
7044 if (NULL == vd->option_video_es_all_tap_file_name)
7045 n = MIN (n, 8u);
7046 }
7047 if (n != fwrite (buf, 1, n, vd->video_es_tap_fp)) {
7048 errno_exit ("Video ES tap write error");
7049 }
7050 }
7051 }
7052
7053 static unsigned int
vesd_make_room(struct video_es_decoder * vd,unsigned int required)7054 vesd_make_room (struct video_es_decoder *vd,
7055 unsigned int required)
7056 {
7057 struct buffer *b;
7058 unsigned int capacity;
7059 unsigned int in;
7060
7061 b = &vd->buffer;
7062 capacity = b->capacity;
7063 in = b->in;
7064
7065 if (unlikely (in + required > capacity)) {
7066 unsigned int consumed;
7067 unsigned int unconsumed;
7068
7069 consumed = b->out;
7070 unconsumed = in - consumed;
7071 if (required > capacity - unconsumed) {
7072 /* XXX make this a recoverable error. */
7073 error_exit ("Video ES buffer overflow.\n");
7074 }
7075 memmove (b->base, b->base + consumed, unconsumed);
7076 in = unconsumed;
7077 b->out = 0;
7078 }
7079
7080 return in;
7081 }
7082
7083 static void
video_es_decoder(struct video_es_decoder * vd,const uint8_t * buf,unsigned int n_bytes,vbi_bool data_lost)7084 video_es_decoder (struct video_es_decoder *vd,
7085 const uint8_t * buf,
7086 unsigned int n_bytes,
7087 vbi_bool data_lost)
7088 {
7089 const uint8_t *s;
7090 const uint8_t *e;
7091 const uint8_t *e_max;
7092 unsigned int in;
7093
7094 /* This code searches for a start code and then decodes the
7095 data between the previous and the current start code. */
7096
7097 in = vesd_make_room (vd, n_bytes);
7098
7099 memcpy (vd->buffer.base + in, buf, n_bytes);
7100 vd->buffer.in = in + n_bytes;
7101
7102 s = vd->buffer.base + vd->buffer.out + vd->skip;
7103 e = vd->buffer.base + in + n_bytes - 4;
7104 e_max = e;
7105
7106 if (unlikely (data_lost)) {
7107 if (vd->min_bytes_valid >= UINT_MAX) {
7108 vd->min_bytes_valid =
7109 in - vd->buffer.out;
7110 }
7111
7112 /* Data is missing after vd->buffer.base + in, so
7113 we must ignore apparent start codes crossing that
7114 boundary. */
7115 e -= n_bytes;
7116 }
7117
7118 for (;;) {
7119 const uint8_t *b;
7120 enum start_code start_code;
7121 unsigned int n_bytes;
7122 unsigned int min_bytes_valid;
7123
7124 for (;;) {
7125 if (s >= e) {
7126 /* Need more data. */
7127
7128 if (unlikely (s < e_max)) {
7129 /* Skip over the lost data. */
7130 s = e + 4;
7131 e = e_max;
7132 continue;
7133 }
7134
7135 /* In the next iteration skip the
7136 bytes we already scanned. */
7137 vd->skip = s - vd->buffer.base
7138 - vd->buffer.out;
7139
7140 return;
7141 }
7142
7143 if (likely (0 != (s[2] & ~1))) {
7144 /* Not 000001 or xx0000 or xxxx00. */
7145 s += 3;
7146 } else if (0 != (s[0] | s[1]) || 1 != s[2]) {
7147 ++s;
7148 } else {
7149 break;
7150 }
7151 }
7152
7153 b = vd->buffer.base + vd->buffer.out;
7154 n_bytes = s - b;
7155 min_bytes_valid = n_bytes;
7156 data_lost = FALSE;
7157
7158 if (unlikely (vd->min_bytes_valid < UINT_MAX)) {
7159 if (n_bytes < vd->min_bytes_valid) {
7160 /* We found a new start code before
7161 the missing data. */
7162 vd->min_bytes_valid -= n_bytes;
7163 } else {
7164 min_bytes_valid = vd->min_bytes_valid;
7165 vd->min_bytes_valid = UINT_MAX;
7166
7167 /* Need a flag in case we lost data just
7168 before the next start code. */
7169 data_lost = TRUE;
7170 }
7171 }
7172
7173 start_code = vd->last_start_code;
7174 if (likely ((int) start_code >= 0)) {
7175 vesd_decode_block (vd, start_code, b,
7176 n_bytes, min_bytes_valid,
7177 data_lost);
7178 }
7179
7180 /* Remove the data we just decoded from the
7181 buffer. Remember the position of the new start code
7182 we found, skip it and continue the search. */
7183 vd->buffer.out = s - vd->buffer.base;
7184 vd->last_start_code = (enum start_code) s[3];
7185 s += 4;
7186 }
7187 }
7188
7189 static void
reset_video_es_decoder(struct video_es_decoder * vd)7190 reset_video_es_decoder (struct video_es_decoder *vd)
7191 {
7192 vd->buffer.in = 0;
7193 vd->buffer.out = 0;
7194
7195 vd->min_bytes_valid = UINT_MAX;
7196 vd->skip = 0;
7197 vd->last_start_code = (enum start_code) -1;
7198
7199 vd->pts = -1;
7200 vd->dts = -1;
7201 vd->picture_coding_type = (enum picture_coding_type) -1;
7202 vd->picture_structure = (enum picture_structure) -1;
7203 vd->received_blocks = 0;
7204 vd->reorder_pictures = 0;
7205 }
7206
7207 static void
init_video_es_decoder(struct video_es_decoder * vd)7208 init_video_es_decoder (struct video_es_decoder *vd)
7209 {
7210 CLEAR (*vd);
7211
7212 init_buffer (&vd->buffer, /* capacity */ 1 << 20);
7213 reset_video_es_decoder (vd);
7214 }
7215
7216 static void
video_es_test_loop(struct program * pr,const char * test_file_name)7217 video_es_test_loop (struct program * pr,
7218 const char * test_file_name)
7219 {
7220 FILE *test_fp;
7221
7222 assert (NULL != ts_buffer);
7223
7224 test_fp = open_test_file (test_file_name);
7225
7226 for (;;) {
7227 size_t todo;
7228 size_t actual;
7229
7230 todo = 4096;
7231 actual = fread (ts_buffer, 1, todo, test_fp);
7232 if (likely (actual == todo)) {
7233 video_es_decoder (&pr->vesd, ts_buffer,
7234 /* n_bytes */ actual,
7235 /* data_lost */ FALSE);
7236 } else if (ferror (test_fp)) {
7237 errno_exit ("Video ES read error");
7238 } else {
7239 log (1, "End of video ES file.\n");
7240 fclose (test_fp);
7241 return;
7242 }
7243 }
7244 }
7245
7246 static void
dump_ts_packet_header(FILE * fp,const uint8_t buf[188])7247 dump_ts_packet_header (FILE * fp,
7248 const uint8_t buf[188])
7249 {
7250 unsigned int sync_byte;
7251 unsigned int transport_error_indicator;
7252 unsigned int payload_unit_start_indicator;
7253 unsigned int transport_priority;
7254 unsigned int PID;
7255 unsigned int transport_scrambling_control;
7256 unsigned int adaptation_field_control;
7257 unsigned int continuity_counter;
7258 unsigned int header_length;
7259
7260 sync_byte = buf[0];
7261 transport_error_indicator = buf[1] & 0x80;
7262 payload_unit_start_indicator = buf[1] & 0x40;
7263 transport_priority = buf[1] & 0x20;
7264 PID = (buf[1] * 256 + buf[2]) & 0x1FFF;
7265 transport_scrambling_control = (buf[3] & 0xC0) >> 6;
7266 adaptation_field_control = (buf[3] & 0x30) >> 4;
7267 continuity_counter = buf[3] & 0x0F;
7268
7269 if (adaptation_field_control >= 2) {
7270 unsigned int adaptation_field_length;
7271
7272 adaptation_field_length = buf[4];
7273 header_length = 5 + adaptation_field_length;
7274 } else {
7275 header_length = 4;
7276 }
7277
7278 fprintf (fp,
7279 "TS %02x %c%c%c %04x %u%u%x %u\n",
7280 sync_byte,
7281 transport_error_indicator ? 'E' : '-',
7282 payload_unit_start_indicator ? 'S' : '-',
7283 transport_priority ? 'P' : '-',
7284 PID,
7285 transport_scrambling_control,
7286 adaptation_field_control,
7287 continuity_counter,
7288 header_length);
7289 }
7290
7291 static void
tsd_program(struct program * pr,const uint8_t buf[188],unsigned int pid,unsigned int es_num)7292 tsd_program (struct program * pr,
7293 const uint8_t buf[188],
7294 unsigned int pid,
7295 unsigned int es_num)
7296 {
7297 unsigned int adaptation_field_control;
7298 unsigned int header_length;
7299 unsigned int payload_length;
7300 vbi_bool data_lost;
7301
7302 adaptation_field_control = (buf[3] & 0x30) >> 4;
7303 if (likely (1 == adaptation_field_control)) {
7304 header_length = 4;
7305 } else if (3 == adaptation_field_control) {
7306 unsigned int adaptation_field_length;
7307
7308 adaptation_field_length = buf[4];
7309
7310 /* Zero length is used for stuffing. */
7311 if (adaptation_field_length > 0) {
7312 unsigned int discontinuity_indicator;
7313
7314 /* ISO 13818-1 Section 2.4.3.5. Also the code
7315 below would be rather upset if
7316 header_length > packet_size. */
7317 if (adaptation_field_length > 182) {
7318 log (2, "Invalid TS header "
7319 "on station %u, stream %u.\n",
7320 station_num (pr), pid);
7321 /* Possibly. */
7322 pr->tsd.data_lost = TRUE;
7323 return;
7324 }
7325
7326 /* ISO 13818-1 Section 2.4.3.5 */
7327 discontinuity_indicator = buf[5] & 0x80;
7328 if (discontinuity_indicator)
7329 pr->tsd.next_ts_cc[es_num] = -1;
7330 }
7331
7332 header_length = 5 + adaptation_field_length;
7333 } else {
7334 /* 0 == adaptation_field_control: invalid;
7335 2 == adaptation_field_control: no payload. */
7336 /* ISO 13818-1 Section 2.4.3.3:
7337 continuity_counter shall not increment. */
7338 return;
7339 }
7340
7341 payload_length = 188 - header_length;
7342
7343 data_lost = pr->tsd.data_lost;
7344
7345 if (unlikely (0 != ((pr->tsd.next_ts_cc[es_num]
7346 ^ buf[3]) & 0x0F))) {
7347 /* Continuity counter mismatch. */
7348
7349 if (pr->tsd.next_ts_cc[es_num] < 0) {
7350 /* First TS packet. */
7351 } else if (0 == (((pr->tsd.next_ts_cc[es_num] - 1)
7352 ^ buf[3]) & 0x0F)) {
7353 /* ISO 13818-1 Section 2.4.3.3: Repeated packet. */
7354 return;
7355 } else {
7356 log (2, "TS continuity error "
7357 "on station %u, stream %u.\n",
7358 station_num (pr), pid);
7359 data_lost = TRUE;
7360 }
7361 }
7362
7363 pr->tsd.next_ts_cc[es_num] = buf[3] + 1;
7364 pr->tsd.data_lost = FALSE;
7365
7366 if (NULL != pr->option_minicut_dir_name)
7367 video_recorder (&pr->vr, buf);
7368
7369 if (0 == es_num) {
7370 video_es_decoder (&pr->vesd, buf + header_length,
7371 payload_length, data_lost);
7372 }
7373 }
7374
7375 static void
ts_decoder(const uint8_t buf[188])7376 ts_decoder (const uint8_t buf[188])
7377 {
7378 unsigned int pid;
7379 unsigned int i;
7380
7381 if (0) {
7382 dump_ts_packet_header (stderr, buf);
7383 }
7384
7385 if (unlikely (NULL != ts_tap_fp)) {
7386 if (188 != fwrite (buf, 1, 188, ts_tap_fp)) {
7387 errno_exit ("TS tap write error");
7388 }
7389 }
7390
7391 if (unlikely (buf[1] & 0x80)) {
7392 log (2, "TS transmission error.\n");
7393
7394 /* The PID may be wrong, we don't know how much data
7395 was lost, and continuity counters match by chance
7396 with 1:16 probability. */
7397 for (i = 0; i < n_programs; ++i) {
7398 video_recorder (&program_table[i].vr, buf);
7399 program_table[i].tsd.data_lost = TRUE;
7400 }
7401
7402 return;
7403 }
7404
7405 pid = (buf[1] * 256 + buf[2]) & 0x1FFF;
7406
7407 /* Note two or more programs may share one elementary stream
7408 (e.g. radio programs with a dummy video stream). */
7409 for (i = 0; i < n_programs; ++i) {
7410 struct program *pr;
7411 unsigned int es_num;
7412
7413 pr = program_table + i;
7414
7415 es_num = 0;
7416 if (pid == pr->tsd.pid[1]) {
7417 es_num = 1;
7418 } else if (pid != pr->tsd.pid[0]) {
7419 continue;
7420 }
7421
7422 tsd_program (pr, buf, pid, es_num);
7423 }
7424 }
7425
7426 static void
init_ts_decoder(struct ts_decoder * td)7427 init_ts_decoder (struct ts_decoder * td)
7428 {
7429 CLEAR (*td);
7430
7431 memset (&td->next_ts_cc, -1, sizeof (td->next_ts_cc));
7432 }
7433
7434 static void
ts_test_loop(const char * test_file_name)7435 ts_test_loop (const char * test_file_name)
7436 {
7437 FILE *test_fp;
7438
7439 assert (NULL != ts_buffer);
7440
7441 test_fp = open_test_file (test_file_name);
7442
7443 for (;;) {
7444 size_t todo;
7445 size_t actual;
7446
7447 todo = 188;
7448 actual = fread (ts_buffer, 1, todo, test_fp);
7449 if (likely (actual == todo)) {
7450 ts_decoder (ts_buffer);
7451 } else if (ferror (test_fp)) {
7452 errno_exit ("TS read error");
7453 } else {
7454 log (1, "End of TS file.\n");
7455 fclose (test_fp);
7456 return;
7457 }
7458 }
7459 }
7460
7461 static void *
demux_thread(void * arg)7462 demux_thread (void * arg)
7463 {
7464 unsigned int in;
7465 unsigned int out;
7466
7467 arg = arg; /* unused */
7468
7469 assert (0 == ts_buffer_capacity % 188);
7470
7471 out = ts_buffer_out;
7472
7473 /* We don't actually need the mutex but pthread_cond_wait()
7474 won't work without it. */
7475 pthread_mutex_lock (&dx_mutex);
7476
7477 for (;;) {
7478 unsigned int avail;
7479
7480 in = ts_buffer_in;
7481
7482 avail = in - out;
7483 if (in < out)
7484 avail += ts_buffer_capacity;
7485
7486 if (avail <= 0) {
7487 /* Yield the CPU if the buffer is empty. */
7488 pthread_cond_wait (&dx_cond, &dx_mutex);
7489 continue;
7490 }
7491
7492 if (0) {
7493 fputc (',', stderr);
7494 fflush (stderr);
7495 } else {
7496 ts_decoder (ts_buffer + out);
7497 }
7498
7499 out += 188;
7500 if (out >= ts_buffer_capacity)
7501 out = 0;
7502
7503 ts_buffer_out = out;
7504 }
7505
7506 pthread_mutex_unlock (&dx_mutex);
7507
7508 return NULL;
7509 }
7510
7511 static void
init_program(struct program * pr)7512 init_program (struct program * pr)
7513 {
7514 CLEAR (*pr);
7515
7516 pr->first_dts = -1;
7517
7518 init_ts_decoder (&pr->tsd);
7519 init_video_es_decoder (&pr->vesd);
7520 init_video_recorder (&pr->vr);
7521 init_caption_recorder (&pr->cr);
7522 }
7523
7524 static void
destroy_demux_state(void)7525 destroy_demux_state (void)
7526 {
7527 free (ts_buffer);
7528
7529 ts_buffer = NULL;
7530 ts_buffer_capacity = 0;
7531
7532 pthread_cond_destroy (&dx_cond);
7533 pthread_mutex_destroy (&dx_mutex);
7534 }
7535
7536 static void
init_demux_state(void)7537 init_demux_state (void)
7538 {
7539 pthread_mutex_init (&dx_mutex, /* attr */ NULL);
7540 pthread_cond_init (&dx_cond, /* attr */ NULL);
7541
7542 /* This buffer prevents data loss if disk activity blocks
7543 a printf() in the caption decoder. Actually we need to
7544 buffer only CC data which trickles in at 9600 bits/s but I
7545 don't want to burden the capture thread with TS and PES
7546 demultiplexing and avoid the overhead of another thread. */
7547 ts_buffer_capacity = 20000 * 188;
7548 ts_buffer = xmalloc (ts_buffer_capacity);
7549
7550 /* Copy-on-write and lock the pages. */
7551 memset (ts_buffer, -1, ts_buffer_capacity);
7552
7553 ts_error = 0x00;
7554
7555 ts_buffer_in = 0;
7556 ts_buffer_out = 0;
7557
7558 ts_n_packets_in = 0;
7559 }
7560
7561 /* Capture thread */
7562
7563 static const char *
fe_type_name(enum fe_type t)7564 fe_type_name (enum fe_type t)
7565 {
7566 #undef CASE
7567 #define CASE(x) case FE_##x: return #x;
7568
7569 switch (t) {
7570 CASE (QPSK)
7571 CASE (QAM)
7572 CASE (OFDM)
7573 CASE (ATSC)
7574 }
7575
7576 return "invalid";
7577 }
7578
7579 static const char *
fe_spectral_inversion_name(enum fe_spectral_inversion t)7580 fe_spectral_inversion_name (enum fe_spectral_inversion t)
7581 {
7582 #undef CASE
7583 #define CASE(x) case INVERSION_##x: return #x;
7584
7585 switch (t) {
7586 CASE (OFF)
7587 CASE (ON)
7588 CASE (AUTO)
7589 }
7590
7591 return "invalid";
7592 }
7593
7594 static const char *
fe_code_rate_name(enum fe_code_rate t)7595 fe_code_rate_name (enum fe_code_rate t)
7596 {
7597 #undef CASE
7598 #define CASE(x) case FEC_##x: return #x;
7599
7600 switch (t) {
7601 CASE (NONE)
7602 CASE (1_2)
7603 CASE (2_3)
7604 CASE (3_4)
7605 CASE (4_5)
7606 CASE (5_6)
7607 CASE (6_7)
7608 CASE (7_8)
7609 CASE (8_9)
7610 CASE (AUTO)
7611 }
7612
7613 return "invalid";
7614 }
7615
7616 static const char *
fe_modulation_name(enum fe_modulation t)7617 fe_modulation_name (enum fe_modulation t)
7618 {
7619 #undef CASE
7620 #define CASE(x) case x: return #x;
7621
7622 switch (t) {
7623 CASE (QPSK)
7624 CASE (QAM_16)
7625 CASE (QAM_32)
7626 CASE (QAM_64)
7627 CASE (QAM_128)
7628 CASE (QAM_256)
7629 CASE (QAM_AUTO)
7630 CASE (VSB_8)
7631 CASE (VSB_16)
7632 }
7633
7634 return "invalid";
7635 }
7636
7637 static const char *
fe_transmit_mode_name(enum fe_transmit_mode t)7638 fe_transmit_mode_name (enum fe_transmit_mode t)
7639 {
7640 #undef CASE
7641 #define CASE(x) case TRANSMISSION_MODE_##x: return #x;
7642
7643 switch (t) {
7644 CASE (2K)
7645 CASE (8K)
7646 CASE (AUTO)
7647 }
7648
7649 return "invalid";
7650 }
7651
7652 static const char *
fe_bandwidth_name(enum fe_bandwidth t)7653 fe_bandwidth_name (enum fe_bandwidth t)
7654 {
7655 #undef CASE
7656 #define CASE(x) case BANDWIDTH_##x: return #x;
7657
7658 switch (t) {
7659 CASE (8_MHZ)
7660 CASE (7_MHZ)
7661 CASE (6_MHZ)
7662 CASE (AUTO)
7663 }
7664
7665 return "invalid";
7666 }
7667
7668 static const char *
fe_guard_interval_name(enum fe_guard_interval t)7669 fe_guard_interval_name (enum fe_guard_interval t)
7670 {
7671 #undef CASE
7672 #define CASE(x) case GUARD_INTERVAL_##x: return #x;
7673
7674 switch (t) {
7675 CASE (1_32)
7676 CASE (1_16)
7677 CASE (1_8)
7678 CASE (1_4)
7679 CASE (AUTO)
7680 }
7681
7682 return "invalid";
7683 }
7684
7685 static const char *
fe_hierarchy_name(enum fe_hierarchy t)7686 fe_hierarchy_name (enum fe_hierarchy t)
7687 {
7688 #undef CASE
7689 #define CASE(x) case HIERARCHY_##x: return #x;
7690
7691 switch (t) {
7692 CASE (NONE)
7693 CASE (1)
7694 CASE (2)
7695 CASE (4)
7696 CASE (AUTO)
7697 }
7698
7699 return "invalid";
7700 }
7701
7702 #undef CASE
7703
7704 static vbi_bool
same_transponder(struct station * s1,struct station * s2)7705 same_transponder (struct station * s1,
7706 struct station * s2)
7707 {
7708 if (s1->frequency != s2->frequency)
7709 return FALSE;
7710
7711 if (s1->type != s2->type)
7712 return FALSE;
7713
7714 switch (s1->type) {
7715 case FE_ATSC:
7716 if (s1->u.atsc.modulation != s1->u.atsc.modulation)
7717 return FALSE;
7718 break;
7719
7720 case FE_OFDM:
7721 if (s1->u.dvb_t.inversion != s2->u.dvb_t.inversion ||
7722 s1->u.dvb_t.bandwidth != s2->u.dvb_t.bandwidth ||
7723 s1->u.dvb_t.code_rate_HP != s2->u.dvb_t.code_rate_HP ||
7724 s1->u.dvb_t.code_rate_LP != s2->u.dvb_t.code_rate_LP ||
7725 s1->u.dvb_t.constellation != s2->u.dvb_t.constellation ||
7726 s1->u.dvb_t.transm_mode != s2->u.dvb_t.transm_mode ||
7727 s1->u.dvb_t.guard_interval != s2->u.dvb_t.guard_interval ||
7728 s1->u.dvb_t.hierarchy != s2->u.dvb_t.hierarchy)
7729 return FALSE;
7730 break;
7731
7732 case FE_QPSK:
7733 case FE_QAM:
7734 assert (0);
7735 }
7736
7737 return TRUE;
7738 }
7739
7740 /* We use a FIFO because the caption decoder may block for
7741 extended periods due to disk activity, and buffering in
7742 the kernel driver is unreliable in my experience. */
7743
7744 static void
ct_filter(const uint8_t buf[188])7745 ct_filter (const uint8_t buf[188])
7746 {
7747 unsigned int in;
7748 unsigned int out;
7749 unsigned int free;
7750
7751 /* Supposedly all modern CPUs read and write ints
7752 atomically so we can avoid the mutex locking
7753 overhead. */
7754 in = ts_buffer_in;
7755 out = ts_buffer_out;
7756
7757 assert (in < ts_buffer_capacity);
7758 assert (out < ts_buffer_capacity);
7759
7760 if (likely (0 == (buf[1] & 0x80))) {
7761 unsigned int pid;
7762
7763 pid = (buf[1] * 256 + buf[2]) & 0x1FFF;
7764
7765 if (0) {
7766 fprintf (stderr, "CT TS 0x%04x = %u\n", pid, pid);
7767 return;
7768 }
7769
7770 if (pid_map[pid].program < 0) {
7771 if (NULL == option_ts_all_tap_file_name)
7772 return;
7773 }
7774 }
7775
7776 free = out - in;
7777 if (out <= in)
7778 free += ts_buffer_capacity;
7779
7780 if (unlikely (free <= 188)) {
7781 ts_error = 0x80;
7782 return;
7783 }
7784
7785 memcpy (ts_buffer + in, buf, 188);
7786
7787 ts_buffer[in + 1] |= ts_error;
7788 ts_error = 0;
7789
7790 ++ts_n_packets_in;
7791
7792 in += 188;
7793 if (in >= ts_buffer_capacity)
7794 in = 0;
7795
7796 ts_buffer_in = in;
7797
7798 /* Hm. This delays the output. */
7799 if (1 || free < (ts_buffer_capacity / 2)) {
7800 pthread_cond_signal (&dx_cond);
7801 }
7802 }
7803
7804 static unsigned int
ct_resync(const uint8_t buf[2* 188])7805 ct_resync (const uint8_t buf[2 * 188])
7806 {
7807 unsigned int i;
7808
7809 for (i = 1; i < 188; ++i) {
7810 if (0x47 == buf[i] && 0x47 == buf[i + 188])
7811 return i;
7812 }
7813
7814 log (1, "Capture thread cannot synchronize.\n");
7815
7816 capture_thread_id = 0;
7817 pthread_exit (NULL);
7818
7819 return 0;
7820 }
7821
7822 static vbi_bool
ct_read(uint8_t * buffer,ssize_t todo)7823 ct_read (uint8_t * buffer,
7824 ssize_t todo)
7825 {
7826 unsigned int retry = 100;
7827
7828 do {
7829 ssize_t actual;
7830
7831 actual = read (dvr_fd, buffer, todo);
7832 if (likely (actual == todo))
7833 return TRUE;
7834
7835 if (actual > 0) {
7836 if (unlikely (actual >= todo)) {
7837 log (1, "DVB device read size "
7838 "error.\n");
7839 return FALSE;
7840 }
7841
7842 buffer += actual;
7843 todo -= actual;
7844
7845 continue;
7846 } else if (actual < 0) {
7847 int saved_errno;
7848
7849 saved_errno = errno;
7850
7851 if (EINTR == saved_errno)
7852 continue;
7853
7854 log_errno (1, "DVB device read error");
7855
7856 errno = saved_errno;
7857
7858 return FALSE;
7859 } else {
7860 log (2, "EOF from DVB device (ignored).\n");
7861 return FALSE;
7862 }
7863 } while (--retry > 0);
7864
7865 log (2, "DVB device read error: EINTR or "
7866 "read size problem.\n");
7867
7868 errno = EINTR;
7869
7870 return FALSE;
7871 }
7872
7873 static void *
capture_thread(void * arg)7874 capture_thread (void * arg)
7875 {
7876 uint8_t *start;
7877 uint8_t *end;
7878 const uint8_t *s;
7879 const uint8_t *e;
7880 unsigned int left;
7881 ssize_t size;
7882
7883 arg = arg; /* unused */
7884
7885 log (2, "Capture thread ready.\n");
7886
7887 /* Don't swap out any code or data pages. If the capture
7888 thread is delayed we may lose packets. Errors ignored. */
7889 mlockall (MCL_CURRENT | MCL_FUTURE);
7890
7891 pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, /* old */ NULL);
7892 pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, /* old */ NULL);
7893
7894 /* Page aligned reads are not required, but who knows, it
7895 may allow some DMA magic or speed up copying. */
7896 start = ct_buffer + 4096;
7897 size = ct_buffer_capacity - 4096;
7898 left = 0;
7899
7900 assert (ct_buffer_capacity > 4096);
7901 assert (0 == ct_buffer_capacity % 4096);
7902
7903 xioctl (dmx_fd, DMX_START, 0);
7904
7905 for (;;) {
7906 if (!ct_read (start, size))
7907 continue;
7908
7909 ct_n_bytes_in += size;
7910
7911 end = start + size;
7912
7913 s = start - left;
7914 e = end - 4096;
7915
7916 while (s < e) {
7917 if (0x47 != s[0] || 0x47 != s[188]) {
7918 if (ts_n_packets_in > 0) {
7919 log (2, "Capture thread "
7920 "lost sync.\n");
7921 }
7922
7923 s += ct_resync (s);
7924 }
7925
7926 if (0) {
7927 fputc ('.', stderr);
7928 fflush (stderr);
7929 } else {
7930 ct_filter (s);
7931 }
7932
7933 s += 188;
7934 }
7935
7936 left = end - s;
7937 memcpy (start - left, s, left);
7938 }
7939
7940 return NULL;
7941 }
7942
7943 static void
destroy_capture_state(void)7944 destroy_capture_state (void)
7945 {
7946 /* FIXME this a glibc feature. */
7947 free (ct_buffer);
7948
7949 ct_buffer = NULL;
7950 ct_buffer_capacity = 0;
7951 }
7952
7953 #ifdef HAVE_POSIX_MEMALIGN
7954
7955 /* posix_memalign() was introduced in POSIX 1003.1d and may not be
7956 implemented on all systems. */
7957 static void *
my_memalign(size_t boundary,size_t size)7958 my_memalign (size_t boundary,
7959 size_t size)
7960 {
7961 void *p;
7962 int err;
7963
7964 /* boundary must be a power of two. */
7965 if (0 != (boundary & (boundary - 1)))
7966 return malloc (size);
7967
7968 err = posix_memalign (&p, boundary, size);
7969 if (0 == err)
7970 return p;
7971
7972 errno = err;
7973 return NULL;
7974 }
7975
7976 #elif defined HAVE_MEMALIGN
7977 /* memalign() is a GNU extension. Due to the DVB driver interface
7978 this program currently runs on Linux only, but it can't hurt
7979 to be prepared. */
7980 # define my_memalign memalign
7981 #else
7982 # define my_memalign(boundary, size) malloc (size)
7983 #endif
7984
7985 static void
init_capture_state(void)7986 init_capture_state (void)
7987 {
7988 ct_buffer_capacity = 32 * 1024;
7989 ct_buffer = my_memalign (4096, ct_buffer_capacity);
7990
7991 if (NULL == ct_buffer) {
7992 no_mem_exit ();
7993 }
7994
7995 /* Copy-on-write and lock the pages. */
7996 memset (ct_buffer, -1, ct_buffer_capacity);
7997
7998 ct_n_bytes_in = 0;
7999 }
8000
8001 static int
xopen_device(const char * dev_name,int flags)8002 xopen_device (const char * dev_name,
8003 int flags)
8004 {
8005 struct stat st;
8006 int fd;
8007
8008 if (-1 == stat (dev_name, &st)) {
8009 goto open_failed;
8010 }
8011
8012 if (!S_ISCHR (st.st_mode)) {
8013 error_exit ("'%s' is not a DVB device.\n",
8014 dev_name);
8015 }
8016
8017 fd = open (dev_name, flags, /* mode */ 0);
8018 if (-1 == fd) {
8019 goto open_failed;
8020 }
8021
8022 return fd;
8023
8024 open_failed:
8025 errno_exit ("Cannot open '%s'", dev_name);
8026
8027 return -1; /* not reached */
8028 }
8029
8030 static void
close_device(void)8031 close_device (void)
8032 {
8033 log (2, "Closing DVB device.\n");
8034
8035 if (0 != capture_thread_id) {
8036 pthread_cancel (capture_thread_id);
8037 pthread_join (capture_thread_id, NULL);
8038
8039 capture_thread_id = 0;
8040 }
8041
8042 destroy_capture_state ();
8043
8044 if (-1 != dmx_fd) {
8045 close (dmx_fd);
8046 dmx_fd = -1;
8047 }
8048
8049 if (-1 != dvr_fd) {
8050 close (dvr_fd);
8051 dvr_fd = -1;
8052 }
8053
8054 if (-1 != fe_fd) {
8055 close (fe_fd);
8056 fe_fd = -1;
8057 }
8058 }
8059
8060 static void
open_device(void)8061 open_device (void)
8062 {
8063 struct dvb_frontend_info fe_info;
8064 struct dvb_frontend_parameters fe_param;
8065 struct dmx_pes_filter_params filter;
8066 char *dev_name;
8067 unsigned int retry;
8068
8069 dev_name = NULL;
8070
8071 init_capture_state ();
8072
8073 /* Front end. */
8074
8075 log (2, "Opening dvb/adapter%lu.\n",
8076 option_dvb_adapter_num);
8077
8078 dev_name = xasprintf ("/dev/dvb/adapter%lu/frontend%lu",
8079 option_dvb_adapter_num,
8080 option_dvb_frontend_id);
8081
8082 fe_fd = xopen_device (dev_name, O_RDWR);
8083
8084 CLEAR (fe_info);
8085
8086 xioctl (fe_fd, FE_GET_INFO, &fe_info);
8087
8088 switch (fe_info.type) {
8089 case FE_ATSC:
8090 case FE_OFDM:
8091 if (fe_info.type != station->type) {
8092 error_exit ("'%s' is not %s device.\n",
8093 dev_name,
8094 (FE_ATSC == station->type) ?
8095 "an ATSC" : "a DVB-T");
8096 }
8097 break;
8098
8099 case FE_QPSK:
8100 case FE_QAM:
8101 error_exit ("'%s' is not an ATSC device.\n",
8102 dev_name);
8103 break;
8104 }
8105
8106 CLEAR (fe_param);
8107
8108 fe_param.frequency = station->frequency;
8109
8110 switch (fe_info.type) {
8111 case FE_ATSC:
8112 fe_param.u.vsb.modulation =
8113 station->u.atsc.modulation;
8114 break;
8115
8116 case FE_OFDM:
8117 fe_param.inversion =
8118 station->u.dvb_t.inversion;
8119 fe_param.u.ofdm.bandwidth =
8120 station->u.dvb_t.bandwidth;
8121 fe_param.u.ofdm.code_rate_HP =
8122 station->u.dvb_t.code_rate_HP;
8123 fe_param.u.ofdm.code_rate_LP =
8124 station->u.dvb_t.code_rate_LP;
8125 fe_param.u.ofdm.constellation =
8126 station->u.dvb_t.constellation;
8127 fe_param.u.ofdm.transmission_mode =
8128 station->u.dvb_t.transm_mode;
8129 fe_param.u.ofdm.guard_interval =
8130 station->u.dvb_t.guard_interval;
8131 fe_param.u.ofdm.hierarchy_information =
8132 station->u.dvb_t.hierarchy;
8133 break;
8134
8135 case FE_QPSK:
8136 case FE_QAM:
8137 assert (0);
8138 }
8139
8140 xioctl (fe_fd, FE_SET_FRONTEND, &fe_param);
8141
8142 for (retry = 0;;) {
8143 fe_status_t status;
8144
8145 xioctl (fe_fd, FE_READ_STATUS, &status);
8146
8147 if (status & FE_HAS_LOCK)
8148 break;
8149
8150 if (++retry > 20) {
8151 error_exit ("No signal detected.\n");
8152 }
8153
8154 if (7 == (retry & 7)) {
8155 log (2, "Waiting for a signal.\n");
8156 }
8157
8158 usleep (250000);
8159 }
8160
8161 log (2, "Signal detected.\n");
8162
8163 free (dev_name);
8164
8165 /* DVR. */
8166
8167 dev_name = xasprintf ("/dev/dvb/adapter%lu/dvr%lu",
8168 option_dvb_adapter_num,
8169 option_dvb_dvr_id);
8170
8171 dvr_fd = xopen_device (dev_name, O_RDONLY);
8172
8173 /* Not implemented? Let's try anyway. */
8174 xioctl_may_fail (dvr_fd, DMX_SET_BUFFER_SIZE, (void *)(4 << 20));
8175
8176 free (dev_name);
8177
8178 /* Demultiplexer. */
8179
8180 dev_name = xasprintf ("/dev/dvb/adapter%lu/demux%lu",
8181 option_dvb_adapter_num,
8182 option_dvb_demux_id);
8183
8184 dmx_fd = xopen_device (dev_name, O_RDWR);
8185
8186 xioctl_may_fail (dmx_fd, DMX_SET_BUFFER_SIZE, (void *)(4 << 20));
8187
8188 CLEAR (filter);
8189
8190 /* We capture the entire transport multiplex so we can receive
8191 all stations on this transponder at once and properly handle
8192 transmission errors in the video ES demultiplexer. */
8193 filter.pid = 0x2000;
8194 filter.input = DMX_IN_FRONTEND;
8195 filter.output = DMX_OUT_TS_TAP;
8196 filter.pes_type = DMX_PES_OTHER;
8197
8198 xioctl (dmx_fd, DMX_SET_PES_FILTER, &filter);
8199
8200 free (dev_name);
8201
8202 /* Start capture thread. */
8203
8204 if (0 != pthread_create (&capture_thread_id,
8205 /* attr */ NULL,
8206 capture_thread,
8207 /* arg */ NULL)) {
8208 errno_exit ("Cannot start capture thread");
8209 }
8210
8211 log (2, "Opened dvb/adapter%lu, tuned to %.3f MHz and "
8212 "started capture thread.\n",
8213 option_dvb_adapter_num,
8214 station->frequency / 1e6);
8215 }
8216
8217 static enum fe_type
device_type(void)8218 device_type (void)
8219 {
8220 struct dvb_frontend_info fe_info;
8221 char *dev_name;
8222 int fd;
8223
8224 dev_name = xasprintf ("/dev/dvb/adapter%lu/frontend%lu",
8225 option_dvb_adapter_num,
8226 option_dvb_frontend_id);
8227
8228 fd = xopen_device (dev_name, O_RDWR);
8229
8230 CLEAR (fe_info);
8231
8232 xioctl (fd, FE_GET_INFO, &fe_info);
8233
8234 close (fd);
8235
8236 switch (fe_info.type) {
8237 case FE_ATSC:
8238 case FE_OFDM:
8239 break;
8240
8241 case FE_QPSK:
8242 case FE_QAM:
8243 error_exit ("'%s' is not an ATSC device.\n",
8244 dev_name);
8245 break;
8246 }
8247
8248 free (dev_name);
8249
8250 return fe_info.type;
8251 }
8252
8253
8254 static void
list_stations(void)8255 list_stations (void)
8256 {
8257 const struct station *st;
8258 size_t max_len;
8259
8260 if (NULL == station_list) {
8261 printf ("The channel config file is empty.\n");
8262 return;
8263 }
8264
8265 /* FIXME the encoding of station names is unknown,
8266 could be a multi-byte coding like UTF-8. */
8267 max_len = 0;
8268 for (st = station_list; NULL != st; st = st->next) {
8269 size_t len;
8270
8271 len = strlen (st->name);
8272 max_len = MAX (max_len, len);
8273 }
8274
8275 for (st = station_list; NULL != st; st = st->next) {
8276 printf ("%-*s %3.3f MHz\n",
8277 (int) max_len,
8278 st->name,
8279 st->frequency / 1e6);
8280 }
8281 }
8282
8283 static struct station *
find_station(const char * station_name)8284 find_station (const char * station_name)
8285 {
8286 struct station *st;
8287
8288 for (st = station_list; NULL != st; st = st->next) {
8289 if (0 == strcmp (station_name, st->name))
8290 return st;
8291 }
8292
8293 return NULL;
8294 }
8295
8296 static char *
parse_station_name(const char ** sp,int delimiter)8297 parse_station_name (const char ** sp,
8298 int delimiter)
8299 {
8300 const char *s;
8301 const char *s_name;
8302 char *station_name;
8303 size_t len;
8304
8305 s = *sp;
8306 while (isspace (*s))
8307 ++s;
8308 s_name = s;
8309 while (0 != *s && delimiter != *s)
8310 ++s;
8311 *sp = s;
8312 while (s > s_name && isspace (s[-1]))
8313 --s;
8314 len = s - s_name;
8315 if (0 == len)
8316 return NULL;
8317
8318 station_name = xmalloc (len + 1);
8319
8320 memcpy (station_name, s_name, len);
8321 station_name[len] = 0;
8322
8323 return station_name;
8324 }
8325
8326 struct key_value {
8327 const char * key;
8328 int value;
8329 };
8330
8331 static vbi_bool
parse_enum(int * value,const char ** sp,const struct key_value * table)8332 parse_enum (int * value,
8333 const char ** sp,
8334 const struct key_value *table)
8335 {
8336 const char *s;
8337 unsigned int i;
8338
8339 s = *sp;
8340
8341 while (isspace (*s))
8342 ++s;
8343
8344 for (i = 0; NULL != table[i].key; ++i) {
8345 size_t len = strlen (table[i].key);
8346
8347 if (0 == strncmp (s, table[i].key, len)) {
8348 s += len;
8349 break;
8350 }
8351 }
8352
8353 if (NULL == table[i].key)
8354 return FALSE;
8355
8356 while (isspace (*s))
8357 ++s;
8358
8359 if (':' != *s++)
8360 return FALSE;
8361
8362 *value = table[i].value;
8363 *sp = s;
8364
8365 return TRUE;
8366 }
8367
8368 static void
parse_tzap_channel_conf_line(const char * filename,unsigned int line_number,const char * buffer)8369 parse_tzap_channel_conf_line (const char * filename,
8370 unsigned int line_number,
8371 const char * buffer)
8372 {
8373 static const struct key_value inversion [] = {
8374 { "INVERSION_OFF", INVERSION_OFF },
8375 { "INVERSION_ON", INVERSION_ON },
8376 { "INVERSION_AUTO", INVERSION_AUTO },
8377 { NULL, 0 }
8378 };
8379 static const struct key_value bandwidth [] = {
8380 { "BANDWIDTH_6_MHZ", BANDWIDTH_6_MHZ },
8381 { "BANDWIDTH_7_MHZ", BANDWIDTH_7_MHZ },
8382 { "BANDWIDTH_8_MHZ", BANDWIDTH_8_MHZ },
8383 { NULL, 0 }
8384 };
8385 static const struct key_value fec [] = {
8386 { "FEC_1_2", FEC_1_2 },
8387 { "FEC_2_3", FEC_2_3 },
8388 { "FEC_3_4", FEC_3_4 },
8389 { "FEC_4_5", FEC_4_5 },
8390 { "FEC_5_6", FEC_5_6 },
8391 { "FEC_6_7", FEC_6_7 },
8392 { "FEC_7_8", FEC_7_8 },
8393 { "FEC_8_9", FEC_8_9 },
8394 { "FEC_AUTO", FEC_AUTO },
8395 { "FEC_NONE", FEC_NONE },
8396 { NULL, 0 }
8397 };
8398 static const struct key_value constellation [] = {
8399 { "QPSK", QPSK },
8400 { "QAM_16", QAM_16 },
8401 { "QAM_32", QAM_32 },
8402 { "QAM_64", QAM_64 },
8403 { "QAM_128", QAM_128 },
8404 { "QAM_256", QAM_256 },
8405 { NULL, 0 }
8406 };
8407 static const struct key_value transmission_mode [] = {
8408 { "TRANSMISSION_MODE_2K", TRANSMISSION_MODE_2K },
8409 { "TRANSMISSION_MODE_8K", TRANSMISSION_MODE_8K },
8410 { NULL, 0 }
8411 };
8412 static const struct key_value guard_interval [] = {
8413 {"GUARD_INTERVAL_1_16", GUARD_INTERVAL_1_16},
8414 {"GUARD_INTERVAL_1_32", GUARD_INTERVAL_1_32},
8415 {"GUARD_INTERVAL_1_4", GUARD_INTERVAL_1_4},
8416 {"GUARD_INTERVAL_1_8", GUARD_INTERVAL_1_8},
8417 { NULL, 0 }
8418 };
8419 static const struct key_value hierarchy [] = {
8420 { "HIERARCHY_1", HIERARCHY_1 },
8421 { "HIERARCHY_2", HIERARCHY_2 },
8422 { "HIERARCHY_4", HIERARCHY_4 },
8423 { "HIERARCHY_NONE", HIERARCHY_NONE },
8424 { NULL, 0 }
8425 };
8426 struct station *st;
8427 struct station **stp;
8428 const struct station *st2;
8429 const char *detail;
8430 const char *s;
8431 char *s_end;
8432 int value;
8433
8434 /* TZAP channel config file format:
8435
8436 A number of lines with the fields:
8437 1. Station name (encoding?)
8438 2. Transponder frequency in Hz
8439 3. Inversion: INVERSION_(ON|OFF|AUTO)
8440 4. Bandwidth: BANDWIDTH_(6|7|8)_MHZ
8441 5. Code rate HP: FEC_(1_2|2_3|3_4|4_5|5_6|6_7|7_8|8_9|AUTO|NONE)
8442 6. Code rate LP: as above
8443 7. Constellation: QPSK, QAM_(16|32|64|128|256)
8444 8. Transmission mode: TRANSMISSION_MODE_(2K|8K)
8445 9. Guard interval: GUARD_INTERVAL_1_(4|8|16|32)
8446 10. Hierarchy information: HIERARCHY_(1|2|4|NONE)
8447 11. Video stream PID
8448 12. Audio stream PID
8449 13. ?
8450
8451 The fields are separated by one colon. We skip whitespace
8452 at the beginning of a line, whitespace before and after
8453 colons, empty lines, and lines starting with a number
8454 sign. */
8455
8456 st = xmalloc (sizeof (*st));
8457
8458 CLEAR (*st);
8459
8460 s = buffer;
8461
8462 while (isspace (*s))
8463 ++s;
8464 if (0 == *s || '#' == *s)
8465 return;
8466
8467 detail = "station name";
8468 st->name = parse_station_name (&s, /* delimiter */ ':');
8469 if (NULL == st->name)
8470 goto invalid;
8471 if (':' != *s++)
8472 goto invalid;
8473
8474 st2 = find_station (st->name);
8475 if (NULL != st2) {
8476 error_exit ("Duplicate station name '%s' "
8477 "in %s line %u.\n",
8478 st->name, filename, line_number);
8479 }
8480
8481 st->type = FE_OFDM;
8482
8483 detail = "frequency";
8484 /* NB. strtoul() skips leading whitespace. */
8485 st->frequency = strtoul (s, &s_end, 0);
8486 if (s_end == s || st->frequency < 1)
8487 goto invalid;
8488 s = s_end;
8489 while (isspace (*s))
8490 ++s;
8491 if (':' != *s++)
8492 goto invalid;
8493
8494 detail = "inversion";
8495 if (!parse_enum (&value, &s, inversion))
8496 goto invalid;
8497 st->u.dvb_t.inversion = value;
8498
8499 detail = "bandwidth";
8500 if (!parse_enum (&value, &s, bandwidth))
8501 goto invalid;
8502 st->u.dvb_t.bandwidth = value;
8503
8504 detail = "code rate HP";
8505 if (!parse_enum (&value, &s, fec))
8506 goto invalid;
8507 st->u.dvb_t.code_rate_HP = value;
8508
8509 detail = "code rate LP";
8510 if (!parse_enum (&value, &s, fec))
8511 goto invalid;
8512 st->u.dvb_t.code_rate_LP = value;
8513
8514 detail = "constellation";
8515 if (!parse_enum (&value, &s, constellation))
8516 goto invalid;
8517 st->u.dvb_t.constellation = value;
8518
8519 detail = "transmission_mode";
8520 if (!parse_enum (&value, &s, transmission_mode))
8521 goto invalid;
8522 st->u.dvb_t.transm_mode = value;
8523
8524 detail = "guard_interval";
8525 if (!parse_enum (&value, &s, guard_interval))
8526 goto invalid;
8527 st->u.dvb_t.guard_interval = value;
8528
8529 detail = "hierarchy";
8530 if (!parse_enum (&value, &s, hierarchy))
8531 goto invalid;
8532 st->u.dvb_t.hierarchy = value;
8533
8534 detail = "video PID";
8535 st->video_pid = strtoul (s, &s_end, 0);
8536 if (s_end == s || (unsigned int) st->video_pid > 0x1FFE)
8537 goto invalid;
8538 s = s_end;
8539 while (isspace (*s))
8540 ++s;
8541 if (':' != *s++)
8542 goto invalid;
8543
8544 detail = "audio PID";
8545 st->audio_pid = strtoul (s, &s_end, 0);
8546 if (s_end == s || (unsigned int) st->audio_pid > 0x1FFE)
8547 goto invalid;
8548 s = s_end;
8549 while (isspace (*s))
8550 ++s;
8551 if (':' != *s++)
8552 goto invalid;
8553 if (0 == st->video_pid) {
8554 if (option_debug & DEBUG_CONFIG) {
8555 fprintf (stderr, "Skipping radio station '%s'.\n",
8556 st->name);
8557 }
8558 free (st->name);
8559 free (st);
8560 return;
8561 }
8562
8563 if (option_debug & DEBUG_CONFIG) {
8564 fprintf (stderr, "%3u: station_name='%s' frequency=%lu "
8565 "inversion=%s bandwidth=%s code_rate=%s/%s "
8566 "constellation=%s transm_mode=%s "
8567 "guard_interval=%s hierarchy=%s "
8568 "video_pid=%u audio_pid=%u.\n",
8569 line_number,
8570 st->name,
8571 st->frequency,
8572 fe_spectral_inversion_name (st->u.dvb_t.inversion),
8573 fe_bandwidth_name (st->u.dvb_t.bandwidth),
8574 fe_code_rate_name (st->u.dvb_t.code_rate_HP),
8575 fe_code_rate_name (st->u.dvb_t.code_rate_LP),
8576 fe_modulation_name (st->u.dvb_t.constellation),
8577 fe_transmit_mode_name (st->u.dvb_t.transm_mode),
8578 fe_guard_interval_name (st->u.dvb_t.guard_interval),
8579 fe_hierarchy_name (st->u.dvb_t.hierarchy),
8580 st->video_pid,
8581 st->audio_pid);
8582 }
8583
8584 /* Append to station list. */
8585 for (stp = &station_list; NULL != *stp; stp = &(*stp)->next)
8586 ;
8587 *stp = st;
8588
8589 return;
8590
8591 invalid:
8592 error_exit ("Invalid %s field in '%s' line %u.\n",
8593 detail, filename, line_number);
8594 }
8595
8596 static void
parse_azap_channel_conf_line(const char * filename,unsigned int line_number,const char * buffer)8597 parse_azap_channel_conf_line (const char * filename,
8598 unsigned int line_number,
8599 const char * buffer)
8600 {
8601 static const struct key_value modulations [] = {
8602 { "8VSB", VSB_8 },
8603 { "16VSB", VSB_16 },
8604 { "QAM_64", QAM_64 },
8605 { "QAM_256", QAM_256 },
8606 { NULL, 0 }
8607 };
8608 struct station *st;
8609 struct station **stp;
8610 const struct station *st2;
8611 const char *detail;
8612 const char *s;
8613 char *s_end;
8614 int value;
8615
8616 /* AZAP channel config file format:
8617
8618 A number of lines with the fields:
8619 1. Station name (encoding?)
8620 2. Transponder frequency in Hz
8621 3. Modulation: 8VSB, 16VSB, QAM_64, QAM_256
8622 4. Video stream PID
8623 5. Audio stream PID (one or more?)
8624 6. Stream ID?
8625
8626 The fields are separated by one colon. We skip whitespace
8627 at the beginning of a line, whitespace before and after
8628 colons, empty lines, and lines starting with a number
8629 sign. */
8630
8631 st = xmalloc (sizeof (*st));
8632
8633 CLEAR (*st);
8634
8635 s = buffer;
8636
8637 while (isspace (*s))
8638 ++s;
8639 if (0 == *s || '#' == *s)
8640 return;
8641
8642 detail = "station name";
8643 st->name = parse_station_name (&s, /* delimiter */ ':');
8644 if (NULL == st->name)
8645 goto invalid;
8646 if (':' != *s++)
8647 goto invalid;
8648
8649 st2 = find_station (st->name);
8650 if (NULL != st2) {
8651 error_exit ("Duplicate station name '%s' "
8652 "in %s line %u.\n",
8653 st->name, filename, line_number);
8654 }
8655
8656 st->type = FE_ATSC;
8657
8658 detail = "frequency";
8659 /* NB. strtoul() skips leading whitespace. */
8660 st->frequency = strtoul (s, &s_end, 0);
8661 if (s_end == s || st->frequency < 1)
8662 goto invalid;
8663 s = s_end;
8664 while (isspace (*s))
8665 ++s;
8666 if (':' != *s++)
8667 goto invalid;
8668
8669 detail = "modulation";
8670 if (!parse_enum (&value, &s, modulations))
8671 goto invalid;
8672 st->u.atsc.modulation = value;
8673
8674 detail = "video PID";
8675 st->video_pid = strtoul (s, &s_end, 0);
8676 if (s_end == s || (unsigned int) st->video_pid > 0x1FFE)
8677 goto invalid;
8678 s = s_end;
8679 while (isspace (*s))
8680 ++s;
8681 if (':' != *s++)
8682 goto invalid;
8683
8684 detail = "audio PID";
8685 st->audio_pid = strtoul (s, &s_end, 0);
8686 if (s_end == s || (unsigned int) st->audio_pid > 0x1FFE)
8687 goto invalid;
8688 s = s_end;
8689 while (isspace (*s))
8690 ++s;
8691 if (':' != *s++)
8692 goto invalid;
8693 if (0 == st->video_pid) {
8694 if (option_debug & DEBUG_CONFIG) {
8695 fprintf (stderr, "Skipping radio station '%s'.\n",
8696 st->name);
8697 }
8698 free (st->name);
8699 free (st);
8700 return;
8701 }
8702
8703 if (option_debug & DEBUG_CONFIG) {
8704 fprintf (stderr, "%3u: station_name='%s' frequency=%lu "
8705 "modulation=%s video_pid=%u audio_pid=%u.\n",
8706 line_number,
8707 st->name,
8708 st->frequency,
8709 fe_modulation_name (st->u.atsc.modulation),
8710 st->video_pid,
8711 st->audio_pid);
8712 }
8713
8714 /* Append to station list. */
8715 for (stp = &station_list; NULL != *stp; stp = &(*stp)->next)
8716 ;
8717 *stp = st;
8718
8719 return;
8720
8721 invalid:
8722 error_exit ("Invalid %s field in '%s' line %u.\n",
8723 detail, filename, line_number);
8724 }
8725
8726 static char *
get_channel_conf_name(enum fe_type type)8727 get_channel_conf_name (enum fe_type type)
8728 {
8729 const char *home;
8730 const char *s;
8731
8732 s = option_channel_conf_file_name;
8733
8734 if (NULL == s) {
8735 switch (type) {
8736 case FE_ATSC:
8737 s = "~/.azap/channels.conf";
8738 break;
8739
8740 case FE_OFDM:
8741 s = "~/.tzap/channels.conf";
8742 break;
8743
8744 case FE_QPSK:
8745 case FE_QAM:
8746 assert (0);
8747 break;
8748 }
8749 }
8750
8751 if (0 == strncmp (s, "~/", 2)) {
8752 home = getenv ("HOME");
8753 if (NULL == home) {
8754 error_exit ("Cannot open '%s' because the "
8755 "HOME environment variable "
8756 "is unset.\n",
8757 s);
8758 }
8759
8760 ++s;
8761 } else {
8762 home = "";
8763 }
8764
8765 return xasprintf ("%s%s", home, s);
8766 }
8767
8768 static void
read_channel_conf(void)8769 read_channel_conf (void)
8770 {
8771 char buffer[256];
8772 char *channel_conf_name;
8773 enum fe_type type;
8774 unsigned int line_number;
8775 FILE *fp;
8776
8777 if (NULL != station_list)
8778 return;
8779
8780 type = option_dvb_type;
8781 if ((enum fe_type) -1 == option_dvb_type)
8782 type = device_type ();
8783
8784 channel_conf_name = get_channel_conf_name (type);
8785
8786 fp = fopen (channel_conf_name, "r");
8787 if (NULL == fp) {
8788 errno_exit ("Cannot open '%s'",
8789 channel_conf_name);
8790 }
8791
8792 if (option_debug & DEBUG_CONFIG) {
8793 fprintf (stderr, "Opened '%s' (%s):\n",
8794 channel_conf_name,
8795 fe_type_name (type));
8796 }
8797
8798 line_number = 1;
8799
8800 while (NULL != fgets (buffer, sizeof (buffer), fp)) {
8801 const char *s;
8802
8803 s = buffer;
8804 while (isspace (*s))
8805 ++s;
8806 if (0 == *s || '#' == *s)
8807 continue;
8808
8809 switch (type) {
8810 case FE_ATSC:
8811 parse_azap_channel_conf_line (channel_conf_name,
8812 line_number,
8813 buffer);
8814 break;
8815
8816 case FE_OFDM:
8817 parse_tzap_channel_conf_line (channel_conf_name,
8818 line_number,
8819 buffer);
8820 break;
8821
8822 case FE_QPSK:
8823 case FE_QAM:
8824 assert (0);
8825 }
8826
8827 ++line_number;
8828 }
8829
8830 if (ferror (fp) || 0 != fclose (fp)) {
8831 errno_exit ("Error while reading '%s'",
8832 channel_conf_name);
8833 }
8834
8835 free (channel_conf_name);
8836 }
8837
8838 static void
usage(FILE * fp)8839 usage (FILE * fp)
8840 {
8841 fprintf (fp, "\
8842 " PROGRAM " " VERSION " -- ATSC Closed Caption and XDS decoder\n\
8843 Copyright (C) 2008 Michael H. Schimek <mschimek@users.sf.net>\n\
8844 Based on code by Mike Baker, Mark K. Kim and timecop@japan.co.jp.\n\
8845 This program is licensed under GPL 2 or later. NO WARRANTIES.\n\n\
8846 Usage: %s [options] [-n] station name\n\
8847 Options:\n\
8848 -? | -h | --help | --usage Print this message, then terminate\n\
8849 -1 ... -4 | --cc1-file ... --cc4-file file name\n\
8850 Append CC1 ... CC4 to this file\n\
8851 -5 ... -8 | --t1-file ... --t4-file file name\n\
8852 Append T1 ... T4 to this file\n\
8853 -9 ... -0 | --s1-file ... --s2-file file name\n\
8854 Append DTVCC service 1 ... 2 to this file\n\
8855 -a | --adapter-num number DVB device adapter [%lu]\n\
8856 -b | --no-webtv Do not print WebTV links\n\
8857 -c | --cc Print Closed Caption (includes WebTV)\n\
8858 -d | --demux-id number DVB device demultiplexer [%lu]\n\
8859 -e | --channel-conf file name Channel config. file [~/.azap/channels.conf]\n\
8860 -f | --filter type[,type]* Select XDS info: all, call, desc, length,\n\
8861 network, rating, time, timecode, timezone,\n\
8862 title. Multiple -f options accumulate. [all]\n\
8863 -i | --frontend-id number DVB device frontend [%lu]\n\
8864 -j | --format type Print caption in 'plain' encoding, with\n\
8865 'vt100' control codes or like the 'ntsc-cc'\n\
8866 tool [ntsc-cc].\n\
8867 -l | --channel number Select caption channel 1 ... 4 [nothing]\n\
8868 -m | --timestamps Prepend timestamps to caption lines\n\
8869 -n | --station name Station name. Usually the -n can be omitted\n\
8870 -q | --quiet Suppress all progress and error messages\n\
8871 -p | --plain Same as -j plain.\n\
8872 -r | --dvr-id number DVB device dvr [%lu]\n\
8873 -s | --sentences Decode caption by sentences\n\
8874 -v | --verbose Increase verbosity\n\
8875 -x | --xds Print XDS info\n\
8876 -C | --cc-file file name Append all caption to this file [stdout]\n\
8877 -L | --list List all TV stations in the channel\n\
8878 configuration file\n\
8879 -T | --ts Decode a DVB Transport Stream on stdin\n\
8880 instead of opening a DVB device\n\
8881 -X | --xds-file file name Append XDS info to this file [stdout]\n\
8882 \n\
8883 To record data from multiple stations sharing a transponder frequency\n\
8884 you can specify caption options and a station name repeatedly.\n\
8885 ",
8886 my_name,
8887 option_dvb_adapter_num,
8888 option_dvb_demux_id,
8889 option_dvb_frontend_id,
8890 option_dvb_dvr_id);
8891 }
8892
8893 static const char
8894 short_options [] = ("-?1:2:3:4:5:6:7:8:9:0:"
8895 "a:bcd:e:f:hi:j:l:mn:pr:svx"
8896 "C:DELM:PTX:");
8897
8898 #ifdef HAVE_GETOPT_LONG
8899 static const struct option
8900 long_options [] = {
8901 { "help", no_argument, NULL, '?' },
8902 /* From ntsc-cc.c. */
8903 { "cc1-file", required_argument, NULL, '1' },
8904 { "cc2-file", required_argument, NULL, '2' },
8905 { "cc3-file", required_argument, NULL, '3' },
8906 { "cc4-file", required_argument, NULL, '4' },
8907 /* From ntsc-cc.c. */
8908 { "t1-file", required_argument, NULL, '5' },
8909 { "t2-file", required_argument, NULL, '6' },
8910 { "t3-file", required_argument, NULL, '7' },
8911 { "t4-file", required_argument, NULL, '8' },
8912 { "s1-file", required_argument, NULL, '9' },
8913 { "s2-file", required_argument, NULL, '0' },
8914 { "adapter-num", required_argument, NULL, 'a' },
8915 /* From ntsc-cc.c. */
8916 { "no-webtv", no_argument, NULL, 'b' },
8917 /* From ntsc-cc.c. */
8918 { "cc", no_argument, NULL, 'c' },
8919 { "demux-id", required_argument, NULL, 'd' },
8920 { "conf-file", required_argument, NULL, 'e' },
8921 /* From ntsc-cc.c. */
8922 { "filter", required_argument, NULL, 'f' },
8923 { "help", no_argument, NULL, 'h' },
8924 { "usage", no_argument, NULL, 'h' },
8925 { "frontend-id", required_argument, NULL, 'i' },
8926 { "format", required_argument, NULL, 'j' },
8927 { "channel", required_argument, NULL, 'l' },
8928 { "timestamps", no_argument, NULL, 'm' },
8929 { "station", required_argument, NULL, 'n' },
8930 /* From ntsc-cc.c. */
8931 { "plain", no_argument, NULL, 'p' },
8932 /* From ntsc-cc.c. Actually the output was never limited to ASCII. */
8933 { "plain-ascii", no_argument, NULL, 'p' },
8934 { "quiet", no_argument, NULL, 'q' },
8935 { "dvr-id", required_argument, NULL, 'r' },
8936 /* From ntsc-cc.c. */
8937 { "sentences", no_argument, NULL, 's' },
8938 { "verbose", no_argument, NULL, 'v' },
8939 /* From ntsc-cc.c. */
8940 { "xds", no_argument, NULL, 'x' },
8941 /* From ntsc-cc.c. */
8942 { "cc-file", required_argument, NULL, 'C' },
8943 /* 'E' - video elementary stream? */
8944 { "list", no_argument, NULL, 'L' },
8945 { "minicut", required_argument, NULL, 'M' },
8946 { "pes", no_argument, NULL, 'P' },
8947 { "ts", no_argument, NULL, 'T' },
8948 /* From ntsc-cc.c. */
8949 { "xds-file", required_argument, NULL, 'X' },
8950
8951 /* Test options, may change. */
8952
8953 { "atsc", no_argument, NULL, 301 },
8954 { "dvb-t", no_argument, NULL, 302 },
8955 { "ts-all-tap", required_argument, NULL, 303 },
8956 { "ts-tap", required_argument, NULL, 304 },
8957 { "video-all-tap", required_argument, NULL, 305 },
8958 { "video-tap", required_argument, NULL, 306 },
8959 { "cc-data-tap", required_argument, NULL, 308 },
8960 { "debug", required_argument, NULL, 309 },
8961 { "mtest", no_argument, NULL, 310 },
8962 { "cc-data", no_argument, NULL, 311 },
8963 { "es", no_argument, NULL, 312 },
8964 { 0, 0, 0, 0 }
8965 };
8966 #else
8967 # define getopt_long(ac, av, s, l, i) getopt(ac, av, s)
8968 #endif
8969
8970 static int option_index;
8971
8972 static void
list_programs(void)8973 list_programs (void)
8974 {
8975 const unsigned int ll = 1; /* log level */
8976 unsigned int i;
8977
8978 for (i = 0; i < n_programs; ++i) {
8979 struct program *pr;
8980 unsigned int j;
8981
8982 pr = &program_table[i];
8983 log (ll, "Station %u: '%s'\n",
8984 station_num (pr),
8985 pr->option_station_name);
8986 for (j = 0; j < 10; ++j) {
8987 const char *stream_name [10] = {
8988 "NTSC CC1", "NTSC CC2",
8989 "NTSC CC3", "NTSC CC4",
8990 "NTSC T1", "NTSC T2",
8991 "NTSC T3", "NTSC T4",
8992 "ATSC S1", "ATSC S2"
8993 };
8994 const char *file_name;
8995
8996 if (0 == (pr->cr.option_caption_mask & (1 << j)))
8997 continue;
8998
8999 file_name = pr->cr.option_caption_file_name[j];
9000 if (NULL != file_name) {
9001 log (ll, " %s -> '%s'\n",
9002 stream_name[j], file_name);
9003 } else if (NULL != pr->option_minicut_dir_name) {
9004 log (ll, " %s -> '%s/"
9005 "YYYYMMDDHH0000/"
9006 "YYYYMMDDHHMM00%s.txt'\n",
9007 stream_name[j],
9008 pr->option_minicut_dir_name,
9009 cr_file_name_suffix[j]);
9010 }
9011 }
9012 if (pr->cr.usexds) {
9013 log (ll, " XDS -> '%s'\n",
9014 pr->cr.option_xds_output_file_name);
9015 }
9016 if (NULL != pr->option_minicut_dir_name) {
9017 log (ll, " TS -> '%s/"
9018 "YYYYMMDDHH0000/"
9019 "YYYYMMDDHHMM00.ts'\n",
9020 pr->option_minicut_dir_name);
9021 }
9022 if (NULL != pr->vesd.video_es_tap_fp) {
9023 const char *name;
9024
9025 name = pr->vesd.option_video_es_all_tap_file_name;
9026 if (NULL == name)
9027 name = pr->vesd.option_video_es_tap_file_name;
9028 log (ll, " V-ES -> '%s'\n",
9029 name);
9030 }
9031 if (NULL != pr->vr.aesp.audio_es_tap_fp) {
9032 log (ll, " A-ES -> '%s'\n",
9033 pr->vr.aesp.option_audio_es_tap_file_name);
9034 }
9035 if (NULL != pr->cr.ccd.cc_data_tap_fp) {
9036 log (ll, " cc_data -> '%s'\n",
9037 pr->cr.ccd.option_cc_data_tap_file_name);
9038 }
9039 }
9040 }
9041
9042 static void
cr_open_xds_output_file(struct caption_recorder * cr)9043 cr_open_xds_output_file (struct caption_recorder *cr)
9044 {
9045 cr->xds_fp = open_output_file (cr->option_xds_output_file_name);
9046 }
9047
9048 static void
cr_open_caption_output_files(struct caption_recorder * cr)9049 cr_open_caption_output_files (struct caption_recorder *cr)
9050 {
9051 unsigned int i;
9052
9053 for (i = 0; i < 10; ++i) {
9054 const char *name;
9055
9056 name = cr->option_caption_file_name[i];
9057 if (cr->option_caption_mask & (1 << i)
9058 && NULL != name) {
9059 cr->caption_fp[i] = open_output_file (name);
9060 }
9061 }
9062 }
9063
9064 static void
open_output_files(void)9065 open_output_files (void)
9066 {
9067 unsigned int i;
9068
9069 for (i = 0; i < n_programs; ++i) {
9070 struct program *pr;
9071
9072 pr = &program_table[i];
9073
9074 if (pr->cr.usecc)
9075 cr_open_caption_output_files (&pr->cr);
9076
9077 if (pr->cr.usexds)
9078 cr_open_xds_output_file (&pr->cr);
9079 }
9080 }
9081
9082 static void
look_up_station_names(void)9083 look_up_station_names (void)
9084 {
9085 unsigned int i;
9086
9087 read_channel_conf ();
9088
9089 for (i = 0; i < n_programs; ++i) {
9090 struct program *pr;
9091 struct station *st;
9092
9093 pr = &program_table[i];
9094
9095 st = find_station (pr->option_station_name);
9096 if (NULL == st) {
9097 error_exit ("Station '%s' is unknown. List "
9098 "all stations with the -L option.\n",
9099 pr->option_station_name);
9100 }
9101
9102 if (NULL == station) {
9103 station = st;
9104 } else if (!same_transponder (st, station)) {
9105 error_exit ("To receive multiple programs the "
9106 "stations must share one "
9107 "transponder frequency.\n");
9108 }
9109
9110 pr->tsd.pid[0] = st->video_pid;
9111 pr->tsd.pid[1] = st->audio_pid;
9112
9113 assert (st->video_pid <= N_ELEMENTS (pid_map));
9114 assert (st->audio_pid <= N_ELEMENTS (pid_map));
9115
9116 pid_map[st->video_pid].program = i;
9117 pid_map[st->audio_pid].program = i;
9118 }
9119 }
9120
9121 static void
finish_program_setup(struct program * pr,vbi_bool have_cc_filter_option,vbi_bool have_xds_filter_option)9122 finish_program_setup (struct program * pr,
9123 vbi_bool have_cc_filter_option,
9124 vbi_bool have_xds_filter_option)
9125 {
9126 if (NULL != pr->option_minicut_dir_name) {
9127 pr->cr.usecc = TRUE;
9128 if (0 == pr->cr.option_caption_mask)
9129 pr->cr.option_caption_mask = 0x30F;
9130 } else {
9131 unsigned int i;
9132
9133 if (!(pr->cr.usecc | pr->cr.usexds)) {
9134 error_exit ("Please give option -c or -x, "
9135 "or -h for help.\n");
9136 }
9137
9138 if (pr->cr.usecc && !have_cc_filter_option)
9139 pr->cr.option_caption_mask = 0x001;
9140
9141 for (i = 0; i < 10; ++i) {
9142 if (0 != (pr->cr.option_caption_mask & (1 << i))
9143 && NULL == pr->cr.option_caption_file_name[i]) {
9144 pr->cr.option_caption_file_name[i] = "-";
9145 }
9146 }
9147 }
9148
9149 if (pr->cr.usexds && !have_xds_filter_option)
9150 xds_filter_option (&pr->cr, "all");
9151
9152 if (NULL != pr->vesd.option_video_es_all_tap_file_name) {
9153 pr->vesd.video_es_tap_fp = open_output_file
9154 (pr->vesd.option_video_es_all_tap_file_name);
9155 } else if (NULL != pr->vesd.option_video_es_tap_file_name) {
9156 pr->vesd.video_es_tap_fp = open_output_file
9157 (pr->vesd.option_video_es_tap_file_name);
9158 }
9159
9160 if (NULL != pr->vr.aesp.option_audio_es_tap_file_name) {
9161 pr->vr.aesp.audio_es_tap_fp = open_output_file
9162 (pr->vr.aesp.option_audio_es_tap_file_name);
9163 }
9164
9165 if (NULL != pr->cr.ccd.option_cc_data_tap_file_name) {
9166 pr->cr.ccd.cc_data_tap_fp = open_output_file
9167 (pr->cr.ccd.option_cc_data_tap_file_name);
9168 }
9169 }
9170
9171 static unsigned int
uint_option(const char * option_name,const char * optarg)9172 uint_option (const char * option_name,
9173 const char * optarg)
9174 {
9175 const char *s;
9176 char *end;
9177 unsigned long ul;
9178
9179 s = optarg;
9180 while (isspace (*s))
9181 ++s;
9182 if (!isdigit (*s))
9183 goto failed;
9184 ul = strtoul (optarg, &end, 0);
9185 while (isspace (*end))
9186 ++end;
9187 if (0 == *end && ul < UINT_MAX)
9188 return ul;
9189
9190 failed:
9191 error_exit ("Invalid %s '%s'.\n", option_name, optarg);
9192
9193 return 0;
9194 }
9195
9196 static void
format_option(struct caption_recorder * cr,const char * optarg)9197 format_option (struct caption_recorder *cr,
9198 const char * optarg)
9199 {
9200 static const struct {
9201 const char * name;
9202 enum caption_format format;
9203 } formats [] = {
9204 { "plain", FORMAT_PLAIN },
9205 { "vt100", FORMAT_VT100 },
9206 { "ntsc-cc", FORMAT_NTSC_CC }
9207 };
9208 unsigned int i;
9209
9210 for (i = 0; i < N_ELEMENTS (formats); ++i) {
9211 if (NULL != optarg
9212 && 0 == strcmp (optarg, formats[i].name)) {
9213 cr->option_caption_format = formats[i].format;
9214 break;
9215 }
9216 }
9217
9218 if (i >= N_ELEMENTS (formats)) {
9219 error_exit ("Invalid caption format '%s'. "
9220 "Try 'plain', 'vt100' or 'ntsc-cc'.\n",
9221 optarg);
9222 }
9223
9224 if (FORMAT_PLAIN == cr->option_caption_format) {
9225 cr->xds_info_prefix = "% ";
9226 cr->xds_info_suffix = "\n";
9227 } else {
9228 cr->xds_info_prefix = "\33[33m% ";
9229 cr->xds_info_suffix = "\33[0m\n";
9230 }
9231 }
9232
9233 static void
debug_option(const char * optarg)9234 debug_option (const char * optarg)
9235 {
9236 static const struct {
9237 const char * name;
9238 unsigned int flag;
9239 } flags [] = {
9240 { "all", -1 },
9241 { "ccdata", DEBUG_CC_DATA },
9242 { "ccdec", DEBUG_CC_DECODER },
9243 { "ccf1", DEBUG_CC_F1 },
9244 { "ccf2", DEBUG_CC_F2 },
9245 { "conf", DEBUG_CONFIG },
9246 { "dtvccp", DEBUG_DTVCC_PACKET },
9247 { "dtvccpc", DEBUG_DTVCC_PUT_CHAR },
9248 { "dtvccse", DEBUG_DTVCC_SE },
9249 { "dtvccsev", DEBUG_DTVCC_STREAM_EVENT },
9250 { "vesdcc", DEBUG_VESD_CC_DATA },
9251 { "vesdpe", DEBUG_VESD_PIC_EXT },
9252 { "vesdph", DEBUG_VESD_PIC_HDR },
9253 { "vesdpesp", DEBUG_VESD_PES_PACKET },
9254 { "vesdsc", DEBUG_VESD_START_CODE },
9255 { "vesdud", DEBUG_VESD_USER_DATA },
9256 };
9257 const char *s;
9258
9259 if (NULL == optarg) {
9260 option_debug = -1;
9261 return;
9262 } else if (0 == strcmp (optarg, "help")) {
9263 unsigned int i;
9264
9265 printf ("Debugging switches:\n");
9266
9267 for (i = 0; i < N_ELEMENTS (flags); ++i) {
9268 printf (" %s\n", flags[i].name);
9269 }
9270
9271 exit (EXIT_SUCCESS);
9272 }
9273
9274 s = optarg;
9275
9276 while (isspace (*s))
9277 ++s;
9278
9279 while (0 != *s) {
9280 unsigned int i;
9281
9282 for (i = 0; i < N_ELEMENTS (flags); ++i) {
9283 const char *t;
9284 const char *u;
9285
9286 t = s;
9287 u = flags[i].name;
9288 for (;;) {
9289 if (0 == *t || ',' == *t || ' ' == *t) {
9290 if (0 != *u)
9291 break;
9292 option_debug |= flags[i].flag;
9293 s = t;
9294 goto next_item;
9295 } else if ('-' == *t || '_' == *t) {
9296 ++t;
9297 continue;
9298 } else if (*t++ != *u++) {
9299 break;
9300 }
9301 }
9302 }
9303
9304 error_exit ("Invalid debugging switch '%s'. "
9305 "Try --debug help.\n", optarg);
9306
9307 next_item:
9308 while (',' == *s || isspace (*s))
9309 ++s;
9310 }
9311 }
9312
9313 static struct program *
add_program(void)9314 add_program (void)
9315 {
9316 struct program *pr;
9317
9318 if (n_programs >= N_ELEMENTS (program_table)) {
9319 error_exit ("Sorry, too many programs.\n");
9320 }
9321
9322 pr = &program_table[n_programs++];
9323
9324 init_program (pr);
9325
9326 return pr;
9327 }
9328
9329 static void
parse_args(int argc,char ** argv)9330 parse_args (int argc,
9331 char ** argv)
9332 {
9333 struct program *pr;
9334 vbi_bool have_cc_filter_option;
9335 vbi_bool have_xds_filter_option;
9336 unsigned int n_program_options;
9337
9338 option_source = SOURCE_DVB_DEVICE;
9339
9340 option_dvb_type = -1; /* query device */
9341
9342 option_dvb_adapter_num = 0;
9343 option_dvb_frontend_id = 0;
9344 option_dvb_demux_id = 0;
9345 option_dvb_dvr_id = 0;
9346
9347 option_verbosity = 1;
9348
9349 pr = add_program ();
9350
9351 format_option (&pr->cr, "ntsc-cc");
9352
9353 have_xds_filter_option = FALSE;
9354 have_cc_filter_option = FALSE;
9355 n_program_options = 0;
9356
9357 for (;;) {
9358 int c;
9359
9360 c = getopt_long (argc, argv, short_options,
9361 long_options, &option_index);
9362 if (-1 == c)
9363 break;
9364
9365 switch (c) {
9366 const char *name;
9367 unsigned int i;
9368 long ch;
9369
9370 case '?':
9371 case 'h':
9372 usage (stdout);
9373 exit (EXIT_SUCCESS);
9374
9375 case '0' ... '9':
9376 assert (NULL != optarg);
9377 if ('0' == c)
9378 i = 9;
9379 else
9380 i = c - '1';
9381 pr->cr.option_caption_file_name[i] = optarg;
9382 pr->cr.option_caption_mask |= 1 << i;
9383 have_cc_filter_option = TRUE;
9384 ++n_program_options;
9385 pr->cr.usecc = 1;
9386 break;
9387
9388 case 'a':
9389 assert (NULL != optarg);
9390 option_dvb_adapter_num =
9391 uint_option ("DVB adapter number",
9392 optarg);
9393 break;
9394
9395 case 'b':
9396 pr->cr.usewebtv = 0; /* sic, compatibility */
9397 ++n_program_options;
9398 break;
9399
9400 case 'c':
9401 pr->cr.usecc = 1;
9402 ++n_program_options;
9403 break;
9404
9405 case 'd':
9406 assert (NULL != optarg);
9407 option_dvb_demux_id =
9408 uint_option ("DVB demux device number",
9409 optarg);
9410 break;
9411
9412 case 'e':
9413 assert (NULL != optarg);
9414 option_channel_conf_file_name = optarg;
9415 break;
9416
9417 case 'f':
9418 pr->cr.usexds = TRUE;
9419 xds_filter_option (&pr->cr, optarg);
9420 have_xds_filter_option = TRUE;
9421 ++n_program_options;
9422 break;
9423
9424 case 'i':
9425 assert (NULL != optarg);
9426 option_dvb_frontend_id =
9427 uint_option ("DVB frontend device number",
9428 optarg);
9429 break;
9430
9431 case 'j':
9432 assert (NULL != optarg);
9433 format_option (&pr->cr, optarg);
9434 ++n_program_options;
9435 break;
9436
9437 case 'l':
9438 assert (NULL != optarg);
9439 ch = strtol (optarg, NULL, 0);
9440 if (ch < 1 || ch > 10) {
9441 error_exit ("Invalid caption stream "
9442 "number %ld. The valid "
9443 "range is 1 ... 10.\n",
9444 ch);
9445 }
9446 pr->cr.option_caption_mask |= 1 << (ch - 1);
9447 have_cc_filter_option = TRUE;
9448 ++n_program_options;
9449 pr->cr.usecc = 1;
9450 break;
9451
9452 case 'm':
9453 pr->cr.option_caption_timestamps = TRUE;
9454 ++n_program_options;
9455 break;
9456
9457 case '\1': /* not an option */
9458 /* NB this is a GNU extension, hence the
9459 -n option. */
9460
9461 case 'n':
9462 assert (NULL != optarg);
9463 name = optarg;
9464 if (NULL == pr->option_station_name) {
9465 pr->option_station_name = name;
9466 if (0 == n_program_options)
9467 break;
9468 name = NULL;
9469 }
9470 finish_program_setup (pr,
9471 have_cc_filter_option,
9472 have_xds_filter_option);
9473 pr = add_program ();
9474 pr->option_station_name = name;
9475 have_xds_filter_option = FALSE;
9476 have_cc_filter_option = FALSE;
9477 n_program_options = 0;
9478 break;
9479
9480 case 'p':
9481 format_option (&pr->cr, "plain");
9482 ++n_program_options;
9483 break;
9484
9485 case 'q':
9486 option_verbosity = 0;
9487 break;
9488
9489 case 'r':
9490 assert (NULL != optarg);
9491 option_dvb_dvr_id =
9492 uint_option ("DVB DVR device number",
9493 optarg);
9494 break;
9495
9496 case 's':
9497 pr->cr.usesen = 1;
9498 ++n_program_options;
9499 break;
9500
9501 case 'v':
9502 ++option_verbosity;
9503 break;
9504
9505 case 'x':
9506 pr->cr.usexds = 1;
9507 ++n_program_options;
9508 break;
9509
9510 case 'C':
9511 assert (NULL != optarg);
9512 for (i = 0; i < 10; ++i) {
9513 pr->cr.option_caption_file_name[i] =
9514 optarg;
9515 }
9516 pr->cr.usecc = 1;
9517 ++n_program_options;
9518 break;
9519
9520 case 'L':
9521 read_channel_conf ();
9522 list_stations ();
9523 exit (EXIT_SUCCESS);
9524
9525 case 'M':
9526 assert (NULL != optarg);
9527 pr->option_minicut_dir_name = optarg;
9528 ++n_program_options;
9529 break;
9530
9531 case 'P':
9532 option_source = SOURCE_STDIN_PES;
9533 break;
9534
9535 case 'T':
9536 option_source = SOURCE_STDIN_TS;
9537 break;
9538
9539 case 'X':
9540 assert (NULL != optarg);
9541 pr->cr.option_xds_output_file_name = optarg;
9542 ++n_program_options;
9543 break;
9544
9545 /* Test options. */
9546
9547 case 301:
9548 option_dvb_type = FE_ATSC;
9549 break;
9550
9551 case 302:
9552 option_dvb_type = FE_OFDM;
9553 break;
9554
9555 case 303:
9556 assert (NULL != optarg);
9557 option_ts_all_tap_file_name = optarg;
9558 break;
9559
9560 case 304:
9561 assert (NULL != optarg);
9562 option_ts_tap_file_name = optarg;
9563 break;
9564
9565 case 305:
9566 assert (NULL != optarg);
9567 pr->vesd.option_video_es_all_tap_file_name = optarg;
9568 ++n_program_options;
9569 break;
9570
9571 case 306:
9572 assert (NULL != optarg);
9573 pr->vesd.option_video_es_tap_file_name = optarg;
9574 ++n_program_options;
9575 break;
9576
9577
9578 case 307:
9579 assert (NULL != optarg);
9580 pr->vr.aesp.option_audio_es_tap_file_name = optarg;
9581 ++n_program_options;
9582 break;
9583
9584 case 308:
9585 assert (NULL != optarg);
9586 pr->cr.ccd.option_cc_data_tap_file_name = optarg;
9587 ++n_program_options;
9588 break;
9589
9590 case 309:
9591 assert (NULL != optarg);
9592 debug_option (optarg);
9593 break;
9594
9595 case 310:
9596 option_minicut_test = TRUE;
9597 break;
9598
9599 case 311:
9600 option_source = SOURCE_STDIN_CC_DATA;
9601 break;
9602
9603 case 312:
9604 option_source = SOURCE_STDIN_VIDEO_ES;
9605 break;
9606
9607 default:
9608 usage (stderr);
9609 exit (EXIT_FAILURE);
9610 }
9611 }
9612
9613 if (pr->cr.usesen
9614 && (pr->cr.option_caption_timestamps
9615 || NULL != pr->option_minicut_dir_name)) {
9616 error_exit ("Sorry, option -s does not "
9617 "combine with -m or -M.\n");
9618 }
9619
9620 if (NULL == pr->option_station_name) {
9621 if (0 == n_program_options) {
9622 --n_programs;
9623 if (SOURCE_DVB_DEVICE == option_source
9624 || SOURCE_STDIN_TS == option_source) {
9625 if (0 == n_programs)
9626 goto no_station;
9627 }
9628 } else {
9629 if (SOURCE_DVB_DEVICE == option_source
9630 || SOURCE_STDIN_TS == option_source) {
9631 if (optind == argc)
9632 goto no_station;
9633
9634 pr->option_station_name = argv[optind];
9635 }
9636
9637 finish_program_setup (pr,
9638 have_cc_filter_option,
9639 have_xds_filter_option);
9640 }
9641 } else {
9642 finish_program_setup (pr,
9643 have_cc_filter_option,
9644 have_xds_filter_option);
9645 }
9646
9647 if (SOURCE_DVB_DEVICE == option_source
9648 || SOURCE_STDIN_TS == option_source) {
9649 look_up_station_names ();
9650 } else {
9651 if (n_programs > 1) {
9652 goto too_many_stations;
9653 } else if (NULL != program_table[0].option_station_name) {
9654 log (1, "Ignoring station name.\n");
9655 }
9656 }
9657
9658 return;
9659
9660 no_station:
9661 error_exit ("Please give a station name. "
9662 "List all stations with the -L option.\n");
9663
9664 too_many_stations:
9665 error_exit ("Sorry, only one program can be decoded with "
9666 "the --cc-data, --es or\n"
9667 "--pes option.\n");
9668 }
9669
9670 int
main(int argc,char ** argv)9671 main (int argc,
9672 char ** argv)
9673 {
9674 my_name = argv[0];
9675
9676 setlocale (LC_ALL, "");
9677
9678 locale_codeset = vbi_locale_codeset (),
9679
9680 /* Don't swap out any code or data pages (if we have the
9681 privilege). If the capture thread is delayed we may lose
9682 packets. Errors ignored. */
9683 mlockall (MCL_CURRENT | MCL_FUTURE);
9684
9685 memset (pid_map, -1, sizeof (pid_map));
9686
9687 parse_args (argc, argv);
9688
9689 init_demux_state ();
9690
9691 if (NULL != option_ts_all_tap_file_name) {
9692 ts_tap_fp = open_output_file (option_ts_all_tap_file_name);
9693 } else if (NULL != option_ts_tap_file_name) {
9694 ts_tap_fp = open_output_file (option_ts_tap_file_name);
9695 }
9696
9697 switch (option_source) {
9698 case SOURCE_DVB_DEVICE:
9699 open_device ();
9700 open_output_files ();
9701 if (n_programs > 1)
9702 list_programs ();
9703 demux_thread (/* arg */ NULL);
9704 close_device ();
9705 break;
9706
9707 case SOURCE_STDIN_TS:
9708 open_output_files ();
9709 if (n_programs > 1)
9710 list_programs ();
9711 ts_test_loop ("-");
9712 break;
9713
9714 case SOURCE_STDIN_PES:
9715 error_exit ("Sorry, the --pes option "
9716 "is not implemented yet.\n");
9717 break;
9718
9719 case SOURCE_STDIN_VIDEO_ES:
9720 /* For tests only. */
9721 open_output_files ();
9722 video_es_test_loop (&program_table[0], "-");
9723 break;
9724
9725 case SOURCE_STDIN_CC_DATA:
9726 /* For tests only. */
9727 open_output_files ();
9728 cc_data_test_loop (&program_table[0], "-");
9729 break;
9730 }
9731
9732 destroy_demux_state ();
9733
9734 exit (EXIT_SUCCESS);
9735 }
9736