~ubuntu-branches/ubuntu/maverick/tvtime/maverick

« back to all changes in this revision

Viewing changes to src/vbidata.c

  • Committer: Bazaar Package Importer
  • Author(s): Simon Law
  • Date: 2004-01-13 18:00:36 UTC
  • Revision ID: james.westby@ubuntu.com-20040113180036-h996q67t476jymsu
Tags: upstream-0.9.12
ImportĀ upstreamĀ versionĀ 0.9.12

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * Copyright (c) 2002, 2003 Billy Biggs <vektor@dumbterm.net>
 
3
 * Copyright (c) 2002 Doug Bell <drbell@users.sourceforge.net>
 
4
 *
 
5
 * CC code from Nathan Laredo's ccdecode, used under the GPL.
 
6
 * Lots of 'hey what does this mean?' code from
 
7
 * Billy Biggs and Doug Bell, like all the crap with
 
8
 * XDS and stuff.  Some help from Zapping's vbi library by
 
9
 * Michael H. Schimek and others, released under the GPL.
 
10
 *
 
11
 * Excellent new filter code by Nathan Laredo, and no, I don't yet know
 
12
 * how he derived it, but it does seem to improve our decoding.
 
13
 *
 
14
 * This program is free software; you can redistribute it and/or modify
 
15
 * it under the terms of the GNU General Public License as published by
 
16
 * the Free Software Foundation; either version 2, or (at your option)
 
17
 * any later version.
 
18
 *
 
19
 * This program is distributed in the hope that it will be useful,
 
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
22
 * GNU General Public License for more details.
 
23
 *
 
24
 * You should have received a copy of the GNU General Public License
 
25
 * along with this program; if not, write to the Free Software Foundation,
 
26
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
27
 */
 
28
 
 
29
#include <stdio.h>
 
30
#include <stdlib.h>
 
31
#include <sys/types.h>
 
32
#include <sys/stat.h>
 
33
#include <string.h>
 
34
#include <fcntl.h>
 
35
#include <ctype.h>
 
36
#include <unistd.h>
 
37
#include <errno.h>
 
38
#include "vbidata.h"
 
39
 
 
40
struct vbidata_s
 
41
{
 
42
    char *filename;
 
43
    int fd;
 
44
    int open;
 
45
    vbiscreen_t *vs;
 
46
    uint8_t buf[ 65536 ];
 
47
    int wanttop;
 
48
    int wanttext;
 
49
 
 
50
    int usexds;
 
51
 
 
52
    unsigned int colour;
 
53
    int row, ital;
 
54
    int indent, ul;
 
55
    int chan;
 
56
 
 
57
    unsigned int current_colour;
 
58
    int current_row, current_ital;
 
59
    int current_indent, current_ul;
 
60
    int current_chan;
 
61
    int current_istext;
 
62
 
 
63
    int initialised;
 
64
    int enabled;
 
65
    int lastcode;
 
66
    int lastcount;
 
67
    int verbose;
 
68
 
 
69
    /* XDS data */
 
70
    char xds_packet[ 2048 ];
 
71
    int xds_cursor;
 
72
 
 
73
    char program_name[ 33 ];
 
74
    char network_name[ 33 ];
 
75
    char call_letters[ 7 ];
 
76
    char program_start_time[ 33 ];
 
77
    char program_length[ 33 ];
 
78
    const char *rating;
 
79
    const char *program_type;
 
80
    int start_day;
 
81
    int start_month;
 
82
    int start_min;
 
83
    int start_hour;
 
84
    int length_hour;
 
85
    int length_min;
 
86
    int length_elapsed_hour;
 
87
    int length_elapsed_min;
 
88
    int length_elapsed_sec;
 
89
    char program_desc[ 8 ][ 33 ];
 
90
};
 
91
 
 
92
 
 
93
/* this is NOT exactly right */
 
94
/*static char *ccode = " !\"#$%&'()\0341+,-./0123456789:;<=>?@"*/
 
95
static char *ccode = " !\"#$%&'()a+,-./0123456789:;<=>?@"
 
96
                     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 
97
/*                     "abcdefghijklmnopqrstuvwxyz"*/
 
98
/*                     "[\0351]\0355\0363\0372abcdefghijklmnopqr"*/
 
99
                     "[e]iouabcdefghijklmnopqr"
 
100
/*                     "stuvwxyz\0347\0367\0245\0244\0240";*/
 
101
                     "stuvwxyzcoNn ";
 
102
static char *wccode = "\0256\0260\0275\0277T\0242\0243#\0340 "
 
103
                      "\0350\0354\0362\0371";
 
104
 
 
105
static char *extcode1 = "\0301\0311\0323\0332\0334\0374"
 
106
                       "`\0241*'-\0251S*\"\"\0300\0302"
 
107
                       "\0307\0310\0312\0313\0353\0316\0317\0357"
 
108
                       "\0324\0331\0371\0333\0253\0273";
 
109
 
 
110
static char *extcode2 = "\0303\0343\0315\0314\0354\0322\0362\0325"
 
111
                        "{}\\^_|~\0304\0344\0326\0366\0337\0245\0244|"
 
112
                        "\0305\0345\0330\0370++++";
 
113
 
 
114
/* Check parity for 2 bytes packed in n. */
 
115
int parityok( int n )
 
116
{
 
117
    int j, k;
 
118
    for (k = 0, j = 0; j < 7; j++)
 
119
        if (n & (1 << j))
 
120
            k++;
 
121
    if ((k & 1) && (n & 0x80))
 
122
        return 0;
 
123
    for (k = 0, j = 8; j < 15; j++)
 
124
        if (n & (1 << j))
 
125
            k++;
 
126
    if ((k & 1) && (n & 0x8000))
 
127
        return 0;
 
128
    return 1;
 
129
}
 
130
 
 
131
int decodebit( uint8_t *data, int threshold )
 
132
{
 
133
    return (data[0] > threshold);
 
134
}
 
135
 
 
136
 
 
137
int ccdecode( uint8_t *vbiline )
 
