From 61898506c8fe0bf85170ab290bf3aecb2c0a81b0 Mon Sep 17 00:00:00 2001 From: "David I. Lehn" Date: Thu, 19 Dec 2002 21:34:56 +0000 Subject: initial checkin of work-in-progress vbidec plugin for closed caption support Original commit message from CVS: initial checkin of work-in-progress vbidec plugin for closed caption support --- gst/vbidec/Makefile.am | 9 + gst/vbidec/gstvbidec.c | 372 +++++++++++++++++ gst/vbidec/gstvbidec.h | 22 + gst/vbidec/vbidata.c | 1079 ++++++++++++++++++++++++++++++++++++++++++++++++ gst/vbidec/vbidata.h | 58 +++ gst/vbidec/vbiscreen.c | 730 ++++++++++++++++++++++++++++++++ gst/vbidec/vbiscreen.h | 49 +++ 7 files changed, 2319 insertions(+) create mode 100644 gst/vbidec/Makefile.am create mode 100644 gst/vbidec/gstvbidec.c create mode 100644 gst/vbidec/gstvbidec.h create mode 100644 gst/vbidec/vbidata.c create mode 100644 gst/vbidec/vbidata.h create mode 100644 gst/vbidec/vbiscreen.c create mode 100644 gst/vbidec/vbiscreen.h (limited to 'gst') diff --git a/gst/vbidec/Makefile.am b/gst/vbidec/Makefile.am new file mode 100644 index 00000000..a7009ec5 --- /dev/null +++ b/gst/vbidec/Makefile.am @@ -0,0 +1,9 @@ +plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@ + +plugin_LTLIBRARIES = libgstvbidec.la + +libgstvbidec_la_SOURCES = gstvbidec.h gstvbidec.c \ + vbidata.h vbidata.c \ + vbiscreen.h vbiscreen.c +libgstvbidec_la_CFLAGS = $(GST_CFLAGS) +libgstvbidec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) diff --git a/gst/vbidec/gstvbidec.c b/gst/vbidec/gstvbidec.c new file mode 100644 index 00000000..1da10543 --- /dev/null +++ b/gst/vbidec/gstvbidec.c @@ -0,0 +1,372 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include "gstvbidec.h" +#include "vbidata.h" +#include "vbiscreen.h" + +#define GST_TYPE_VBIDEC \ + (gst_vbidec_get_type()) +#define GST_VBIDEC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VBIDEC,GstVBIDec)) +#define GST_VBIDEC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VBIDEC,GstVBIDec)) +#define GST_IS_VBIDEC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VBIDEC)) +#define GST_IS_VBIDEC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VBIDEC)) + +//typedef struct _GstVBIDec GstVBIDec; +typedef struct _GstVBIDecClass GstVBIDecClass; + +struct _GstVBIDec { + GstElement element; + + /* pads */ + GstPad *sinkpad, + *srcpad; + char caption[128]; + vbiscreen_t *vbiscreen; + vbidata_t *vbidata; + int caption_type; + gboolean dvd_input; +}; + +struct _GstVBIDecClass { + GstElementClass parent_class; +}; + +GType gst_vbidec_get_type(void); + +/* elementfactory information */ +static GstElementDetails gst_vbidec_details = { + "VBI decoder", + "Codec/Video/Decoder", + "GPL", + "Decodes closed captions and XDS data from VBI data", + VERSION, + "David I. Lehn ", + "(C) 2002" +}; + +/* VBIDec signals and args */ +enum { + LAST_SIGNAL +}; + +enum { + ARG_0, + ARG_CAPTION_TYPE, + ARG_DVD_INPUT +}; + +GST_PAD_TEMPLATE_FACTORY (sink_template_factory, + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "vbidec_sink", + "application/octet-stream", + NULL + ) +); + +GST_PAD_TEMPLATE_FACTORY (src_template_factory, + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "vbidec_src", + "text/plain", + NULL + ) +); + + +#define GST_TYPE_VBIDEC_CAPTION_TYPE_TYPE (gst_vbidec_caption_type_get_type()) +static GType +gst_vbidec_caption_type_get_type (void) +{ + static GType vbidec_caption_type_type = 0; + static GEnumValue vbidec_caption_type[] = { + { CAPTURE_OFF, "0", "Closed Captions off"}, + { CAPTURE_CC1, "1", "Closed Caption CC1"}, + { CAPTURE_CC2, "2", "Closed Caption CC2"}, + { CAPTURE_CC3, "4", "Closed Caption CC3"}, + { CAPTURE_CC4, "5", "Closed Caption CC4"}, + { CAPTURE_T1, "6", "Closed Caption T1"}, + { CAPTURE_T2, "7", "Closed Caption T2"}, + { CAPTURE_T3, "8", "Closed Caption T3"}, + { CAPTURE_T4, "9", "Closed Caption T4"}, + {0, NULL, NULL}, + }; + if (!vbidec_caption_type_type) { + vbidec_caption_type_type = g_enum_register_static ("GstVBIDecCaptionTypeType", vbidec_caption_type); + } + return vbidec_caption_type_type; +} + +static void gst_vbidec_class_init (GstVBIDecClass *klass); +static void gst_vbidec_init (GstVBIDec *vbidec); + +static void gst_vbidec_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec); +static void gst_vbidec_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec); + +static void gst_vbidec_chain (GstPad *pad, GstBuffer *buffer); + +static GstElementClass *parent_class = NULL; +/*static guint gst_vbidec_signals[LAST_SIGNAL] = { 0 };*/ + +GType +gst_vbidec_get_type (void) +{ + static GType vbidec_type = 0; + + if (!vbidec_type) { + static const GTypeInfo vbidec_info = { + sizeof(GstVBIDecClass), + NULL, + NULL, + (GClassInitFunc)gst_vbidec_class_init, + NULL, + NULL, + sizeof(GstVBIDec), + 0, + (GInstanceInitFunc)gst_vbidec_init, + }; + vbidec_type = g_type_register_static(GST_TYPE_ELEMENT, "GstVBIDec", &vbidec_info, 0); + } + return vbidec_type; +} + +static void +gst_vbidec_class_init(GstVBIDecClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass*)klass; + gstelement_class = (GstElementClass*)klass; + + parent_class = g_type_class_ref(GST_TYPE_ELEMENT); + + gobject_class->set_property = gst_vbidec_set_property; + gobject_class->get_property = gst_vbidec_get_property; + + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_CAPTION_TYPE, + g_param_spec_enum ("caption type", "caption type", "Closed Caption Type", + GST_TYPE_VBIDEC_CAPTION_TYPE_TYPE, CAPTURE_OFF, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DVD_INPUT, + g_param_spec_boolean ("dvd input", "dvd input", "VBI is encapsulated in MPEG2 GOP user_data field (as on DVDs)", + FALSE, G_PARAM_READWRITE)); +} + +static void +gst_vbidec_init (GstVBIDec *vbidec) +{ + /* create the sink and src pads */ + vbidec->sinkpad = gst_pad_new_from_template ( + GST_PAD_TEMPLATE_GET (sink_template_factory), "sink"); + gst_element_add_pad (GST_ELEMENT (vbidec), vbidec->sinkpad); + gst_pad_set_chain_function (vbidec->sinkpad, GST_DEBUG_FUNCPTR (gst_vbidec_chain)); + + vbidec->srcpad = gst_pad_new_from_template ( + GST_PAD_TEMPLATE_GET (src_template_factory), "src"); + gst_element_add_pad (GST_ELEMENT (vbidec), vbidec->srcpad); + + vbidec->vbiscreen = vbiscreen_new(0, 0, 1.0, 0, (void *)vbidec); + vbidec->vbidata = vbidata_new_line(vbidec->vbiscreen, 0); + vbidec->caption_type = CAPTURE_OFF; + vbidata_capture_mode(vbidec->vbidata, vbidec->caption_type); + vbidec->dvd_input = FALSE; +} + +static void +line21_decode(GstVBIDec *vbidec, guint8 *data, guint32 size) +{ + vbidata_process_line(vbidec->vbidata, data, 0); +} + +static void +dvd_user_data_decode(GstVBIDec *vbidec, guint8 *data, guint32 size) +{ + //char caption[128]; + //int ci; /* caption index */ + int i; /* buf index */ + int num_disp_field; + guint8 b1, b2; + int w; + + //g_print("%%%% vbi decode\n"); + //g_print("== %p %d\n", data, size); + i = 0; + /* Check for Closed Captioning data */ + if (data[i] != 0x43 || data[i+1] != 0x43 || + data[i+2] != 0x01 || data[i+3] != 0xf8) { + g_print ("non-CC data\n"); + return; + } + //g_print ("CC data\n"); + i += 4; /* above */ + i += 4; /* ? */ + num_disp_field = data[i] & 0x3f; + //g_print ("ndf %d\n", num_disp_field); + while ((data[i] & 0xfe) == 0xfe) { + if (data[i] & 0x1) { + b1 = data[i+1] & 0x7f; + b2 = data[i+2] & 0x7f; + w = (b2 << 8) | b1; + vbidata_process_16b(vbidec->vbidata, 0, w); + } + i += 3; + } +} + +static void +gst_vbidec_chain (GstPad *pad, GstBuffer *buf) +{ + GstVBIDec *vbidec = GST_VBIDEC (gst_pad_get_parent (pad)); + guint32 size; + guint8 *data; + guint64 pts; + + size = GST_BUFFER_SIZE (buf); + data = GST_BUFFER_DATA (buf); + pts = GST_BUFFER_TIMESTAMP (buf); + + /* + g_print("** user_data: addr:%p len:%d state:%d\n", data, size, 0); + { + int i; + guint8 ud; + g_print("** \""); + for (i=0; idvd_input) { + dvd_user_data_decode(vbidec, data, size); + } else { + line21_decode(vbidec, data, size); + } + + gst_buffer_unref(buf); +} + +void +gst_vbidec_show_text (GstVBIDec *vbidec, char *text, int len) +{ + //fprintf(stderr, "%*s\n", len, text); + if (len > 0) { + if (GST_PAD_IS_USABLE (vbidec->srcpad)) { + GstBuffer *buf = gst_buffer_new_and_alloc (len); + memcpy (GST_BUFFER_DATA (buf), text, len); + GST_BUFFER_SIZE (buf) = len; + // FIXME + //GST_BUFFER_TIMESTAMP (buf) = vbidec->... + //... + //fprintf(stderr, "vbi text pushed\n"); + gst_pad_push (vbidec->srcpad, buf); + } + } +} + +static void +gst_vbidec_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstVBIDec *vbidec; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_VBIDEC (object)); + vbidec = GST_VBIDEC (object); + + switch (prop_id) { + case ARG_DVD_INPUT: + vbidec->dvd_input = g_value_get_boolean(value); + break; + case ARG_CAPTION_TYPE: + vbidec->caption_type = g_value_get_enum(value); + vbidata_capture_mode(vbidec->vbidata, vbidec->caption_type); + break; + default: + break; + } +} + +static void +gst_vbidec_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstVBIDec *vbidec; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_VBIDEC (object)); + vbidec = GST_VBIDEC (object); + + switch (prop_id) { + case ARG_DVD_INPUT: + g_value_set_boolean(value, vbidec->dvd_input); + break; + case ARG_CAPTION_TYPE: + g_value_set_enum(value, vbidec->caption_type); + break; + default: + break; + } +} + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + + /* create an elementfactory for the vbidec element */ + factory = gst_element_factory_new("vbidec",GST_TYPE_VBIDEC, + &gst_vbidec_details); + g_return_val_if_fail(factory != NULL, FALSE); + gst_element_factory_set_rank (factory, GST_ELEMENT_RANK_PRIMARY); + + gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (src_template_factory)); + gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (sink_template_factory)); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "vbidec", + plugin_init +}; diff --git a/gst/vbidec/gstvbidec.h b/gst/vbidec/gstvbidec.h new file mode 100644 index 00000000..8a5ea7e5 --- /dev/null +++ b/gst/vbidec/gstvbidec.h @@ -0,0 +1,22 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +typedef struct _GstVBIDec GstVBIDec; + +void gst_vbidec_show_text (GstVBIDec *vbidec, char *text, int len); 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 . + * Copyright (c) 2002 Doug Bell + * + * 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 ); +} + diff --git a/gst/vbidec/vbidata.h b/gst/vbidec/vbidata.h new file mode 100644 index 00000000..e84e3b18 --- /dev/null +++ b/gst/vbidec/vbidata.h @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2002 Billy Biggs . + * Copyright (c) 2002 Doug Bell + * + * CC code from Nathan Laredo's ccdecode. + * 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 + * + * 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. + */ + +#ifndef VBIDATA_H_INCLUDED +#define VBIDATA_H_INCLUDED + +#include "vbiscreen.h" +/*#include "tvtimeosd.h"*/ + +typedef struct vbidata_s vbidata_t; + +#define CAPTURE_OFF 0 +#define CAPTURE_CC1 1 +#define CAPTURE_CC2 2 +#define CAPTURE_CC3 4 +#define CAPTURE_CC4 5 +#define CAPTURE_T1 6 +#define CAPTURE_T2 7 +#define CAPTURE_T3 8 +#define CAPTURE_T4 9 + +vbidata_t *vbidata_new_file( const char *filename, vbiscreen_t *vs, + /*tvtime_osd_t* osd,*/ int verbose ); +vbidata_t *vbidata_new_line( vbiscreen_t *vs, int verbose ); + +void vbidata_delete( vbidata_t *vbi ); +void vbidata_reset( vbidata_t *vbi ); +void vbidata_capture_mode( vbidata_t *vbi, int mode ); +void vbidata_process_frame( vbidata_t *vbi, int printdebug ); +void vbidata_process_line( vbidata_t *vbi, unsigned char *s, int bottom ); +void vbidata_process_16b( vbidata_t *vbi, int bottom, int w ); + +#endif /* VBIDATA_H_INCLUDED */ diff --git a/gst/vbidec/vbiscreen.c b/gst/vbidec/vbiscreen.c new file mode 100644 index 00000000..1143e06b --- /dev/null +++ b/gst/vbidec/vbiscreen.c @@ -0,0 +1,730 @@ +/** + * Copyright (c) 2002 Billy Biggs . + * Copyright (c) 2002 Doug Bell . + * + * Modified and adapted to GStreamer by + * David I. Lehn + * + * 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 +#include +#include +#include +#include +#include +/*#include "osdtools.h"*/ +/*#include "speedy.h"*/ +#include "vbiscreen.h" +#include "gstvbidec.h" + +#define ROLL_2 6 +#define ROLL_3 7 +#define ROLL_4 8 +#define POP_UP 9 +#define PAINT_ON 10 + + +#define NUM_LINES 15 +#define ROWS 15 +#define COLS 32 +#define FONT_SIZE 20 + +typedef struct osd_string_s osd_string_t; +struct osd_string_s { + int width; + int height; + int r, g, b; + int visible; + GstVBIDec *vbidec; +}; + +osd_string_t *osd_string_new(char *c, int s, int w, int h, int a, void *user_data) { + osd_string_t *os; + os = (osd_string_t *)malloc(sizeof(osd_string_t)); + if (!os) + return NULL; + os->width = 0; + os->height = 0; + os->r = os->g = os->b = 0; + os->visible = 1; + os->vbidec = (GstVBIDec *)user_data; + return os; +} +void osd_string_show_text(osd_string_t *os, char *s, int len ) { + /* FIXME: just print data when it gets here */ + if (len > 0) { + gst_vbidec_show_text(os->vbidec, s, len); + } +} +int osd_string_get_height(osd_string_t *os) { + return os->height; +} +int osd_string_get_width(osd_string_t *os) { + return os->width; +} +void osd_string_delete(osd_string_t *os) { + free(os); +} +void osd_string_set_colour_rgb(osd_string_t *os, int r, int g, int b) { + os->r = r; + os->g = g; + os->b = b; +} +void blit_colour_packed422_scanline( unsigned char *d, int w, int luma, int cb, int cr) { +} +int osd_string_visible(osd_string_t *os) { + return os->visible; +} +void osd_string_composite_packed422_scanline(osd_string_t *os, unsigned char *a, unsigned char *b, int w, int x, int y) { +} + +struct vbiscreen_s { + + osd_string_t *line[ ROWS ]; + + char buffers[ ROWS * COLS * 2 ]; + char text[ 2 * ROWS * COLS ]; + char hiddenbuf[ COLS ]; + char paintbuf[ ROWS * COLS ]; + + unsigned int fgcolour; + unsigned int bgcolour; + int bg_luma, bg_cb, bg_cr; + + int frame_width; + int frame_height; + int frame_aspect; + + int x, y; /* where to draw console */ + int width, height; /* the size box we have to draw in */ + int rowheight, charwidth; + + int curx, cury; /* cursor position */ + int rows, cols; /* 32 cols 15 rows */ + int captions, style; /* CC (1) or Text (0), RU2 RU3 RU4 POP_UP PAINT_ON */ + int first_line; /* where to start drawing */ + int curbuffer; + int top_of_screen; /* a pointer into line[] */ + int indent; + int got_eoc; + int scroll; + + char *fontfile; + int fontsize; + int verbose; + + void *user_data; +}; + +vbiscreen_t *vbiscreen_new( int video_width, int video_height, + double video_aspect, int verbose, void *user_data ) +{ + int i=0, fontsize = FONT_SIZE; + vbiscreen_t *vs = (vbiscreen_t *)malloc(sizeof(struct vbiscreen_s)); + + if( !vs ) { + return NULL; + } + + vs->verbose = verbose; + vs->x = 0; + vs->y = 0; + vs->frame_width = video_width; + vs->frame_height = video_height; + vs->frame_aspect = video_aspect; + vs->curx = 0; + vs->cury = 0; + vs->fgcolour = 0xFFFFFFFFU; /* white */ + vs->bgcolour = 0xFF000000U; /* black */ + vs->bg_luma = 16; + vs->bg_cb = 128; + vs->bg_cr = 128; + vs->rows = ROWS; + vs->cols = COLS; + /*vs->fontfile = DATADIR "/FreeMonoBold.ttf";*/ + vs->fontfile = NULL; + vs->fontsize = fontsize; + vs->width = video_width; + vs->height = video_height; + vs->first_line = 0; + vs->captions = 0; + vs->style = 0; + vs->curbuffer = 0; + vs->top_of_screen = 0; + vs->indent = 0; + memset( vs->buffers, 0, 2 * COLS * ROWS ); + memset( vs->hiddenbuf, 0, COLS ); + memset( vs->paintbuf, 0, ROWS * COLS ); + vs->scroll = 0; + + vs->user_data = user_data; + + vs->line[0] = osd_string_new( vs->fontfile, fontsize, video_width, + video_height, + video_aspect, + user_data); + + if( !vs->line[0] ) { + vs->fontfile = "./FreeMonoBold.ttf"; + + vs->line[0] = osd_string_new( vs->fontfile, fontsize, + video_width, + video_height, + video_aspect, + user_data); + } + + if( !vs->line[0] ) { + fprintf( stderr, "vbiscreen: Could not find my font (%s)!\n", + vs->fontfile ); + vbiscreen_delete( vs ); + return NULL; + } + + osd_string_show_text( vs->line[ 0 ], "W", 0 ); + vs->rowheight = osd_string_get_height( vs->line[ 0 ] ); + vs->charwidth = osd_string_get_width( vs->line[ 0 ] ); + osd_string_delete( vs->line[ 0 ] ); + + for( i = 0; i < ROWS; i++ ) { + vs->line[ i ] = osd_string_new( vs->fontfile, fontsize, + video_width, video_height, + video_aspect, + user_data); + if( !vs->line[ i ] ) { + fprintf( stderr, "vbiscreen: Could not allocate a line.\n" ); + vbiscreen_delete( vs ); + return NULL; + } + osd_string_set_colour_rgb( vs->line[ i ], + (vs->fgcolour & 0xff0000) >> 16, + (vs->fgcolour & 0xff00) >> 8, + (vs->fgcolour & 0xff) ); + osd_string_show_text( vs->line[ i ], " ", 0 ); + } + memset( vs->text, 0, 2 * ROWS * COLS ); + return vs; +} + +void blank_screen( vbiscreen_t *vs ) +{ + int i; + + if( vs->verbose ) fprintf( stderr, "in blank\n"); + for( i = 0; i < ROWS; i++ ) { + osd_string_show_text( vs->line[ i ], " ", 0 ); + } +} + +void clear_screen( vbiscreen_t *vs ) +{ + int base, i; + if( !vs ) return; + + base = vs->top_of_screen * COLS; + for( i = 0; i < ROWS * COLS; i++ ) { + vs->text[ base ] = 0; + base++; + base %= 2 * ROWS * COLS; + } + blank_screen( vs ); +} + +void clear_hidden_roll( vbiscreen_t *vs ) +{ + if( !vs ) return; + memset( vs->hiddenbuf, 0, COLS ); +} + +void clear_hidden_pop( vbiscreen_t *vs ) +{ + if( !vs ) return; + memset( vs->buffers + vs->curbuffer * COLS * ROWS , 0, COLS * ROWS ); +} + +void clear_hidden_paint( vbiscreen_t *vs ) +{ + if( !vs ) return; + memset( vs->paintbuf , 0, COLS * ROWS ); +} + +void clear_displayed_pop( vbiscreen_t *vs ) +{ + if( !vs ) return; + memset( vs->buffers + ( vs->curbuffer ^ 1 ) * COLS * ROWS , 0, COLS * ROWS ); +} + +void vbiscreen_dump_screen_text( vbiscreen_t *vs ) +{ + int i, offset; + + if( !vs ) return; + offset = vs->top_of_screen * COLS; + + fprintf( stderr, "\n 0123456789abcdefghij012345678901" ); + for( i = 0; i < ROWS * COLS; i++ ) { + if( !(i % COLS) ) + fprintf( stderr, "\n%.2d ", i / COLS ); + fprintf( stderr, "%c", vs->text[ offset ] ? vs->text[ offset ] : ' ' ); + offset++; + offset %= 2 * ROWS * COLS; + } + fprintf( stderr, "\n 0123456789abcdefghij012345678901\n " ); + for( i = 0; i < COLS; i++ ) { + fprintf( stderr, "%c", vs->text[ offset ] ? vs->text[ offset ] : ' ' ); + offset++; + offset %= 2 * ROWS * COLS; + } + fprintf( stderr, "\n 0123456789abcdefghij012345678901\n" ); +} + +int update_row_x( vbiscreen_t *vs, int row ) +{ + char text[ COLS + 1 ]; + int i, j, haschars = 0, base; + + if( !vs ) return 0; + + text[ COLS ] = 0; + base = ( ( vs->top_of_screen + row ) % ( 2 * ROWS ) ) * COLS; + for( j = 0, i = base; i < base + COLS; i++, j++ ) { + if( vs->text[ i ] ) { + text[ j ] = vs->text[ i ]; + haschars = 1; + } else { + text[ j ] = ' '; + } + } + + osd_string_set_colour_rgb( vs->line[ row ], + ( vs->fgcolour & 0xff0000 ) >> 16, + ( vs->fgcolour & 0xff00 ) >> 8, + ( vs->fgcolour & 0xff ) ); + if( !haschars ) + osd_string_show_text( vs->line[ row ], " ", 0 ); + else + osd_string_show_text( vs->line[ row ], text, 51 ); + + return haschars; +} + +void update_row( vbiscreen_t *vs ) +{ + if( !vs ) return; + + update_row_x( vs, vs->cury ); + //vbiscreen_dump_screen_text( vs ); +} + +void update_all_rows( vbiscreen_t *vs ) +{ + int row = 0; + + if( !vs ) return; + + for( row = 0; row < ROWS; row++ ) { + update_row_x( vs, row ); + } + //vbiscreen_dump_screen_text( vs ); +} + +void vbiscreen_delete( vbiscreen_t *vs ) +{ + free( vs ); +} + +void copy_row_to_screen( vbiscreen_t *vs, char *row ) +{ + int base, i, j; + + base = ( ( vs->top_of_screen + vs->cury ) % ( 2 * ROWS ) ) * COLS; + for( j = 0, i = base; + i < base + COLS; + j++, i++ ) { + vs->text[ i ] = row[ j ]; + } + update_row( vs ); +} + +void scroll_screen( vbiscreen_t *vs ) +{ + int start_row; + + if( !vs || !vs->captions || !vs->style || vs->style > ROLL_4 ) + return; + + start_row = ( vs->first_line + vs->top_of_screen ) % ( 2 * ROWS ); + if( vs->verbose ) + fprintf ( stderr, "start row : %d first line %d\n ", start_row, + vs->first_line ); + + /* zero out top row */ + memset( (char *)( vs->text + start_row * COLS ), 0, COLS ); + vs->top_of_screen = ( vs->top_of_screen + 1 ) % ( 2 * ROWS ); + vs->curx = vs->indent; + update_all_rows( vs ); + copy_row_to_screen( vs, vs->hiddenbuf ); + clear_hidden_roll( vs ); + vs->scroll = 26; +} + +void vbiscreen_new_caption( vbiscreen_t *vs, int indent, int ital, + unsigned int colour, int row ) +{ + if( !vs ) return; + if( vs->verbose ) fprintf( stderr, "indent: %d, ital: %d, colour: 0x%x, row: %d\n", indent, ital, colour, row ); + + if( 0 && vs->captions && vs->style <= ROLL_4 && vs->style ) { + if( row != vs->cury+1 ) { + vs->cury = row - 1; + clear_hidden_roll( vs ); + } else { +// scroll_screen( vs ); + } + } + + if( vs->style > ROLL_4 ) { + vs->cury = ( ( row > 0 ) ? row - 1 : 0 ); + } + + vs->fgcolour = colour; + vs->indent = indent; + vs->curx = indent; +} + +void vbiscreen_set_mode( vbiscreen_t *vs, int caption, int style ) +{ + if( !vs ) return; + if( vs->verbose ) + fprintf( stderr, "in set mode\n"); + + if( vs->verbose ) { + fprintf( stderr, "Caption: %d ", caption ); + switch( style ) { + case ROLL_2: + fprintf( stderr, "ROLL 2\n"); + break; + case ROLL_3: + fprintf( stderr, "ROLL 3\n" ); + break; + case ROLL_4: + fprintf( stderr, "ROLL 4\n" ); + break; + case POP_UP: + fprintf( stderr, "POP UP\n" ); + break; + case PAINT_ON: + fprintf( stderr, "PAINT ON\n" ); + break; + default: + break; + } + } + if( !caption ) { + /* text mode */ + vs->cury = 0; + } else { + /* captioning mode */ + /* styles: ru2 ru3 ru4 pop paint + */ + if( style != POP_UP && vs->style == POP_UP && !vs->got_eoc ) { + /* stupid that sometimes they dont send a EOC */ + vbiscreen_end_of_caption( vs ); + } + + switch( style ) { + case ROLL_2: + case ROLL_3: + case ROLL_4: + if( vs->style == style ) { + return; + } + vs->first_line = ROWS - (style - 4); + + if( vs->verbose ) + fprintf( stderr, "first_line %d\n", vs->first_line ); + + vs->cury = ROWS - 1; + break; + case POP_UP: + vs->got_eoc = 0; + break; + case PAINT_ON: + break; + } + } + + vs->captions = caption; + vs->style = style; +} + +void vbiscreen_tab( vbiscreen_t *vs, int cols ) +{ + if( !vs ) return; + if( cols < 0 || cols > 3 ) return; + vs->curx += cols; + if( vs->curx > 31 ) vs->curx = 31; +} + +void vbiscreen_set_colour( vbiscreen_t *vs, unsigned int col ) +{ + if( !vs ) return; + vs->fgcolour = col; +} + +void vbiscreen_clear_current_cell( vbiscreen_t *vs ) +{ + vs->text[ ( ( vs->top_of_screen + vs->cury ) % ( 2 * ROWS ) ) * COLS + + vs->curx + vs->indent ] = 0; +} + +void vbiscreen_set_current_cell( vbiscreen_t *vs, char text ) +{ + int base; + if( !vs ) return; + base = ( ( vs->top_of_screen + vs->cury ) % ( 2 * ROWS ) ) * COLS; + if( isprint( text ) ) + vs->text[ base + vs->curx + vs->indent ] = text; + else + vs->text[ base + vs->curx + vs->indent ] = ' '; +} + +void vbiscreen_delete_to_end( vbiscreen_t *vs ) +{ + int i; + if( !vs ) return; + if( vs->verbose ) fprintf( stderr, "in del to end\n"); + for( i = vs->curx; i < COLS; i++ ) { + vbiscreen_clear_current_cell( vs ); + vs->curx++; + } + vs->curx = COLS-1; /* is this right ? */ + if( vs->captions && vs->style && vs->style != POP_UP ) + update_row( vs ); +} + +void vbiscreen_backspace( vbiscreen_t *vs ) +{ + if( !vs ) return; + if( vs->verbose ) fprintf( stderr, "in backspace\n"); + if( !vs->curx ) return; + vs->curx--; + vbiscreen_clear_current_cell( vs ); + update_row( vs ); +} + +void vbiscreen_erase_displayed( vbiscreen_t *vs ) +{ + if( !vs ) return; + if( vs->verbose ) fprintf( stderr, "in erase disp\n"); + + if( vs->captions && vs->style && vs->style <= ROLL_4 ) { + clear_hidden_roll( vs ); + } + + clear_displayed_pop( vs ); + clear_screen( vs ); +} + +void vbiscreen_erase_non_displayed( vbiscreen_t *vs ) +{ + if( !vs ) return; + if( vs->verbose ) fprintf( stderr, "in erase non disp\n"); + + if( vs->captions && vs->style == POP_UP ) { + memset( vs->buffers + vs->curbuffer * COLS * ROWS + vs->cury * COLS, 0, COLS ); +// clear_hidden_pop( vs ); + } else if( vs->captions && vs->style && vs->style <= ROLL_4 ) { + clear_hidden_roll( vs ); + } +} + +void vbiscreen_carriage_return( vbiscreen_t *vs ) +{ + if( !vs ) return; + if( vs->verbose ) fprintf( stderr, "in CR\n"); + if( vs->style != POP_UP) { + /* not sure if this is right for text mode */ + /* in text mode, perhaps a CR on last row clears screen and goes + * to (0,0) */ + scroll_screen( vs ); + } + + /* keep cursor on bottom for rollup */ + if( vs->captions && vs->style && vs->style <= ROLL_4 ) + vs->cury--; + + vs->cury++; + vs->curx = 0; +} + +void copy_buf_to_screen( vbiscreen_t *vs, char *buf ) +{ + int base, i, j; + if( !vs ) return; + + base = vs->top_of_screen * COLS; + for( j = 0, i = 0; i < ROWS * COLS; i++, j++ ) { + vs->text[ base ] = buf[ j ]; + base++; + base %= 2 * ROWS * COLS; + } + update_all_rows( vs ); +} + +void vbiscreen_end_of_caption( vbiscreen_t *vs ) +{ + /*int i;*/ + if( !vs ) return; + if( vs->verbose ) fprintf( stderr, "in end of caption\n"); + + if( vs->style == PAINT_ON ) { + copy_buf_to_screen( vs, vs->paintbuf ); + clear_hidden_paint( vs ); + } else if( vs->style == POP_UP ) { + copy_buf_to_screen( vs, vs->buffers + vs->curbuffer * COLS * ROWS ); + vs->curbuffer ^= 1; + } + + /* to be safe? */ + vs->curx = 0; + vs->cury = ROWS - 1; + vs->got_eoc = 1; +} + +void vbiscreen_print( vbiscreen_t *vs, char c1, char c2 ) +{ + if( !vs ) return; + if( vs->verbose ) fprintf( stderr, "in print (%d, %d)[%c %c]\n", vs->curx, vs->cury, c1, c2); + if( vs->captions && vs->style == POP_UP ) { + /* this all gets displayed at another time */ + if( vs->curx != COLS-1 ) { + *(vs->buffers + vs->curx + vs->curbuffer * ROWS * COLS + vs->cury * COLS ) = c1; + vs->curx++; + } + + if( vs->curx != COLS-1 && c2 ) { + *(vs->buffers + vs->curx + vs->curbuffer * ROWS * COLS + vs->cury * COLS ) = c2; + vs->curx++; + } else if( c2 ) { + *(vs->buffers + vs->curx + vs->curbuffer * ROWS * COLS + vs->cury * COLS ) = c2; + } + } + + if( vs->captions && vs->style == PAINT_ON ) { + if( vs->curx != COLS-1 ) { + vs->paintbuf[ vs->curx + vs->cury * COLS ] = c1; + vs->curx++; + } + + if( vs->curx != COLS-1 && c2 ) { + vs->paintbuf[ vs->curx + vs->cury * COLS ] = c2; + vs->curx++; + } else if( c2 ) { + vs->paintbuf[ vs->curx + vs->cury * COLS ] = c2; + } + } + + if( vs->captions && vs->style && vs->style <= ROLL_4 ) { + if( vs->curx != COLS-1 ) { + vs->hiddenbuf[ vs->curx ] = c1; + vs->curx++; + } else { + vs->hiddenbuf[ vs->curx ] = c1; + } + + if( vs->curx != COLS-1 && c2 ) { + vs->hiddenbuf[ vs->curx ] = c2; + vs->curx++; + } else if( c2 ) { + vs->hiddenbuf[ vs->curx ] = c2; + } + } +} + +void vbiscreen_reset( vbiscreen_t *vs ) +{ + if( !vs ) return; + clear_screen( vs ); + clear_hidden_pop( vs ); + clear_displayed_pop( vs ); + clear_hidden_roll( vs ); + vs->captions = 0; + vs->style = 0; +} + +void vbiscreen_composite_packed422_scanline( vbiscreen_t *vs, + unsigned char *output, + int width, int xpos, + int scanline ) +{ + int x=0, y=0, row=0, index=0; + + if( !vs ) return; + if( !output ) return; + if( scanline >= vs->y && scanline < vs->y + vs->height ) { + + if( 0 && !vs->captions ) + blit_colour_packed422_scanline( output + (vs->x*2), vs->width, + vs->bg_luma, vs->bg_cb, + vs->bg_cr ); + + index = vs->top_of_screen * COLS; + x = ( vs->x + vs->charwidth) & ~1; + for( row = 0; row < ROWS; row++ ) { + y = vs->y + row * vs->rowheight + vs->rowheight; + if( osd_string_visible( vs->line[ row ] ) ) { + if( scanline >= y && + scanline < y + vs->rowheight ) { + + int startx; + int strx; + + startx = x - xpos; + strx = 0; + + if( startx < 0 ) { + strx = -startx; + startx = 0; + } + + + if( startx < width ) { + + if( vs->captions ) + blit_colour_packed422_scanline( + output + (startx*2), + osd_string_get_width( vs->line[ row ] ), + vs->bg_luma, + vs->bg_cb, + vs->bg_cr ); + + osd_string_composite_packed422_scanline( + vs->line[ row ], + output + (startx*2), + output + (startx*2), + width - startx, + strx, + scanline - y ); + } + } + index++; + } + } + } +} + diff --git a/gst/vbidec/vbiscreen.h b/gst/vbidec/vbiscreen.h new file mode 100644 index 00000000..5f376331 --- /dev/null +++ b/gst/vbidec/vbiscreen.h @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2002 Billy Biggs . + * Copyright (c) 2002 Doug Bell . + * + * Modified and adapted to GStreamer by + * David I. Lehn + * + * 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. + */ + +#ifndef HAVE_VBISCREEN_H +#define HAVE_VBISCREEN_H + +typedef struct vbiscreen_s vbiscreen_t; + +vbiscreen_t *vbiscreen_new( int video_width, int video_height, + double video_aspect, int verbose, void *user_data ); +void vbiscreen_delete( vbiscreen_t *vs ); +void vbiscreen_set_mode( vbiscreen_t *vs, int caption, int style); +void vbiscreen_new_caption( vbiscreen_t *vs, int indent, int ital, + unsigned int colour, int row ); +void vbiscreen_tab( vbiscreen_t *vs, int cols ); +void vbiscreen_delete_to_end( vbiscreen_t *vs ); +void vbiscreen_backspace( vbiscreen_t *vs ); +void vbiscreen_erase_displayed( vbiscreen_t *vs ); +void vbiscreen_erase_non_displayed( vbiscreen_t *vs ); +void vbiscreen_carriage_return( vbiscreen_t *vs ); +void vbiscreen_end_of_caption( vbiscreen_t *vs ); +void vbiscreen_print( vbiscreen_t *vs, char c1, char c2 ); +void vbiscreen_composite_packed422_scanline( vbiscreen_t *vs, + unsigned char *output, + int width, int xpos, + int scanline ); +void vbiscreen_dump_screen_text( vbiscreen_t *vs ); +void vbiscreen_reset( vbiscreen_t *vs ); + +#endif -- cgit v1.2.1