2
* Copyright (c) 2002, 2003 Billy Biggs <vektor@dumbterm.net>
3
* Copyright (c) 2002 Doug Bell <drbell@users.sourceforge.net>
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.
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.
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)
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.
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.
31
#include <sys/types.h>
57
unsigned int current_colour;
58
int current_row, current_ital;
59
int current_indent, current_ul;
70
char xds_packet[ 2048 ];
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 ];
79
const char *program_type;
86
int length_elapsed_hour;
87
int length_elapsed_min;
88
int length_elapsed_sec;
89
char program_desc[ 8 ][ 33 ];
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";*/
102
static char *wccode = "\0256\0260\0275\0277T\0242\0243#\0340 "
103
"\0350\0354\0362\0371";
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";
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++++";
114
/* Check parity for 2 bytes packed in n. */
115
int parityok( int n )
118
for (k = 0, j = 0; j < 7; j++)
121
if ((k & 1) && (n & 0x80))
123
for (k = 0, j = 8; j < 15; j++)
126
if ((k & 1) && (n & 0x8000))
131
int decodebit( uint8_t *data, int threshold )
133
return (data[0] > threshold);
137
int ccdecode( uint8_t *vbiline )
139
int max = 48, maxval = 128, minval = 255, i = 0, clk = 0, tmp = 0;
140
int sample, packedbits = 0;
142
for (i=0; i<250; i++) {
144
if (sample - maxval > 10)
145
(maxval = sample, max = i);
148
if (maxval - sample > 40)
151
sample = ((maxval + minval) >> 1);
153
/* found clock lead-in, double-check start */
159
if (!decodebit(&vbiline[i], sample))
162
tmp = i + 57; /* tmp = data bit zero */
166
for (i = 0; i < 16; i++) {
172
if (decodebit(&vbiline[clk], sample)) {
173
packedbits |= 1 << i;
176
if (parityok(packedbits))
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",
191
const char *months[] = { 0, "Jan", "Feb", "Mar", "Apr", "May",
192
"Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
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"
214
static void parse_xds_packet( vbidata_t *vbi, char *packet, int length )
219
/* Check the checksum for validity of the packet. */
220
for( i = 0; i < length - 1; i++ ) {
223
if( (((~sum) & 0x7f) + 1) != packet[ length - 1 ] ) {
227
/* Stick a null at the end, and cut off the last two characters. */
228
packet[ length - 2 ] = '\0';
231
if( packet[ 0 ] == 0x01 && packet[ 1 ] == 0x03 ) {
232
if( !strcmp( vbi->program_name, packet + 2 ) ) {
236
fprintf( stderr, "Current program name: '%s'\n", packet + 2 );
238
snprintf( vbi->program_name, sizeof( vbi->program_name ), "%s", packet + 2 );
239
} else if( packet[ 0 ] == 0x03 && packet[ 1 ] == 0x03 ) {
241
fprintf( stderr, "Future program name: '%s'\n", packet + 2 );
243
} else if( packet[ 0 ] == 0x05 && packet[ 1 ] == 0x01 ) {
244
if( !strcmp( vbi->network_name, packet + 2 ) ) {
249
fprintf( stderr, "Network name: '%s'\n", packet + 2 );
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;
259
switch( VSL | scheme ) {
260
case 3: /* Canadian English TV */
261
str = cane_tv[ tv_rating ];
263
case 7: /* Canadian French TV */
264
str = canf_tv[ tv_rating ];
266
case 19: /* Reserved */
271
if( ((VSL | scheme) & 3) == 1 ) {
273
str = usa_tv[ tv_rating ];
275
/* MPAA Movie Rating */
276
str = movies[ movie_rating ];
281
if( vbi->rating && !strcmp(vbi->rating, str ) ) {
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" );
294
fprintf( stderr, "\n" );
297
} else if( packet[ 0 ] == 0x05 && packet[ 1 ] == 0x02 ) {
298
if( !strcmp( vbi->call_letters, packet + 2 ) ) {
303
fprintf( stderr, "Network call letters: '%s'\n", packet + 2 );
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];
310
int hour = packet[3];
313
if( month < 1 || month > 12 ) month = 1;
316
fprintf( stderr, "Program Start: %02d %s, %02d:%02d\n",
317
day & 31, months[month & 15], hour & 31, min & 63 );
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 ) {
327
fprintf( stderr, "Program type: " );
329
for( i = 0; i < length - 2; i++ ) {
330
int cur = packet[ 2 + i ] - 0x20;
331
if( cur >= 0 && cur < 96 ) {
333
fprintf( stderr, "%s%s", i ? ", " : "", eia608_program_type[ cur ] );
335
/* this will cause us to keep only the last type we check */
336
vbi->program_type = eia608_program_type[ cur ];
339
if( vbi->verbose ) fprintf( stderr, "\n" );
340
} else if( packet[ 0 ] < 0x03 && packet[ 1 ] >= 0x10 && packet[ 1 ] <= 0x17 ) {
342
if( !strcmp( vbi->program_desc[ packet[ 1 ] & 0xf ], packet + 2 ) ) {
347
fprintf( stderr, "Program Description: Line %d: %s\n", packet[1] & 0xf, packet + 2 );
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 ) {
354
fprintf( stderr, "Program Length: %02d:%02d",
355
packet[ 3 ] & 63, packet[ 2 ] & 63 );
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 );
364
fprintf( stderr, " Elapsed: %02d:%02d", packet[ 5 ] & 63,
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 );
374
vbi->length_elapsed_hour = 0;
375
vbi->length_elapsed_min = 0;
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 );
386
vbi->length_elapsed_hour = 0;
389
fprintf( stderr, "\n" );
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 ] );
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;
403
case 0x3: fprintf( stderr, "FUTURE start" ); break;
404
case 0x4: fprintf( stderr, "FUTURE continue" ); break;
406
case 0x5: fprintf( stderr, "CHANNEL start" ); break;
407
case 0x6: fprintf( stderr, "CHANNEL continue" ); break;
409
case 0x7: fprintf( stderr, "MISC start" ); break;
410
case 0x8: fprintf( stderr, "MISC continue" ); break;
412
case 0x9: fprintf( stderr, "PUB start" ); break;
413
case 0xa: fprintf( stderr, "PUB continue" ); break;
415
case 0xb: fprintf( stderr, "RES start" ); break;
416
case 0xc: fprintf( stderr, "RES continue" ); break;
418
case 0xd: fprintf( stderr, "UNDEF start" ); break;
419
case 0xe: fprintf( stderr, "UNDEF continue" ); break;
421
fprintf( stderr, "\nvbidata: Data " );
422
for( i = 0; i < length; i++ ) {
423
fprintf( stderr, "0x%02x ", packet[ i ] );
425
fprintf( stderr, "\n" );
430
static int xds_decode( vbidata_t *vbi, int b1, int b2 )
433
if( vbi->xds_cursor > 2046 ) {
437
if( !vbi->xds_cursor && b1 > 0xf ) {
442
if( b1 < 0xf && (b1 & 0x2) ) {
443
/* ignore the continue and thus 'support' continuation of
446
} else if( b1 < 0xf ) {
447
/* kill old packet cause we got a new one */
451
vbi->xds_packet[ vbi->xds_cursor ] = b1;
452
vbi->xds_packet[ vbi->xds_cursor + 1 ] = b2;
453
vbi->xds_cursor += 2;
457
parse_xds_packet( vbi, vbi->xds_packet, vbi->xds_cursor );
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 */
513
int ProcessLine( vbidata_t *vbi, uint8_t *s, int bottom )
520
b2 = (w1 >> 8) & 0x7f;
526
if( vbi->vs && vbi->enabled && b1 >= 0x10 && b1 <= 0x1F && b2 >= 0x20 && b2 <= 0x7F ) {
530
/* This sets up colors and indenting */
532
if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
533
vbi->lastcount = (vbi->lastcount + 1) % 2;
537
vbi->current_chan = (b1 & 8) >> 3;
538
if( !bottom == vbi->wanttop ) {
539
if( vbi->chan != vbi->current_chan )
543
vbi->current_ital = (b2 & 1);
545
vbi->current_colour = colours[ (b2 & 30) >> 1 ];
546
vbi->current_indent = 0;
548
vbi->current_colour = 0xFFFFFFFFU; /* white */
549
vbi->current_indent = 4*( (b2 & 14) >> 1 );
551
vbi->current_row = rows[ ((b1 & 7) << 1) | ((b2 & 32) >> 5) ];
552
vbi->current_ul = b2 & 1;
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 );
559
if( !bottom == vbi->wanttop &&
560
vbi->current_chan == vbi->chan &&
561
vbi->current_istext == vbi->wanttext ) {
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;
569
vbiscreen_new_caption( vbi->vs, vbi->indent, vbi->ital,
570
vbi->colour, vbi->row );
574
vbi->lastcode = ( b1 << 8) | b2;
579
if( (b1 & 8) == 1 ) {
581
if( !vbi->initialised ) return 0;
583
if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
584
vbi->lastcount = (vbi->lastcount + 1) % 2;
588
if( vbi->verbose ) fprintf( stderr, "Midrow TODO: Add me.\n" );
590
vbi->lastcode = ( b1 << 8) | b2;
594
if( (b1 & 2) && !(b2 & 64) ) {
595
if( !vbi->initialised ) return 0;
597
if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
598
vbi->lastcount = (vbi->lastcount + 1) % 2;
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 );
607
vbi->lastcode = ( b1 << 8) | b2;
611
switch( (code = b2 & 15) ) {
613
case 5: /* ROLL UP 2 */
614
case 6: /* ROLL UP 3 */
615
case 7: /* ROLL UP 4 */
616
case 9: /* PAINT-ON */
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;
627
if( !vbi->wanttext && vbi->current_chan == vbi->chan &&
628
!bottom == vbi->wanttop ) {
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 );
639
case 5: /* ROLL UP 2 */
640
if( !vbi->wanttext && vbi->current_chan == vbi->chan &&
641
!bottom == vbi->wanttop ) {
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 );
652
case 6: /* ROLL UP 3 */
653
if( !vbi->wanttext && vbi->current_chan == vbi->chan &&
654
!bottom == vbi->wanttop ) {
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 );
665
case 7: /* ROLL UP 4 */
666
if( !vbi->wanttext && vbi->current_chan == vbi->chan &&
667
!bottom == vbi->wanttop ) {
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 );
678
case 9: /* PAINT-ON */
679
if( !vbi->wanttext && vbi->current_chan == vbi->chan &&
680
!bottom == vbi->wanttop ) {
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 );
692
if( vbi->wanttext && vbi->current_chan == vbi->chan &&
693
!bottom == vbi->wanttop ) {
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 );
705
if( vbi->wanttext && vbi->current_chan == vbi->chan &&
706
!bottom == vbi->wanttop ) {
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 );
717
default: /* impossible */
722
if( !vbi->initialised ) return 0;
723
if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
724
vbi->lastcount = (vbi->lastcount + 1) % 2;
726
if( !bottom == vbi->wanttop && vbi->current_chan == vbi->chan &&
727
vbi->current_istext == vbi->wanttext ) {
729
fprintf( stderr, "Backspace\n");
730
vbiscreen_backspace( vbi->vs );
735
if( !vbi->initialised ) return 0;
736
fprintf( stderr, "Reserved\n");
739
if( !vbi->initialised ) return 0;
740
if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
741
vbi->lastcount = (vbi->lastcount + 1) % 2;
743
if( !bottom == vbi->wanttop && vbi->current_chan == vbi->chan &&
744
vbi->current_istext == vbi->wanttext ) {
746
fprintf( stderr, "Delete to End of Row\n");
747
vbiscreen_delete_to_end( vbi->vs );
751
if( !vbi->initialised ) return 0;
753
fprintf( stderr, "Flash On\n");
759
if( !vbi->initialised ) return 0;
760
if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
761
vbi->lastcount = (vbi->lastcount + 1) % 2;
767
/* Show buffer 1, Fill buffer 2 */
768
if( !bottom == vbi->wanttop &&
769
vbi->current_chan == vbi->chan &&
770
vbi->current_istext == vbi->wanttext ) {
772
fprintf( stderr, "Erase Displayed Memory\n");
773
vbiscreen_erase_displayed( vbi->vs );
777
if( !bottom == vbi->wanttop &&
778
vbi->current_chan == vbi->chan &&
779
vbi->current_istext == vbi->wanttext ) {
781
fprintf( stderr, "Carriage Return\n");
782
vbiscreen_carriage_return( vbi->vs );
786
if( !bottom == vbi->wanttop &&
787
vbi->current_chan == vbi->chan &&
788
vbi->current_istext == vbi->wanttext ) {
790
fprintf( stderr, "Erase Non-Displayed\n");
791
vbiscreen_erase_non_displayed( vbi->vs );
795
/* Show buffer 2, Fill Buffer 1 */
796
if( !bottom == vbi->wanttop &&
797
vbi->current_chan == vbi->chan &&
798
vbi->current_istext == vbi->wanttext ) {
800
fprintf( stderr, "End Of Caption\n");
801
vbiscreen_end_of_caption( vbi->vs );
804
default: /* impossible */
809
default: /* Impossible */
814
if( vbi->lastcode != ((b1 << 8) | b2) ) {
818
vbi->lastcode = (b1 << 8) | b2;
822
if( bottom && xds_decode( vbi, b1, b2 ) ) {
826
if( !vbi->vs ) return 0;
827
if( !vbi->enabled ) return 0;
832
if( !vbi->initialised ) {
836
if( !bottom != vbi->wanttop || vbi->current_chan != vbi->chan ||
837
vbi->current_istext != vbi->wanttext ) {
841
if( b1 == 0x11 || b1 == 0x19 ||
842
b1 == 0x12 || b1 == 0x13 ||
843
b1 == 0x1A || b1 == 0x1B ) {
848
if( b1 > 31 && b2 > 31 && b1 <= 0x3F && b2 <= 0x3F )
850
fprintf( stderr, "char %d (%c), char %d (%c)\n", b1,
851
extcode1[b1-32] , b2, extcode1[b2-32] );
857
if( b1 > 31 && b2 > 31 && b1 <= 0x3F && b2 <= 0x3F )
859
fprintf( stderr, "char %d (%c), char %d (%c)\n", b1,
860
extcode2[b1-32] , b2, extcode2[b2-32] );
866
if( b1 > 31 && b2 > 31 && b1 <= 0x3F && b2 <= 0x3F )
868
fprintf( stderr, "char %d (%c), char %d (%c)\n", b1,
869
wccode[b1-32] , b2, wccode[b2-32] );
877
if( b1 < 32 ) b1 = 32;
878
if( b2 < 32 ) b2 = 32;
880
fprintf( stderr, "vbidata: data: %c %c\n", ccode[b1-32],
882
vbiscreen_print( vbi->vs, ccode[b1-32], ccode[b2-32] );
889
vbidata_t *vbidata_new( const char *filename, vbiscreen_t *vs, int verbose )
891
vbidata_t *vbi = malloc( sizeof( vbidata_t ) );
897
vbi->filename = strdup( filename );
898
if( !vbi->filename ) {
906
vbi->verbose = verbose;
908
vbidata_reset( vbi );
913
static void vbidata_open_device( vbidata_t *vbi )
915
vbi->fd = open( vbi->filename, O_RDONLY );
917
fprintf( stderr, "vbidata: Can't open %s: %s\n",
918
vbi->filename, strerror( errno ) );
924
static void vbidata_close_device( vbidata_t *vbi )
930
void vbidata_delete( vbidata_t *vbi )
932
if( vbi->open ) vbidata_close_device( vbi );
936
void vbidata_reset( vbidata_t *vbi )
942
vbi->colour = 0xFFFFFFFF;
951
vbi->initialised = 0;
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 ) );
960
vbi->program_type = "";
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 ] ) );
968
vbi->start_month = 0;
971
vbi->length_hour = 0;
973
vbi->length_elapsed_hour = 0;
974
vbi->length_elapsed_min = 0;
975
vbi->length_elapsed_sec = 0;
979
vbi->xds_packet[ 0 ] = 0;
983
vbiscreen_reset( vbi->vs );
987
void vbidata_capture_mode( vbidata_t *vbi, int mode )
1046
if( !vbi->enabled && vbi->vs ) {
1047
vbiscreen_reset( vbi->vs );
1050
if( vbi->enabled && !vbi->open ) {
1051
vbidata_open_device( vbi );
1054
if( !vbi->enabled && !vbi->usexds && vbi->open ) {
1055
vbidata_reset( vbi );
1056
vbidata_close_device( vbi );
1060
void vbidata_capture_xds( vbidata_t *vbi, int xds )
1064
if( vbi->usexds && !vbi->open ) {
1065
vbidata_open_device( vbi );
1068
if( !vbi->usexds && !vbi->enabled && vbi->open ) {
1069
vbidata_reset( vbi );
1070
vbidata_close_device( vbi );
1074
void vbidata_process_frame( vbidata_t *vbi, int printdebug )
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 ) );
1083
int scanline = 11; /* Process line 21. */
1086
/* Apply diz' new filter. */
1087
for( k = 1; k < 7; k++ ) {
1088
int j = scanline * 2048;
1091
for( i = 1600; i > 0; i-- ) {
1092
vbi->buf[i + j] = (vbi->buf[i + j + k] + vbi->buf[i + j]) / 2;
1095
ProcessLine( vbi, &vbi->buf[ scanline * 2048 ], 0 );
1097
/* Apply diz' new filter. */
1098
for( k = 1; k < 7; k++ ) {
1099
int j = ( 16 + scanline )*2048;
1102
for( i = 1600; i > 0; i-- ) {
1103
vbi->buf[i + j] = (vbi->buf[i + j + k] + vbi->buf[i + j]) / 2;
1106
ProcessLine( vbi, &vbi->buf[ ( 16 + scanline ) * 2048 ], 1 );
1111
const char *vbidata_get_program_name( vbidata_t *vbi )
1113
return vbi->program_name;
1116
const char *vbidata_get_program_type( vbidata_t *vbi )
1118
return vbi->program_type;
1121
const char *vbidata_get_program_rating( vbidata_t *vbi )
1126
const char *vbidata_get_network_name( vbidata_t *vbi )
1128
return vbi->network_name;
1131
const char *vbidata_get_program_start_time( vbidata_t *vbi )
1133
return vbi->program_start_time;
1136
const char *vbidata_get_program_length( vbidata_t *vbi )
1138
return vbi->program_length;
1141
const char *vbidata_get_network_call_letters( vbidata_t *vbi )
1143
return vbi->call_letters;