138
{
 
139
    int max = 48, maxval = 128, minval = 255, i = 0, clk = 0, tmp = 0;
 
140
    int sample, packedbits = 0;
 
141
 
 
142
    for (i=0; i<250; i++) {
 
143
        sample = vbiline[i];
 
144
        if (sample - maxval > 10)
 
145
            (maxval = sample, max = i);
 
146
        if (sample < minval)
 
147
            minval = sample;
 
148
        if (maxval - sample > 40)
 
149
            break;
 
150
    }
 
151
    sample = ((maxval + minval) >> 1);
 
152
 
 
153
    /* found clock lead-in, double-check start */
 
154
#ifndef PAL_DECODE
 
155
    i = max + 478;
 
156
#else
 
157
    i = max + 538;
 
158
#endif
 
159
    if (!decodebit(&vbiline[i], sample))
 
160
        return 0;
 
161
#ifndef PAL_DECODE
 
162
    tmp = i + 57;  /* tmp = data bit zero */
 
163
#else
 
164
    tmp = i + 71;
 
165
#endif
 
166
    for (i = 0; i < 16; i++) {
 
167
#ifndef PAL_DECODE
 
168
        clk = tmp + i * 57;
 
169
#else
 
170
        clk = tmp + i * 71;
 
171
#endif
 
172
        if (decodebit(&vbiline[clk], sample)) {
 
173
            packedbits |= 1 << i;
 
174
        }
 
175
    }
 
176
    if (parityok(packedbits))
 
177
        return packedbits;
 
178
    return 0;
 
179
}
 
180
 
 
181
const char *movies[] = { "N/A", "G", "PG", "PG-13", "R", 
 
182
                         "NC-17", "X", "Not Rated" };
 
183
const char *usa_tv[] = { "Not Rated", "TV-Y", "TV-Y7", "TV-G", 
 
184
                         "TV-PG", "TV-14", "TV-MA", "Not Rated" };
 
185
const char *cane_tv[] = { "Exempt", "C", "C8+", "G", "PG", 
 
186
                          "14+", "18+", "Reserved" };
 
187
const char *canf_tv[] = { "Exempt", "G", "8 ans +", "13 ans +", 
 
188
                          "16 ans +", "18 ans +", "Reserved", 
 
189
                          "Reserved" };
 
