~ubuntu-branches/ubuntu/trusty/zvbi/trusty

« back to all changes in this revision

Viewing changes to src/cc608_decoder.c

  • Committer: Package Import Robot
  • Author(s): Jackson Doak
  • Date: 2013-10-15 06:29:56 UTC
  • mfrom: (1.1.11) (2.1.13 sid)
  • Revision ID: package-import@ubuntu.com-20131015062956-0b9vqh1f8y90f38k
Tags: 0.2.35-2
* QA upload
* Add 06_sizeof_FTBFS.diff. Closes: #726186

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  libzvbi - EIA 608-B Closed Caption decoder
 
3
 *
 
4
 *  Copyright (C) 2008 Michael H. Schimek
 
5
 *
 
6
 *  This library is free software; you can redistribute it and/or
 
7
 *  modify it under the terms of the GNU Library General Public
 
8
 *  License as published by the Free Software Foundation; either
 
9
 *  version 2 of the License, or (at your option) any later version.
 
10
 *
 
11
 *  This library is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
 *  Library General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU Library General Public
 
17
 *  License along with this library; if not, write to the 
 
18
 *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 
 
19
 *  Boston, MA  02110-1301  USA.
 
20
 */
 
21
 
 
22
/* $Id: cc608_decoder.c,v 1.2 2009/12/14 23:43:23 mschimek Exp $ */
 
23
 
 
24
/* This code is experimental and not yet part of the library.
 
25
   Tests pending. */
 
26
 
 
27
#ifdef HAVE_CONFIG_H
 
28
#  include "config.h"
 
29
#endif
 
30
 
 
31
#include "hamm.h"
 
32
#include "lang.h"
 
33
#include "conv.h"
 
34
#include "format.h"
 
35
#include "event-priv.h"
 
36
#include "cc608_decoder.h"
 
37
 
 
38
#ifndef CC608_DECODER_LOG_INPUT
 
39
#  define CC608_DECODER_LOG_INPUT 0
 
40
#endif
 
41
 
 
42
enum field_num {
 
43
        FIELD_1 = 0,
 
44
        FIELD_2,
 
45
        MAX_FIELDS
 
46
};
 
47
 
 
48
#define UNKNOWN_CHANNEL 0
 
49
#define MAX_CHANNELS 8
 
50
 
 
51
/* 47 CFR 15.119 (d) Screen format. */
 
52
 
 
53
#define FIRST_ROW               0
 
54
#define LAST_ROW                14
 
55
#define MAX_ROWS                15
 
56
 
 
57
#define ALL_ROWS_MASK ((1 << MAX_ROWS) - 1)
 
58
 
 
59
/* Note these are visible columns. We also buffer a zeroth column
 
60
   which is implied by 47 CFR 15.119 and EIA 608-B to set the default
 
61
   or PAC attributes for column one, and visible as a solid space if
 
62
   padding for legibility is enabled. We do not reserve a 33rd column
 
63
   for padding since format_row() can just append a space to the
 
64
   output. */
 
65
#define FIRST_COLUMN            1
 
66
#define LAST_COLUMN             32
 
67
#define MAX_COLUMNS             32
 
68
 
 
69
struct timestamp {
 
70
        /* System time when the event occured, zero if no event
 
71
           occured yet. */
 
72
        double                  sys;
 
73
 
 
74
        /* ISO 13818-1 Presentation Time Stamp of the event. Unit is
 
75
           1/90000 second. Only the 33 least significant bits are
 
76
           valid. < 0 if no event occured yet. */
 
77
        int64_t                 pts;
 
78
};
 
79
 
 
80
struct channel {
 
81
        /**
 
82
         * [0] and [1] are the displayed and non-displayed buffer as
 
83
         * defined in 47 CFR 15.119, and selected by @a
 
84
         * displayed_buffer below. [2] is a snapshot of the displayed
 
85
         * buffer at the last stream event.
 
86
         *
 
87
         * XXX Text channels don't need buffer[2] and buffer[3], we're
 
88
         * wasting memory.
 
89
         */
 
90
        uint16_t                buffer[3][MAX_ROWS][1 + MAX_COLUMNS];
 
91
 
 
92
        /**
 
93
         * For buffer[0 ... 2], if bit 1 << row is set this row
 
94
         * contains displayable characters, spacing or non-spacing
 
95
         * attributes. (Special character 0x1139 "transparent space"
 
96
         * is not a displayable character.) This information is
 
97
         * intended to speed up copying, erasing and formatting.
 
98
         */
 
99
        unsigned int            dirty[3];
 
100
 
 
101
        /** Index of the displayed buffer, 0 or 1. */
 
102
        unsigned int            displayed_buffer;
 
103
 
 
104
        /**
 
105
         * Cursor position: FIRST_ROW ... LAST_ROW and
 
106
         * FIRST_COLUMN ... LAST_COLUMN.
 
107
         */
 
108
        unsigned int            curr_row;
 
109
        unsigned int            curr_column;
 
110
 
 
111
        /**
 
112
         * Text window height in VBI_CC608_MODE_ROLL_UP. The top row
 
113
         * of the window is curr_row - window_rows + 1, the bottom row
 
114
         * is curr_row.
 
115
         *
 
116
         * Note: curr_row - window_rows + 1 may be < FIRST_ROW, this
 
117
         * must be clipped before using window_rows:
 
118
         *
 
119
         * actual_rows = MIN (curr_row - FIRST_ROW + 1, window_rows);
 
120
         *
 
121
         * We won't do that at the RUx command because usually a PAC
 
122
         * command follows which may change curr_row.
 
123
         */
 
124
        unsigned int            window_rows;
 
125
 
 
126
        /* Most recently received PAC command. */
 
127
        unsigned int            last_pac;
 
128
 
 
129
        /**
 
130
         * This variable counts successive transmissions of the
 
131
         * letters A to Z. It is reset to zero upon reception of any
 
132
         * letter a to z.
 
133
         *
 
134
         * Some stations do not transmit EIA 608-B extended characters
 
135
         * and except for N with tilde the standard and special
 
136
         * character sets contain only lower case accented
 
137
         * characters. We force these characters to upper case if this
 
138
         * variable indicates live caption, where the text is usually
 
139
         * all upper case.
 
140
         */
 
141
        unsigned int            uppercase_predictor;
 
142
 
 
143
        /** Current caption mode or VBI_CC608_MODE_UNKNOWN. */
 
144
        _vbi_cc608_mode         mode;
 
145
 
 
146
        /**
 
147
         * The time when we last received data for this
 
148
         * channel. Intended to detect if this caption channel is
 
149
         * active.
 
150
         */
 
151
        struct timestamp        timestamp;
 
152
 
 
153
        /**
 
154
         * The time when we received the first (but not necessarily
 
155
         * leftmost) character in the current row. Unless the mode is
 
156
         * VBI_CC608_MODE_POP_ON the next stream event will carry this
 
157
         * timestamp.
 
158
         */
 
159
        struct timestamp        timestamp_c0;
 
160
};
 
161
 
 
162
struct _vbi_cc608_decoder {
 
163
        /**
 
164
         * Decoder state. We decode all channels in parallel, this way
 
165
         * clients can switch between channels without data loss or
 
166
         * capture multiple channels with a single decoder instance.
 
167
         *
 
168
         * Also 47 CFR 15.119 and EIA 608-C require us to remember the
 
169
         * cursor position on each channel.
 
170
         */
 
171
        struct channel          channel[MAX_CHANNELS];
 
172
 
 
173
        /**
 
174
         * Current channel, switched by caption control codes. Can be
 
175
         * one of @c VBI_CAPTION_CC1 (1) ... @c VBI_CAPTION_CC4 (4) or
 
176
         * @c VBI_CAPTION_T1 (5) ... @c VBI_CAPTION_T4 (8) or @c
 
177
         * UNKNOWN_CHANNEL (0) if no channel number was received yet.
 
178
         */
 
179
        vbi_pgno                curr_ch_num[MAX_FIELDS];
 
180
 
 
181
        /**
 
182
         * Caption control codes (two bytes) may repeat once for error
 
183
         * correction. -1 if no repeated control code can be expected.
 
184
         */
 
185
        int                     expect_ctrl[MAX_FIELDS][2];
 
186
 
 
187
        /**
 
188
         * Receiving XDS data, as opposed to caption / ITV data.
 
189
         * There's no XDS data on the first field, we just use an
 
190
         * array for convenience.
 
191
         */
 
192
        vbi_bool                in_xds[MAX_FIELDS];
 
193
 
 
194
        /**
 
195
         * Pointer into the channel[] array if a display update event
 
196
         * shall be sent at the end of this iteration, @c NULL
 
197
         * otherwise. Purpose is to suppress an event for the first of
 
198
         * two displayable characters in a caption byte pair.
 
199
         */
 
200
        struct channel *        event_pending;
 
201
 
 
202
        /**
 
203
         * Remembers past parity errors: One bit for each call of
 
204
         * vbi_cc608_decoder_feed(), most recent result in lsb. The
 
205
         * idea is to disable the decoder if we detect too many
 
206
         * errors.
 
207
         */
 
208
        unsigned int            error_history;
 
209
 
 
210
        /**
 
211
         * The time when we last received data, including NUL bytes.
 
212
         * Intended to detect if the station transmits any data on
 
213
         * line 21 or 284.
 
214
         */
 
215
        struct timestamp        timestamp;
 
216
 
 
217
        _vbi_event_handler_list handlers;
 
218
};
 
219
 
 
220
/* 47 CFR 15.119 Mid-Row Codes, Preamble Address Codes.
 
221
   EIA 608-B Table 3. */
 
222
static const vbi_color
 
223
color_map [8] = {
 
224
        VBI_WHITE, VBI_GREEN, VBI_BLUE, VBI_CYAN,
 
225
        VBI_RED, VBI_YELLOW, VBI_MAGENTA,
 
226
 
 
227
        /* Note Mid-Row Codes interpret this value as "Italics"; PACs
 
228
           as "White Italics"; Background Attributes as "Black". */
 
229
        VBI_BLACK
 
230
};
 
231
 
 
232
/* 47 CFR 15.119 Preamble Address Codes. */
 
233
static const int8_t
 
234
pac_row_map [16] = {
 
235
        /* 0 */ 10,                     /* 0x1040 */
 
236
        /* 1 */ -1,                     /* no function */
 
237
        /* 2 */ 0, 1, 2, 3,             /* 0x1140 ... 0x1260 */
 
238
        /* 6 */ 11, 12, 13, 14,         /* 0x1340 ... 0x1460 */
 
239
        /* 10 */ 4, 5, 6, 7, 8, 9       /* 0x1540 ... 0x1760 */
 
240
};
 
241
 
 
242
/** @internal */
 
243
void
 
244
_vbi_cc608_dump                 (FILE *                 fp,
 
245
                                 unsigned int           c1,
 
246
                                 unsigned int           c2)
 
247
{
 
248
        const vbi_bool to_upper = FALSE;
 
249
        const int repl_char = '?';
 
250
        uint16_t ucs2_str[2];
 
251
        unsigned int c;
 
252
        unsigned int f;
 
253
        unsigned int u;
 
254
 
 
255
        assert (NULL != fp);
 
256
 
 
257
        fprintf (fp, "%02X%02X %02X%c%02X%c",
 
258
                 c1 & 0xFF, c2 & 0xFF,
 
259
                 c1 & 0x7F, vbi_unpar8 (c1) < 0 ? '*' : ' ',
 
260
                 c2 & 0x7F, vbi_unpar8 (c2) < 0 ? '*' : ' ');
 
261
 
 
262
        /* Note we ignore wrong parity. */
 
263
        c1 &= 0x7F;
 
264
        c2 &= 0x7F;
 
265
 
 
266
        if (0 == c1) {
 
267
                fputs (" null\n", fp);
 
268
                return;
 
269
        } else if (c1 < 0x10) {
 
270
                if (0x0F == c1)
 
271
                        fputs (" XDS packet end\n", fp);
 
272
                else
 
273
                        fputs (" XDS packet start/continue\n", fp);
 
274
                return;
 
275
        } else if (c1 >= 0x20) {
 
276
                unsigned int i = 0;
 
277
 
 
278
                fputs (" '", fp);
 
279
                ucs2_str[i++] = vbi_caption_unicode (c1, to_upper);
 
280
                if (c2 >= 0x20) {
 
281
                        ucs2_str[i++] = vbi_caption_unicode (c2, to_upper);
 
282
                }
 
283
                vbi_fputs_iconv_ucs2 (fp, vbi_locale_codeset (),
 
284
                                      ucs2_str, i, repl_char);
 
285
                fprintf (fp, "'%s\n",
 
286
                         (c2 > 0 && c2 < 0x20) ? " invalid" : "");
 
287
                return;
 
288
        }
 
289
 
 
290
        /* Some common bits. */
 
291
        c = (c1 >> 3) & 1; /* channel */
 
292
        f = c1 & 1; /* field */
 
293
        u = c2 & 1; /* underline */
 
294
 
 
295
        if (c2 < 0x20) {
 
296
                fputs (" invalid\n", fp);
 
297
                return;
 
298
        } else if (c2 >= 0x40) {
 
299
                unsigned int rrrr;
 
300
                unsigned int xxx;
 
301
                int row;
 
302
 
 
303
                /* Preamble Address Codes -- 001 crrr  1ri xxxu */
 
304
  
 
305
                rrrr = (c1 & 7) * 2 + ((c2 & 0x20) > 0);
 
306
                xxx = (c2 >> 1) & 7;
 
307
 
 
308
                row = pac_row_map [rrrr];
 
309
                if (c2 & 0x10) {
 
310
                        fprintf (fp, " PAC ch=%u row=%d column=%u u=%u\n",
 
311
                                 c, row, xxx * 4, u);
 
312
                } else {
 
313
                        fprintf (fp, " PAC ch=%u row=%d color=%u u=%u\n",
 
314
                                 c, row, xxx, u);
 
315
                }
 
316
 
 
317
                return;
 
318
        }
 
319
 
 
320
        /* Control codes -- 001 caaa  01x bbbu */
 
321
 
 
322
        switch (c1 & 0x07) {
 
323
        case 0:
 
324
                if (c2 < 0x30) {
 
325
                        static const char mnemo [16 * 4] =
 
326
                                "BWO\0BWS\0BGO\0BGS\0"
 
327
                                "BBO\0BBS\0BCO\0BCS\0"
 
328
                                "BRO\0BRS\0BYO\0BYS\0"
 
329
                                "BMO\0BMS\0BAO\0BAS";
 
330
 
 
331
                        /* Backgr. Attr. Codes -- 001 c000  010 xxxt */
 
332
 
 
333
                        fprintf (fp, " %s ch=%u\n",
 
334
                                 mnemo + (c2 & 0xF) * 4, c);
 
335
                        return;
 
336
                }
 
337
                break;
 
338
 
 
339
        case 1:
 
340
                if (c2 < 0x30) {
 
341
                        unsigned int xxx;
 
342
 
 
343
                        /* Mid-Row Codes -- 001 c001  010 xxxu */
 
344
 
 
345
                        xxx = (c2 >> 1) & 7;
 
346
                        fprintf (fp, " mid-row ch=%u color=%u u=%u\n",
 
347
                                 c, xxx, u);
 
348
                } else {
 
349
                        /* Special Characters -- 001 c001  011 xxxx */
 
350
 
 
351
                        fprintf (fp, " special character ch=%u '", c);
 
352
                        ucs2_str[0] = vbi_caption_unicode
 
353
                                (0x1100 | c2, to_upper);
 
354
                        vbi_fputs_iconv_ucs2 (fp, vbi_locale_codeset (),
 
355
                                              ucs2_str, 1, repl_char);
 
356
                        fputs ("'\n", fp);
 
357
                }
 
358
                return;
 
359
 
 
360
        case 2: /* first group */
 
361
        case 3: /* second group */
 
362
                /* Extended Character Set -- 001 c01x  01x xxxx */
 
363
 
 
364
                fprintf (fp, " extended character ch=%u '", c);
 
365
                ucs2_str[0] = vbi_caption_unicode (c1 * 256 + c2, to_upper);
 
366
                vbi_fputs_iconv_ucs2 (fp, vbi_locale_codeset (),
 
367
                                      ucs2_str, 1, repl_char);
 
368
                fputs ("'\n", fp);
 
369
                return;
 
370
 
 
371
        case 4: /* f = 0 */
 
372
        case 5: /* f = 1 */
 
373
                if (c2 < 0x30) {
 
374
                        static const char mnemo [16 * 4] =
 
375
                                "RCL\0BS \0AOF\0AON\0"
 
376
                                "DER\0RU2\0RU3\0RU4\0"
 
377
                                "FON\0RDC\0TR \0RTD\0"
 
378
                                "EDM\0CR \0ENM\0EOC";
 
379
 
 
380
                        /* Misc. Control Codes -- 001 c10f  010 xxxx */
 
381
 
 
382
                        fprintf (fp, " %s ch=%u f=%u\n",
 
383
                                 mnemo + (c2 & 0xF) * 4, c, f);
 
384
                        return;
 
385
                }
 
386
                break;
 
387
 
 
388
        case 6: /* reserved */
 
389
                break;
 
390
 
 
391
        case 7:
 
392
                switch (c2) {
 
393
                case 0x21:
 
394
                case 0x22:
 
395
                case 0x23:
 
396
                        fprintf (fp, " TO%u ch=%u\n", c2 - 0x20, c);
 
397
                        return;
 
398
 
 
399
                case 0x2D:
 
400
                        fprintf (fp, " BT ch=%u\n", c);
 
401
                        return;
 
402
 
 
403
                case 0x2E:
 
404
                        fprintf (fp, " FA ch=%u\n", c);
 
405
                        return;
 
406
 
 
407
                case 0x2F:
 
408
                        fprintf (fp, " FAU ch=%u\n", c);
 
409
                        return;
 
410
 
 
411
                default:
 
412
                        break;
 
413
                }
 
414
                break;
 
415
        }
 
416
 
 
417
        fprintf (fp, " unknown\n");
 
418
}
 
