summaryrefslogtreecommitdiff
path: root/src/libspudec
diff options
context:
space:
mode:
Diffstat (limited to 'src/libspudec')
-rw-r--r--src/libspudec/Makefile.am36
-rw-r--r--src/libspudec/spu.c399
-rw-r--r--src/libspudec/spu.h67
-rw-r--r--src/libspudec/spu_decoder_api.h69
-rw-r--r--src/libspudec/xine_decoder.c184
5 files changed, 750 insertions, 5 deletions
diff --git a/src/libspudec/Makefile.am b/src/libspudec/Makefile.am
index c96adda1d..11d4cb535 100644
--- a/src/libspudec/Makefile.am
+++ b/src/libspudec/Makefile.am
@@ -1,12 +1,38 @@
-CFLAGS = @BUILD_LIB_STATIC@ @GLOBAL_CFLAGS@
+CFLAGS = @GLOBAL_CFLAGS@
-EXTRA_DIST =
+LIBTOOL = $(SHELL) $(top_builddir)/libtool-nofpic
-noinst_LTLIBRARIES = libspudec.la
+libdir = $(XINE_PLUGINDIR)
-libspudec_la_SOURCES = spudec.c spudec.h
+lib_LTLIBRARIES = xineplug_decode_spu.la
+
+xineplug_decode_spu_la_SOURCES = spu.c xine_decoder.c
+xineplug_decode_spu_la_LDFLAGS = -avoid-version -module
+
+noinst_HEADERS = spu.h spu_decoder_api.h
+
+##
+## Install header files (default=$includedir/xine)
+##
+install-includeHEADERS: $(include_HEADERS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(includedir)/xine
+ @list='$(include_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \
+ echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/xine/$$p"; \
+ $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/xine/$$p; \
+ done
+
+
+##
+## Remove them
+##
+uninstall-includeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ list='$(include_HEADERS)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(includedir)/xine/$$p; \
+ done
-noinst_HEADERS = spudec.h
debug:
$(MAKE) CFLAGS="$(DEBUG_CFLAGS)"
diff --git a/src/libspudec/spu.c b/src/libspudec/spu.c
new file mode 100644
index 000000000..13d9c92c8
--- /dev/null
+++ b/src/libspudec/spu.c
@@ -0,0 +1,399 @@
+/*****
+*
+* This file is part of the OMS program.
+*
+* 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, 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; see the file COPYING. If not, write to
+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*****/
+
+#define DENT_TEST
+
+/*
+ * subpic_decode.c - converts DVD subtitles to an XPM image
+ *
+ * Mostly based on hard work by:
+ *
+ * Copyright (C) 2000 Samuel Hocevar <sam@via.ecp.fr>
+ * and Michel Lespinasse <walken@via.ecp.fr>
+ *
+ * Lots of rearranging by:
+ * Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ * Thomas Mirlacher <dent@cosy.sbg.ac.at>
+ * implemented reassembling
+ * cleaner implementation of SPU are saving
+ * overlaying (proof of concept for now)
+ * ... and yes, it works now with oms
+ * added tranparency (provided by the SPU hdr)
+ * changed structures for easy porting to MGAs DVD mode
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <inttypes.h>
+#include <malloc.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+//#include <oms/plugin/output_video.h> // for clut_t
+#include "spu.h"
+
+static u_int field; // which field we are currently decoding
+
+#define DISPLAY_INIT
+
+#define REASSEMBLY_START 0
+#define REASSEMBLY_MID 1
+#define REASSEMBLY_UNNEEDED 2
+
+static u_int reassembly_flag = REASSEMBLY_START;
+
+struct reassembly_s {
+ uint8_t *buf;
+ uint8_t *buf_ptr; // actual pointer to still empty buffer
+ u_int buf_len;
+ u_int cmd_offset;
+} reassembly;
+
+#define LOG_DEBUG 1
+
+#ifdef DEBUG
+#define LOG(lvl, fmt...) fprintf (stderr, fmt);
+#else
+#define LOG(lvl, fmt...)
+#endif
+
+
+static u_int _get_bits (u_int bits, vo_overlay_t *spu)
+{
+ static u_int data;
+ static u_int bits_left;
+ u_int ret = 0;
+
+ if (!bits) { /* for realignment to next byte */
+ bits_left = 0;
+ }
+
+ while (bits) {
+ if (bits > bits_left) {
+ ret |= data << (bits - bits_left);
+ bits -= bits_left;
+
+ data = reassembly.buf[spu->offset[field]++];
+ bits_left = 8;
+ } else {
+ bits_left -= bits;
+ ret |= data >> (bits_left);
+ data &= (1 << bits_left) - 1;
+ bits = 0;
+ }
+ }
+
+ return ret;
+}
+
+
+void spuInit (void)
+{
+}
+
+
+static inline void _spu_put_pixel (vo_overlay_t *spu, u_int len, uint8_t colorid)
+{
+ uint8_t *spu_data_ptr = &spu->data[spu->_x + spu->_y * spu->width];
+
+ spu->_x += len;
+
+ memset (spu_data_ptr, spu->trans[colorid]<<4 | colorid, len);
+}
+
+
+static int _spu_next_line (vo_overlay_t *spu)
+{
+ _get_bits (0, spu); // byte align rle data
+
+ spu->_x = 0;
+ spu->_y++;
+ field = (field+1) & 0x01; // Toggle fields
+
+ if (spu->_y >= spu->height) {
+ LOG (LOG_DEBUG, ".");
+ return -1;
+ }
+ return 0;
+}
+
+
+// DENT: we need a mechanism here, when having non-linearities (like jumps, ff)
+ // like pass NULL pkt_data to reset reassembly
+
+static struct reassembly_s *_reassembly (uint8_t *pkt_data, u_int pkt_len)
+{
+ LOG (LOG_DEBUG, "pkt_len: %d", pkt_len);
+
+ if (reassembly_flag == REASSEMBLY_UNNEEDED)
+ reassembly_flag = REASSEMBLY_START;
+
+ if (reassembly_flag == REASSEMBLY_START) {
+ reassembly.buf_len = (((u_int)pkt_data[0])<<8) | pkt_data[1];
+ reassembly.cmd_offset = (((u_int)pkt_data[2])<<8) | pkt_data[3];
+
+ LOG (LOG_DEBUG, "buf_len: %d", reassembly.buf_len);
+ LOG (LOG_DEBUG, "cmd_off: %d", reassembly.cmd_offset);
+
+ // the whole spu fits into the supplied packet
+ if (pkt_len >= reassembly.buf_len) {
+ LOG (LOG_DEBUG, "0)");
+ reassembly.buf = pkt_data;
+ reassembly_flag = REASSEMBLY_UNNEEDED;
+ return &reassembly;
+ } else {
+ LOG (LOG_DEBUG, "1)");
+ if (!(reassembly.buf = malloc (reassembly.buf_len + 1))) {
+ LOG (LOG_DEBUG, "unable to alloc buffer");
+ return NULL;
+ }
+ reassembly.buf_ptr = reassembly.buf;
+
+ memcpy (reassembly.buf_ptr, pkt_data, pkt_len);
+ reassembly.buf_ptr += pkt_len;
+ reassembly_flag = REASSEMBLY_MID;
+ }
+ } else {
+ LOG (LOG_DEBUG, "2)");
+ if ((reassembly.buf_ptr+pkt_len) > (reassembly.buf+reassembly.buf_len))
+ pkt_len = reassembly.buf_len - (reassembly.buf_ptr - reassembly.buf);
+
+
+ memcpy (reassembly.buf_ptr, pkt_data, pkt_len);
+ reassembly.buf_ptr += pkt_len;
+
+ if (reassembly.buf_ptr >= (reassembly.buf+reassembly.buf_len)) {
+ reassembly_flag = REASSEMBLY_START;
+ return &reassembly;
+ }
+ }
+
+ LOG (LOG_DEBUG, "3)");
+ return NULL;
+}
+
+
+#define CMD_SPU_MENU 0x00
+#define CMD_SPU_SHOW 0x01
+#define CMD_SPU_HIDE 0x02
+#define CMD_SPU_SET_PALETTE 0x03
+#define CMD_SPU_SET_ALPHA 0x04
+#define CMD_SPU_SET_SIZE 0x05
+#define CMD_SPU_SET_PXD_OFFSET 0x06
+#define CMD_SPU_EOF 0xff
+
+/* The time is given as an offset from the presentation time stamp
+ and it is measured in number of fields. If we play a NTSC movie
+ the time for each field is 1/(2*29.97) seconds. */
+#define TIME_UNIT 1000*1.0/(2*29.97)
+
+int spuParseHdr (vo_overlay_t *spu, uint8_t *pkt_data, u_int pkt_len)
+{
+ struct reassembly_s *reassembly;
+ uint8_t *buf;
+ u_int DCSQ_offset, prev_DCSQ_offset = -1;
+
+ if (!(reassembly = _reassembly (pkt_data, pkt_len)))
+ return -1;
+
+ buf = reassembly->buf;
+ DCSQ_offset = reassembly->cmd_offset;
+
+ while (DCSQ_offset != prev_DCSQ_offset) { /* Display Control Sequences */
+ u_int i = DCSQ_offset;
+
+ spu->duration = /* PTS + */ ((buf[i] << 8) + buf[i+1]) * TIME_UNIT;
+ LOG (LOG_DEBUG, "time = %d ms", spu->duration);
+ i += 2;
+
+ prev_DCSQ_offset = DCSQ_offset;
+ DCSQ_offset = (buf[i] << 8) + buf[i+1];
+ i += 2;
+
+ while (buf[i] != CMD_SPU_EOF) { /* Command Sequence */
+ switch (buf[i]) {
+ case CMD_SPU_SHOW: /* show subpicture */
+ LOG (LOG_DEBUG, "\tshow subpicture");
+ i++;
+ break;
+
+ case CMD_SPU_HIDE: /* hide subpicture */
+ LOG (LOG_DEBUG, "\thide subpicture");
+ i++;
+ break;
+
+ case CMD_SPU_SET_PALETTE: { /* CLUT */
+ spu_clut_t *clut = (spu_clut_t *) &buf[i+1];
+
+ spu->clut[0] = clut->entry0;
+ spu->clut[1] = clut->entry1;
+ spu->clut[2] = clut->entry2;
+ spu->clut[3] = clut->entry3;
+ LOG (LOG_DEBUG, "\tclut [%d %d %d %d]",
+ spu->clut[0], spu->clut[1], spu->clut[2], spu->clut[3]);
+ i += 3;
+ break;
+ }
+ case CMD_SPU_SET_ALPHA: { /* transparency palette */
+#ifndef DENT_TEST
+ spu_clut_t *trans = (spu_clut_t *) &buf[i+1];
+
+ spu->trans[3] = trans->entry0;
+ spu->trans[2] = trans->entry1;
+ spu->trans[1] = trans->entry2;
+ spu->trans[0] = trans->entry3;
+#else
+ spu->trans[0] = 0;
+ spu->trans[1] = spu->trans[2] = spu->trans[3] = 15;
+#endif
+ LOG (LOG_DEBUG, "\ttrans [%d %d %d %d]\n",
+ spu->trans[0], spu->trans[1], spu->trans[2], spu->trans[3]);
+ i += 3;
+ break;
+ }
+
+ case CMD_SPU_SET_SIZE: /* image coordinates */
+ spu->x = (buf[i+1] << 4) |
+ (buf[i+2] >> 4);
+ spu->width = (((buf[i+2] & 0x0f) << 8) |
+ buf[i+3]) - spu->x + 1; /* 1-720 */
+
+ spu->y = (buf[i+4] << 4) |
+ (buf[i+5] >> 4);
+ spu->height = (((buf[i+5] & 0x0f) << 8)
+ | buf[i+6]) - spu->y + 1; /* 1-576 */
+
+ spu->data = (uint8_t *) malloc (spu->width * spu->height * sizeof (uint8_t));
+ /* Private stuff */
+ spu->_x = spu->_y = 0;
+ LOG (LOG_DEBUG, "\tx = %d y = %d width = %d height = %d",
+ spu->x, spu->y, spu->width, spu->height);
+ i += 7;
+ break;
+
+ case CMD_SPU_SET_PXD_OFFSET: /* image 1 / image 2 offsets */
+ spu->offset[0] = (((u_int)buf[i+1]) << 8) | buf[i+2];
+ spu->offset[1] = (((u_int)buf[i+3]) << 8) | buf[i+4];
+ LOG (LOG_DEBUG, "\toffset[0] = %d offset[1] = %d",
+ spu->offset[0], spu->offset[1]);
+ i += 5;
+ break;
+
+ case CMD_SPU_MENU:
+ /*
+ * hardcoded menu clut, uncomment this and comment CMD_SPU_SET_PALETTE and
+ * CMD_SPU_SET_ALPHA to see the menu buttons
+ */
+#ifdef DENT_TEST
+ spu->clut[0] = 0;
+ spu->clut[1] = 9;
+ spu->clut[2] = 8;
+ spu->clut[3] = 12;
+ spu->trans[0] = 0;
+ spu->trans[1] = spu->trans[2] = spu->trans[3] = 15;
+#endif
+ i++;
+ break;
+
+ default:
+ LOG (LOG_DEBUG, "invalid sequence in control header (%.2x)", buf[i]);
+ i++;
+ break;
+ }
+ }
+ i++; /* lose the CMD_SPU_EOF code (no need to, really) */
+
+ /* Until we change the interface we parse all 'Command Sequence's
+ but just overwrite the data in spu. Should be a list instead. */
+ }
+
+ /* Here we should have a linked list of display commands ready to
+ be decoded/executed by later calling some spu???() */
+
+ return 0;
+}
+
+
+void spuParseData (vo_overlay_t *spu)
+{
+ field = 0;
+ _get_bits (0, spu); /* Reset/init bit code */
+
+ while ((spu->offset[1] < reassembly.cmd_offset)) {
+ u_int len;
+ u_int color;
+ u_int vlc;
+
+ vlc = _get_bits (4, spu);
+ if (vlc < 0x0004) {
+ vlc = (vlc << 4) | _get_bits (4, spu);
+ if (vlc < 0x0010) {
+ vlc = (vlc << 4) | _get_bits (4, spu);
+ if (vlc < 0x0040) {
+ vlc = (vlc << 4) | _get_bits (4, spu);
+ }
+ }
+ }
+
+ color = vlc & 0x03;
+ len = vlc>>2;
+
+ /* if len == 0 -> end sequence - fill to end of line */
+ len = len ? : spu->width - spu->_x;
+
+ _spu_put_pixel (spu, len, color);
+
+ if (spu->_x >= spu->width)
+ if (_spu_next_line (spu) < 0)
+ goto clean_up;
+ }
+
+ /* Like the eof-line escape, fill the rest of the sp. with background */
+ _spu_put_pixel (spu, spu->width - spu->_x, 0);
+ while (!_spu_next_line (spu)) {
+ _spu_put_pixel (spu, spu->width - spu->_x, 0);
+ }
+
+ clean_up:
+ if (reassembly_flag != REASSEMBLY_UNNEEDED) {
+ LOG (LOG_DEBUG, "freeing reassembly.buf");
+ free (reassembly.buf);
+ }
+
+ reassembly_flag = REASSEMBLY_START;
+}
diff --git a/src/libspudec/spu.h b/src/libspudec/spu.h
new file mode 100644
index 000000000..844010243
--- /dev/null
+++ b/src/libspudec/spu.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2000-2001 the xine project
+ *
+ * This file is part of xine, a free video player.
+ *
+ * xine 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.
+ *
+ * xine 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: spu.h,v 1.1 2001/07/04 17:10:24 uid32519 Exp $
+ *
+ * This file was originally part of the OMS program.
+ *
+ */
+
+#ifndef __SPU_H__
+#define __SPU_H__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <inttypes.h>
+#include "video_out.h"
+
+#ifndef CLUT_T
+#define CLUT_T
+typedef struct { // CLUT == Color LookUp Table
+ uint8_t:8;
+ uint8_t y:8;
+ uint8_t cr:8;
+ uint8_t cb:8;
+} __attribute__ ((packed)) clut_t;
+#endif
+
+typedef struct spu_clut_struct {
+#ifdef WORDS_BIGENDIAN
+ uint8_t entry0 : 4;
+ uint8_t entry1 : 4;
+ uint8_t entry2 : 4;
+ uint8_t entry3 : 4;
+#else
+ uint8_t entry1 : 4;
+ uint8_t entry0 : 4;
+ uint8_t entry3 : 4;
+ uint8_t entry2 : 4;
+#endif
+} spu_clut_t;
+
+
+void spuInit (void);
+void decode_spu (u_char *data_start, u_char *data_end);
+u_int buffer_spupack (u_int *length, u_char **start, u_char *end);
+int spuParseHdr (vo_overlay_t *spu, u_char *pkt_data, u_int pkt_len);
+void spuParseData (vo_overlay_t *spu);
+
+#endif
diff --git a/src/libspudec/spu_decoder_api.h b/src/libspudec/spu_decoder_api.h
new file mode 100644
index 000000000..4dfd2739a
--- /dev/null
+++ b/src/libspudec/spu_decoder_api.h
@@ -0,0 +1,69 @@
+/*
+ * spu_decoder_api.h
+ *
+ * Copyright (C) James Courtier-Dutton James@superbug.demon.co.uk - July 2001
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine 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.
+ *
+ * xine 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 GNU Make; see the file COPYING. If not, write to
+ * the Free Software Foundation,
+ *
+ */
+
+#ifndef HAVE_SPU_API_H
+#define HAVE_SPU_API_H
+
+ /*
+ * generic xine spu decoder plugin interface
+ *
+ * for a dynamic plugin make sure you provide this function call:
+ * spu_decoder_t *init_spu_decoder_plugin (int iface_version,
+ * config_values_t *cfg);
+ */
+
+typedef struct spu_decoder_s spu_decoder_t;
+
+struct spu_decoder_s {
+
+ int interface_version;
+
+ int (*can_handle) (spu_decoder_t *this, int buf_type);
+
+ void (*init) (spu_decoder_t *this, vo_instance_t *video_out);
+
+ void (*decode_data) (spu_decoder_t *this, buf_element_t *buf);
+
+ void (*close) (spu_decoder_t *this);
+
+ char* (*get_identifier) (void);
+
+};
+
+
+
+typedef struct spudec_s spudec_t;
+
+struct spudec_s {
+
+ /*
+ * reset spudec for a new stream
+ *
+ * clut : pointer to array of 16 cluts for palette info
+ */
+
+ void (*spudec_start) (spudec_t *this, clut_t *clut);
+
+};
+
+#endif /* HAVE_SPUDEC_H */
diff --git a/src/libspudec/xine_decoder.c b/src/libspudec/xine_decoder.c
new file mode 100644
index 000000000..bcbcbb4ce
--- /dev/null
+++ b/src/libspudec/xine_decoder.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2000-2001 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine 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.
+ *
+ * xine 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: xine_decoder.c,v 1.1 2001/07/04 17:10:24 uid32519 Exp $
+ *
+ * stuff needed to turn libspu into a xine decoder plugin
+ */
+
+/*
+ * FIXME: libspu uses global variables (that are written to)
+ */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "spu.h"
+#include "buffer.h"
+#include "xine_internal.h"
+
+#define FRAME_SIZE 4096
+
+
+typedef struct spudec_decoder_s {
+ spu_decoder_t spu_decoder;
+
+ uint32_t pts;
+
+ uint8_t frame_buffer[FRAME_SIZE];
+ uint8_t *frame_ptr;
+ int sync_todo;
+ int frame_length, frame_todo;
+ uint16_t syncword;
+
+ vo_instance_t *vo_out;
+ vo_overlay_t *spu;
+ int spu_caps;
+ int bypass_mode;
+ int max_num_channels;
+ int output_sampling_rate;
+ int output_open;
+ int output_mode;
+
+} spudec_decoder_t;
+
+int spudec_can_handle (spu_decoder_t *this_gen, int buf_type) {
+ return ((buf_type & 0xFFFF0000) == BUF_SPU_PACKAGE) ;
+}
+
+
+void spudec_init (spu_decoder_t *this_gen, vo_instance_t *vo_out) {
+
+ spudec_decoder_t *this = (spudec_decoder_t *) this_gen;
+ printf("spudec_init %p\n",&vo_out);
+ this->vo_out = vo_out;
+ this->spu_caps = vo_out->get_capabilities(vo_out);
+ this->syncword = 0;
+ this->sync_todo = 6;
+ this->output_open = 0;
+
+// spu_init ();
+
+}
+
+u_int *overlay_txt (vo_overlay_t *spu, float o1)
+{
+ u_int x, y;
+ u_char tmp;
+ /* u_char *clr_ptr1 = (u_char *) img1; */
+ u_char *clr_ptr2;
+ u_char *spu_data_ptr = (u_char *) spu->data;
+ float o;
+
+ /* don't know why this can happen - but it does happen */
+ if ((spu->width <= 0) || (spu->height <= 0) ||
+ (spu->width > 1024) || (spu->height > 1024)) {
+ fprintf (stderr, "width || height out of range.\n");
+ return NULL;
+ }
+
+ for (y = spu->y; y < (spu->height + spu->y); y++) {
+ // clr_ptr1 = (u_char *) (img1 + y * 720 + spu->x);
+ for (x = spu->x; x < (spu->width + spu->x); x++) {
+ o = ((float) (*spu_data_ptr>>4) / 15.0) * o1;
+ //clr_ptr2 = (u_char *) &spu_clut[*spu_data_ptr&0x0f];
+ *clr_ptr2 = *spu_data_ptr&0x0f;
+ tmp=*spu_data_ptr;
+ printf("%X%X",tmp&0x0f,((tmp>>4)&0x0f));
+ spu_data_ptr ++;
+
+ // printf("%d ",(*clr_ptr2++));
+ // printf("%d ",(*clr_ptr2++));
+ // printf("%d ",(*clr_ptr2++));
+ // printf("%d \n",(*clr_ptr2++));
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+void spudec_decode_data (spu_decoder_t *this_gen, buf_element_t *buf) {
+
+ spudec_decoder_t *this = (spudec_decoder_t *) this_gen;
+
+ uint8_t *current = buf->content;
+ /* uint8_t *end = buf->content + buf->size; */
+
+ printf ("spudec_decode_data\n");
+
+ if (!this->spu) {
+ this->spu = this->vo_out->get_overlay (this->vo_out);
+ }
+
+ /* FIXME: shouldn't happen, but get_overlay function isn't implemented yet */
+ if (!this->spu)
+ return;
+
+ if (!spuParseHdr (this->spu, current, buf->size)) {
+ spuParseData (this->spu);
+ printf("X=%d Y=%d w=%d h=%d\n",
+ this->spu->x,this->spu->y,
+ this->spu->width,this->spu->height);
+ /* overlay_txt(this->spu,1.0); ??? */
+ this->spu->PTS = buf->PTS;
+ this->vo_out->queue_overlay (this->vo_out, this->spu);
+ this->spu = NULL;
+ }
+
+}
+
+void spudec_close (spu_decoder_t *this_gen) {
+
+ /* spudec_decoder_t *this = (spudec_decoder_t *) this_gen; */
+
+// if (this->output_open)
+// this->spu_out->close (this->spu_out);
+
+ /* close (spufile); */
+}
+
+static char *spudec_get_id(void) {
+ return "spudec";
+}
+
+spu_decoder_t *init_spu_decoder_plugin (int iface_version, config_values_t *cfg) {
+
+ spudec_decoder_t *this ;
+
+ if (iface_version != 1)
+ return NULL;
+
+ this = (spudec_decoder_t *) malloc (sizeof (spudec_decoder_t));
+
+ this->spu_decoder.interface_version = 1;
+ this->spu_decoder.can_handle = spudec_can_handle;
+ this->spu_decoder.init = spudec_init;
+ this->spu_decoder.decode_data = spudec_decode_data;
+ this->spu_decoder.close = spudec_close;
+ this->spu_decoder.get_identifier = spudec_get_id;
+
+ return (spu_decoder_t *) this;
+}
+