190
 
 
191
const char *months[] = { 0, "Jan", "Feb", "Mar", "Apr", "May",
 
192
    "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
 
193
 
 
194
static const char *eia608_program_type[ 96 ] = {
 
195
  "education", "entertainment", "movie", "news", "religious", "sports",
 
196
  "other", "action", "advertisement", "animated", "anthology",
 
197
  "automobile", "awards", "baseball", "basketball", "bulletin", "business",
 
198
  "classical", "college", "combat", "comedy", "commentary", "concert",
 
199
  "consumer", "contemporary", "crime", "dance", "documentary", "drama",
 
200
  "elementary", "erotica", "exercise", "fantasy", "farm", "fashion",
 
201
  "fiction", "food", "football", "foreign", "fund raiser", "game/quiz",
 
202
  "garden", "golf", "government", "health", "high school", "history",
 
203
  "hobby", "hockey", "home", "horror", "information", "instruction",
 
204
  "international", "interview", "language", "legal", "live", "local",
 
205
  "math", "medical", "meeting", "military", "miniseries", "music", "mystery",
 
206
  "national", "nature", "police", "politics", "premiere", "prerecorded",
 
207
  "product", "professional", "public", "racing", "reading", "repair", "repeat",
 
208
  "review", "romance", "science", "series", "service", "shopping",
 
209
  "soap opera", "special", "suspense", "talk", "technical", "tennis",
 
210
  "travel", "variety", "video", "weather", "western"
 
211
};
 
212
 
 
213
 
 
214
static void parse_xds_packet( vbidata_t *vbi, char *packet, int length )
 
215
{
 
216
    int sum = 0;
 
217
    int i;
 
218
 
 
219
    /* Check the checksum for validity of the packet. */
 
220
    for( i = 0; i < length - 1; i++ ) {
 
221
        sum += packet[ i ];
 
222
    }
 
223
    if( (((~sum) & 0x7f) + 1) != packet[ length - 1 ] ) {
 
224
        return;
 
225
    }
 
226
 
 
227
    /* Stick a null at the end, and cut off the last two characters. */
 
228
    packet[ length - 2 ] = '\0';
 
229
    length -= 2;
 
230
 
 
231
    if( packet[ 0 ] == 0x01 && packet[ 1 ] == 0x03 ) {
 
232
        if( !strcmp( vbi->program_name, packet + 2 ) ) {
 
233
            return;
 
234
        }
 
235
        if( vbi->verbose ) {
 
236
            fprintf( stderr, "Current program name: '%s'\n", packet + 2 );
 
237
        }
 
238
        snprintf( vbi->program_name, sizeof( vbi->program_name ), "%s", packet + 2 );
 
239
    } else if( packet[ 0 ] == 0x03 && packet[ 1 ] == 0x03 ) {
 
240
        if( vbi->verbose ) {
 
241
            fprintf( stderr, "Future program name: '%s'\n", packet + 2 );
 
242
        }
 
243
    } else if( packet[ 0 ] == 0x05 && packet[ 1 ] == 0x01 ) {
 
244
        if( !strcmp( vbi->network_name, packet + 2 ) ) {
 
245
            return;
 
246
        }
 
247
 
 
248
        if( vbi->verbose ) {
 
249
            fprintf( stderr, "Network name: '%s'\n", packet + 2 );
 
250
        }
 
251
        snprintf( vbi->network_name, sizeof( vbi->network_name ), "%s", packet + 2 );
 
252
    } else if( packet[ 0 ] == 0x01 && packet[ 1 ] == 0x05 ) {
 
253
        int movie_rating = packet[ 2 ] & 7;
 
254
        int scheme = (packet[ 2 ] & 56) >> 3;
 
255
        int tv_rating = packet[ 3 ] & 7;
 
256
        int VSL = packet[ 3 ] & 56;
 
257
        const char * str;
 
258
 
 
259
        switch( VSL | scheme ) {
 
260
        case 3: /* Canadian English TV */
 
261
            str = cane_tv[ tv_rating ];
 
262
            break;
 
263
        case 7: /* Canadian French TV */
 
264
            str = canf_tv[ tv_rating ];
 
265
            break;
 
266
        case 19: /* Reserved */
 
267
        case 31:
 
268
            str = "";
 
269
            break;
 
270
        default:
 
271
            if( ((VSL | scheme) & 3) == 1 ) {
 
272
                /* USA TV */
 
273
                str = usa_tv[ tv_rating ];
 
274
            } else {
 
275
                /* MPAA Movie Rating */
 
276
                str = movies[ movie_rating ];
 
277
            }
 
278
            break;
 
279
        }
 
280
 
 
281
        if( vbi->rating && !strcmp(vbi->rating, str ) ) {
 
282
            return;
 
283
        }
 
284
 
 
285
        if( vbi->verbose ) {
 
286
            fprintf( stderr, "Show rating: %s", str );
 
287
            if( ((VSL | scheme) & 3) == 1 || ((VSL | scheme) & 3) == 0 ) {
 
288
                /* show VSLD for the americans */
 
289
                if( (VSL | scheme) & 32 ) fprintf( stderr, " V" );
 
290
                if( (VSL | scheme) & 16 ) fprintf( stderr, " S" );
 
291
                if( (VSL | scheme) &  8 ) fprintf( stderr, " L" );
 
292
                if( (VSL | scheme) &  4 ) fprintf( stderr, " D" );
 
293
            }
 
294
            fprintf( stderr, "\n" );
 
295
        }
 
296
        vbi->rating = str;
 
297
    } else if( packet[ 0 ] == 0x05 && packet[ 1 ] == 0x02 ) {
 
298
        if( !strcmp( vbi->call_letters, packet + 2 ) ) {
 
299
            return;
 
300
        }
 
301
 
 
302
        if( vbi->verbose ) {
 
303
            fprintf( stderr, "Network call letters: '%s'\n", packet + 2 );
 
304
        }
 
305
 
 
306
        snprintf( vbi->call_letters, sizeof( vbi->call_letters ), "%s", packet + 2 );
 
307
    } else if( packet[ 0 ] == 0x01 && packet[ 1 ] == 0x01 ) {
 
308
        int month = packet[5];
 
309
        int day = packet[4];
 
310
        int hour = packet[3];
 
311
        int min = packet[2];
 
312
 
 
313
        if( month < 1 || month > 12 ) month = 1;
 
314
 
 
315
        if( vbi->verbose ) {
 
316
            fprintf( stderr, "Program Start: %02d %s, %02d:%02d\n",
 
317
                     day & 31, months[month & 15], hour & 31, min & 63 );
 
318
        }
 
319
        vbi->start_month = month & 15;
 
320
        vbi->start_day = day & 31;
 
321
        vbi->start_hour = hour & 31;
 
322
        vbi->start_min = hour & 63;
 
323
        snprintf( vbi->program_start_time, sizeof( vbi->program_start_time ), "%02d %s, %02d:%02d",
 
324
                  day & 31, months[month & 15], hour & 31, min & 63 );
 
325
    } else if( packet[ 0 ] == 0x01 && packet[ 1 ] == 0x04 ) {
 
326
        if( vbi->verbose ) {
 
327
            fprintf( stderr, "Program type: " );
 
328
        }
 
329
        for( i = 0; i < length - 2; i++ ) {
 
330
            int cur = packet[ 2 + i ] - 0x20;
 
331
            if( cur >= 0 && cur < 96 ) {
 
332
                if( vbi->verbose ) {
 
333
                    fprintf( stderr, "%s%s", i ? ", " : "", eia608_program_type[ cur ] );
 
334
                }
 
335
                /* this will cause us to keep only the last type we check */
 
336
                vbi->program_type = eia608_program_type[ cur ];
 
337
            }
 
338
        }
 
339
        if( vbi->verbose ) fprintf( stderr, "\n" );
 
340
    } else if( packet[ 0 ] < 0x03 && packet[ 1 ] >= 0x10 && packet[ 1 ] <= 0x17 ) {
 
341
 
 
342
        if( !strcmp( vbi->program_desc[ packet[ 1 ] & 0xf ], packet + 2 ) ) {
 
343
            return;
 
344
        }
 
345
 
 
346
        if( vbi->verbose ) {
 
347
            fprintf( stderr, "Program Description: Line %d: %s\n", packet[1] & 0xf, packet + 2 );
 
348
        }
 
349
        snprintf( vbi->program_desc[ packet[ 1 ] & 0xf ],
 
350
                  sizeof( vbi->program_desc[ packet[ 1 ] & 0xf ] ), "%s", packet + 2 );
 
351
    } else if( packet[ 0 ] == 0x01 && packet[ 1 ] == 0x02 ) {
 
352
 
 
353
        if( vbi->verbose ) {
 
354
            fprintf( stderr, "Program Length: %02d:%02d", 
 
355
                     packet[ 3 ] & 63, packet[ 2 ] & 63 ); 
 
356
        }
 
357
 
 
358
        vbi->length_hour = packet[ 3 ] & 63;
 
359
        vbi->length_min = packet[ 2 ] & 63;
 
360
        snprintf( vbi->program_length, sizeof( vbi->program_length ),
 
361
                  "%02d:%02d", packet[ 3 ] & 63, packet[ 2 ] & 63 );
 
362
        if( length > 4 ) {
 
363
            if( vbi->verbose ) {
 
364
                fprintf( stderr, " Elapsed: %02d:%02d", packet[ 5 ] & 63, 
 
365
                         packet[ 4 ] & 63 );
 
366
            }
 
367
            vbi->length_elapsed_hour = packet[ 5 ] & 63;
 
368
            vbi->length_elapsed_min = packet[ 4 ] & 63;
 
369
            snprintf( vbi->program_length, sizeof( vbi->program_length ),
 
370
                      "%02d:%02d/%02d:%02d", 
 
371
                      packet[ 5 ] & 63, packet[ 4 ] & 63,
 
372
                      packet[ 3 ] & 63, packet[ 2 ] & 63 );
 
373
        } else {
 
374
            vbi->length_elapsed_hour = 0;
 
375
            vbi->length_elapsed_min = 0;
 
376
        }
 
377
 
 
378
        if( length > 6 ) {
 
379
            if( vbi->verbose ) fprintf( stderr, ".%02d", packet[ 6 ] & 63 );
 
380
            vbi->length_elapsed_hour = packet[ 6 ] & 63;
 
381
            snprintf( vbi->program_length, sizeof( vbi->program_length ),
 
382
                      "%02d:%02d.%02d/%02d:%02d", 
 
383
                      packet[ 5 ] & 63, packet[ 4 ] & 63, packet[ 6 ] & 63, 
 
384
                      packet[ 3 ] & 63, packet[ 2 ] & 63 );
 
385
        } else {
 
386
            vbi->length_elapsed_hour = 0;
 
387
        }
 
388
        if( vbi->verbose ) {
 
389
            fprintf( stderr, "\n" );
 
390
        }
 
391
    } else if( packet[ 0 ] == 0x05 && packet[ 1 ] == 0x04 ) {
 
392
        if( vbi->verbose ) fprintf( stderr, "Transmission Signal Identifier (TSID): 0x%04x\n",
 
393
                 packet[ 2 ] << 24 | packet[ 3 ] << 16 | packet[ 4 ] << 8 | packet[ 5 ] );
 
394
    } else {
 
395
        /* unknown */
 
396
 
 
397
        if( vbi->verbose ) {
 
398
            fprintf( stderr, "vbidata: Unknown XDS packet, class " );
 
399
            switch( packet[ 0 ] ) {
 
400
            case 0x1: fprintf( stderr, "CURRENT start" ); break;
 
401
            case 0x2: fprintf( stderr, "CURRENT continue" ); break;
 
402
 
 
403
            case 0x3: fprintf( stderr, "FUTURE start" ); break;
 
404
            case 0x4: fprintf( stderr, "FUTURE continue" ); break;
 
405
 
 
406
            case 0x5: fprintf( stderr, "CHANNEL start" ); break;
 
407
            case 0x6: fprintf( stderr, "CHANNEL continue" ); break;
 
408
 
 
409
            case 0x7: fprintf( stderr, "MISC start" ); break;
 
410
            case 0x8: fprintf( stderr, "MISC continue" ); break;
 
411
 
 
412
            case 0x9: fprintf( stderr, "PUB start" ); break;
 
413
            case 0xa: fprintf( stderr, "PUB continue" ); break;
 
414
 
 
415
            case 0xb: fprintf( stderr, "RES start" ); break;
 
416
            case 0xc: fprintf( stderr, "RES continue" ); break;
 
417
 
 
418
            case 0xd: fprintf( stderr, "UNDEF start" ); break;
 
419
            case 0xe: fprintf( stderr, "UNDEF continue" ); break;
 
420
            }
 
421
            fprintf( stderr, "\nvbidata: Data " );
 
422
            for( i = 0; i < length; i++ ) {
 
423
                fprintf( stderr, "0x%02x ", packet[ i ] );
 
424
            }
 
425
            fprintf( stderr, "\n" );
 
426
        }
 
427
    }
 
428
}
 
429
 
 
430
static int xds_decode( vbidata_t *vbi, int b1, int b2 )
 
431
{
 
432
    if( !vbi ) return 0;
 
433
    if( vbi->xds_cursor > 2046 ) {
 
434
        vbi->xds_cursor = 0;
 
435
    }
 
436
 
 
437
    if( !vbi->xds_cursor && b1 > 0xf ) {
 
438
        return 0;
 
439
    }
 
440
 
 
441
 
 
442
    if( b1 < 0xf && (b1 & 0x2) ) {
 
443
        /* ignore the continue and thus 'support' continuation of
 
444
           a single packet */
 
445
        return 1;
 
446
    } else if( b1 < 0xf ) {
 
447
        /* kill old packet cause we got a new one */
 
448
        vbi->xds_cursor = 0;
 
449
    }
 
450
 
 
451
    vbi->xds_packet[ vbi->xds_cursor ] = b1;
 
452
    vbi->xds_packet[ vbi->xds_cursor + 1 ] = b2;
 
453
    vbi->xds_cursor += 2;
 
454
 
 
455
    if( b1 == 0xf ) {
 
456
        if( vbi->usexds ) {
 
457
            parse_xds_packet( vbi, vbi->xds_packet, vbi->xds_cursor );
 
458
        }
 
459
        vbi->xds_cursor = 0;
 
460
    }
 
461
 
 
462
    return 1;
 
463
}
 
464
 
 
465
#define NOMODE  0
 
466
 
 
467
#define CC1     1
 
468
#define CC2     2
 
469
#define T1      3
 
470
#define T2      4
 
471
 
 
472
#define CC3     1
 
473
#define CC4     2
 
474
#define T3      3
 
475
#define T4      4
 
476
 
 
477
const unsigned int colours[] = { 
 
478
    0xFFFFFFFFU, /* white */
 
479
    0xFF00FF00U, /* green */
 
480
    0xFF0000FFU, /* blue */
 
481
    0xFF00C7C7U, /* cyan */
 
482
    0xFFFF0000U, /* red */
 
483
    0xFFFFFF00U, /* yellow */
 
484
    0xFFC700C7U  /* magenta */
 
485
};
 
486
 
 
487
const int rows[] = {
 
488
    11,
 
489
    0, /* unused */
 
490
    1,
 
491
    2,
 
492
    3,
 
493
    4,
 
494
    12,
 
495
    13,
 
496
    14,
 
497
    15,
 
498
    5,
 
499
    6,
 
500
    7,
 
501
    8,
 
502
    9,
 
503
    10    
 
504
};
 
505
 
 
506
#define ROLL_2      6
 
507
#define ROLL_3      7
 
508
#define ROLL_4      8
 
509
#define POP_UP      9
 
510
#define PAINT_ON    10
 
511
 
 
512
 
 
513
int ProcessLine( vbidata_t *vbi, uint8_t *s, int bottom )
 
514
{
 
515
    int w1, b1, b2;
 
516
 
 
517
    w1 = ccdecode( s );
 
518
 
 
519
    b1 = w1 & 0x7f;
 
520
    b2 = (w1 >> 8) & 0x7f;
 
521
 
 
522
    if( !b1 && !b2 ) {
 
523
        return 0;
 
524
    }
 
525
 
 
526
    if( vbi->vs && vbi->enabled && b1 >= 0x10 && b1 <= 0x1F && b2 >= 0x20 && b2 <= 0x7F ) {
 
527
        int code;
 
528
        if( (b2 & 64) ) {
 
529
            /* Preamble Code */
 
530
            /* This sets up colors and indenting */
 
531
 
 
532
            if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
 
533
                vbi->lastcount = (vbi->lastcount + 1) % 2;
 
534
                return 1;
 
535
            }
 
536
 
 
537
            vbi->current_chan = (b1 & 8) >> 3;
 
538
            if( !bottom == vbi->wanttop ) {
 
539
                if( vbi->chan != vbi->current_chan )
 
540
                    return 0;
 
541
            } else return 0;
 
542
 
 
543
            vbi->current_ital = (b2 & 1);
 
544
            if( !(b2 & 16) ) {
 
545
                vbi->current_colour = colours[ (b2 & 30) >> 1 ];
 
546
                vbi->current_indent = 0;
 
547
            } else {
 
548
                vbi->current_colour = 0xFFFFFFFFU; /* white */
 
549
                vbi->current_indent = 4*( (b2 & 14) >> 1 );
 
550
            }
 
551
            vbi->current_row = rows[ ((b1 & 7) << 1) | ((b2 & 32) >> 5) ];
 
552
            vbi->current_ul = b2 & 1;
 
553
 
 
554
            if( vbi->verbose ) fprintf( stderr, "field: %d chan %d, ital %d, ul %d, colour 0x%x, "
 
555
                     "indent %d, row %d\n", bottom, vbi->current_chan,
 
556
                     vbi->current_ital, vbi->current_ul, vbi->current_colour,
 
557
                     vbi->current_indent, vbi->current_row );
 
558
 
 
559
            if( !bottom == vbi->wanttop && 
 
560
                vbi->current_chan == vbi->chan && 
 
561
                vbi->current_istext == vbi->wanttext ) {
 
562
 
 
563
                vbi->indent = vbi->current_indent;
 
564
                vbi->ital = vbi->current_ital;
 
565
                vbi->colour = vbi->current_colour;
 
566
                vbi->row = vbi->current_row;
 
567
                vbi->current_istext = 0;
 
568
 
 
569
                vbiscreen_new_caption( vbi->vs, vbi->indent, vbi->ital,
 
570
                                       vbi->colour, vbi->row );
 
571
 
 
572
            }
 
573
 
 
574
            vbi->lastcode = ( b1 << 8) | b2;
 
575
            vbi->lastcount = 0;
 
576
            return 1;
 
577
        }
 
578
 
 
579
        if( (b1 & 8) == 1 ) {
 
580
            /* Midrow code */
 
581
            if( !vbi->initialised ) return 0;
 
582
 
 
583
            if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
 
584
                vbi->lastcount = (vbi->lastcount + 1) % 2;
 
585
                return 1;
 
586
            }
 
587
 
 
588
            if( vbi->verbose ) fprintf( stderr, "Midrow TODO: Add me.\n" );
 
589
 
 
590
            vbi->lastcode = ( b1 << 8) | b2;
 
591
            return 1;
 
592
        }
 
593
 
 
594
        if( (b1 & 2) && !(b2 & 64) ) {
 
595
            if( !vbi->initialised ) return 0;
 
596
 
 
597
            if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
 
598
                vbi->lastcount = (vbi->lastcount + 1) % 2;
 
599
                return 1;
 
600
            }
 
601
 
 
602
            if( vbi->verbose ) fprintf( stderr, "Tab Offset: %d columns\n", b2 & 3 );
 
603
            if( vbi->wanttext && vbi->current_istext && 
 
604
                vbi->current_chan == vbi->chan && !bottom == vbi->wanttop ) {
 
605
                vbiscreen_tab( vbi->vs, b2 & 3 );
 
606
            }
 
607
            vbi->lastcode = ( b1 << 8) | b2;
 
608
            return 1;
 
609
        }
 