419
 
 
420
/* Future stuff. */
 
421
enum {
 
422
        VBI_UNDERLINE   = (1 << 0),
 
423
        VBI_ITALIC      = (1 << 2),
 
424
        VBI_FLASH       = (1 << 3)
 
425
};
 
426
 
 
427
_vbi_inline void
 
428
vbi_char_copy_attr              (struct vbi_char *      cp1,
 
429
                                 const struct vbi_char *cp2,
 
430
                                 unsigned int           attr)
 
431
{
 
432
        if (attr & VBI_UNDERLINE)
 
433
                cp1->underline = cp2->underline;
 
434
        if (attr & VBI_ITALIC)
 
435
                cp1->italic = cp2->italic;
 
436
        if (attr & VBI_FLASH)
 
437
                cp1->flash = cp2->flash;
 
438
}
 
439
 
 
440
_vbi_inline void
 
441
vbi_char_clear_attr             (struct vbi_char *      cp,
 
442
                                 unsigned int           attr)
 
443
{
 
444
        if (attr & VBI_UNDERLINE)
 
445
                cp->underline = 0;
 
446
        if (attr & VBI_ITALIC)
 
447
                cp->italic = 0;
 
448
        if (attr & VBI_FLASH)
 
449
                cp->flash = 0;
 
450
}
 
451
 
 
452
_vbi_inline void
 
453
vbi_char_set_attr               (struct vbi_char *      cp,
 
454
                                 unsigned int           attr)
 
455
{
 
456
        if (attr & VBI_UNDERLINE)
 
457
                cp->underline = 1;
 
458
        if (attr & VBI_ITALIC)
 
459
                cp->italic = 1;
 
460
        if (attr & VBI_FLASH)
 
461
                cp->flash = 1;
 
462
}
 
463
 
 
464
_vbi_inline unsigned int
 
465
vbi_char_has_attr               (const struct vbi_char *cp,
 
466
                                 unsigned int           attr)
 
467
{
 
468
        attr &= (VBI_UNDERLINE | VBI_ITALIC | VBI_FLASH);
 
469
 
 
470
        if (0 == cp->underline)
 
471
                attr &= ~VBI_UNDERLINE;
 
472
        if (0 == cp->italic)
 
473
                attr &= ~VBI_ITALIC;
 
474
        if (0 == cp->flash)
 
475
                attr &= ~VBI_FLASH;
 
476
 
 
477
        return attr;
 
478
}
 
479
 
 
480
_vbi_inline unsigned int
 
481
vbi_char_xor_attr               (const struct vbi_char *cp1,
 
482
                                 const struct vbi_char *cp2,
 
483
                                 unsigned int           attr)
 
484
{
 
485
        attr &= (VBI_UNDERLINE | VBI_ITALIC | VBI_FLASH);
 
486
 
 
487
        if (0 == (cp1->underline ^ cp2->underline))
 
488
                attr &= ~VBI_UNDERLINE;
 
489
        if (0 == (cp1->italic ^ cp2->italic))
 
490
                attr &= ~VBI_ITALIC;
 
491
        if (0 == (cp1->flash ^ cp2->flash))
 
492
                attr &= ~VBI_FLASH;
 
493
 
 
494
        return attr;
 
495
}
 
496
 
 
497
static void
 
498
timestamp_reset                 (struct timestamp *     ts)
 
499
{
 
500
        ts->sys = 0.0;
 
501
        ts->pts = -1;
 
502
}
 
503
 
 
504
static vbi_bool
 
505
timestamp_is_set                (const struct timestamp *ts)
 
506
{
 
507
        return (ts->pts >= 0 || ts->sys > 0.0);
 
508
}
 
509
 
 
510
static vbi_pgno
 
511
channel_num                     (const _vbi_cc608_decoder *cd,
 
512
                                 const struct channel * ch)
 
513
{
 
514
        return (ch - cd->channel) + 1;
 
515
}
 
516
 
 
517
/* This implementation of character attributes is based on 47 CFR
 
518
   15.119 (h) and the following sections of EIA 608-B:
 
519
 
 
520
   EIA 608-B Annex C.7 "Preamble Address Codes and Tab Offsets
 
521
   (Regulatory/Preferred)": "In general, Preamble Address Codes (PACs)
 
522
   have no immediate effect on the display. A major exception is the
 
523
   receipt of a PAC during roll-up captioning. In that case, if the
 
524
   base row designated in the PAC is not the same as the current base
 
525
   row, the display shall be moved immediately to the new base
 
526
   row. [...] An indenting PAC carries the attributes of white,
 
527
   non-italicized, and it sets underlining on or off. Tab Offset
 
528
   commands do not change these attributes. If an indenting PAC with
 
529
   underline ON is received followed by a Tab Offset and by text, the
 
530
   text shall be underlined (except as noted below). When a
 
531
   displayable character is received, it is deposited at the current
 
532
   cursor position. If there is already a displayable character in the
 
533
   column immediately to the left, the new character assumes the
 
534
   attributes of that character. The new character may be arriving as
 
535
   the result of an indenting PAC (with or without a Tab Offset), and
 
536
   that PAC may designate other attributes, but the new character is
 
537
   forced to assume the attributes of the character immediately to its
 
538
   left, and the PAC's attributes are ignored. If, when a displayable
 
539
   character is received, it overwrites an existing PAC or mid-row
 
540
   code, and there are already characters to the right of the new
 
541
   character, these existing characters shall assume the same
 
542
   attributes as the new character. This adoption can result in a
 
543
   whole caption row suddenly changing color, underline, italics,
 
544
   and/or flash attributes."
 
545
 
 
546
   EIA 608-B Annex C.14 "Special Cases Regarding Attributes
 
547
   (Normative)": "In most cases, Preamble Address Codes shall set
 
548
   attributes for the caption elements they address. It is
 
549
   theoretically possible for a service provider to use an indenting
 
550
   PAC to start a row at Column 5 or greater, and then to use
 
551
   Backspace to move the cursor to the left of the PAC into an area to
 
552
   which no attributes have been assigned. It is also possible for a
 
553
   roll-up row, having been created by a Carriage Return, to receive
 
554
   characters with no PAC used to set attributes. In these cases, and
 
555
   in any other case where no explicit attributes have been assigned,
 
556
   the display shall be white, non-underlined, non-italicized, and
 
557
   non-flashing. In case new displayable characters are received
 
558
   immediately after a Delete to End of Row (DER), the display
 
559
   attributes of the first deleted character shall remain in effect if
 
560
   there is a displayable character to the left of the cursor;
 
561
   otherwise, the most recently received PAC shall set the display
 
562
   attributes."
 
563
 
 
564
   47 CFR 15.119 (n) clarifies that Special Character "transparent
 
565
   space" is not a "displayable character". */
 
566
 
 
567
/**
 
568
 * @internal
 
569
 * @param to_upper Convert the lower case Latin characters in the
 
570
 *   standard character set to upper case.
 
571
 * @param padding Add spaces around words for improved legibility
 
572
 *   as defined in 47 CFR 15.119. If @c TRUE the resulting page will
 
573
 *   be 34 columns wide, otherwise 32 columns. The height is always 15
 
574
 *   rows.
 
575
 * @param alpha Add an offset to the vbi_color of characters: +0 for
 
576
 *   opaque, +8 for translucent, +16 for transparent characters. Intended
 
577
 *   for formatting with an alpha color map.
 
578
 */
 
579
static void
 
580
format_row                      (struct vbi_char *      cp,
 
581
                                 unsigned int           max_columns,
 
582
                                 const struct channel * ch,
 
583
                                 unsigned int           buffer,
 
584
                                 unsigned int           row,
 
585
                                 vbi_bool               to_upper,
 
586
                                 vbi_bool               padding,
 
587
                                 vbi_bool               alpha)
 
