summaryrefslogtreecommitdiffstats
path: root/gst/vbidec/vbidata.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst/vbidec/vbidata.c')
-rw-r--r--gst/vbidec/vbidata.c1079
1 files changed, 1079 insertions, 0 deletions
diff --git a/gst/vbidec/vbidata.c b/gst/vbidec/vbidata.c
new file mode 100644
index 00000000..14d7a7e0
--- /dev/null
+++ b/gst/vbidec/vbidata.c
@@ -0,0 +1,1079 @@
+/**
+ * Copyright (c) 2002 Billy Biggs <vektor@dumbterm.net>.
+ * Copyright (c) 2002 Doug Bell <drbell@users.sourceforge.net>
+ *
+ * CC code from Nathan Laredo's ccdecode, used under the GPL.
+ * Lots of 'hey what does this mean?' code from
+ * Billy Biggs and Doug Bell, like all the crap with
+ * XDS and stuff. Some help from Zapping's vbi library by
+ * Michael H. Schimek and others, released under the GPL.
+ *
+ * Modified and adapted to GStreamer by
+ * David I. Lehn <dlehn@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include "vbidata.h"
+#include "vbiscreen.h"
+/*#include "tvtimeosd.h"*/
+
+#define DO_LINE 11
+static int pll = 0;
+
+struct vbidata_s
+{
+ int fd;
+ vbiscreen_t *vs;
+ /*tvtime_osd_t *osd;*/
+ char buf[ 65536 ];
+ int wanttop;
+ int wanttext;
+
+ unsigned int colour;
+ int row, ital;
+ int indent, ul;
+ int chan;
+
+ unsigned int current_colour;
+ int current_row, current_ital;
+ int current_indent, current_ul;
+ int current_chan;
+ int current_istext;
+
+ int initialised;
+ int enabled;
+ int lastcode;
+ int lastcount;
+ int verbose;
+
+ /* XDS data */
+ char xds_packet[ 2048 ];
+ int xds_cursor;
+
+ char *program_name;
+ char *network_name;
+ char *call_letters;
+ const char *rating;
+ const char *program_type;
+ int start_day;
+ int start_month;
+ int start_min;
+ int start_hour;
+ int length_hour;
+ int length_min;
+ int length_elapsed_hour;
+ int length_elapsed_min;
+ int length_elapsed_sec;
+ char *program_desc[8];
+};
+
+
+/* this is NOT exactly right */
+//static char *ccode = " !\"#$%&'()\0341+,-./0123456789:;<=>?@"
+static char *ccode = " !\"#$%&'()a+,-./0123456789:;<=>?@"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+// "abcdefghijklmnopqrstuvwxyz"
+// "[\0351]\0355\0363\0372abcdefghijklmnopqr"
+ "[e]iouabcdefghijklmnopqr"
+// "stuvwxyz\0347\0367\0245\0244\0240";
+ "stuvwxyzcoNn ";
+static char *wccode = "\0256\0260\0275\0277T\0242\0243#\0340 "
+ "\0350\0354\0362\0371";
+
+static char *extcode1 = "\0301\0311\0323\0332\0334\0374"
+ "`\0241*'-\0251S*\"\"\0300\0302"
+ "\0307\0310\0312\0313\0353\0316\0317\0357"
+ "\0324\0331\0371\0333\0253\0273";
+
+static char *extcode2 = "\0303\0343\0315\0314\0354\0322\0362\0325"
+ "{}\\^_|~\0304\0344\0326\0366\0337\0245\0244|"
+ "\0305\0345\0330\0370++++";
+
+int parityok(int n)
+{ /* check parity for 2 bytes packed in n */
+ int j, k;
+ for (k = 0, j = 0; j < 7; j++)
+ if (n & (1 << j))
+ k++;
+ if ((k & 1) && (n & 0x80))
+ return 0;
+ for (k = 0, j = 8; j < 15; j++)
+ if (n & (1 << j))
+ k++;
+ if ((k & 1) && (n & 0x8000))
+ return 0;
+ return 1;
+}
+
+int decodebit(unsigned char *data, int threshold)
+{
+ return ((data[0] + data[1] + data[2] + data[3] + data[4] + data[5] +
+ data[6] + data[7] + data[8] + data[9] + data[10] + data[11] +
+ data[12] + data[13] + data[14] + data[15] + data[16] + data[17] +
+ data[18] + data[19] + data[20] + data[21] + data[22] + data[23] +
+ data[24] + data[25] + data[26] + data[27] + data[28] + data[29] +
+ data[30] + data[31])>>5 > threshold);
+}
+
+
+int ccdecode(unsigned char *vbiline)
+{
+ int max = 0, maxval = 0, minval = 255, i = 0, clk = 0, tmp = 0;
+ int sample, packedbits = 0;
+
+ for (i=0; i<250; i++) {
+ sample = vbiline[i];
+ if (sample - maxval > 10)
+ (maxval = sample, max = i);
+ if (sample < minval)
+ minval = sample;
+ if (maxval - sample > 40)
+ break;
+ }
+ sample = ((maxval + minval) >> 1);
+ pll = max;
+
+ /* found clock lead-in, double-check start */
+#ifndef PAL_DECODE
+ i = max + 478;
+#else
+ i = max + 538;
+#endif
+ if (!decodebit(&vbiline[i], sample))
+ return 0;
+#ifndef PAL_DECODE
+ tmp = i + 57; /* tmp = data bit zero */
+#else
+ tmp = i + 71;
+#endif
+ for (i = 0; i < 16; i++) {
+#ifndef PAL_DECODE
+ clk = tmp + i * 57;
+#else
+ clk = tmp + i * 71;
+#endif
+ if (decodebit(&vbiline[clk], sample)) {
+ packedbits |= 1 << i;
+ }
+ }
+ if (parityok(packedbits))
+ return packedbits;
+ return 0;
+} /* ccdecode */
+
+const char *movies[] = { "N/A", "G", "PG", "PG-13", "R",
+ "NC-17", "X", "Not Rated" };
+const char *usa_tv[] = { "Not Rated", "TV-Y", "TV-Y7", "TV-G",
+ "TV-PG", "TV-14", "TV-MA", "Not Rated" };
+const char *cane_tv[] = { "Exempt", "C", "C8+", "G", "PG",
+ "14+", "18+", "Reserved" };
+const char *canf_tv[] = { "Exempt", "G", "8 ans +", "13 ans +",
+ "16 ans +", "18 ans +", "Reserved",
+ "Reserved" };
+
+const char *months[] = { 0, "Jan", "Feb", "Mar", "Apr", "May",
+ "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+static const char *eia608_program_type[ 96 ] = {
+ "education", "entertainment", "movie", "news", "religious", "sports",
+ "other", "action", "advertisement", "animated", "anthology",
+ "automobile", "awards", "baseball", "basketball", "bulletin", "business",
+ "classical", "college", "combat", "comedy", "commentary", "concert",
+ "consumer", "contemporary", "crime", "dance", "documentary", "drama",
+ "elementary", "erotica", "exercise", "fantasy", "farm", "fashion",
+ "fiction", "food", "football", "foreign", "fund raiser", "game/quiz",
+ "garden", "golf", "government", "health", "high school", "history",
+ "hobby", "hockey", "home", "horror", "information", "instruction",
+ "international", "interview", "language", "legal", "live", "local",
+ "math", "medical", "meeting", "military", "miniseries", "music", "mystery",
+ "national", "nature", "police", "politics", "premiere", "prerecorded",
+ "product", "professional", "public", "racing", "reading", "repair", "repeat",
+ "review", "romance", "science", "series", "service", "shopping",
+ "soap opera", "special", "suspense", "talk", "technical", "tennis",
+ "travel", "variety", "video", "weather", "western"
+};
+
+
+static void parse_xds_packet( vbidata_t *vbi, char *packet, int length )
+{
+ int sum = 0;
+ int i;
+
+ if( !vbi ) return;
+
+ /* Check the checksum for validity of the packet. */
+ for( i = 0; i < length - 1; i++ ) {
+ sum += packet[ i ];
+ }
+ if( (((~sum) & 0x7f) + 1) != packet[ length - 1 ] ) {
+ return;
+ }
+
+ /* Stick a null at the end, and cut off the last two characters. */
+ packet[ length - 2 ] = '\0';
+ length -= 2;
+
+ if( packet[ 0 ] == 0x01 && packet[ 1 ] == 0x03 ) {
+ if( vbi->program_name && !strcmp(vbi->program_name, packet + 2 ) ) {
+ return;
+ }
+ if( vbi->verbose ) fprintf( stderr, "Current program name: '%s'\n", packet + 2 );
+ if( vbi->program_name ) free( vbi->program_name );
+ vbi->program_name = strdup(packet + 2);
+ /*tvtime_osd_set_show_name( vbi->osd, vbi->program_name );*/
+ } else if( packet[ 0 ] == 0x03 && packet[ 1 ] == 0x03 ) {
+ if( vbi->verbose ) fprintf( stderr, "Future program name: '%s'\n", packet + 2 );
+ } else if( packet[ 0 ] == 0x05 && packet[ 1 ] == 0x01 ) {
+ if( vbi->network_name && !strcmp(vbi->network_name, packet + 2 ) ) {
+ return;
+ }
+
+ if( vbi->verbose ) fprintf( stderr, "Network name: '%s'\n", packet + 2 );
+ if( vbi->network_name ) free( vbi->network_name );
+ vbi->network_name = strdup( packet + 2 );
+ /*tvtime_osd_set_network_name( vbi->osd, vbi->network_name );*/
+ } else if( packet[ 0 ] == 0x01 && packet[ 1 ] == 0x05 ) {
+ int movie_rating = packet[ 2 ] & 7;
+ int scheme = (packet[ 2 ] & 56) >> 3;
+ int tv_rating = packet[ 3 ] & 7;
+ int VSL = packet[ 3 ] & 56;
+ const char * str;
+
+ switch( VSL | scheme ) {
+ case 3: /* Canadian English TV */
+ str = cane_tv[ tv_rating ];
+ break;
+ case 7: /* Canadian French TV */
+ str = canf_tv[ tv_rating ];
+ break;
+ case 19: /* Reserved */
+ case 31:
+ str = "";
+ break;
+ default:
+ if( ((VSL | scheme) & 3) == 1 ) {
+ /* USA TV */
+ str = usa_tv[ tv_rating ];
+ } else {
+ /* MPAA Movie Rating */
+ str = movies[ movie_rating ];
+ }
+ break;
+ }
+
+ if( vbi->rating && !strcmp(vbi->rating, str ) ) {
+ return;
+ }
+
+ if( vbi->verbose ) fprintf( stderr, "Show rating: %s", str );
+ if( ((VSL | scheme) & 3) == 1 || ((VSL | scheme) & 3) == 0 ) {
+ /* show VSLD for the americans */
+ if( (VSL | scheme) & 32 ) {
+ if( vbi->verbose ) fprintf( stderr, " V" );
+ }
+ if( (VSL | scheme) & 16 ) {
+ if( vbi->verbose ) fprintf( stderr, " S" );
+ }
+ if( (VSL | scheme) & 8 ) {
+ if( vbi->verbose ) fprintf( stderr, " L" );
+ }
+ if( (VSL | scheme) & 4 ) {
+ if( vbi->verbose ) fprintf( stderr, " D" );
+ }
+ }
+ if( vbi->verbose ) fprintf( stderr, "\n" );
+ vbi->rating = str;
+ /*tvtime_osd_set_show_rating( vbi->osd, vbi->rating );*/
+ } else if( packet[ 0 ] == 0x05 && packet[ 1 ] == 0x02 ) {
+ if( vbi->call_letters && !strcmp(vbi->call_letters, packet + 2 ) ) {
+ return;
+ }
+
+ if( vbi->verbose ) fprintf( stderr, "Network call letters: '%s'\n", packet + 2 );
+ if( vbi->call_letters ) free( vbi->call_letters );
+ vbi->call_letters = strdup( packet + 2 );
+ /*tvtime_osd_set_network_call( vbi->osd, vbi->call_letters );*/
+ } else if( packet[ 0 ] == 0x01 && packet[ 1 ] == 0x01 ) {
+ int month = packet[5];// & 15;
+ int day = packet[4];// & 31;
+ int hour = packet[3];// & 31;
+ int min = packet[2];// & 63;
+ char str[33];
+ if( vbi->verbose ) fprintf( stderr, "Program Start: %02d %s, %02d:%02d\n",
+ day & 31, months[month & 15], hour & 31, min & 63 );
+ // packet[ 3 ], packet[ 4 ], packet[ 5 ], packet[ 6 ] );
+ //packet[ 5 ] & 31, packet[ 6 ], packet[ 4 ] & 31, packet[ 3 ] & 63 );
+ vbi->start_month = month & 15;
+ vbi->start_day = day & 31;
+ vbi->start_hour = hour & 31;
+ vbi->start_min = hour & 63;
+ snprintf( str, 32, "%02d %s, %02d:%02d",
+ day & 31, months[month & 15], hour & 31, min & 63 );
+ /*tvtime_osd_set_show_start( vbi->osd, str );*/
+ } else if( packet[ 0 ] == 0x01 && packet[ 1 ] == 0x04 ) {
+ if( vbi->verbose ) fprintf( stderr, "Program type: " );
+ for( i = 0; i < length - 2; i++ ) {
+ int cur = packet[ 2 + i ] - 0x20;
+ if( cur >= 0 && cur < 96 ) {
+ if( vbi->verbose ) fprintf( stderr, "%s%s", i ? ", " : "", eia608_program_type[ cur ] );
+ /* this will cause us to keep only the last type we check */
+ vbi->program_type = eia608_program_type[ cur ];
+ }
+ }
+ if( vbi->verbose ) fprintf( stderr, "\n" );
+ } else if( packet[ 0 ] < 0x03 && packet[ 1 ] >= 0x10 && packet[ 1 ] <= 0x17 ) {
+
+ if( vbi->program_desc[ packet[1] & 0xf ] &&
+ !strcmp(vbi->program_desc[ packet[1] & 0xf ], packet + 2 ) ) {
+ return;
+ }
+
+ if( vbi->verbose ) fprintf( stderr, "Program Description: Line %d", packet[1] & 0xf );
+ if( vbi->verbose ) fprintf( stderr, "%s\n", packet + 2 );
+ if( vbi->program_desc[ packet[1] & 0xf ] )
+ free( vbi->program_desc[ packet[1] & 0xf ] );
+ vbi->program_desc[ packet[1] & 0xf ] = strdup( packet + 2 );
+ } else if( packet[ 0 ] == 0x01 && packet[ 1 ] == 0x02 ) {
+ char str[ 33 ];
+ str[0] = 0;
+ if( vbi->verbose ) fprintf( stderr, "Program Length: %02d:%02d",
+ packet[ 3 ] & 63, packet[ 2 ] & 63 );
+ vbi->length_hour = packet[ 3 ] & 63;
+ vbi->length_min = packet[ 2 ] & 63;
+ snprintf( str, 32, "%02d:%02d",
+ packet[ 3 ] & 63, packet[ 2 ] & 63 );
+ if( length > 4 ) {
+ if( vbi->verbose ) fprintf( stderr, " Elapsed: %02d:%02d", packet[ 5 ] & 63,
+ packet[ 4 ] & 63 );
+ vbi->length_elapsed_hour = packet[ 5 ] & 63;
+ vbi->length_elapsed_min = packet[ 4 ] & 63;
+ snprintf( str, 32, "%02d:%02d/%02d:%02d",
+ packet[ 5 ] & 63, packet[ 4 ] & 63,
+ packet[ 3 ] & 63, packet[ 2 ] & 63 );
+ } else {
+ vbi->length_elapsed_hour = 0;
+ vbi->length_elapsed_min = 0;
+ }
+
+ if( length > 6 ) {
+ if( vbi->verbose ) fprintf( stderr, ".%02d", packet[ 6 ] & 63 );
+ vbi->length_elapsed_hour = packet[ 6 ] & 63;
+ snprintf( str, 32, "%02d:%02d.%02d/%02d:%02d",
+ packet[ 5 ] & 63, packet[ 4 ] & 63, packet[ 6 ] & 63,
+ packet[ 3 ] & 63, packet[ 2 ] & 63 );
+ } else {
+ vbi->length_elapsed_hour = 0;
+ }
+ /*tvtime_osd_set_show_length( vbi->osd, str );*/
+ if( vbi->verbose ) fprintf( stderr, "\n" );
+ } else if( packet[ 0 ] == 0x05 && packet[ 1 ] == 0x04 ) {
+ if( vbi->verbose ) fprintf( stderr, "Transmission Signal Identifier (TSID): 0x%04x\n",
+ packet[ 2 ] << 24 | packet[ 3 ] << 16 | packet[ 4 ] << 8 | packet[ 5 ] );
+ } else {
+ /* unknown */
+
+ if( vbi->verbose ) fprintf( stderr, "Unknown XDS packet, class " );
+ switch( packet[ 0 ] ) {
+ case 0x1: if( vbi->verbose ) fprintf( stderr, "CURRENT start\n" ); break;
+ case 0x2: if( vbi->verbose ) fprintf( stderr, "CURRENT continue\n" ); break;
+
+ case 0x3: if( vbi->verbose ) fprintf( stderr, "FUTURE start\n" ); break;
+ case 0x4: if( vbi->verbose ) fprintf( stderr, "FUTURE continue\n" ); break;
+
+ case 0x5: if( vbi->verbose ) fprintf( stderr, "CHANNEL start\n" ); break;
+ case 0x6: if( vbi->verbose ) fprintf( stderr, "CHANNEL continue\n" ); break;
+
+ case 0x7: if( vbi->verbose ) fprintf( stderr, "MISC start\n" ); break;
+ case 0x8: if( vbi->verbose ) fprintf( stderr, "MISC continue\n" ); break;
+
+ case 0x9: if( vbi->verbose ) fprintf( stderr, "PUB start\n" ); break;
+ case 0xa: if( vbi->verbose ) fprintf( stderr, "PUB continue\n" ); break;
+
+ case 0xb: if( vbi->verbose ) fprintf( stderr, "RES start\n" ); break;
+ case 0xc: if( vbi->verbose ) fprintf( stderr, "RES continue\n" ); break;
+
+ case 0xd: if( vbi->verbose ) fprintf( stderr, "UNDEF start\n" ); break;
+ case 0xe: if( vbi->verbose ) fprintf( stderr, "UNDEF continue\n" ); break;
+ }
+ for( i = 0; i < length; i++ ) {
+ if( vbi->verbose ) fprintf( stderr, "0x%02x ", packet[ i ] );
+ }
+ if( vbi->verbose ) fprintf( stderr, "\n" );
+ }
+}
+
+static int xds_decode( vbidata_t *vbi, int b1, int b2 )
+{
+ if( !vbi ) return 0;
+ if( vbi->xds_cursor > 2046 ) {
+ vbi->xds_cursor = 0;
+ }
+
+ if( !vbi->xds_cursor && b1 > 0xf ) {
+ return 0;
+ }
+
+
+ if( b1 < 0xf && (b1 & 0x2) ) {
+ /* ignore the continue and thus 'support' continuation of
+ a single packet */
+ return 1;
+ } else if( b1 < 0xf ) {
+ /* kill old packet cause we got a new one */
+ vbi->xds_cursor = 0;
+ }
+
+ vbi->xds_packet[ vbi->xds_cursor ] = b1;
+ vbi->xds_packet[ vbi->xds_cursor + 1 ] = b2;
+ vbi->xds_cursor += 2;
+
+ if( b1 == 0xf ) {
+ parse_xds_packet( vbi, vbi->xds_packet, vbi->xds_cursor );
+ vbi->xds_cursor = 0;
+ }
+
+ return 1;
+}
+
+#define NOMODE 0
+
+#define CC1 1
+#define CC2 2
+#define T1 3
+#define T2 4
+
+#define CC3 1
+#define CC4 2
+#define T3 3
+#define T4 4
+
+const unsigned int colours[] = {
+ 0xFFFFFFFFU, /* white */
+ 0xFF00FF00U, /* green */
+ 0xFF0000FFU, /* blue */
+ 0xFF00C7C7U, /* cyan */
+ 0xFFFF0000U, /* red */
+ 0xFFFFFF00U, /* yellow */
+ 0xFFC700C7U /* magenta */
+};
+
+const int rows[] = {
+ 11,
+ 0, /* unused */
+ 1,
+ 2,
+ 3,
+ 4,
+ 12,
+ 13,
+ 14,
+ 15,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10
+};
+
+#define ROLL_2 6
+#define ROLL_3 7
+#define ROLL_4 8
+#define POP_UP 9
+#define PAINT_ON 10
+
+
+static int Process16b( vbidata_t *vbi, int bottom, int w1 )
+{
+ int b1, b2;
+
+ b1 = w1 & 0x7f;
+ b2 = (w1 >> 8) & 0x7f;
+
+ if( !b1 && !b2 ) {
+ return 0;
+ }
+
+ if( vbi->enabled &&
+ b1 >= 0x10 && b1 <= 0x1F && b2 >= 0x20 && b2 <= 0x7F ) {
+ int code;
+ if( (b2 & 64) ) {
+ /* Preamble Code */
+ /* This sets up colors and indenting */
+
+ if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
+ vbi->lastcount = (vbi->lastcount + 1) % 2;
+ return 1;
+ }
+
+ vbi->current_chan = (b1 & 8) >> 3;
+ if( !bottom == vbi->wanttop ) {
+ if( vbi->chan != vbi->current_chan )
+ return 0;
+ } else return 0;
+
+ vbi->current_ital = (b2 & 1);
+ if( !(b2 & 16) ) {
+ vbi->current_colour = colours[ (b2 & 30) >> 1 ];
+ vbi->current_indent = 0;
+ } else {
+ vbi->current_colour = 0xFFFFFFFFU; /* white */
+ vbi->current_indent = 4*( (b2 & 14) >> 1 );
+ }
+ vbi->current_row = rows[ ((b1 & 7) << 1) | ((b2 & 32) >> 5) ];
+ vbi->current_ul = b2 & 1;
+
+ if( vbi->verbose ) fprintf( stderr, "field: %d chan %d, ital %d, ul %d, colour 0x%x, "
+ "indent %d, row %d\n", bottom, vbi->current_chan,
+ vbi->current_ital, vbi->current_ul, vbi->current_colour,
+ vbi->current_indent, vbi->current_row );
+
+ if( !bottom == vbi->wanttop &&
+ vbi->current_chan == vbi->chan &&
+ vbi->current_istext == vbi->wanttext ) {
+
+ vbi->indent = vbi->current_indent;
+ vbi->ital = vbi->current_ital;
+ vbi->colour = vbi->current_colour;
+ vbi->row = vbi->current_row;
+ vbi->current_istext = 0;
+
+ vbiscreen_new_caption( vbi->vs, vbi->indent, vbi->ital,
+ vbi->colour, vbi->row );
+
+ }
+
+ vbi->lastcode = ( b1 << 8) | b2;
+ vbi->lastcount = 0;
+ return 1;
+ }
+
+ if( (b1 & 8) == 1 ) {
+ /* Midrow code */
+ if( !vbi->initialised ) return 0;
+
+ if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
+ vbi->lastcount = (vbi->lastcount + 1) % 2;
+ return 1;
+ }
+
+ if( vbi->verbose ) fprintf( stderr, "Midrow TODO: Add me.\n" );
+
+ vbi->lastcode = ( b1 << 8) | b2;
+ return 1;
+ }
+
+ if( (b1 & 2) && !(b2 & 64) ) {
+ if( !vbi->initialised ) return 0;
+
+ if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
+ vbi->lastcount = (vbi->lastcount + 1) % 2;
+ return 1;
+ }
+
+ if( vbi->verbose ) fprintf( stderr, "Tab Offset: %d columns\n", b2 & 3 );
+ if( vbi->wanttext && vbi->current_istext &&
+ vbi->current_chan == vbi->chan && !bottom == vbi->wanttop ) {
+ vbiscreen_tab( vbi->vs, b2 & 3 );
+ }
+ vbi->lastcode = ( b1 << 8) | b2;
+ return 1;
+ }
+
+ switch( (code = b2 & 15) ) {
+ case 0: /* POP-UP */
+ case 5: /* ROLL UP 2 */
+ case 6: /* ROLL UP 3 */
+ case 7: /* ROLL UP 4 */
+ case 9: /* PAINT-ON */
+ case 10:/* TEXT */
+ case 11:/* TEXT */
+ vbi->initialised = 1;
+ if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
+ /* This is the repeated Control Code */
+ vbi->lastcount = (vbi->lastcount + 1) % 2;
+ return 1;
+ }
+ switch( code ) {
+ case 0: /* POP-UP */
+ if( !vbi->wanttext && vbi->current_chan == vbi->chan &&
+ !bottom == vbi->wanttop ) {
+ if( vbi->verbose )
+ fprintf( stderr, "Pop-Up\n");
+ vbi->indent = vbi->current_indent;
+ vbi->ital = vbi->current_ital;
+ vbi->colour = vbi->current_colour;
+ vbi->row = vbi->current_row;
+ vbi->current_istext = 0;
+ vbiscreen_set_mode( vbi->vs, 1, POP_UP );
+ }
+ break;
+ case 5: /* ROLL UP 2 */
+ if( !vbi->wanttext && vbi->current_chan == vbi->chan &&
+ !bottom == vbi->wanttop ) {
+ if( vbi->verbose )
+ fprintf( stderr, "Roll-Up 2 (RU2)\n");
+ vbi->indent = vbi->current_indent;
+ vbi->ital = vbi->current_ital;
+ vbi->colour = vbi->current_colour;
+ vbi->row = vbi->current_row;
+ vbi->current_istext = 0;
+ vbiscreen_set_mode( vbi->vs, 1, ROLL_2 );
+ }
+ break;
+ case 6: /* ROLL UP 3 */
+ if( !vbi->wanttext && vbi->current_chan == vbi->chan &&
+ !bottom == vbi->wanttop ) {
+ if( vbi->verbose )
+ fprintf( stderr, "Roll-Up 3 (RU3)\n");
+ vbi->indent = vbi->current_indent;
+ vbi->ital = vbi->current_ital;
+ vbi->colour = vbi->current_colour;
+ vbi->row = vbi->current_row;
+ vbi->current_istext = 0;
+ vbiscreen_set_mode( vbi->vs, 1, ROLL_3 );
+ }
+ break;
+ case 7: /* ROLL UP 4 */
+ if( !vbi->wanttext && vbi->current_chan == vbi->chan &&
+ !bottom == vbi->wanttop ) {
+ if( vbi->verbose )
+ fprintf( stderr, "Roll-Up 4 (RU4)\n");
+ vbi->indent = vbi->current_indent;
+ vbi->ital = vbi->current_ital;
+ vbi->colour = vbi->current_colour;
+ vbi->row = vbi->current_row;
+ vbi->current_istext = 0;
+ vbiscreen_set_mode( vbi->vs, 1, ROLL_4 );
+ }
+ break;
+ case 9: /* PAINT-ON */
+ if( !vbi->wanttext && vbi->current_chan == vbi->chan &&
+ !bottom == vbi->wanttop ) {
+ if( vbi->verbose )
+ fprintf( stderr, "Paint-On\n");
+ vbi->indent = vbi->current_indent;
+ vbi->ital = vbi->current_ital;
+ vbi->colour = vbi->current_colour;
+ vbi->row = vbi->current_row;
+ vbi->current_istext = 0;
+ vbiscreen_set_mode( vbi->vs, 1, PAINT_ON );
+ }
+ break;
+ case 10:/* TEXT */
+ if( vbi->wanttext && vbi->current_chan == vbi->chan &&
+ !bottom == vbi->wanttop ) {
+ if( vbi->verbose )
+ fprintf( stderr, "Text Restart\n");
+ vbi->indent = vbi->current_indent;
+ vbi->ital = vbi->current_ital;
+ vbi->colour = vbi->current_colour;
+ vbi->row = vbi->current_row;
+ vbi->current_istext = 1;
+ vbiscreen_set_mode( vbi->vs, 0, 0 );
+ }
+ break;
+ case 11:/* TEXT */
+ if( vbi->wanttext && vbi->current_chan == vbi->chan &&
+ !bottom == vbi->wanttop ) {
+ if( vbi->verbose )
+ fprintf( stderr, "Resume Text Display\n");
+ vbi->indent = vbi->current_indent;
+ vbi->ital = vbi->current_ital;
+ vbi->colour = vbi->current_colour;
+ vbi->row = vbi->current_row;
+ vbi->current_istext = 1;
+ vbiscreen_set_mode( vbi->vs, 0, 0 );
+ }
+ break;
+ default: /* impossible */
+ break;
+ }
+ break;
+ case 1:
+ if( !vbi->initialised ) return 0;
+ if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
+ vbi->lastcount = (vbi->lastcount + 1) % 2;
+ }
+ if( !bottom == vbi->wanttop && vbi->current_chan == vbi->chan &&
+ vbi->current_istext == vbi->wanttext ) {
+ if( vbi->verbose )
+ fprintf( stderr, "Backspace\n");
+ vbiscreen_backspace( vbi->vs );
+ }
+ break;
+ case 2:
+ case 3:
+ if( !vbi->initialised ) return 0;
+ fprintf( stderr, "Reserved\n");
+ break;
+ case 4:
+ if( !vbi->initialised ) return 0;
+ if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
+ vbi->lastcount = (vbi->lastcount + 1) % 2;
+ }
+ if( !bottom == vbi->wanttop && vbi->current_chan == vbi->chan &&
+ vbi->current_istext == vbi->wanttext ) {
+ if( vbi->verbose )
+ fprintf( stderr, "Delete to End of Row\n");
+ vbiscreen_delete_to_end( vbi->vs );
+ }
+ break;
+ case 8:
+ if( !vbi->initialised ) return 0;
+ if( vbi->verbose )
+ fprintf( stderr, "Flash On\n");
+ break;
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ if( !vbi->initialised ) return 0;
+ if( !bottom && vbi->lastcode == ( (b1 << 8) | b2 ) ) {
+ vbi->lastcount = (vbi->lastcount + 1) % 2;
+ return 1;
+ }
+
+ switch( code ) {
+ case 12:
+ /* Show buffer 1, Fill buffer 2 */
+ if( !bottom == vbi->wanttop &&
+ vbi->current_chan == vbi->chan &&
+ vbi->current_istext == vbi->wanttext ) {
+ if( vbi->verbose )
+ fprintf( stderr, "Erase Displayed Memory\n");
+ vbiscreen_erase_displayed( vbi->vs );
+ }
+ break;
+ case 13:
+ if( !bottom == vbi->wanttop &&
+ vbi->current_chan == vbi->chan &&
+ vbi->current_istext == vbi->wanttext ) {
+ if( vbi->verbose )
+ fprintf( stderr, "Carriage Return\n");
+ vbiscreen_carriage_return( vbi->vs );
+ }
+ break;
+ case 14:
+ if( !bottom == vbi->wanttop &&
+ vbi->current_chan == vbi->chan &&
+ vbi->current_istext == vbi->wanttext ) {
+ if( vbi->verbose )
+ fprintf( stderr, "Erase Non-Displayed\n");
+ vbiscreen_erase_non_displayed( vbi->vs );
+ }
+ break;
+ case 15:
+ /* Show buffer 2, Fill Buffer 1 */
+ if( !bottom == vbi->wanttop &&
+ vbi->current_chan == vbi->chan &&
+ vbi->current_istext == vbi->wanttext ) {
+ if( vbi->verbose )
+ fprintf( stderr, "End Of Caption\n");
+ vbiscreen_end_of_caption( vbi->vs );
+ }
+ break;
+ default: /* impossible */
+ return 0;
+ break;
+ }
+ break;
+ default: /* Impossible */
+ return 0;
+ break;
+ }
+
+ if( vbi->lastcode != ((b1 << 8) | b2) ) {
+ vbi->lastcount = 0;
+ }
+
+ vbi->lastcode = (b1 << 8) | b2;
+ return 1;
+ }
+
+ if( bottom && xds_decode( vbi, b1, b2 ) ) {
+ return 1;
+ }
+
+ if( !vbi->enabled ) return 0;
+
+ vbi->lastcode = 0;
+ vbi->lastcount = 0;
+
+ if( !vbi->initialised )
+ return 0;
+
+ if( !bottom != vbi->wanttop || vbi->current_chan != vbi->chan ||
+ vbi->current_istext != vbi->wanttext ) {
+ return 0;
+ }
+
+ if( b1 == 0x11 || b1 == 0x19 ||
+ b1 == 0x12 || b1 == 0x13 ||
+ b1 == 0x1A || b1 == 0x1B ) {
+ switch( b1 ) {
+ case 0x1A:
+ case 0x12:
+ /* use extcode1 */
+ if( b1 > 31 && b2 > 31 && b1 <= 0x3F && b2 <= 0x3F )
+ if( vbi->verbose )
+ fprintf( stderr, "char %d (%c), char %d (%c)\n", b1,
+ extcode1[b1-32] , b2, extcode1[b2-32] );
+
+ break;
+ case 0x13:
+ case 0x1B:
+ /* use extcode2 */
+ if( b1 > 31 && b2 > 31 && b1 <= 0x3F && b2 <= 0x3F )
+ if( vbi->verbose )
+ fprintf( stderr, "char %d (%c), char %d (%c)\n", b1,
+ extcode2[b1-32] , b2, extcode2[b2-32] );
+
+ break;
+ case 0x11:
+ case 0x19:
+ /* use wcode */
+ if( b1 > 31 && b2 > 31 && b1 <= 0x3F && b2 <= 0x3F )
+ if( vbi->verbose )
+ fprintf( stderr, "char %d (%c), char %d (%c)\n", b1,
+ wccode[b1-32] , b2, wccode[b2-32] );
+
+ break;
+ default:
+ break;
+ }
+ } else if( b1 ) {
+ /* use ccode */
+ if( b1 < 32 ) b1 = 32;
+ if( b2 < 32 ) b2 = 32;
+ if( vbi->verbose )
+ fprintf( stderr, "vbidata: data: %c %c\n", ccode[b1-32],
+ ccode[b2-32] );
+ vbiscreen_print( vbi->vs, ccode[b1-32], ccode[b2-32] );
+ }
+
+
+ return 1;
+} /* Process16b */
+
+int ProcessLine( vbidata_t *vbi, unsigned char *s, int bottom )
+{
+ int w1;
+ /*char *outbuf = NULL;*/
+
+ if( !vbi ) return 0;
+
+ w1 = ccdecode(s);
+
+ return Process16b(vbi, bottom, w1);
+} /* ProcessLine */
+
+
+
+vbidata_t *vbidata_new_file( const char *filename, vbiscreen_t *vs,
+ /*tvtime_osd_t* osd,*/ int verbose )
+{
+ vbidata_t *vbi = (vbidata_t *) malloc( sizeof( vbidata_t ) );
+ if( !vbi ) {
+ return 0;
+ }
+
+ vbi->fd = open( filename, O_RDONLY );
+ if( vbi->fd < 0 ) {
+ fprintf( stderr, "vbidata: Can't open %s: %s\n",
+ filename, strerror( errno ) );
+ free( vbi );
+ return 0;
+ }
+
+ vbi->vs = vs;
+ /*vbi->osd = osd;*/
+ vbi->verbose = verbose;
+
+ vbidata_reset( vbi );
+
+ return vbi;
+}
+
+vbidata_t *vbidata_new_line( vbiscreen_t *vs, int verbose )
+{
+ vbidata_t *vbi = (vbidata_t *) malloc( sizeof( vbidata_t ) );
+ if( !vbi ) {
+ return 0;
+ }
+
+ vbi->vs = vs;
+ /*vbi->osd = osd;*/
+ vbi->verbose = verbose;
+
+ vbidata_reset( vbi );
+
+ return vbi;
+}
+
+void vbidata_delete( vbidata_t *vbi )
+{
+ if( !vbi ) return;
+ if( vbi->fd != 0 ) {
+ close( vbi->fd );
+ }
+ free( vbi );
+}
+
+void vbidata_reset( vbidata_t *vbi )
+{
+ if( !vbi ) return;
+
+ vbi->wanttop = 0;
+ vbi->wanttext = 0;
+ vbi->colour = 0xFFFFFFFFU;
+ vbi->row = 0;
+
+ vbi->ital = 0;
+ vbi->indent = 0;
+ vbi->ul=0;
+
+ vbi->chan=0;
+
+ vbi->initialised = 0;
+ vbi->enabled = 0;
+
+ memset(vbi->program_desc, 0, 8*sizeof(char*) );
+ vbi->program_name = NULL;
+ vbi->network_name = NULL;
+ vbi->call_letters = NULL;
+ vbi->rating = NULL;
+ vbi->program_type = NULL;
+
+ vbi->start_day = 0;
+ vbi->start_month = 0;
+ vbi->start_min = 0;
+ vbi->start_hour = 0;
+ vbi->length_hour = 0;
+ vbi->length_min = 0;
+ vbi->length_elapsed_hour = 0;
+ vbi->length_elapsed_min = 0;
+ vbi->length_elapsed_sec = 0;
+
+ /*
+ tvtime_osd_set_network_call( vbi->osd, "" );
+ tvtime_osd_set_network_name( vbi->osd, "" );
+ tvtime_osd_set_show_name( vbi->osd, "" );
+ tvtime_osd_set_show_rating( vbi->osd, "" );
+ tvtime_osd_set_show_start( vbi->osd, "" );
+ tvtime_osd_set_show_length( vbi->osd, "" );
+ */
+
+
+
+ vbi->lastcode = 0;
+ vbi->lastcount = 0;
+ vbi->xds_packet[ 0 ] = 0;
+ vbi->xds_cursor = 0;
+ vbiscreen_reset( vbi->vs );
+}
+
+void vbidata_capture_mode( vbidata_t *vbi, int mode )
+{
+ if( !vbi ) return;
+ switch( mode ) {
+ case CAPTURE_OFF:
+ vbi->enabled = 0;
+ break;
+ case CAPTURE_CC1:
+ vbi->wanttop = 1;
+ vbi->wanttext = 0;
+ vbi->chan = 0;
+ vbi->enabled = 1;
+ break;
+ case CAPTURE_CC2:
+ vbi->wanttop = 1;
+ vbi->wanttext = 0;
+ vbi->chan = 1;
+ vbi->enabled = 1;
+ break;
+ case CAPTURE_CC3:
+ vbi->wanttop = 0;
+ vbi->wanttext = 0;
+ vbi->chan = 0;
+ vbi->enabled = 1;
+ break;
+ case CAPTURE_CC4:
+ vbi->wanttop = 0;
+ vbi->wanttext = 0;
+ vbi->chan = 1;
+ vbi->enabled = 1;
+ break;
+ case CAPTURE_T1:
+ vbi->wanttop = 1;
+ vbi->wanttext = 1;
+ vbi->chan = 0;
+ vbi->enabled = 1;
+ break;
+ case CAPTURE_T2:
+ vbi->wanttop = 1;
+ vbi->wanttext = 1;
+ vbi->chan = 1;
+ vbi->enabled = 1;
+ break;
+ case CAPTURE_T3:
+ vbi->wanttop = 0;
+ vbi->wanttext = 1;
+ vbi->chan = 0;
+ vbi->enabled = 1;
+ break;
+ case CAPTURE_T4:
+ vbi->wanttop = 0;
+ vbi->wanttext = 1;
+ vbi->chan = 1;
+ vbi->enabled = 1;
+ break;
+ default:
+ vbi->enabled = 0;
+ break;
+ }
+}
+
+void vbidata_process_frame( vbidata_t *vbi, int printdebug )
+{
+ if( read( vbi->fd, vbi->buf, 65536 ) < 65536 ) {
+ fprintf( stderr, "error, can't read vbi data.\n" );
+ return;
+ }
+
+ ProcessLine( vbi, &vbi->buf[ DO_LINE*2048 ], 0 );
+ ProcessLine( vbi, &vbi->buf[ (16+DO_LINE)*2048 ], 1 );
+}
+
+void vbidata_process_line( vbidata_t *vbi, unsigned char *s, int bottom)
+{
+ ProcessLine( vbi, s, bottom );
+}
+
+void vbidata_process_16b( vbidata_t *vbi, int bottom, int w)
+{
+ Process16b( vbi, bottom, w );
+}
+