610
 
 
611
        switch( (code = b2 & 15) ) {
 
612
        case 0: /* POP-UP */
 
613
        case 5: /* ROLL UP 2 */
 
614
        case 6: /* ROLL UP 3 */
 
615
        case 7: /* ROLL UP 4 */
 
616
        case 9: /* PAINT-ON */
 
617
        case 10:/* TEXT */
 
618
        case 11:/* TEXT */
 
619
            vbi->initialised = 1;
 
620
            if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
 
621
                /* This is the repeated Control Code */
 
622
                vbi->lastcount = (vbi->lastcount + 1) % 2;
 
623
                return 1;
 
624
            }
 
625
            switch( code ) {
 
626
            case 0: /* POP-UP */
 
627
                if( !vbi->wanttext && vbi->current_chan == vbi->chan &&
 
628
                    !bottom == vbi->wanttop ) {
 
629
                    if( vbi->verbose )
 
630
                        fprintf( stderr, "Pop-Up\n");
 
631
                    vbi->indent = vbi->current_indent;
 
632
                    vbi->ital = vbi->current_ital;
 
633
                    vbi->colour = vbi->current_colour;
 
634
                    vbi->row = vbi->current_row;
 
635
                    vbi->current_istext = 0;
 
636
                    vbiscreen_set_mode( vbi->vs, 1, POP_UP );
 
637
                }
 
638
                break;
 
639
            case 5: /* ROLL UP 2 */ 
 
640
                if( !vbi->wanttext && vbi->current_chan == vbi->chan &&
 
641
                    !bottom == vbi->wanttop ) {
 
642
                    if( vbi->verbose )
 
643
                        fprintf( stderr, "Roll-Up 2 (RU2)\n");
 
644
                    vbi->indent = vbi->current_indent;
 
645
                    vbi->ital = vbi->current_ital;
 
646
                    vbi->colour = vbi->current_colour;
 
647
                    vbi->row = vbi->current_row;
 
648
                    vbi->current_istext = 0;
 
649
                    vbiscreen_set_mode( vbi->vs, 1, ROLL_2 );
 
650
                }
 
651
                break;
 
652
            case 6: /* ROLL UP 3 */ 
 
653
                if( !vbi->wanttext && vbi->current_chan == vbi->chan &&
 
654
                    !bottom == vbi->wanttop ) {
 
655
                    if( vbi->verbose )
 
656
                        fprintf( stderr, "Roll-Up 3 (RU3)\n");
 
657
                    vbi->indent = vbi->current_indent;
 
658
                    vbi->ital = vbi->current_ital;
 
659
                    vbi->colour = vbi->current_colour;
 
660
                    vbi->row = vbi->current_row;
 
661
                    vbi->current_istext = 0;
 
662
                    vbiscreen_set_mode( vbi->vs, 1, ROLL_3 );
 
663
                }
 
664
                break;
 
665
            case 7: /* ROLL UP 4 */ 
 
666
                if( !vbi->wanttext && vbi->current_chan == vbi->chan &&
 
667
                    !bottom == vbi->wanttop ) {
 
668
                    if( vbi->verbose )
 
669
                        fprintf( stderr, "Roll-Up 4 (RU4)\n");
 
670
                    vbi->indent = vbi->current_indent;
 
671
                    vbi->ital = vbi->current_ital;
 
672
                    vbi->colour = vbi->current_colour;
 
673
                    vbi->row = vbi->current_row;
 
674
                    vbi->current_istext = 0;
 
675
                    vbiscreen_set_mode( vbi->vs, 1, ROLL_4 );
 
676
                }
 
677
                break;
 
678
            case 9: /* PAINT-ON */
 
679
                if( !vbi->wanttext && vbi->current_chan == vbi->chan &&
 
680
                    !bottom == vbi->wanttop ) {
 
681
                    if( vbi->verbose )
 
682
                        fprintf( stderr, "Paint-On\n");
 
683
                    vbi->indent = vbi->current_indent;
 
684
                    vbi->ital = vbi->current_ital;
 
685
                    vbi->colour = vbi->current_colour;
 
686
                    vbi->row = vbi->current_row;
 
687
                    vbi->current_istext = 0;
 
688
                    vbiscreen_set_mode( vbi->vs, 1, PAINT_ON );
 
689
                }
 
690
                break;
 
691
            case 10:/* TEXT */
 
692
                if( vbi->wanttext && vbi->current_chan == vbi->chan &&
 
693
                    !bottom == vbi->wanttop ) {
 
694
                    if( vbi->verbose )
 
695
                        fprintf( stderr, "Text Restart\n");
 
696
                    vbi->indent = vbi->current_indent;
 
697
                    vbi->ital = vbi->current_ital;
 
698
                    vbi->colour = vbi->current_colour;
 
699
                    vbi->row = vbi->current_row;
 
700
                    vbi->current_istext = 1;
 
701
                    vbiscreen_set_mode( vbi->vs, 0, 0 );
 
702
                }
 
703
                break;
 
704
            case 11:/* TEXT */
 
705
                if( vbi->wanttext && vbi->current_chan == vbi->chan &&
 
706
                    !bottom == vbi->wanttop ) {
 
707
                    if( vbi->verbose )
 
708
                        fprintf( stderr, "Resume Text Display\n");
 
709
                    vbi->indent = vbi->current_indent;
 
710
                    vbi->ital = vbi->current_ital;
 
711
                    vbi->colour = vbi->current_colour;
 
712
                    vbi->row = vbi->current_row;
 
713
                    vbi->current_istext = 1;
 
714
                    vbiscreen_set_mode( vbi->vs, 0, 0 );
 
715
                }
 
716
                break;
 
717
            default: /* impossible */
 
718
                break;
 
719
            }
 