588
{
 
589
        struct vbi_char ac;
 
590
        struct vbi_char ac_ts;
 
591
        vbi_char *end;
 
592
        unsigned int i;
 
593
 
 
594
        /* 47 CFR 15.119 (h)(1). EIA 608-B Section 6.4. */
 
595
        CLEAR (ac);
 
596
        ac.opacity = VBI_OPAQUE;
 
597
        ac.foreground = VBI_WHITE;
 
598
        ac.background = VBI_BLACK;
 
599
 
 
600
        ac_ts = ac;
 
601
        ac_ts.unicode = 0x20;
 
602
        ac_ts.opacity = VBI_TRANSPARENT_SPACE;
 
603
        if (alpha) {
 
604
                ac_ts.foreground += 16;
 
605
                ac_ts.background += 16;
 
606
        }
 
607
 
 
608
        end = cp + MAX_COLUMNS;
 
609
        if (padding)
 
610
                end += 2;
 
611
 
 
612
        assert (end <= cp + max_columns);
 
613
 
 
614
        /* Shortcut. */
 
615
        if (0 == (ch->dirty[buffer] & (1 << row))) {
 
616
                while (cp < end)
 
617
                        *cp++ = ac_ts;
 
618
 
 
619
                return;
 
620
        }
 
621
 
 
622
        if (padding) {
 
623
                *cp++ = ac_ts;
 
624
        }
 
625
 
 
626
        for (i = FIRST_COLUMN - 1; i <= LAST_COLUMN; ++i) {
 
627
                unsigned int c;
 
628
 
 
629
                ac.unicode = 0x20;
 
630
 
 
631
                c = ch->buffer[buffer][row][i];
 
632
                if (0 == c) {
 
633
                        if (padding
 
634
                            && VBI_TRANSPARENT_SPACE != cp[-1].opacity
 
635
                            && 0x20 != cp[-1].unicode) {
 
636
                                /* Append a space with the same colors
 
637
                                   and opacity (opaque or transp.
 
638
                                   backgr.) as the text to the left of
 
639
                                   it. */
 
640
                                *cp++ = ac;
 
641
                                /* We don't underline spaces, see
 
642
                                   below. */
 
643
                                vbi_char_clear_attr (cp - 1, -1);
 
644
                        } else if (i > 0) {
 
645
                                *cp++ = ac;
 
646
                                cp[-1].opacity = VBI_TRANSPARENT_SPACE;
 
647
                                if (alpha) {
 
648
                                        cp[-1].foreground =
 
649
                                                16 + (ac.foreground & 7);
 
650
                                        cp[-1].background =
 
651
                                                16 + (ac.background & 7);
 
652
                                }
 
653
                        }
 
654
 
 
655
                        continue;
 
656
                } else if (c < 0x1020) {
 
657
                        if (padding
 
658
                            && VBI_TRANSPARENT_SPACE == cp[-1].opacity) {
 
659
                                /* Prepend a space with the same
 
660
                                   colors and opacity (opaque or
 
661
                                   transp. backgr.) as the text to the
 
662
                                   right of it. */
 
663
                                cp[-1] = ac;
 
664
                                /* We don't underline spaces, see
 
665
                                   below. */
 
666
                                vbi_char_clear_attr (cp - 1, -1);
 
667
                        }
 
668
 
 
669
                        if ((c >= 'a' && c <= 'z')
 
670
                            || 0x7E == c /* n with tilde */) {
 
671
                                /* We do not force these characters to
 
672
                                   upper case because the standard
 
673
                                   character set includes upper case
 
674
                                   versions of these characters and
 
675
                                   lower case was probably
 
676
                                   deliberately transmitted. */
 
677
                                ac.unicode = vbi_caption_unicode
 
678
                                        (c, /* to_upper */ FALSE);
 
679
                        } else {
 
680
                                ac.unicode = vbi_caption_unicode
 
681
                                        (c, to_upper);
 
682
                        }
 
683
                } else if (c < 0x1040) {
 
684
                        unsigned int color;
 
685
 
 
686
                        /* Backgr. Attr. Codes -- 001 c000  010 xxxt */
 
687
                        /* EIA 608-B Section 6.2. */
 
688
 
 
689
                        /* This is a set-at spacing attribute. */
 
690
 
 
691
                        color = (c >> 1) & 7;
 
692
                        ac.background = color_map[color];
 
693
 
 
694
                        if (c & 0x0001) {
 
695
                                if (alpha)
 
696
                                        ac.background += 8;
 
697
                                ac.opacity = VBI_SEMI_TRANSPARENT;
 
698
                        } else {
 
699
                                ac.opacity = VBI_OPAQUE;
 
700
                        }
 
701
                } else if (c < 0x1120) {
 
702
                        /* Preamble Address Codes -- 001 crrr  1ri xxxu */
 
703
 
 
704
                        /* PAC is a non-spacing attribute and only
 
705
                           stored in the buffer at the addressed
 
706
                           column minus one if it replaces a
 
707
                           transparent space (EIA 608-B Annex C.7,
 
708
                           C.14). There's always a transparent space
 
709
                           to the left of the first column but we show
 
710
                           this zeroth column only if padding is
 
711
                           enabled. */
 
712
                        if (padding
 
713
                            && VBI_TRANSPARENT_SPACE != cp[-1].opacity
 
714
                            && 0x20 != cp[-1].unicode) {
 
715
                                /* See 0 == c. */
 
716
                                *cp++ = ac;
 
717
                                vbi_char_clear_attr (cp - 1, -1);
 
718
                        } else if (i > 0) {
 
719
                                *cp++ = ac;
 
720
                                cp[-1].opacity = VBI_TRANSPARENT_SPACE;
 
721
                                if (alpha) {
 
722
                                        cp[-1].foreground =
 
723
                                                16 + (ac.foreground & 7);
 
724
                                        cp[-1].background =
 
725
                                                16 + (ac.background & 7);
 
726
                                }
 
727
                        }
 
728
 
 
729
                        vbi_char_clear_attr (&ac, VBI_UNDERLINE | VBI_ITALIC);
 
730
                        if (c & 0x0001)
 
731
                                vbi_char_set_attr (&ac, VBI_UNDERLINE);
 
732
                        if (c & 0x0010) {
 
733
                                ac.foreground = VBI_WHITE;
 
734
                        } else {
 
735
                                unsigned int color;
 
736
 
 
737
                                color = (c >> 1) & 7;
 
738
                                if (7 == color) {
 
739
                                        ac.foreground = VBI_WHITE;
 
740
                                        vbi_char_set_attr (&ac, VBI_ITALIC);
 
741
                                } else {
 
742
                                        ac.foreground = color_map[color];
 
743
                                }
 
744
                        }
 
745
 
 
746
                        continue;
 
747
                } else if (c < 0x1130) {
 
748
                        unsigned int color;
 
749
 
 
750
                        /* Mid-Row Codes -- 001 c001  010 xxxu */
 
751
                        /* 47 CFR 15.119 Mid-Row Codes table,
 
752
                           (h)(1)(ii), (h)(1)(iii). */
 
753
 
 
754
                        /* 47 CFR 15.119 (h)(1)(i), EIA 608-B Section
 
755
                           6.2: Mid-Row codes, FON, BT, FA and FAU are
 
756
                           set-at spacing attributes. */
 
757
 
 
758
                        vbi_char_clear_attr (&ac, -1);
 
759
                        if (c & 0x0001)
 
760
                                vbi_char_set_attr (&ac, VBI_UNDERLINE);
 
761
                        color = (c >> 1) & 7;
 
762
                        if (7 == color) {
 
763
                                vbi_char_set_attr (&ac, VBI_ITALIC);
 
764
                        } else {
 
765
                                ac.foreground = color_map[color];
 
766
                        }
 
767
                } else if (c < 0x1220) {
 
768
                        /* Special Characters -- 001 c001  011 xxxx */
 
769
                        /* 47 CFR 15.119 Character Set Table. */
 
770
 
 
771
                        if (padding
 
772
                            && VBI_TRANSPARENT_SPACE == cp[-1].opacity) {
 
773
                                cp[-1] = ac;
 
774
                                vbi_char_clear_attr (cp - 1, -1);
 
775
                        }
 
776
 
 
777
                        assert (0x1139 /* transparent space */ != c);
 
778
                        ac.unicode = vbi_caption_unicode (c, to_upper);
 
779
                } else if (c < 0x1428) {
 
780
                        /* Extended Character Set -- 001 c01x  01x xxxx */
 
781
                        /* EIA 608-B Section 6.4.2 */
 
782
 
 
783
                        if (padding
 
784
                            && VBI_TRANSPARENT_SPACE == cp[-1].opacity) {
 
785
                                cp[-1] = ac;
 
786
                                vbi_char_clear_attr (cp - 1, -1);
 
787
                        }
 
788
 
 
789
                        /* We do not force these characters to upper
 
790
                           case because the extended character set
 
791
                           includes upper case versions of all letters
 
792
                           and lower case was probably deliberately
 
793
                           transmitted. */
 
794
                        ac.unicode = vbi_caption_unicode
 
795
                                (c, /* to_upper */ FALSE);
 
796
 
 
797
                        if (0x2500 == (ac.unicode & 0xFFE0)) {
 
798
                                /* Box drawing characters probably
 
799
                                   shouldn't have these attributes. */
 
800
                                *cp++ = ac;
 
801
                                vbi_char_clear_attr (cp - 1,
 
802
                                                     (VBI_ITALIC |
 
803
                                                      VBI_UNDERLINE));
 
804
                                continue;
 
805
                        }
 
806
                } else if (c < 0x172D) {
 
807
                        /* FON Flash On -- 001 c10f  010 1000 */
 
808
                        /* 47 CFR 15.119 (h)(1)(iii). */
 
809
 
 
810
                        vbi_char_set_attr (&ac, VBI_FLASH);
 
811
                } else if (c < 0x172E) {
 
812
                        /* BT Background Transparent -- 001 c111  010 1101 */
 
813
                        /* EIA 608-B Section 6.4. */
 
814
 
 
815
                        ac.opacity = VBI_TRANSPARENT_FULL;
 
816
                        if (alpha) {
 
817
                                ac.background = 16 + (ac.background & 7);
 
818
                        }
 
819
                } else if (c <= 0x172F) {
 
820
                        /* FA Foreground Black -- 001 c111  010 111u */
 
821
                        /* EIA 608-B Section 6.4. */
 
822
 
 
823
                        vbi_char_clear_attr (&ac, -1);
 
824
                        if (c & 0x0001)
 
825
                                vbi_char_set_attr (&ac, VBI_UNDERLINE);
 
826
                        ac.foreground = VBI_BLACK;
 
827
                }
 
828
 
 
829
                *cp++ = ac;
 
830
 
 
831
                /* 47 CFR 15.119 and EIA 608-B are silent about
 
832
                   underlined spaces, but considering the example in
 
833
                   47 CFR (h)(1)(iv) which would produce something
 
834
                   ugly like "__text" I suppose we should not
 
835
                   underline them. For good measure we also clear the
 
836
                   invisible italic and flash attribute. */
 
837
                if (0x20 == ac.unicode)
 
838
                        vbi_char_clear_attr (cp - 1, -1);
 
839
        }
 
840
 
 
841
        if (padding) {
 
842
                ac.unicode = 0x20;
 
843
                vbi_char_clear_attr (&ac, -1);
 
844
 
 
845
                if (VBI_TRANSPARENT_SPACE != cp[-1].opacity
 
846
                    && 0x20 != cp[-1].unicode) {
 
847
                        *cp++ = ac;
 
848
                } else {
 
849
                        ac.opacity = VBI_TRANSPARENT_SPACE;
 
850
                        ac.foreground = 16 + (ac.foreground & 7);
 
851
                        ac.background = 16 + (ac.background & 7);
 
852
                        *cp++ = ac;
 
853
                }
 
854
        }
 
855
 
 
856
        assert (cp == end);
 
857
}
 
858
 
 
859
#ifndef VBI_RGBA
 
860
#  define VBI_RGBA(r, g, b)                                             \
 
861
        ((((r) & 0xFF) << 0) | (((g) & 0xFF) << 8)                      \
 
862
         | (((b) & 0xFF) << 16) | (0xFF << 24))
 
863
#endif
 
864
 
 
865
/**
 
866
 * @param cd Caption decoder allocated with vbi_cc608_decoder_new().
 
867
 * @param pg The display state will be stored here.
 
868
 * @param channel Caption channel @c VBI_CHANNEL_CC1 ...
 
869
 *   @c VBI_CHANNEL_CC4 or @c VBI_CHANNEL_T1 ... @c VBI_CHANNEL_T4.
 
870
 * @param padding Add spaces around words for improved legibility
 
871
 *   as defined in 47 CFR 15.119. If @c TRUE the resulting page will
 
872
 *   be 34 columns wide, otherwise 32 columns. The height is always 15
 
873
 *   rows.
 
874
 *
 
875
 * This function stores the current display state of the given caption
 
876
 * channel in the @a pg structure. (There is no channel switch
 
877
 * function; all channels are decoded simultaneously.)
 
878
 *
 
879
 * All fields of @a pg will be initialized but the @a vbi, @a nuid, @a
 
880
 * dirty, @a nav_link, @a nav_index, and @a font fields will not
 
881
 * contain useful information.
 
882
 *
 
883
 * @returns
 
884
 * @c FALSE on failure: The channel number is out of bounds.
 
885
 */
 
886
vbi_bool
 
887
_vbi_cc608_decoder_get_page     (_vbi_cc608_decoder *   cd,
 
888
                                 vbi_page *             pg,
 
889
                                 vbi_pgno               channel,
 
890
                                 vbi_bool               padding)
 
891
{
 
892
        static const vbi_rgba default_color_map [3 * 8] = {
 
893
                0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF,
 
894
                0xFFFF0000, 0xFFFF00FF, 0xFFFFFF00, 0xFFFFFFFF,
 
895
 
 
896
                0x80000000, 0x800000FF, 0x8000FF00, 0x8000FFFF,
 
897
                0x80FF0000, 0x80FF00FF, 0x80FFFF00, 0x80FFFFFF,
 
898
 
 
899
                0x00000000, 0x000000FF, 0x0000FF00, 0x0000FFFF,
 
900
                0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x00FFFFFF,
 
901
        };
 
902
        vbi_char *cp;
 
903
        struct channel *ch;
 
904
        unsigned int row;
 
905
        vbi_bool to_upper;
 
906
 
 
907
        assert (NULL != cd);
 
908
        assert (NULL != pg);
 
909
 
 
910
        if (channel < VBI_CAPTION_CC1 || channel > VBI_CAPTION_T4)
 
911
                return FALSE;
 
912
 
 
913
        ch = &cd->channel[channel - VBI_CAPTION_CC1];
 
914
 
 
915
        CLEAR (*pg);
 
916
 
 
917
        pg->pgno = channel;
 
918
 
 
919
        pg->rows = MAX_ROWS;
 
920
 
 
921
        if (padding)
 
922
                pg->columns = MAX_COLUMNS + 2;
 
923
        else
 
924
                pg->columns = MAX_COLUMNS;
 
925
 
 
926
        assert (N_ELEMENTS (pg->text) >= MAX_ROWS * (MAX_COLUMNS + 2));
 
927
 
 
928
        pg->dirty.y1 = LAST_ROW;
 
929
 
 
930
        pg->screen_opacity = VBI_TRANSPARENT_SPACE;
 
931
 
 
932
        assert (sizeof (pg->color_map) >= sizeof (default_color_map));
 
933
        memcpy (pg->color_map, default_color_map,
 
934
                sizeof (default_color_map));
 
935
 
 
936
        cp = pg->text;
 
937
 
 
938
        to_upper = (ch->uppercase_predictor > 3);
 
939
 
 
940
        for (row = 0; row < MAX_ROWS; ++row) {
 
941
                format_row (cp, pg->columns,
 
942
                            ch, ch->displayed_buffer,
 
943
                            row, to_upper, padding,
 
944
                            /* alpha */ TRUE);
 
945
 
 
946
                cp += pg->columns;
 
947
        }
 
948
 
 
949
        return TRUE;
 
950
}
 
951
 
 
952
static void
 
953
display_event                   (_vbi_cc608_decoder *   cd,
 
954
                                 struct channel *       ch,
 
955
                                 _vbi_cc608_event_flags flags)
 
956
{
 
957
        vbi_event ev;
 
958
        struct _vbi_event_cc608_page cc608;
 
959
 
 
960
        CLEAR (ev);
 
961
 
 
962
        ev.type = _VBI_EVENT_CC608;
 
963
        ev.ev._cc608 = &cc608;
 
964
        cc608.channel = channel_num (cd, ch);
 
965
        cc608.mode = ch->mode;
 
966
        cc608.flags = flags;
 
967
 
 
968
        _vbi_event_handler_list_send (&cd->handlers, &ev);
 
969
}
 
970
 
 
971
/* This decoder is mainly designed to overlay caption onto live video,
 
972
   but to create transcripts we also offer an event every time a line
 
973
   of caption is complete. The event occurs when certain control codes
 
974
   are received:
 
975
 
 
976
   In POP_ON mode we send the event upon reception of EOC, which swaps
 
977
   the displayed and non-displayed memory.
 
978
 
 
979
   In ROLL_UP and TEXT mode captioners are not expected to display new
 
980
   text by erasing and overwriting a row with PAC, TOx, BS and DER so
 
981
   we do not send an event on reception of these codes. In ROLL_UP
 
982
   mode CR, EDM, EOC, RCL and RDC complete a line: CR moves the cursor
 
983
   to a new row, EDM erases the displayed memory. The remaining codes
 
984
   switch to POP_ON or PAINT_ON mode. In TEXT mode CR and TR are our
 
985
   line completion indicators. CR works as above and TR erases the
 
986
   displayed memory. EDM, EOC, RDC, RCL and RUx have no effect on Text
 
987
   channels according to EIA 608.
 
988
 
 
989
   In PAINT_ON mode RDC never erases the displayed memory and CR has
 
990
   no function. Instead captioners can freely position the cursor and
 
991
   erase or overwrite (parts of) rows with PAC, TOx, BS and DER, or
 
992
   erase all rows with EDM. We send an event on PAC, EDM, EOC, RCL and
 
993
   RUx, provided the characters (including spacing attributes) in the
 
994
   current row changed since the last event: PAC is the only control
 
995
   code which can move the cursor to the left and/or to a new row, and
 
996
   likely to introduce a new line. EOC, RCL and RUx switch to POP_ON
 
997
   or ROLL_UP mode. */
 