720
            break;
 
721
        case 1:
 
722
            if( !vbi->initialised ) return 0;
 
723
            if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
 
724
                vbi->lastcount = (vbi->lastcount + 1) % 2;
 
725
            }
 
726
            if( !bottom == vbi->wanttop && vbi->current_chan == vbi->chan &&
 
727
                vbi->current_istext == vbi->wanttext ) {
 
728
                if( vbi->verbose )
 
729
                    fprintf( stderr, "Backspace\n");
 
730
                vbiscreen_backspace( vbi->vs );
 
731
            }
 
732
            break;
 
733
        case 2:
 
734
        case 3:
 
735
            if( !vbi->initialised ) return 0;
 
736
            fprintf( stderr, "Reserved\n");
 
737
            break;
 
738
        case 4:
 
739
            if( !vbi->initialised ) return 0;
 
740
            if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
 
741
                vbi->lastcount = (vbi->lastcount + 1) % 2;
 
742
            }
 
743
            if( !bottom == vbi->wanttop && vbi->current_chan == vbi->chan &&
 
744
                vbi->current_istext == vbi->wanttext ) {
 
745
                if( vbi->verbose )
 
746
                    fprintf( stderr, "Delete to End of Row\n");
 
747
                vbiscreen_delete_to_end( vbi->vs );
 
748
            }
 