998
 
 
999
static void
 
1000
stream_event                    (_vbi_cc608_decoder *   cd,
 
1001
                                 struct channel *       ch,
 
1002
                                 unsigned int           first_row,
 
1003
                                 unsigned int           last_row)
 
1004
{
 
1005
        vbi_event ev;
 
1006
        struct _vbi_event_cc608_stream cc608_stream;
 
1007
        unsigned int row;
 
1008
        vbi_bool to_upper;
 
1009
 
 
1010
        CLEAR (ev);
 
1011
 
 
1012
        ev.type = _VBI_EVENT_CC608_STREAM;
 
1013
        ev.ev._cc608_stream = &cc608_stream;
 
1014
        cc608_stream.capture_time = ch->timestamp_c0.sys;
 
1015
        cc608_stream.pts = ch->timestamp_c0.pts;
 
1016
        cc608_stream.channel = channel_num (cd, ch);
 
1017
        cc608_stream.mode = ch->mode;
 
1018
 
 
1019
        to_upper = (ch->uppercase_predictor > 3);
 
1020
 
 
1021
        for (row = first_row; row <= last_row; ++row) {
 
1022
                unsigned int end;
 
1023
 
 
1024
                format_row (cc608_stream.text,
 
1025
                            N_ELEMENTS (cc608_stream.text),
 
1026
                            ch, ch->displayed_buffer,
 
1027
                            row, to_upper,
 
1028
                            /* padding */ FALSE,
 
1029
                            /* alpha */ FALSE);
 
1030
 
 
1031
                for (end = N_ELEMENTS (cc608_stream.text);
 
1032
                     end > 0; --end) {
 
1033
                        if (VBI_TRANSPARENT_SPACE
 
1034
                            != cc608_stream.text[end - 1].opacity)
 
1035
                                break;
 
1036
                }
 
1037
 
 
1038
                if (0 == end)
 
1039
                        continue;
 
1040
 
 
1041
                _vbi_event_handler_list_send (&cd->handlers, &ev);
 
1042
        }
 
1043
 
 
1044
        timestamp_reset (&ch->timestamp_c0);
 
1045
}
 
1046
 
 
1047
static void
 
1048
put_char                        (_vbi_cc608_decoder *   cd,
 
1049
                                 struct channel *       ch,
 
1050
                                 int                    c,
 
1051
                                 vbi_bool               displayable,
 
1052
                                 vbi_bool               backspace)
 
1053
{
 
1054
        uint16_t *text;
 
1055
        unsigned int curr_buffer;
 
1056
        unsigned int row;
 
1057
        unsigned int column;
 
1058
 
 
1059
        /* 47 CFR Section 15.119 (f)(1), (f)(2), (f)(3). */
 
1060
        curr_buffer = ch->displayed_buffer
 
1061
                ^ (_VBI_CC608_MODE_POP_ON == ch->mode);
 
1062
 
 
1063
        row = ch->curr_row;
 
1064
        column = ch->curr_column;
 
1065
 
 
1066
        if (unlikely (backspace)) {
 
1067
                /* 47 CFR 15.119 (f)(1)(vi), (f)(2)(ii),
 
1068
                   (f)(3)(i). EIA 608-B Section 6.4.2, 7.4. */
 
1069
                if (column > FIRST_COLUMN)
 
1070
                        --column;
 
1071
        } else {
 
1072
                /* 47 CFR 15.119 (f)(1)(v), (f)(1)(vi), (f)(2)(ii),
 
1073
                   (f)(3)(i). EIA 608-B Section 7.4. */
 
1074
                if (column < LAST_COLUMN)
 
1075
                        ch->curr_column = column + 1;
 
1076
        }
 
1077
 
 
1078
        text = &ch->buffer[curr_buffer][row][0];
 
1079
        text[column] = c;
 
1080
 
 
1081
        /* Send a display update event when the displayed buffer of
 
1082
           the current channel changed, but no more than once for each
 
1083
           pair of Closed Caption bytes. */
 
1084
        /* XXX This may not be a visible change, but such cases are
 
1085
           rare and we'd probably need a function almost as complex as
 
1086
           format_row() to find out. */
 
1087
        if (_VBI_CC608_MODE_POP_ON != ch->mode) {
 
1088
                cd->event_pending = ch;
 
1089
        }
 
1090
 
 
1091
        if (likely (displayable)) {
 
1092
                /* EIA 608-B Annex C.7, C.14. */
 
1093
                if (FIRST_COLUMN == column
 
1094
                    || 0 == text[column - 1]) {
 
1095
                        /* Note last_pac may be 0 as well. */
 
1096
                        text[column - 1] = ch->last_pac;
 
1097
                }
 
1098
 
 
1099
                if (c >= 'a' && c <= 'z') {
 
1100
                        ch->uppercase_predictor = 0;
 
1101
                } else if (c >= 'A' && c <= 'Z') {
 
1102
                        unsigned int up;
 
1103
 
 
1104
                        up = ch->uppercase_predictor + 1;
 
1105
                        if (up > 0)
 
1106
                                ch->uppercase_predictor = up;
 
1107
                }
 
1108
        } else if (unlikely (0 == c)) {
 
1109
                unsigned int i;
 
1110
 
 
1111
                /* This is special character "transparent space". */
 
1112
 
 
1113
                for (i = FIRST_COLUMN; i <= LAST_COLUMN; ++i)
 
1114
                        c |= ch->buffer[curr_buffer][row][i];
 
1115
 
 
1116
                ch->dirty[curr_buffer] &= ~((0 == c) << row);
 
1117
 
 
1118
                return;
 
1119
        } else {
 
1120
                /* This is a spacing attribute. */
 
1121
 
 
1122
                /* EIA 608-B Annex C.7, C.14. */
 
1123
                if (FIRST_COLUMN == column
 
1124
                    || 0 == text[column - 1]) {
 
1125
                        /* Note last_pac may be 0 as well. */
 
1126
                        text[column - 1] = ch->last_pac;
 
1127
                }
 
1128
        }
 
1129
 
 
1130
        assert (sizeof (ch->dirty[0]) * 8 - 1 >= MAX_ROWS);
 
1131
        ch->dirty[curr_buffer] |= 1 << row;
 
1132
 
 
1133
        if (!timestamp_is_set (&ch->timestamp_c0)) {
 
1134
                ch->timestamp_c0 = cd->timestamp;
 
1135
        }
 
1136
}
 
1137
 
 
1138
static void
 
1139
ext_control_code                (_vbi_cc608_decoder *   cd,
 
1140
                                 struct channel *       ch,
 
1141
                                 unsigned int           c2)
 
1142
{
 
1143
        unsigned int column;
 
1144
 
 
1145
        switch (c2) {
 
1146
        case 0x21: /* TO1 */
 
1147
        case 0x22: /* TO2 */
 
1148
        case 0x23: /* TO3 Tab Offset -- 001 c111  010 00xx */
 
1149
                /* 47 CFR 15.119 (e)(1)(ii). EIA 608-B Section 7.4,
 
1150
                   Annex C.7. */
 
1151
                column = ch->curr_column + (c2 & 3);
 
1152
                ch->curr_column = MIN (column,
 
1153
                                       (unsigned int) LAST_COLUMN);
 
1154
                break;
 
1155
 
 
1156
        case 0x24: /* Select standard character set in normal size */
 
1157
        case 0x25: /* Select standard character set in double size */
 
1158
        case 0x26: /* Select first private character set */
 
1159
        case 0x27: /* Select second private character set */
 
1160
        case 0x28: /* Select character set GB 2312-80 (Chinese) */
 
1161
        case 0x29: /* Select character set KSC 5601-1987 (Korean) */
 
1162
        case 0x2A: /* Select first registered character set. */
 
1163
                /* EIA 608-B Section 6.3 Closed Group Extensions. */
 
1164
                break;
 
1165
 
 
1166
        case 0x2D: /* BT Background Transparent -- 001 c111  010 1101 */
 
1167
        case 0x2E: /* FA Foreground Black -- 001 c111  010 1110 */
 
1168
        case 0x2F: /* FAU Foregr. Black Underl. -- 001 c111  010 1111 */
 
1169
                /* EIA 608-B Section 6.2. */
 
1170
                put_char (cd, ch, 0x1700 | c2,
 
1171
                          /* displayable */ FALSE,
 
1172
                          /* backspace */ TRUE);
 
1173
                break;
 
1174
 
 
1175
        default:
 
1176
                /* 47 CFR Section 15.119 (j): Ignore. */
 
1177
                break;
 
1178
        }
 
1179
}
 
1180
 
 
1181
/* Send a stream event if the current row has changed since the last
 
1182
   stream event. This is necessary in paint-on mode where CR has no
 
1183
   function and captioners can freely position the cursor to erase or
 
1184
   overwrite (parts of) rows. */
 
1185
static void
 
1186
stream_event_if_changed         (_vbi_cc608_decoder *   cd,
 
1187
                                 struct channel *       ch)
 
1188
{
 
1189
        unsigned int curr_buffer;
 
1190
        unsigned int row;
 
1191
        unsigned int i;
 
1192
 
 
1193
        curr_buffer = ch->displayed_buffer;
 
1194
        row = ch->curr_row;
 
1195
 
 
1196
        if (0 == (ch->dirty[curr_buffer] & (1 << row)))
 
1197
                return;
 
1198
 
 
1199
        for (i = FIRST_COLUMN; i <= LAST_COLUMN; ++i) {
 
1200
                unsigned int c1;
 
1201
                unsigned int c2;
 
1202
 
 
1203
                c1 = ch->buffer[curr_buffer][row][i];
 
1204
                if (c1 >= 0x1040) {
 
1205
                        if (c1 < 0x1120) {
 
1206
                                c1 = 0; /* PAC -- non-spacing */
 
1207
                        } else if (c1 < 0x1130 || c1 >= 0x1428) {
 
1208
                                /* MR, FON, BT, FA, FAU -- spacing */
 
1209
                                c1 = 0x20;
 
1210
                        }
 
1211
                }
 
1212
 
 
1213
                c2 = ch->buffer[2][row][i];
 
1214
                if (c2 >= 0x1040) {
 
1215
                        if (c2 < 0x1120) {
 
1216
                                c2 = 0;
 
1217
                        } else if (c2 < 0x1130 || c2 >= 0x1428) {
 
1218
                                c1 = 0x20;
 
1219
                        }
 
1220
                }
 
1221
 
 
1222
                if (c1 != c2) {
 
1223
                        stream_event (cd, ch, row, row);
 
1224
 
 
1225
                        memcpy (ch->buffer[2][row],
 
1226
                                ch->buffer[curr_buffer][row],
 
1227
                                sizeof (ch->buffer[0][0]));
 
1228
 
 
1229
                        ch->dirty[2] = ch->dirty[curr_buffer];
 
1230
 
 
1231
                        return;
 
1232
                }
 
1233
        }
 
1234
}
 
1235
 
 
1236
static void
 
1237
end_of_caption                  (_vbi_cc608_decoder *   cd,
 
1238
                                 struct channel *       ch)
 
1239
{
 
1240
        unsigned int curr_buffer;
 
1241
        unsigned int row;
 
1242
 
 
1243
        /* EOC End Of Caption -- 001 c10f  010 1111 */
 
1244
 
 
1245
        curr_buffer = ch->displayed_buffer;
 
1246
 
 
1247
        switch (ch->mode) {
 
1248
        case _VBI_CC608_MODE_UNKNOWN:
 
1249
        case _VBI_CC608_MODE_POP_ON:
 
1250
                break;
 
1251
 
 
1252
        case _VBI_CC608_MODE_ROLL_UP:
 
1253
                row = ch->curr_row;
 
1254
                if (0 != (ch->dirty[curr_buffer] & (1 << row)))
 
1255
                        stream_event (cd, ch, row, row);
 
1256
                break;
 
1257
 
 
1258
        case _VBI_CC608_MODE_PAINT_ON:
 
1259
                stream_event_if_changed (cd, ch);
 
1260
                break;
 
1261
 
 
1262
        case _VBI_CC608_MODE_TEXT:
 
1263
                /* Not reached. (ch is a caption channel.) */
 
1264
                return;
 
1265
        }
 
1266
 
 
1267
        ch->displayed_buffer = curr_buffer ^= 1;
 
1268
 
 
1269
        /* 47 CFR Section 15.119 (f)(2). */
 
1270
        ch->mode = _VBI_CC608_MODE_POP_ON;
 
1271
 
 
1272
        if (0 != ch->dirty[curr_buffer]) {
 
1273
                ch->timestamp_c0 = cd->timestamp;
 
1274
 
 
1275
                stream_event (cd, ch,
 
1276
                              FIRST_ROW,
 
1277
                              LAST_ROW);
 
1278
 
 
1279
                display_event (cd, ch, /* flags */ 0);
 
1280
        }
 
1281
}
 
1282
 
 
1283
static void
 
1284
carriage_return                 (_vbi_cc608_decoder *   cd,
 
1285
                                 struct channel *       ch)
 