749
            break;
 
750
        case 8:
 
751
            if( !vbi->initialised ) return 0;
 
752
            if( vbi->verbose )
 
753
                fprintf( stderr, "Flash On\n");
 
754
            break;
 
755
        case 12:
 
756
        case 13:
 
757
        case 14:
 
758
        case 15:
 
759
            if( !vbi->initialised ) return 0;
 
760
            if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
 
761
                vbi->lastcount = (vbi->lastcount + 1) % 2;
 
762
                return 1;
 
763
            }
 
764
 
 
765
            switch( code ) {
 
766
            case 12:
 
767
                /* Show buffer 1, Fill buffer 2 */
 
768
                if( !bottom == vbi->wanttop && 
 
769
                    vbi->current_chan == vbi->chan && 
 
770
                    vbi->current_istext == vbi->wanttext ) {
 
771
                    if( vbi->verbose )
 
772
                        fprintf( stderr, "Erase Displayed Memory\n");
 
773
                    vbiscreen_erase_displayed( vbi->vs );
 
774
                }
 
775
                break;
 
776
            case 13:
 
777
                if( !bottom == vbi->wanttop && 
 
778
                    vbi->current_chan == vbi->chan && 
 
779
                    vbi->current_istext == vbi->wanttext ) {
 
780
                    if( vbi->verbose )
 
781
                        fprintf( stderr, "Carriage Return\n");
 
782
                    vbiscreen_carriage_return( vbi->vs );
 
783
                }
 
784
                break;
 
785
            case 14:
 
786
                if( !bottom == vbi->wanttop && 
 
787
                    vbi->current_chan == vbi->chan && 
 
788
                    vbi->current_istext == vbi->wanttext ) {
 
789
                    if( vbi->verbose )
 
790
                        fprintf( stderr, "Erase Non-Displayed\n");
 
791
                    vbiscreen_erase_non_displayed( vbi->vs );
 
792
                }
 
793
                break;
 
794
            case 15:
 
795
                /* Show buffer 2, Fill Buffer 1 */
 
796
                if( !bottom == vbi->wanttop && 
 
797
                    vbi->current_chan == vbi->chan && 
 
798
                    vbi->current_istext == vbi->wanttext ) {
 
799
                    if( vbi->verbose )
 
800
                        fprintf( stderr, "End Of Caption\n");
 
801
                    vbiscreen_end_of_caption( vbi->vs );
 
802
                }
 
803
                break;
 
804
            default: /* impossible */
 
805
                return 0;
 
806
                break;
 
807
            }
 
808
            break;
 
809
        default: /* Impossible */
 
810
            return 0;
 
811
            break;
 
812
        }
 
813
 
 
814
        if( vbi->lastcode != ((b1 << 8) | b2) ) {
 
815
            vbi->lastcount = 0;
 
816
        }
 
817
 
 
818
        vbi->lastcode =  (b1 << 8) | b2;
 
819
        return 1;
 
820
    }
 
821
 
 
822
    if( bottom && xds_decode( vbi, b1, b2 ) ) {
 
823
        return 1;
 
824
    }
 
825
 
 
826
    if( !vbi->vs ) return 0;
 
827
    if( !vbi->enabled ) return 0;
 
828
 
 
829
    vbi->lastcode = 0;
 