1286
{
 
1287
        unsigned int curr_buffer;
 
1288
        unsigned int row;
 
1289
        unsigned int window_rows;
 
1290
        unsigned int first_row;
 
1291
 
 
1292
        /* CR Carriage Return -- 001 c10f  010 1101 */
 
1293
 
 
1294
        curr_buffer = ch->displayed_buffer;
 
1295
        row = ch->curr_row;
 
1296
 
 
1297
        switch (ch->mode) {
 
1298
        case _VBI_CC608_MODE_UNKNOWN:
 
1299
                return;
 
1300
 
 
1301
        case _VBI_CC608_MODE_ROLL_UP:
 
1302
                /* 47 CFR Section 15.119 (f)(1)(iii). */
 
1303
                ch->curr_column = FIRST_COLUMN;
 
1304
 
 
1305
                /* 47 CFR 15.119 (f)(1): "The cursor always remains on
 
1306
                   the base row." */
 
1307
 
 
1308
                /* XXX Spec? */
 
1309
                ch->last_pac = 0;
 
1310
 
 
1311
                /* No event if the buffer contains only
 
1312
                   TRANSPARENT_SPACEs. */
 
1313
                if (0 == ch->dirty[curr_buffer])
 
1314
                        return;
 
1315
 
 
1316
                window_rows = MIN (row + 1 - FIRST_ROW,
 
1317
                                   ch->window_rows);
 
1318
                break;
 
1319
 
 
1320
        case _VBI_CC608_MODE_POP_ON:
 
1321
        case _VBI_CC608_MODE_PAINT_ON:
 
1322
                /* 47 CFR 15.119 (f)(2)(i), (f)(3)(i): No effect. */
 
1323
                return;
 
1324
 
 
1325
        case _VBI_CC608_MODE_TEXT:
 
1326
                /* 47 CFR Section 15.119 (f)(1)(iii). */
 
1327
                ch->curr_column = FIRST_COLUMN;
 
1328
 
 
1329
                /* XXX Spec? */
 
1330
                ch->last_pac = 0;
 
1331
 
 
1332
                /* EIA 608-B Section 7.4: "When Text Mode has
 
1333
                   initially been selected and the specified Text
 
1334
                   memory is empty, the cursor starts at the topmost
 
1335
                   row, Column 1, and moves down to Column 1 on the
 
1336
                   next row each time a Carriage Return is received
 
1337
                   until the last available row is reached. A variety
 
1338
                   of methods may be used to accomplish the scrolling,
 
1339
                   provided that the text is legible while moving. For
 
1340
                   example, as soon as all of the available rows of
 
1341
                   text are on the screen, Text Mode switches to the
 
1342
                   standard roll-up type of presentation." */
 
1343
 
 
1344
                if (LAST_ROW != row) {
 
1345
                        if (0 != (ch->dirty[curr_buffer] & (1 << row))) {
 
1346
                                stream_event (cd, ch, row, row);
 
1347
                        }
 
1348
 
 
1349
                        ch->curr_row = row + 1;
 
1350
 
 
1351
                        return;
 
1352
                }
 
1353
 
 
1354
                /* No event if the buffer contains all
 
1355
                   TRANSPARENT_SPACEs. */
 
1356
                if (0 == ch->dirty[curr_buffer])
 
1357
                        return;
 
1358
 
 
1359
                window_rows = MAX_ROWS;
 
1360
 
 
1361
                break;
 
1362
        }
 
1363
 
 
1364
        /* 47 CFR Section 15.119 (f)(1)(iii). */
 
1365
 
 
1366
        if (0 != (ch->dirty[curr_buffer] & (1 << row))) {
 
1367
                stream_event (cd, ch, row, row);
 
1368
        }
 
1369
 
 
1370
        first_row = row + 1 - window_rows;
 
1371
        memmove (ch->buffer[curr_buffer][first_row],
 
1372
                 ch->buffer[curr_buffer][first_row + 1],
 
1373
                 (window_rows - 1) * sizeof (ch->buffer[0][0]));
 
1374
 
 
1375
        ch->dirty[curr_buffer] >>= 1;
 
1376
 
 
1377
        memset (ch->buffer[curr_buffer][row], 0,
 
1378
                sizeof (ch->buffer[0][0]));
 
1379
 
 
1380
        /* See the description of VBI_CC608_START_ROLLING and
 
1381
           test/caption for the expected effect. */
 
1382
        display_event (cd, ch, _VBI_CC608_START_ROLLING);
 
1383
}
 
1384
 
 
1385
static void
 
1386
erase_memory                    (_vbi_cc608_decoder *   cd,
 
1387
                                 struct channel *       ch,
 
1388
                                 unsigned int           buffer)
 
1389
{
 
1390
        if (0 != ch->dirty[buffer]) {
 
1391
                CLEAR (ch->buffer[buffer]);
 
1392
 
 
1393
                ch->dirty[buffer] = 0;
 
1394
 
 
1395
                if (buffer == ch->displayed_buffer)
 
1396
                        display_event (cd, ch, /* flags */ 0);
 
1397
        }
 
1398
}
 
1399
 
 
1400
static void
 
1401
erase_displayed_memory          (_vbi_cc608_decoder *   cd,
 
1402
                                 struct channel *       ch)
 
1403
{
 
1404
        unsigned int row;
 
1405
 
 
1406
        /* EDM Erase Displayed Memory -- 001 c10f  010 1100 */
 
1407
 
 
1408
        switch (ch->mode) {
 
1409
        case _VBI_CC608_MODE_UNKNOWN:
 
1410
                /* We have not received EOC, RCL, RDC or RUx yet, but
 
1411
                   ch is valid. */
 
1412
                break;
 
1413
 
 
1414
        case _VBI_CC608_MODE_ROLL_UP:
 
1415
                row = ch->curr_row;
 
1416
                if (0 != (ch->dirty[ch->displayed_buffer] & (1 << row)))
 
1417
                        stream_event (cd, ch, row, row);
 
1418
                break;
 
1419
 
 
1420
        case _VBI_CC608_MODE_PAINT_ON:
 
1421
                stream_event_if_changed (cd, ch);
 
1422
                break;
 
1423
 
 
1424
        case _VBI_CC608_MODE_POP_ON:
 
1425
                /* Nothing to do. */
 
1426
                break;
 
1427
 
 
1428
        case _VBI_CC608_MODE_TEXT:
 
1429
                /* Not reached. (ch is a caption channel.) */
 
1430
                return;
 
1431
        }
 
1432
 
 
1433
        /* May send a display event. */
 
1434
        erase_memory (cd, ch, ch->displayed_buffer);
 
1435
}
 
1436
 
 
1437
static void
 
1438
text_restart                    (_vbi_cc608_decoder *   cd,
 
1439
                                 struct channel *       ch)
 
1440
{
 
1441
        unsigned int curr_buffer;
 
1442
        unsigned int row;
 
1443
 
 
1444
        /* TR Text Restart -- 001 c10f  010 1010 */
 
1445
 
 
1446
        curr_buffer = ch->displayed_buffer;
 
1447
        row = ch->curr_row;
 
1448
 
 
1449
        /* ch->mode is invariably VBI_CC608_MODE_TEXT. */
 
1450
 
 
1451
        if (0 != (ch->dirty[curr_buffer] & (1 << row))) {
 
1452
                stream_event (cd, ch, row, row);
 
1453
        }
 
1454
 
 
1455
        /* EIA 608-B Section 7.4. */
 
1456
        /* May send a display event. */
 
1457
        erase_memory (cd, ch, ch->displayed_buffer);
 
1458
 
 
1459
        /* EIA 608-B Section 7.4. */
 
1460
        ch->curr_row = FIRST_ROW;
 
1461
        ch->curr_column = FIRST_COLUMN;
 
1462
}
 
1463
 
 
1464
static void
 
1465
resume_direct_captioning        (_vbi_cc608_decoder *   cd,
 
1466
                                 struct channel *       ch)
 
1467
{
 
1468
        unsigned int curr_buffer;
 
1469
        unsigned int row;
 
1470
 
 
1471
        /* RDC Resume Direct Captioning -- 001 c10f  010 1001 */
 
1472
 
 
1473
        /* 47 CFR 15.119 (f)(1)(x), (f)(2)(vi) and EIA 608-B Annex
 
1474
           B.7: Does not erase memory, does not move the cursor when
 
1475
           resuming after a Text transmission.
 
1476
 
 
1477
           XXX If ch->mode is unknown, roll-up or pop-on, what is
 
1478
           expected if no PAC is received between RDC and the text? */
 
1479
 
 
1480
        curr_buffer = ch->displayed_buffer;
 
1481
        row = ch->curr_row;
 
1482
 
 
1483
        switch (ch->mode) {
 
1484
        case _VBI_CC608_MODE_ROLL_UP:
 
1485
                if (0 != (ch->dirty[curr_buffer] & (1 << row)))
 
1486
                        stream_event (cd, ch, row, row);
 
1487
 
 
1488
                /* fall through */
 
1489
 
 
1490
        case _VBI_CC608_MODE_UNKNOWN:
 
1491
        case _VBI_CC608_MODE_POP_ON:
 
1492
                /* No change since last stream_event(). */
 
1493
                memcpy (ch->buffer[2], ch->buffer[curr_buffer],
 
1494
                        sizeof (ch->buffer[2]));
 
1495
                break;
 
1496
 
 
1497
        case _VBI_CC608_MODE_PAINT_ON:
 
1498
                /* Mode continues. */
 
1499
                break;
 
1500
 
 
1501
        case _VBI_CC608_MODE_TEXT:
 
1502
                /* Not reached. (ch is a caption channel.) */
 
1503
                return;
 
1504
        }
 
1505
 
 
1506
        ch->mode = _VBI_CC608_MODE_PAINT_ON;
 
1507
}
 
1508
 
 
1509
static void
 
1510
resize_window                   (_vbi_cc608_decoder *   cd,
 
1511
                                 struct channel *       ch,
 
1512
                                 unsigned int           new_rows)
 
1513
{
 
1514
        unsigned int curr_buffer;
 
1515
        unsigned int max_rows;
 
1516
        unsigned int old_rows;
 
1517
        unsigned int row1;
 
1518
 
 
1519
        curr_buffer = ch->displayed_buffer;
 
1520
 
 
1521
        /* Shortcut. */
 
1522
        if (0 == ch->dirty[curr_buffer])
 
1523
                return;
 
1524
 
 
1525
        row1 = ch->curr_row + 1;
 
1526
        max_rows = row1 - FIRST_ROW;
 
1527
        old_rows = MIN (ch->window_rows, max_rows);
 
1528
        new_rows = MIN (new_rows, max_rows);
 
1529
 
 
1530
        /* Nothing to do unless the window shrinks. */
 
1531
        if (0 == new_rows || new_rows >= old_rows)
 
1532
                return;
 
1533
 
 
1534
        memset (&ch->buffer[curr_buffer][row1 - old_rows][0], 0,
 
1535
                (old_rows - new_rows)
 
1536
                * sizeof (ch->buffer[0][0]));
 
1537
 
 
1538
        ch->dirty[curr_buffer] &= -1 << (row1 - new_rows);
 
1539
 
 
1540
        display_event (cd, ch, /* flags */ 0);
 
1541
}
 
1542
 
 
1543
static void
 
1544
roll_up_caption                 (_vbi_cc608_decoder *   cd,
 
1545
                                 struct channel *       ch,
 
1546
                                 unsigned int           c2)
 
1547
{
 
1548
        unsigned int window_rows;
 
1549
 
 
1550
        /* Roll-Up Captions -- 001 c10f  010 01xx */
 
1551
 
 
1552
        window_rows = (c2 & 7) - 3; /* 2, 3, 4 */
 
1553
 
 
1554
        switch (ch->mode) {
 
1555
        case _VBI_CC608_MODE_ROLL_UP:
 
1556
                /* 47 CFR 15.119 (f)(1)(iv). */
 
1557
                /* May send a display event. */
 
1558
                resize_window (cd, ch, window_rows);
 
1559
 
 
1560
                /* fall through */
 
1561
 
 
1562
        case _VBI_CC608_MODE_UNKNOWN:
 
1563
                ch->mode = _VBI_CC608_MODE_ROLL_UP;
 
1564
                ch->window_rows = window_rows;
 
1565
 
 
1566
                /* 47 CFR 15.119 (f)(1)(ix): No cursor movements,
 
1567
                   no memory erasing. */
 
1568
 
 
1569
                break;
 
1570
 
 
1571
        case _VBI_CC608_MODE_PAINT_ON:
 
1572
                stream_event_if_changed (cd, ch);
 
1573
 
 
1574
                /* fall through */
 
1575
 
 
1576
        case _VBI_CC608_MODE_POP_ON:
 
1577
                ch->mode = _VBI_CC608_MODE_ROLL_UP;
 
1578
                ch->window_rows = window_rows;
 
1579
 
 
1580
                /* 47 CFR 15.119 (f)(1)(ii). */
 
1581
                ch->curr_row = LAST_ROW;
 
1582
                ch->curr_column = FIRST_COLUMN;
 
1583
 
 
1584
                /* 47 CFR 15.119 (f)(1)(x). */
 
1585
                /* May send a display event. */
 
1586
                erase_memory (cd, ch, ch->displayed_buffer);
 
1587
                erase_memory (cd, ch, ch->displayed_buffer ^ 1);
 
1588
 
 
1589
                break;
 
1590
 
 
1591
        case _VBI_CC608_MODE_TEXT:
 
1592
                /* Not reached. (ch is a caption channel.) */
 
1593
                return;
 
1594
        }
 
1595
}
 
1596
 
 
1597
static void
 
1598
delete_to_end_of_row            (_vbi_cc608_decoder *   cd,
 
1599
                                 struct channel *       ch)
 
1600
{
 
1601
        unsigned int curr_buffer;
 
1602
        unsigned int row;
 
1603
 
 
1604
        /* DER Delete To End Of Row -- 001 c10f  010 0100 */
 
1605
 
 
1606
        /* 47 CFR 15.119 (f)(1)(vii), (f)(2)(iii), (f)(3)(ii) and EIA
 
1607
           608-B Section 7.4: In all caption modes and Text mode
 
1608
           "[the] Delete to End of Row command will erase from memory
 
1609
           any characters or control codes starting at the current
 
1610
           cursor location and in all columns to its right on the same
 
1611
           row." */
 
1612
 
 
1613
        curr_buffer = ch->displayed_buffer
 
1614
                ^ (_VBI_CC608_MODE_POP_ON == ch->mode);
 
1615
 
 
1616
        row = ch->curr_row;
 
1617
 
 
1618
        /* No event if the row contains only TRANSPARENT_SPACEs. */
 
1619
        if (0 != (ch->dirty[curr_buffer] & (1 << row))) {
 
1620
                unsigned int column;
 
1621
                unsigned int i;
 
1622
                uint16_t c;
 
1623
 
 
1624
                column = ch->curr_column;
 
1625
 
 
1626
                memset (&ch->buffer[curr_buffer][row][column], 0,
 
1627
                        (LAST_COLUMN - column + 1)
 
1628
                        * sizeof (ch->buffer[0][0][0]));
 
1629
 
 
1630
                c = 0;
 
1631
                for (i = FIRST_COLUMN; i < column; ++i)
 
1632
                        c |= ch->buffer[curr_buffer][row][i];
 
1633
 
 
1634
                ch->dirty[curr_buffer] &= ~((0 == c) << row);
 
1635
 
 
1636
                display_event (cd, ch, /* flags */ 0);
 
1637
        }
 
1638
}
 
1639
 
 
1640
static void
 
1641
backspace                       (_vbi_cc608_decoder *   cd,
 
1642
                                 struct channel *       ch)
 
1643
{
 
1644
        unsigned int curr_buffer;
 
1645
        unsigned int row;
 
1646
        unsigned int column;
 
1647
 
 
1648
        /* BS Backspace -- 001 c10f  010 0001 */
 
1649
 
 
1650
        /* 47 CFR Section 15.119 (f)(1)(vi), (f)(2)(ii), (f)(3)(i) and
 
1651
           EIA 608-B Section 7.4. */
 
1652
        column = ch->curr_column;
 
1653
        if (column <= FIRST_COLUMN)
 
1654
                return;
 
1655
 
 
1656
        ch->curr_column = --column;
 
1657
 
 
1658
        curr_buffer = ch->displayed_buffer
 
1659
                ^ (_VBI_CC608_MODE_POP_ON == ch->mode);
 
1660
 
 
1661
        row = ch->curr_row;
 
1662
 
 
1663
        /* No event if there's no visible effect. */
 
1664
        if (0 != ch->buffer[curr_buffer][row][column]) {
 
1665
                unsigned int i;
 
1666
                uint16_t c;
 
1667
 
 
1668
                /* 47 CFR 15.119 (f), (f)(1)(vi), (f)(2)(ii) and EIA
 
1669
                   608-B Section 7.4. */
 
1670
                ch->buffer[curr_buffer][row][column] = 0;
 
1671
 
 
1672
                c = 0;
 
1673
                for (i = FIRST_COLUMN; i <= LAST_COLUMN; ++i)
 
1674
                        c |= ch->buffer[curr_buffer][row][i];
 
1675
 
 
1676
                ch->dirty[curr_buffer] &= ~((0 == c) << row);
 
1677
 
 
1678
                display_event (cd, ch, /* flags */ 0);
 
1679
        }
 
1680
}
 
1681
 
 
1682
static void
 
1683
resume_caption_loading          (_vbi_cc608_decoder *   cd,
 
1684
                                 struct channel *       ch)
 
1685
{
 
1686
        unsigned int row;
 
1687
 
 
1688
        /* RCL Resume Caption Loading -- 001 c10f  010 0000 */
 
1689
 
 
1690
        switch (ch->mode) {
 
1691
        case _VBI_CC608_MODE_UNKNOWN:
 
1692
        case _VBI_CC608_MODE_POP_ON:
 
1693
                break;
 
1694
 
 
1695
        case _VBI_CC608_MODE_ROLL_UP:
 
1696
                row = ch->curr_row;
 
1697
                if (0 != (ch->dirty[ch->displayed_buffer] & (1 << row)))
 
1698
                        stream_event (cd, ch, row, row);
 
1699
                break;
 
1700
 
 
1701
        case _VBI_CC608_MODE_PAINT_ON:
 
1702
                stream_event_if_changed (cd, ch);
 
1703
                break;
 
1704
 
 
1705
        case _VBI_CC608_MODE_TEXT:
 
1706
                /* Not reached. (ch is a caption channel.) */
 
1707
                return;
 
1708
        }
 
1709
 
 
1710
        /* 47 CFR 15.119 (f)(1)(x): Does not erase memory.
 
1711
           (f)(2)(iv): Cursor position remains unchanged. */
 
1712
 
 
1713
        ch->mode = _VBI_CC608_MODE_POP_ON;
 
1714
}
 
1715
 
 
1716
/* Note curr_ch is invalid if UNKNOWN_CHANNEL == cd->cc.curr_ch_num. */
 
1717
static struct channel *
 
1718
switch_channel                  (_vbi_cc608_decoder *   cd,
 
1719
                                 struct channel *       curr_ch,
 
1720
                                 vbi_pgno               new_ch_num,
 
1721
                                 enum field_num         f)
 
1722
{
 
1723
        struct channel *new_ch;
 
1724
 
 
1725
        if (UNKNOWN_CHANNEL != cd->curr_ch_num[f]
 
1726
            && _VBI_CC608_MODE_UNKNOWN != curr_ch->mode) {
 
1727
                /* XXX Force a display update if we do not send events
 
1728
                   on every display change. */
 
1729
        }
 
1730
 
 
1731
        cd->curr_ch_num[f] = new_ch_num;
 
1732
        new_ch = &cd->channel[new_ch_num - VBI_CAPTION_CC1];
 
1733
 
 
1734
        return new_ch;
 
1735
}
 
1736
 
 
1737
/* Note ch is invalid if UNKNOWN_CHANNEL == cd->cc.curr_ch_num[f]. */
 
1738
static void
 
1739
misc_control_code               (_vbi_cc608_decoder *   cd,
 
1740
                                 struct channel *       ch,
 
1741
                                 unsigned int           c2,
 
1742
                                 unsigned int           ch_num0,
 
1743
                                 enum field_num         f)
 
1744
{
 
1745
        unsigned int new_ch_num;
 
1746
 
 
1747
        /* Misc Control Codes -- 001 c10f  010 xxxx */
 
1748
 
 
1749
        /* c = channel (0 -> CC1/CC3/T1/T3, 1 -> CC2/CC4/T2/T4)
 
1750
             -- 47 CFR Section 15.119, EIA 608-B Section 7.7.
 
1751
           f = field (0 -> F1, 1 -> F2)
 
1752
             -- EIA 608-B Section 8.4, 8.5. */
 
1753
 
 
1754
        /* XXX The f flag is intended to detect accidential field
 
1755
           swapping and we should use it for that purpose. */
 
1756
 
 
1757
        switch (c2 & 15) {
 
1758
        case 0: /* RCL Resume Caption Loading -- 001 c10f  010 0000 */
 
1759
                /* 47 CFR 15.119 (f)(2) and EIA 608-B Section 7.7. */
 
1760
                new_ch_num = VBI_CAPTION_CC1 + (ch_num0 & 3);
 
1761
                ch = switch_channel (cd, ch, new_ch_num, f);
 
1762
                resume_caption_loading (cd, ch);
 
1763
                break;
 
1764
 
 
1765
        case 1: /* BS Backspace -- 001 c10f  010 0001 */
 
1766
                if (UNKNOWN_CHANNEL == cd->curr_ch_num[f]
 
1767
                    || _VBI_CC608_MODE_UNKNOWN == ch->mode)
 
1768
                        break;
 
1769
                backspace (cd, ch);
 
1770
                break;
 
1771
 
 
1772
        case 2: /* reserved (formerly AOF Alarm Off) */
 
1773
        case 3: /* reserved (formerly AON Alarm On) */
 
1774
                break;
 
1775
 
 
1776
        case 4: /* DER Delete To End Of Row -- 001 c10f  010 0100 */
 
1777
                if (UNKNOWN_CHANNEL == cd->curr_ch_num[f]
 
1778
                    || _VBI_CC608_MODE_UNKNOWN == ch->mode)
 
1779
                        break;
 
1780
                delete_to_end_of_row (cd, ch);
 
1781
                break;
 
1782
 
 
1783
        case 5: /* RU2 */
 
1784
        case 6: /* RU3 */
 
1785
        case 7: /* RU4 Roll-Up Captions -- 001 c10f  010 01xx */
 
1786
                /* 47 CFR 15.119 (f)(1) and EIA 608-B Section 7.7. */
 
1787
                new_ch_num = VBI_CAPTION_CC1 + (ch_num0 & 3);
 
1788
                ch = switch_channel (cd, ch, new_ch_num, f);
 
1789
                roll_up_caption (cd, ch, c2);
 
1790
                break;
 
1791
 
 
1792
        case 8: /* FON Flash On -- 001 c10f  010 1000 */
 
1793
                if (UNKNOWN_CHANNEL == cd->curr_ch_num[f]
 
1794
                    || _VBI_CC608_MODE_UNKNOWN == ch->mode)
 
1795
                        break;
 
1796
 
 
1797
                /* 47 CFR 15.119 (h)(1)(i): Spacing attribute. */
 
1798
                put_char (cd, ch, 0x1428,
 
1799
                          /* displayable */ FALSE,
 
1800
                          /* backspace */ FALSE);
 
1801
                break;
 
1802
 
 
1803
        case 9: /* RDC Resume Direct Captioning -- 001 c10f  010 1001 */
 
1804
                /* 47 CFR 15.119 (f)(3) and EIA 608-B Section 7.7. */
 
1805
                new_ch_num = VBI_CAPTION_CC1 + (ch_num0 & 3);
 
1806
                ch = switch_channel (cd, ch, new_ch_num, f);
 
1807
                resume_direct_captioning (cd, ch);
 
1808
                break;
 
1809
 
 
1810
        case 10: /* TR Text Restart -- 001 c10f  010 1010 */
 
1811
                /* EIA 608-B Section 7.4. */
 
1812
                new_ch_num = VBI_CAPTION_T1 + (ch_num0 & 3);
 
1813
                ch = switch_channel (cd, ch, new_ch_num, f);
 
1814
                text_restart (cd, ch);
 
1815
                break;
 
1816
 
 
1817
        case 11: /* RTD Resume Text Display -- 001 c10f  010 1011 */
 
1818
                /* EIA 608-B Section 7.4. */
 
1819
                new_ch_num = VBI_CAPTION_T1 + (ch_num0 & 3);
 
1820
                ch = switch_channel (cd, ch, new_ch_num, f);
 
1821
                /* ch->mode is invariably VBI_CC608_MODE_TEXT. */
 
1822
                break;
 
1823
 
 
1824
        case 12: /* EDM Erase Displayed Memory -- 001 c10f  010 1100 */
 
1825
                /* 47 CFR 15.119 (f). EIA 608-B Section 7.7 and Annex
 
1826
                   B.7: "[The] command shall be acted upon as
 
1827
                   appropriate for caption processing without
 
1828
                   terminating the Text Mode data stream." */
 
1829
 
 
1830
                /* We need not check cd->curr_ch_num because bit 2 is
 
1831
                   implied, bit 1 is the known field number and bit 0
 
1832
                   is coded in the control code. */
 
1833
                ch = &cd->channel[ch_num0 & 3];
 
1834
 
 
1835
                erase_displayed_memory (cd, ch);
 
1836
 
 
1837
                break;
 
1838
 
 
1839
        case 13: /* CR Carriage Return -- 001 c10f  010 1101 */
 
1840
                if (UNKNOWN_CHANNEL == cd->curr_ch_num[f])
 
1841
                        break;
 
1842
                carriage_return (cd, ch);
 
1843
                break;
 
1844
 
 
1845
        case 14: /* ENM Erase Non-Displayed Memory -- 001 c10f  010 1110 */
 
1846
                /* 47 CFR 15.119 (f)(2)(v). EIA 608-B Section 7.7 and
 
1847
                   Annex B.7: "[The] command shall be acted upon as
 
1848
                   appropriate for caption processing without
 
1849
                   terminating the Text Mode data stream." */
 
1850
 
 
1851
                /* See EDM. */
 
1852
                ch = &cd->channel[ch_num0 & 3];
 
1853
 
 
1854
                erase_memory (cd, ch, ch->displayed_buffer ^ 1);
 
1855
 
 
1856
                break;
 
1857
 
 
1858
        case 15: /* EOC End Of Caption -- 001 c10f  010 1111 */
 
1859
                /* 47 CFR 15.119 (f), (f)(2), (f)(3)(iv) and EIA 608-B
 
1860
                   Section 7.7, Annex C.11. */
 
1861
                new_ch_num = VBI_CAPTION_CC1 + (ch_num0 & 3);
 
1862
                ch = switch_channel (cd, ch, new_ch_num, f);
 
1863
                end_of_caption (cd, ch);
 
1864
                break;
 
1865
        }
 
1866
}
 
1867
 
 
1868
static void
 
1869
move_window                     (_vbi_cc608_decoder *   cd,
 
1870
                                 struct channel *       ch,
 
1871
                                 unsigned int           new_base_row)
 
1872
{
 
1873
        uint8_t *base;
 
1874
        unsigned int curr_buffer;
 
1875
        unsigned int bytes_per_row;
 
1876
        unsigned int old_max_rows;
 
1877
        unsigned int new_max_rows;
 
1878
        unsigned int copy_bytes;
 
1879
        unsigned int erase_begin;
 
1880
        unsigned int erase_end;
 
1881
 
 
1882
        curr_buffer = ch->displayed_buffer;
 
1883
 
 
1884
        /* Shortcut and no event if we do not move the window or the
 
1885
           buffer contains only TRANSPARENT_SPACEs. */
 
1886
        if (new_base_row == ch->curr_row
 
1887
            || 0 == ch->dirty[curr_buffer])
 
1888
                return;
 
1889
 
 
1890
        base = (void *) &ch->buffer[curr_buffer][FIRST_ROW][0];
 
1891
        bytes_per_row = sizeof (ch->buffer[0][0]);
 
1892
 
 
1893
        old_max_rows = ch->curr_row + 1 - FIRST_ROW;
 
1894
        new_max_rows = new_base_row + 1 - FIRST_ROW;
 
1895
        copy_bytes = MIN (MIN (old_max_rows, new_max_rows),
 
1896
                          ch->window_rows) * bytes_per_row;
 
1897
 
 
1898
        if (new_base_row < ch->curr_row) {
 
1899
                erase_begin = (new_base_row + 1) * bytes_per_row;
 
1900
                erase_end = (ch->curr_row + 1) * bytes_per_row;
 
1901
 
 
1902
                memmove (base + erase_begin - copy_bytes,
 
1903
                         base + erase_end - copy_bytes, copy_bytes);
 
1904
 
 
1905
                ch->dirty[curr_buffer] >>= ch->curr_row - new_base_row;
 
1906
        } else {
 
1907
                erase_begin = (ch->curr_row + 1) * bytes_per_row
 
1908
                        - copy_bytes;
 
1909
                erase_end = (new_base_row + 1) * bytes_per_row
 
1910
                        - copy_bytes;
 
1911
 
 
1912
                memmove (base + erase_end,
 
1913
                         base + erase_begin, copy_bytes);
 
1914
 
 
1915
                ch->dirty[curr_buffer] <<= new_base_row - ch->curr_row;
 
1916
                ch->dirty[curr_buffer] &= ALL_ROWS_MASK;
 
1917
        }
 
1918
 
 
1919
        memset (base + erase_begin, 0, erase_end - erase_begin);
 
1920
 
 
1921
        display_event (cd, ch, /* flags */ 0);
 
1922
}
 