830
    vbi->lastcount = 0;
 
831
 
 
832
    if( !vbi->initialised ) {
 
833
        return 0;
 
834
    }
 
835
 
 
836
    if( !bottom != vbi->wanttop || vbi->current_chan != vbi->chan || 
 
837
        vbi->current_istext != vbi->wanttext ) {
 
838
        return 0;
 
839
    }
 
840
 
 
841
    if( b1 == 0x11 || b1 == 0x19 || 
 
842
        b1 == 0x12 || b1 == 0x13 || 
 
843
        b1 == 0x1A || b1 == 0x1B ) {
 
844
        switch( b1 ) {
 
845
        case 0x1A:
 
846
        case 0x12:
 
847
            /* use extcode1 */
 
848
            if( b1 > 31 && b2 > 31 && b1 <= 0x3F && b2 <= 0x3F )
 
849
                if( vbi->verbose )
 
850
                    fprintf( stderr, "char %d (%c),  char %d (%c)\n", b1, 
 
851
                             extcode1[b1-32] , b2, extcode1[b2-32] );
 
852
 
 
853
            break;
 
854
        case 0x13:
 
855
        case 0x1B:
 
856
            /* use extcode2 */
 
857
            if( b1 > 31 && b2 > 31 && b1 <= 0x3F && b2 <= 0x3F )
 
858
                if( vbi->verbose )
 
859
                    fprintf( stderr, "char %d (%c),  char %d (%c)\n", b1, 
 
860
                             extcode2[b1-32] , b2, extcode2[b2-32] );
 
861
 
 
862
            break;
 
863
        case 0x11:
 
864
        case 0x19:
 
865
            /* use wcode */
 
866
            if( b1 > 31 && b2 > 31 && b1 <= 0x3F && b2 <= 0x3F )
 
867
                if( vbi->verbose )
 
868
                    fprintf( stderr, "char %d (%c),  char %d (%c)\n", b1, 
 
869
                             wccode[b1-32] , b2, wccode[b2-32] );
 
870
 
 
871
            break;
 
872
        default:
 
873
            break;
 
874
        }
 
875
    } else if( b1 ) {
 
876
        /* use ccode */
 
877
        if( b1 < 32 ) b1 = 32;
 
878
        if( b2 < 32 ) b2 = 32;
 
879
        if( vbi->verbose )
 
880
            fprintf( stderr, "vbidata: data: %c %c\n", ccode[b1-32], 
 
881
                     ccode[b2-32] );
 
882
        vbiscreen_print( vbi->vs, ccode[b1-32], ccode[b2-32] );
 
883
    }
 
884
 
 
885
 
 
886
    return 1;
 
887
}
 
888
 
 
889
vbidata_t *vbidata_new( const char *filename, vbiscreen_t *vs, int verbose )
 
890
{
 
891
    vbidata_t *vbi = malloc( sizeof( vbidata_t ) );
 
892
 
 
893
    if( !vbi ) {
 
894
        return 0;
 
895
    }
 
896
 
 
897
    vbi->filename = strdup( filename );
 
898
    if( !vbi->filename ) {
 
899
        free( vbi );
 
900
        return 0;
 
901
    }
 
902
 
 
903
    vbi->open = 0;
 
904
    vbi->usexds = 0;
 
905
    vbi->vs = vs;
 
906
    vbi->verbose = verbose;
 
907
 
 
908
    vbidata_reset( vbi );
 
909
 
 
910
    return vbi;
 
911
}
 
912
 
 
913
static void vbidata_open_device( vbidata_t *vbi )
 
914
{
 
915
    vbi->fd = open( vbi->filename, O_RDONLY );
 
916
    if( vbi->fd < 0 ) {
 
917
        fprintf( stderr, "vbidata: Can't open %s: %s\n",
 
918
                 vbi->filename, strerror( errno ) );
 
919
    } else {
 
920
        vbi->open = 1;
 
921
    }
 
922
}
 
923
 
 
924
static void vbidata_close_device( vbidata_t *vbi )
 
925
{
 
926
    close( vbi->fd );
 
927
    vbi->open = 0;
 
928
}
 
929
 
 
930
void vbidata_delete( vbidata_t *vbi )
 
931
{
 
932
    if( vbi->open ) vbidata_close_device( vbi );
 
933
    free( vbi );
 
934
}
 
935
 
 
936
void vbidata_reset( vbidata_t *vbi )
 
937
{
 
938
    int i;
 
939
 
 
940
    vbi->wanttop = 0;
 
941
    vbi->wanttext = 0;
 
942
    vbi->colour = 0xFFFFFFFF;
 
943
    vbi->row = 0; 
 
944
 
 
945
    vbi->ital = 0; 
 
946
    vbi->indent = 0;
 
947
    vbi->ul = 0;
 
948
 
 
949
    vbi->chan = 0;
 
950
 
 
951
    vbi->initialised = 0;
 
952
    vbi->enabled = 0;
 
953
 
 
954
    memset( vbi->program_name, 0, sizeof( vbi->program_name ) );
 
955
    memset( vbi->program_start_time, 0, sizeof( vbi->program_start_time ) );
 
956
    memset( vbi->program_length, 0, sizeof( vbi->program_length ) );
 
957
    memset( vbi->network_name, 0, sizeof( vbi->network_name ) );
 
958
    memset( vbi->call_letters, 0, sizeof( vbi->call_letters ) );
 
959
    vbi->rating = "";
 
960
    vbi->program_type = "";
 
961
 
 
962
    memset( vbi->program_desc, 0, 8 * sizeof( char * ) );
 
963
    for( i = 0; i < 8; i++ ) {
 
964
        memset( vbi->program_desc[ i ], 0, sizeof( vbi->program_desc[ i ] ) );
 
965
    }
 
966
 
 
967
    vbi->start_day = 0;
 
968
    vbi->start_month = 0;
 
969
    vbi->start_min = 0;
 
970
    vbi->start_hour = 0;
 
971
    vbi->length_hour = 0;
 
972
    vbi->length_min = 0;
 
973
    vbi->length_elapsed_hour = 0;
 
974
    vbi->length_elapsed_min = 0;
 
975
    vbi->length_elapsed_sec = 0;
 
976
 
 
977
    vbi->lastcode = 0;
 
978
    vbi->lastcount = 0;
 
979
    vbi->xds_packet[ 0 ] = 0;
 
980
    vbi->xds_cursor = 0;
 
981
 
 
982
    if( vbi->vs ) {
 
983
        vbiscreen_reset( vbi->vs );
 
984
    }
 
985
}
 