1923
 
 
1924
static void
 
1925
preamble_address_code           (_vbi_cc608_decoder *   cd,
 
1926
                                 struct channel *       ch,
 
1927
                                 unsigned int           c1,
 
1928
                                 unsigned int           c2)
 
1929
{
 
1930
        unsigned int row;
 
1931
 
 
1932
        /* PAC Preamble Address Codes -- 001 crrr  1ri xxxu */
 
1933
 
 
1934
        row = pac_row_map[(c1 & 7) * 2 + ((c2 >> 5) & 1)];
 
1935
        if ((int) row < 0)
 
1936
                return;
 
1937
 
 
1938
        switch (ch->mode) {
 
1939
        case _VBI_CC608_MODE_UNKNOWN:
 
1940
                return;
 
1941
 
 
1942
        case _VBI_CC608_MODE_ROLL_UP:
 
1943
                /* EIA 608-B Annex C.4. */
 
1944
                if (ch->window_rows > row + 1)
 
1945
                        row = ch->window_rows - 1;
 
1946
 
 
1947
                /* 47 CFR Section 15.119 (f)(1)(ii). */
 
1948
                /* May send a display event. */
 
1949
                move_window (cd, ch, row);
 
1950
 
 
1951
                ch->curr_row = row;
 
1952
 
 
1953
                break;
 
1954
 
 
1955
        case _VBI_CC608_MODE_PAINT_ON:
 
1956
                stream_event_if_changed (cd, ch);
 
1957
 
 
1958
                /* fall through */
 
1959
 
 
1960
        case _VBI_CC608_MODE_POP_ON:
 
1961
                /* XXX 47 CFR 15.119 (f)(2)(i), (f)(3)(i): In Pop-on
 
1962
                   and paint-on mode "Preamble Address Codes can be
 
1963
                   used to move the cursor around the screen in random
 
1964
                   order to place captions on Rows 1 to 15." We do not
 
1965
                   have a limit on the number of displayable rows, but
 
1966
                   as EIA 608-B Annex C.6 points out, if more than
 
1967
                   four rows must be displayed they were probably
 
1968
                   received in error and we should respond
 
1969
                   accordingly. */
 
1970
 
 
1971
                /* 47 CFR Section 15.119 (d)(1)(i) and EIA 608-B Annex
 
1972
                   C.7. */
 
1973
                ch->curr_row = row;
 
1974
 
 
1975
                break;
 
1976
 
 
1977
        case _VBI_CC608_MODE_TEXT:
 
1978
                /* 47 CFR 15.119 (e)(1) and EIA 608-B Section 7.4:
 
1979
                   Does not change the cursor row. */
 
1980
                break;
 
1981
        }
 
1982
 
 
1983
        if (c2 & 0x10) {
 
1984
                /* 47 CFR 15.119 (e)(1)(i) and EIA 608-B Table 71. */
 
1985
                ch->curr_column = FIRST_COLUMN + (c2 & 0x0E) * 2;
 
1986
        }
 
1987
 
 
1988
        /* PAC is a non-spacing attribute for the next character, see
 
1989
           put_char(). */
 
1990
        ch->last_pac = 0x1000 | c2;
 
1991
}
 
1992
 
 
1993
static void
 
1994
control_code                    (_vbi_cc608_decoder *   cd,
 
1995
                                 unsigned int           c1,
 
1996
                                 unsigned int           c2,
 
1997
                                 enum field_num         f)
 
1998
{
 
1999
        struct channel *ch;
 
2000
        unsigned int ch_num0;
 
2001
 
 
2002
        if (CC608_DECODER_LOG_INPUT) {
 
2003
                fprintf (stdout, "%s:%u: %s c1=%02x c2=%02x f=%d\n",
 
2004
                         __FILE__, __LINE__, __FUNCTION__,
 
2005
                         c1, c2, f);
 
2006
        }
 
2007
 
 
2008
        /* b2: Caption / text,
 
2009
           b1: field 1 / 2,
 
2010
           b0 (lsb): primary / secondary channel. */
 
2011
        ch_num0 = (((cd->curr_ch_num[f] - VBI_CAPTION_CC1) & 4)
 
2012
                   + f * 2
 
2013
                   + ((c1 >> 3) & 1));
 
2014
 
 
2015
        /* Note ch is invalid if UNKNOWN_CHANNEL ==
 
2016
           cd->curr_ch_num[f]. */
 
2017
        ch = &cd->channel[ch_num0];
 
2018
 
 
2019
        if (c2 >= 0x40) {
 
2020
                /* Preamble Address Codes -- 001 crrr  1ri xxxu */
 
2021
                if (UNKNOWN_CHANNEL != cd->curr_ch_num[f])
 
2022
                        preamble_address_code (cd, ch, c1, c2);
 
2023
                return;
 
2024
        }
 
2025
 
 
2026
        switch (c1 & 7) {
 
2027
        case 0:
 
2028
                if (UNKNOWN_CHANNEL == cd->curr_ch_num[f]
 
2029
                    || _VBI_CC608_MODE_UNKNOWN == ch->mode)
 
2030
                        break;
 
2031
 
 
2032
                if (c2 < 0x30) {
 
2033
                        /* Backgr. Attr. Codes -- 001 c000  010 xxxt */
 
2034
                        /* EIA 608-B Section 6.2. */
 
2035
                        put_char (cd, ch, 0x1000 | c2,
 
2036
                                  /* displayable */ FALSE,
 
2037
                                  /* backspace */ TRUE);
 
2038
                } else {
 
2039
                        /* Undefined. */
 
2040
                }
 
2041
 
 
2042
                break;
 
2043
 
 
2044
        case 1:
 
2045
                if (UNKNOWN_CHANNEL == cd->curr_ch_num[f]
 
2046
                    || _VBI_CC608_MODE_UNKNOWN == ch->mode)
 
2047
                        break;
 
2048
 
 
2049
                if (c2 < 0x30) {
 
2050
                        /* Mid-Row Codes -- 001 c001  010 xxxu */
 
2051
                        /* 47 CFR 15.119 (h)(1)(i): Spacing attribute. */
 
2052
                        put_char (cd, ch, 0x1100 | c2,
 
2053
                                  /* displayable */ FALSE,
 
2054
                                  /* backspace */ FALSE);
 
2055
                } else {
 
2056
                        /* Special Characters -- 001 c001  011 xxxx */
 
2057
                        if (0x39 == c2) {
 
2058
                                /* Transparent space. */
 
2059
                                put_char (cd, ch, 0,
 
2060
                                          /* displayable */ FALSE,
 
2061
                                          /* backspace */ FALSE);
 
2062
                        } else {
 
2063
                                put_char (cd, ch, 0x1100 | c2,
 
2064
                                          /* displayable */ TRUE,
 
2065
                                          /* backspace */ FALSE);
 
2066
                        }
 
2067
                }
 
2068
 
 
2069
                break;
 
2070
 
 
2071
        case 2:
 
2072
        case 3: /* Extended Character Set -- 001 c01x  01x xxxx */
 
2073
                if (UNKNOWN_CHANNEL == cd->curr_ch_num[f]
 
2074
                    || _VBI_CC608_MODE_UNKNOWN == ch->mode)
 
2075
                        break;
 
2076
 
 
2077
                /* EIA 608-B Section 6.4.2. */
 
2078
                put_char (cd, ch, (c1 * 256 + c2) & 0x777F,
 
2079
                          /* displayable */ TRUE,
 
2080
                          /* backspace */ TRUE);
 
2081
                break;
 
2082
 
 
2083
        case 4:
 
2084
        case 5:
 
2085
                if (c2 < 0x30) {
 
2086
                        /* Misc. Control Codes -- 001 c10f  010 xxxx */
 
2087
                        misc_control_code (cd, ch, c2, ch_num0, f);
 
2088
                } else {
 
2089
                        /* Undefined. */
 
2090
                }
 
2091
 
 
2092
                break;
 
2093
 
 
2094
        case 6: /* reserved */
 
2095
                break;
 
2096
 
 
2097
        case 7: /* Extended control codes -- 001 c111  01x xxxx */
 
2098
                if (UNKNOWN_CHANNEL == cd->curr_ch_num[f]
 
2099
                    || _VBI_CC608_MODE_UNKNOWN == ch->mode)
 
2100
                        break;
 
2101
 
 
2102
                ext_control_code (cd, ch, c2);
 
2103
 
 
2104
                break;
 
2105
        }
 
2106
}
 
2107
 
 
2108
static vbi_bool
 
2109
characters                      (_vbi_cc608_decoder *   cd,
 
2110
                                 struct channel *       ch,
 
2111
                                 int                    c)
 
2112
{
 
2113
        if (CC608_DECODER_LOG_INPUT) {
 
2114
                fprintf (stdout, "%s:%u: %s c=0x%02x='%c'\n",
 
2115
                         __FILE__, __LINE__, __FUNCTION__,
 
2116
                         c, _vbi_to_ascii (c));
 
2117
        }
 
2118
 
 
2119
        if (0 == c) {
 
2120
                if (_VBI_CC608_MODE_UNKNOWN == ch->mode)
 
2121
                        return TRUE;
 
2122
 
 
2123
                /* XXX After x NUL characters (presumably a caption
 
2124
                   pause), force a display update if we do not send
 
2125
                   events on every display change. */
 
2126
 
 
2127
                return TRUE;
 
2128
        }
 
2129
 
 
2130
        if (c < 0x20) {
 
2131
                /* Parity error or invalid data. */
 
2132
 
 
2133
                if (c < 0 && _VBI_CC608_MODE_UNKNOWN != ch->mode) {
 
2134
                        /* 47 CFR Section 15.119 (j)(1). */
 
2135
                        put_char (cd, ch, 0x7F,
 
2136
                                  /* displayable */ TRUE,
 
2137
                                  /* backspace */ FALSE);
 
2138
                }
 
2139
 
 
2140
                return FALSE;
 
2141
        }
 
2142
 
 
2143
        if (_VBI_CC608_MODE_UNKNOWN != ch->mode) {
 
2144
                put_char (cd, ch, c,
 
2145
                          /* displayable */ TRUE,
 
2146
                          /* backspace */ FALSE);
 
2147
        }
 
2148
 
 
2149
        return TRUE;
 
2150
}
 
2151
 
 
2152
/**
 
2153
 * @param cd Caption decoder allocated with _vbi_cc608_decoder_new().
 
2154
 * @param buffer A caption byte pair with parity bits.
 
2155
 * @param line ITU-R line number this data originated from,
 
2156
 *   usually 21 or 284.
 
2157
 * @param capture_time System time in seconds when the sliced data was
 
2158
 *   captured.
 
2159
 * @param pts ISO 13818-1 Presentation Time Stamp of the sliced
 
2160
 *   data. @a pts counts 1/90000 seconds from an arbitrary point in the
 
2161
 *   video stream. Only the 33 least significant bits have to be valid.
 
2162
 *   If @a pts is negative the function converts @a capture_time to a
 
2163
 *   PTS.
 
2164
 *
 
2165
 * This function decodes two bytes of Closed Caption data and updates
 
2166
 * the decoder state. It may send one VBI_EVENT_CC608 and one or more
 
2167
 * VBI_EVENT_CC608_STREAM.
 
2168
 *
 
2169
 * @returns
 
2170
 * @c FALSE if the caption byte pair contained errors.
 
2171
 */
 
2172
vbi_bool
 
2173
_vbi_cc608_decoder_feed         (_vbi_cc608_decoder *   cd,
 
2174
                                 const uint8_t          buffer[2],
 
2175
                                 unsigned int           line,
 
2176
                                 double                 capture_time,
 
2177
                                 int64_t                pts)
 