986
 
 
987
void vbidata_capture_mode( vbidata_t *vbi, int mode )
 
988
{
 
989
    switch( mode ) {
 
990
    case CAPTURE_OFF:
 
991
        vbi->enabled = 0;
 
992
        break;
 
993
    case CAPTURE_CC1:
 
994
        vbi->wanttop = 1;
 
995
        vbi->wanttext = 0;
 
996
        vbi->chan = 0;
 
997
        vbi->enabled = 1;
 
998
        break;
 
999
    case CAPTURE_CC2:
 
1000
        vbi->wanttop = 1;
 
1001
        vbi->wanttext = 0;
 
1002
        vbi->chan = 1;
 
1003
        vbi->enabled = 1;
 
1004
        break;
 
1005
    case CAPTURE_CC3:
 
1006
        vbi->wanttop = 0;
 
1007
        vbi->wanttext = 0;
 
1008
        vbi->chan = 0;
 
1009
        vbi->enabled = 1;
 
1010
        break;
 
1011
    case CAPTURE_CC4:
 
1012
        vbi->wanttop = 0;
 
1013
        vbi->wanttext = 0;
 
1014
        vbi->chan = 1;
 
1015
        vbi->enabled = 1;
 
1016
        break;
 
1017
    case CAPTURE_T1:
 
1018
        vbi->wanttop = 1;
 
1019
        vbi->wanttext = 1;
 
1020
        vbi->chan = 0;
 
1021
        vbi->enabled = 1;
 
1022
        break;
 
1023
    case CAPTURE_T2:
 
1024
        vbi->wanttop = 1;
 
1025
        vbi->wanttext = 1;
 
1026
        vbi->chan = 1;
 
1027
        vbi->enabled = 1;
 
1028
        break;
 
1029
    case CAPTURE_T3:
 
1030
        vbi->wanttop = 0;
 
1031
        vbi->wanttext = 1;
 
1032
        vbi->chan = 0;
 
1033
        vbi->enabled = 1;
 
1034
        break;
 
1035
    case CAPTURE_T4:
 
1036
        vbi->wanttop = 0;
 
1037
        vbi->wanttext = 1;
 
1038
        vbi->chan = 1;
 
1039
        vbi->enabled = 1;
 
1040
        break;
 
1041
    default:
 
1042
        vbi->enabled = 0;
 
1043
        break;
 
1044
    }
 
1045
 
 
1046
    if( !vbi->enabled && vbi->vs ) {
 
1047
        vbiscreen_reset( vbi->vs );
 
1048
    }
 
1049
 
 
1050
    if( vbi->enabled && !vbi->open ) {
 
1051
        vbidata_open_device( vbi );
 
1052
    }
 
1053
 
 
1054
    if( !vbi->enabled && !vbi->usexds && vbi->open ) {
 
1055
        vbidata_reset( vbi );
 
1056
        vbidata_close_device( vbi );
 
1057
    }
 
1058
}
 
1059
 
 
1060
void vbidata_capture_xds( vbidata_t *vbi, int xds )
 
1061
{
 
1062
    vbi->usexds = xds;
 
1063
 
 
1064
    if( vbi->usexds && !vbi->open ) {
 
1065
        vbidata_open_device( vbi );
 
1066
    }
 
1067
 
 
1068
    if( !vbi->usexds && !vbi->enabled && vbi->open ) {
 
1069
        vbidata_reset( vbi );
 
1070
        vbidata_close_device( vbi );
 
1071
    }
 
1072
}
 
1073
 
 
1074
void vbidata_process_frame( vbidata_t *vbi, int printdebug )
 
1075
{
 
1076
    if( vbi->open ) {
 
1077
        if( read( vbi->fd, vbi->buf, 65536 ) < 65536 ) {
 
1078
            if( vbi->verbose ) {
 
1079
                fprintf( stderr, "vbidata: Can't read vbi data: %s\n",
 
1080
                         strerror( errno ) );
 
1081
            }
 
1082
        } else {
 
1083
            int scanline = 11; /* Process line 21. */
 
1084
            int k;
 
1085
 
 
1086
            /* Apply diz' new filter. */
 
1087
            for( k = 1; k < 7; k++ ) {
 
1088
                int j = scanline * 2048;
 
1089
                int i;
 
1090
 
 
1091
                for( i = 1600; i > 0; i-- ) {
 
1092
                    vbi->buf[i + j] = (vbi->buf[i + j + k] + vbi->buf[i + j]) / 2;
 
1093
                }
 
1094
            }
 
1095
            ProcessLine( vbi, &vbi->buf[ scanline * 2048 ], 0 );
 
1096
 
 
1097
            /* Apply diz' new filter. */
 
1098
            for( k = 1; k < 7; k++ ) {
 
1099
                int j = ( 16 + scanline )*2048;
 
1100
                int i;
 
1101
 
 
1102
                for( i = 1600; i > 0; i-- ) {
 
1103
                    vbi->buf[i + j] = (vbi->buf[i + j + k] + vbi->buf[i + j]) / 2;
 
1104
                }
 
1105
            }
 
1106
            ProcessLine( vbi, &vbi->buf[ ( 16 + scanline ) * 2048 ], 1 );
 
1107
        }
 
1108
    }
 
1109
}
 
1110
 
 
1111
const char *vbidata_get_program_name( vbidata_t *vbi )
 
1112
{
 
1113
    return vbi->program_name;
 
1114
}
 
1115
 
 
1116
const char *vbidata_get_program_type( vbidata_t *vbi )
 
1117
{
 
1118
    return vbi->program_type;
 
1119
}
 
1120
 
 
1121
const char *vbidata_get_program_rating( vbidata_t *vbi )
 
1122
{
 
1123
    return vbi->rating;
 
1124
}
 
1125
 
 
1126
const char *vbidata_get_network_name( vbidata_t *vbi )
 
1127
{
 
1128
    return vbi->network_name;
 
1129
}
 
1130
 
 
1131
const char *vbidata_get_program_start_time( vbidata_t *vbi )
 
1132
{
 
1133
    return vbi->program_start_time;
 
1134
}
 
1135
 
 
1136
const char *vbidata_get_program_length( vbidata_t *vbi )
 
1137
{
 
1138
    return vbi->program_length;
 
1139
}
 
1140
 
 
1141
const char *vbidata_get_network_call_letters( vbidata_t *vbi )
 
1142
{
 
1143
    return vbi->call_letters;
 
1144
}
 
1145