2178
{
 
2179
        int c1, c2;
 
2180
        enum field_num f;
 
2181
        vbi_bool all_successful;
 
2182
 
 
2183
        assert (NULL != cd);
 
2184
 
 
2185
        if (0) {
 
2186
                fprintf (stdout, "%s:%u: %s "
 
2187
                         "buffer={ 0x%02x 0x%02x '%c%c' } "
 
2188
                         "line=%3d capture_time=%f "
 
2189
                         "pts=%" PRId64 "\n",
 
2190
                         __FILE__, __LINE__, __FUNCTION__,
 
2191
                         buffer[0] & 0x7F,
 
2192
                         buffer[1] & 0x7F,
 
2193
                         _vbi_to_ascii (buffer[0]),
 
2194
                         _vbi_to_ascii (buffer[1]),
 
2195
                         line, capture_time, pts);
 
2196
        }
 
2197
 
 
2198
        f = FIELD_1;
 
2199
 
 
2200
        switch (line) {
 
2201
        case 21: /* NTSC */
 
2202
        case 22: /* PAL/SECAM? */
 
2203
                break;
 
2204
 
 
2205
        case 284: /* NTSC */
 
2206
                f = FIELD_2;
 
2207
                break;
 
2208
 
 
2209
        default:
 
2210
                return FALSE;
 
2211
        }
 
2212
 
 
2213
        cd->timestamp.sys = capture_time;
 
2214
 
 
2215
        if (pts < 0)
 
2216
                pts = (int64_t)(capture_time * 90000);
 
2217
 
 
2218
        /* Modulo 1 << 33 guaranteed in VBI_EVENT_CC608_STREAM dox. */
 
2219
        cd->timestamp.pts = pts & (((int64_t) 1 << 33) - 1);
 
2220
 
 
2221
        /* XXX deferred reset here */
 
2222
 
 
2223
        if (0 && FIELD_1 == f) {
 
2224
                _vbi_cc608_dump (stderr, buffer[0], buffer[1]);
 
2225
        }
 
2226
 
 
2227
        c1 = vbi_unpar8 (buffer[0]);
 
2228
        c2 = vbi_unpar8 (buffer[1]);
 
2229
 
 
2230
        all_successful = TRUE;
 
2231
 
 
2232
        /* See 47 CFR 15.119 (2)(i)(4). EIA 608-B Section 8.3: Caption
 
2233
           control codes on field 2 may repeat as on field 1. Section
 
2234
           8.6.2: XDS control codes shall not repeat. */
 
2235
 
 
2236
        if (unlikely (c1 < 0)) {
 
2237
                goto parity_error;
 
2238
        } else if (c1 == cd->expect_ctrl[f][0]
 
2239
                   && c2 == cd->expect_ctrl[f][1]) {
 
2240
                /* Already acted upon. */
 
2241
                cd->expect_ctrl[f][0] = -1;
 
2242
                goto finish;
 
2243
        }
 
2244
 
 
2245
        if (c1 >= 0x10 && c1 < 0x20) {
 
2246
                /* Caption control code. */
 
2247
 
 
2248
                /* There's no XDS on field 1, we just
 
2249
                   use an array to save a branch. */
 
2250
                cd->in_xds[f] = FALSE;
 
2251
 
 
2252
                /* 47 CFR Section 15.119 (i)(1), (i)(2). */
 
2253
                if (c2 < 0x20) {
 
2254
                        /* Parity error or invalid control code.
 
2255
                           Let's hope this code will repeat. */
 
2256
                        goto parity_error;
 
2257
                }
 
2258
 
 
2259
                control_code (cd, c1, c2, f);
 
2260
 
 
2261
                if (cd->event_pending) {
 
2262
                        display_event (cd, cd->event_pending,
 
2263
                                       /* flags */ 0);
 
2264
                        cd->event_pending = NULL;
 
2265
                }
 
2266
 
 
2267
                cd->expect_ctrl[f][0] = c1;
 
2268
                cd->expect_ctrl[f][1] = c2;
 
2269
        } else {
 
2270
                cd->expect_ctrl[f][0] = -1;
 
2271
 
 
2272
                if (c1 < 0x10) {
 
2273
                        if (FIELD_1 == f) {
 
2274
                                /* 47 CFR Section 15.119 (i)(1): "If the
 
2275
                                   non-printing character in the pair is
 
2276
                                   in the range 00h to 0Fh, that character
 
2277
                                   alone will be ignored and the second
 
2278
                                   character will be treated normally." */
 
2279
                                c1 = 0;
 
2280
                        } else if (0x0F == c1) {
 
2281
                                /* XDS packet terminator. */
 
2282
                                cd->in_xds[FIELD_2] = FALSE;
 
2283
                                goto finish;
 
2284
                        } else if (c1 >= 0x01) {
 
2285
                                /* XDS packet start or continuation.
 
2286
                                   EIA 608-B Section 7.7, 8.5: Also
 
2287
                                   interrupts a Text mode
 
2288
                                   transmission. */
 
2289
                                cd->in_xds[FIELD_2] = TRUE;
 
2290
                                goto finish;
 
2291
                        }
 
2292
                }
 
2293
 
 
2294
                {
 
2295
                        struct channel *ch;
 
2296
                        vbi_pgno ch_num;
 
2297
 
 
2298
                        ch_num = cd->curr_ch_num[f];
 
2299
                        if (UNKNOWN_CHANNEL == ch_num)
 
2300
                                goto finish;
 
2301
 
 
2302
                        ch_num = ((ch_num - VBI_CAPTION_CC1) & 5) + f * 2;
 
2303
                        ch = &cd->channel[ch_num];
 
2304
 
 
2305
                        all_successful &= characters (cd, ch, c1);
 
2306
                        all_successful &= characters (cd, ch, c2);
 
2307
 
 
2308
                        if (cd->event_pending) {
 
2309
                                display_event (cd, cd->event_pending,
 
2310
                                               /* flags */ 0);
 
2311
                                cd->event_pending = NULL;
 
2312
                        }
 
2313
                }
 
2314
        }
 
2315
 
 
2316
 finish:
 
2317
        cd->error_history = cd->error_history * 2 + all_successful;
 
2318
 
 
2319
        return all_successful;
 
2320
 
 
2321
 parity_error:
 
2322
        cd->expect_ctrl[f][0] = -1;
 
2323
 
 
2324
        /* XXX Some networks stupidly transmit 0x0000 instead of
 
2325
           0x8080 as filler. Perhaps we shouldn't take that as a
 
2326
           serious parity error. */
 
2327
        cd->error_history *= 2;
 
2328
 
 
2329
        return FALSE;
 
2330
}
 
2331
 
 
2332
/**
 
2333
 * @param cd Caption decoder allocated with _vbi_cc608_decoder_new().
 
2334
 * @param sliced Sliced VBI data.
 
2335
 * @param n_lines Number of lines in the @a sliced array.
 
2336
 * @param capture_time System time in seconds when the sliced data was
 
2337
 *   captured.
 
2338
 * @param pts ISO 13818-1 Presentation Time Stamp of all elements
 
2339
 *   in the sliced data array. @a pts counts 1/90000 seconds from an
 
2340
 *   arbitrary point in the video stream. Only the 33 least significant
 
2341
 *   bits have to be valid. If @a pts is negative the function
 
2342
 *   converts @a capture_time to a PTS.
 
2343
 *
 
2344
 * This function works like _vbi_cc608_decoder_feed() but operates
 
2345
 * on sliced VBI data and filters out @c VBI_SLICED_CAPTION_525.
 
2346
 */
 
2347
vbi_bool
 
2348
_vbi_cc608_decoder_feed_frame   (_vbi_cc608_decoder *   cd,
 
2349
                                 const vbi_sliced *     sliced,
 
2350
                                 unsigned int           n_lines,
 
2351
                                 double                 capture_time,
 
2352
                                 int64_t                pts)
 
2353
{
 
2354
        const vbi_sliced *end;
 
2355
 
 
2356
        assert (NULL != cd);
 
2357
        assert (NULL != sliced);
 
2358
 
 
2359
        for (end = sliced + n_lines; sliced < end; ++sliced) {
 
2360
                if (sliced->id & VBI_SLICED_CAPTION_525) {
 
2361
                        if (!_vbi_cc608_decoder_feed (cd,
 
2362
                                                      sliced->data,
 
2363
                                                      sliced->line,
 
2364
                                                      capture_time,
 
2365
                                                      pts))
 
2366
                                return FALSE;
 
2367
                }
 
2368
        }
 
2369
 
 
2370
        return TRUE;
 
2371
}
 
2372
 
 
2373
/**
 
2374
 * @param cd Caption decoder allocated with _vbi_cc608_decoder_new().
 
2375
 * @param callback Function to be called on events.
 
2376
 * @param user_data User pointer passed through to the @a callback
 
2377
 *   function.
 
2378
 * 
 
2379
 * Removes an event handler from the caption decoder, if a handler with
 
2380
 * this @a callback and @a user_data has been registered.
 
2381
 */
 
2382
void
 
2383
_vbi_cc608_decoder_remove_event_handler
 
2384
                                (_vbi_cc608_decoder *   cd,
 
2385
                                 vbi_event_handler      callback,
 
2386
                                 void *                 user_data)
 
2387
{
 
2388
        _vbi_event_handler_list_remove_by_callback (&cd->handlers,
 
2389
                                                    callback,
 
2390
                                                    user_data);
 
2391
}
 
2392
 
 
2393
/**
 
2394
 * @param cd Caption decoder allocated with _vbi_cc608_decoder_new().
 
2395
 * @param event_mask Set of events the handler is waiting for,
 
2396
 *   VBI_EVENT_CC608 or VBI_EVENT_CC608_STREAM.
 
2397
 * @param callback Function to be called on events by
 
2398
 *   _vbi_cc608_decoder_feed().
 
2399
 * @param user_data User pointer passed through to the @a callback
 
2400
 *   function.
 
2401
 * 
 
2402
 * Adds a new event handler to the caption decoder. When the @a
 
2403
 * callback with this @a user_data is already registered the function
 
2404
 * changes the set of events the callback function will receive in the
 
2405
 * future.
 
2406
 *
 
2407
 * Any number of handlers can be added, also different handlers for the
 
2408
 * same event, which will be called in registration order.
 
2409
 *
 
2410
 * @returns
 
2411
 * @c FALSE on failure (out of memory).
 
2412
 */
 
2413
vbi_bool
 
2414
_vbi_cc608_decoder_add_event_handler
 
2415
                                (_vbi_cc608_decoder *   cd,
 
2416
                                 unsigned int           event_mask,
 
2417
                                 vbi_event_handler      callback,
 
2418
                                 void *                 user_data)
 
2419
{
 
2420
        event_mask &= (_VBI_EVENT_CC608 |
 
2421
                       _VBI_EVENT_CC608_STREAM);
 
2422
 
 
2423
        if (0 == event_mask) {
 
2424
                _vbi_event_handler_list_remove_by_callback (&cd->handlers,
 
2425
                                                            callback,
 
2426
                                                            user_data);
 
2427
                return TRUE;
 
2428
        }
 
2429
 
 
2430
        if (NULL != _vbi_event_handler_list_add (&cd->handlers,
 
2431
                                                 event_mask,
 
2432
                                                 callback,
 
2433
                                                 user_data)) {
 
2434
                return TRUE;
 
2435
        }
 
2436
 
 
2437
        return FALSE;
 
2438
}
 
2439
 
 
2440
/**
 
2441
 * @param cd Caption decoder allocated with _vbi_cc608_decoder_new().
 
2442
 *
 
2443
 * Resets the caption decoder, useful for example after a channel
 
2444
 * change.
 
2445
 */
 
2446
void
 
2447
_vbi_cc608_decoder_reset                (_vbi_cc608_decoder *   cd)
 
2448
{
 
2449
        unsigned int ch_num;
 
2450
 
 
2451
        assert (NULL != cd);
 
2452
 
 
2453
        if (CC608_DECODER_LOG_INPUT) {
 
2454
                fprintf (stderr, "%s:%u: %s\n",
 
2455
                         __FILE__, __LINE__, __FUNCTION__);
 
2456
 
 
2457
        }
 
2458
 
 
2459
        for (ch_num = 0; ch_num < MAX_CHANNELS; ++ch_num) {
 
2460
                struct channel *ch;
 
2461
 
 
2462
                ch = &cd->channel[ch_num];
 
2463
 
 
2464
                if (ch_num <= 3) {
 
2465
                        ch->mode = _VBI_CC608_MODE_UNKNOWN;
 
2466
 
 
2467
                        /* Plausible for roll-up mode. We don't
 
2468
                           display text while the caption mode is
 
2469
                           unknown and may choose more suitable
 
2470
                           defaults when we receive a mode changing
 
2471
                           control code. */
 
2472
                        ch->curr_row = LAST_ROW;
 
2473
                        ch->curr_column = FIRST_COLUMN;
 
2474
                        ch->window_rows = 4;
 
2475
                } else {
 
2476
                        ch->mode = _VBI_CC608_MODE_TEXT; /* invariable */
 
2477
 
 
2478
                        /* EIA 608-B Section 7.4: "When Text Mode has
 
2479
                           initially been selected and the specified
 
2480
                           Text memory is empty, the cursor starts at
 
2481
                           the topmost row, Column 1." */
 
2482
                        ch->curr_row = FIRST_ROW;
 
2483
                        ch->curr_column = FIRST_COLUMN;
 
2484
                        ch->window_rows = 0; /* n/a */
 
2485
                }
 
2486
 
 
2487
                ch->displayed_buffer = 0;
 
2488
 
 
2489
                ch->last_pac = 0;
 
2490
 
 
2491
                CLEAR (ch->buffer);
 
2492
                CLEAR (ch->dirty);
 
2493
 
 
2494
                timestamp_reset (&ch->timestamp);
 
2495
                timestamp_reset (&ch->timestamp_c0);
 
2496
        }
 
2497
 
 
2498
        cd->curr_ch_num[0] = UNKNOWN_CHANNEL;
 
2499
        cd->curr_ch_num[1] = UNKNOWN_CHANNEL;
 
2500
 
 
2501
        memset (cd->expect_ctrl, -1, sizeof (cd->expect_ctrl));
 
2502
 
 
2503
        CLEAR (cd->in_xds);
 
2504
 
 
2505
        cd->event_pending = NULL;
 
2506
}
 
2507
 
 
2508
static void
 
2509
_vbi_cc608_decoder_destroy      (_vbi_cc608_decoder *   cd)
 
2510
{
 
2511
        assert (NULL != cd);
 
2512
 
 
2513
        _vbi_event_handler_list_destroy (&cd->handlers);
 
2514
 
 
2515
        CLEAR (*cd);
 
2516
}
 
2517
 
 
2518
static void
 
2519
_vbi_cc608_decoder_init         (_vbi_cc608_decoder *   cd)
 
2520
{
 
2521
        assert (NULL != cd);
 
2522
 
 
2523
        CLEAR (*cd);
 
2524
 
 
2525
        _vbi_event_handler_list_init (&cd->handlers);
 
2526
        
 
2527
        _vbi_cc608_decoder_reset (cd);
 
2528
 
 
2529
        timestamp_reset (&cd->timestamp);
 
2530
}
 
2531
 
 
2532
/**
 
2533
 * @param cd Caption decoder allocated with _vbi_cc608_decoder_new(),
 
2534
 *   can be @a NULL.
 
2535
 *
 
2536
 * Frees all resources associated with @a cd.
 
2537
 */
 
2538
void
 
2539
_vbi_cc608_decoder_delete       (_vbi_cc608_decoder *   cd)
 
2540
{
 
2541
        if (NULL == cd)
 
2542
                return;
 
2543
 
 
2544
        _vbi_cc608_decoder_destroy (cd);
 
2545
 
 
2546
        vbi_free (cd);
 
2547
}
 
2548
 
 
2549
/**
 
2550
 * Allocates a new EIA 608-B Closed Caption decoder.
 
2551
 *
 
2552
 * To enter caption data call the _vbi_cc608_decoder_feed()
 
2553
 * function. Decoded data is available through VBI_EVENT_CC608_STREAM
 
2554
 * and the _vbi_cc608_decoder_get_page() function.
 
2555
 *
 
2556
 * To be notified when new data is available call
 
2557
 * _vbi_cc608_decoder_add_event_handler().
 
2558
 *
 
2559
 * @returns
 
2560
 * Pointer to a newly allocated caption decoder which must be freed
 
2561
 * with _vbi_cc608_decoder_delete() when no longer needed. @c NULL
 
2562
 * on failure (out of memory).
 
2563
 */
 
2564
_vbi_cc608_decoder *
 
2565
_vbi_cc608_decoder_new          (void)
 
2566
{
 
2567
        _vbi_cc608_decoder *cd;
 
2568
 
 
2569
        cd = vbi_malloc (sizeof (*cd));
 
2570
 
 
2571
        if (NULL != cd) {
 
2572
                _vbi_cc608_decoder_init (cd);
 
2573
        }
 
2574
 
 
2575
        return cd;
 
2576
}
 
2577
 
 
2578
/*
 
2579
Local variables:
 
2580
c-set-style: K&R
 
2581
c-basic-offset: 8
 
2582
End:
 
2583
*/