summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Courtier-Dutton <jcdutton@users.sourceforge.net>2001-10-20 17:51:58 +0000
committerJames Courtier-Dutton <jcdutton@users.sourceforge.net>2001-10-20 17:51:58 +0000
commit7391de8e6a14274fb7368aa4f1e71d091dc5c73c (patch)
treeca9f39e44be131b2003d19dbf84a81231ceb5b04
parente3eb18aa6868ad17f01cfffafb001a95aa1ffb71 (diff)
downloadxine-lib-7391de8e6a14274fb7368aa4f1e71d091dc5c73c.tar.gz
xine-lib-7391de8e6a14274fb7368aa4f1e71d091dc5c73c.tar.bz2
A reorganisation of libspudec, so we can support OSD and have better menu support.
Work still needs to be done on it and some xine-lib api changes. CVS patchset: 841 CVS date: 2001/10/20 17:51:58
-rw-r--r--src/libspudec/spu.c142
-rw-r--r--src/libspudec/spu.h15
-rw-r--r--src/libspudec/spu_decoder_api.h2
-rw-r--r--src/libspudec/xine_decoder.c579
4 files changed, 584 insertions, 154 deletions
diff --git a/src/libspudec/spu.c b/src/libspudec/spu.c
index e25f62656..7338f2ae7 100644
--- a/src/libspudec/spu.c
+++ b/src/libspudec/spu.c
@@ -1,29 +1,7 @@
-/*****
-*
+/*
+ *
* Copyright (C) James Courtier-Dutton James@superbug.demon.co.uk - July 2001
*
- * This file is part of xine
- * This file was originally 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.
-*
-* $Id: spu.c,v 1.15 2001/10/09 22:20:11 miguelfreitas Exp $
-*
-*****/
-
-/*
* spu.c - converts DVD subtitles to an XPM image
*
* Mostly based on hard work by:
@@ -40,11 +18,13 @@
* ... and yes, it works now with oms
* added tranparency (provided by the SPU hdr)
* changed structures for easy porting to MGAs DVD mode
+ * This file is part of xine
+ * This file was originally 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 of the License, or
- * (at your option) any later version.
+ * 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
@@ -52,9 +32,11 @@
* 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
- *
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: spu.c,v 1.16 2001/10/20 17:51:58 jcdutton Exp $
+ *
*/
#include <stdio.h>
@@ -92,9 +74,10 @@
/* Return value: reassembly complete = 1 */
-int spuReassembly (spu_seq_t *seq, int start, uint8_t *pkt_data, u_int pkt_len)
+int spu_reassembly (spu_seq_t *seq, int start, uint8_t *pkt_data, u_int pkt_len)
{
- LOG (LOG_DEBUG, "pkt_len: %d", pkt_len);
+ LOG (LOG_DEBUG, "pkt_len: %d\n", pkt_len);
+ LOG (LOG_DEBUG, "Reassembly: start=%d seq=%p\n", start,seq);
if (start) {
seq->seq_len = (((u_int)pkt_data[0])<<8) | pkt_data[1];
@@ -109,8 +92,8 @@ int spuReassembly (spu_seq_t *seq, int start, uint8_t *pkt_data, u_int pkt_len)
}
seq->ra_offs = 0;
- LOG (LOG_DEBUG, "buf_len: %d", seq->buf_len);
- LOG (LOG_DEBUG, "cmd_off: %d", seq->cmd_offs);
+ LOG (LOG_DEBUG, "buf_len: %d\n", seq->buf_len);
+ LOG (LOG_DEBUG, "cmd_off: %d\n", seq->cmd_offs);
}
if (seq->ra_offs < seq->buf_len) {
@@ -129,7 +112,7 @@ int spuReassembly (spu_seq_t *seq, int start, uint8_t *pkt_data, u_int pkt_len)
return 0;
}
-int spuNextEvent(spu_state_t *state, spu_seq_t* seq, int pts)
+int spu_next_event(spu_state_t *state, spu_seq_t* seq, int pts)
{
uint8_t *buf = state->cmd_ptr;
@@ -149,16 +132,23 @@ int spuNextEvent(spu_state_t *state, spu_seq_t* seq, int pts)
#define CMD_SPU_SET_ALPHA 0x04
#define CMD_SPU_SET_SIZE 0x05
#define CMD_SPU_SET_PXD_OFFSET 0x06
+#define CMD_SPU_WIPE 0x07 /* Not currently implemented */
#define CMD_SPU_EOF 0xff
-void spuDoCommands(spu_state_t *state, spu_seq_t* seq, vo_overlay_t *ovl)
+void spu_do_commands(spu_state_t *state, spu_seq_t* seq, vo_overlay_t *ovl)
{
uint8_t *buf = state->cmd_ptr;
uint8_t *next_seq;
- next_seq = seq->buf + (buf[0] << 8) + buf[1];
- buf += 2;
+ LOG (LOG_DEBUG, "SPU EVENT\n");
+
+ state->delay = (buf[0] << 8) + buf[1];
+ LOG (LOG_DEBUG, "\tdelay=%d\n",state->delay);
+ next_seq = seq->buf + (buf[2] << 8) + buf[3];
+ buf += 4;
+/* if next equals current, this is the last one
+ */
if (state->cmd_ptr >= next_seq)
next_seq = seq->buf + seq->seq_len; /* allow to run until end */
@@ -167,29 +157,31 @@ void spuDoCommands(spu_state_t *state, spu_seq_t* seq, vo_overlay_t *ovl)
while (buf < next_seq && *buf != CMD_SPU_EOF) {
switch (*buf) {
case CMD_SPU_SHOW: /* show subpicture */
- LOG (LOG_DEBUG, "\tshow subpicture");
+ LOG (LOG_DEBUG, "\tshow subpicture\n");
state->visible = 1;
buf++;
break;
case CMD_SPU_HIDE: /* hide subpicture */
- LOG (LOG_DEBUG, "\thide subpicture");
- state->visible = 0;
+ LOG (LOG_DEBUG, "\thide subpicture\n");
+ state->visible = 2;
buf++;
break;
case CMD_SPU_SET_PALETTE: { /* CLUT */
spu_clut_t *clut = (spu_clut_t *) (buf+1);
- state->cur_colors[3] = clut->entry0;
+/* state->cur_colors[3] = clut->entry0;
state->cur_colors[2] = clut->entry1;
state->cur_colors[1] = clut->entry2;
state->cur_colors[0] = clut->entry3;
- ovl->color[3] = state->clut[clut->entry0];
+ */
+/* This is a bit out of context for now */
+ ovl->color[3] = state->clut[clut->entry0];
ovl->color[2] = state->clut[clut->entry1];
ovl->color[1] = state->clut[clut->entry2];
ovl->color[0] = state->clut[clut->entry3];
- LOG (LOG_DEBUG, "\tclut [%x %x %x %x]",
+ LOG (LOG_DEBUG, "\tclut [%x %x %x %x]\n",
ovl->color[0], ovl->color[1], ovl->color[2], ovl->color[3]);
state->modified = 1;
buf += 3;
@@ -197,6 +189,7 @@ void spuDoCommands(spu_state_t *state, spu_seq_t* seq, vo_overlay_t *ovl)
}
case CMD_SPU_SET_ALPHA: { /* transparency palette */
spu_clut_t *trans = (spu_clut_t *) (buf+1);
+/* This should go into state for now */
ovl->trans[3] = trans->entry0;
ovl->trans[2] = trans->entry1;
@@ -210,28 +203,38 @@ void spuDoCommands(spu_state_t *state, spu_seq_t* seq, vo_overlay_t *ovl)
}
case CMD_SPU_SET_SIZE: /* image coordinates */
- state->o_left = (buf[1] << 4) | (buf[2] >> 4);
+/* state->o_left = (buf[1] << 4) | (buf[2] >> 4);
state->o_right = (((buf[2] & 0x0f) << 8) | buf[3]);
state->o_top = (buf[4] << 4) | (buf[5] >> 4);
state->o_bottom = (((buf[5] & 0x0f) << 8) | buf[6]);
-
- LOG (LOG_DEBUG, "\ttop = %d bottom = %d left = %d right = %d",
- state->o_left, state->o_right, state->o_top, state->o_bottom);
+ */
+ ovl->x = (buf[1] << 4) | (buf[2] >> 4);
+ ovl->y = (buf[4] << 4) | (buf[5] >> 4);
+ ovl->width = (((buf[2] & 0x0f) << 8) | buf[3]) - ovl->x + 1;
+ ovl->height = (((buf[5] & 0x0f) << 8) | buf[6]) - ovl->y + 1;
+ ovl->clip_top = 0;
+ ovl->clip_bottom = ovl->height - 1;
+ ovl->clip_left = 0;
+ ovl->clip_right = ovl->width - 1;
+
+ LOG (LOG_DEBUG, "\tx = %d y = %d width = %d height = %d\n",
+ ovl->x, ovl->y, ovl->width, ovl->height );
state->modified = 1;
buf += 7;
break;
- case CMD_SPU_SET_PXD_OFFSET: /* image 1 / image 2 offsets */
+ case CMD_SPU_SET_PXD_OFFSET: /* image top[0] field / image bottom[1] field*/
state->field_offs[0] = (((u_int)buf[1]) << 8) | buf[2];
state->field_offs[1] = (((u_int)buf[3]) << 8) | buf[4];
- LOG (LOG_DEBUG, "\toffset[0] = %d offset[1] = %d",
+ LOG (LOG_DEBUG, "\toffset[0] = %d offset[1] = %d\n",
state->field_offs[0], state->field_offs[1]);
state->modified = 1;
buf += 5;
break;
case CMD_SPU_MENU:
+ LOG (LOG_DEBUG, "\tForce Display/Menu\n");
state->menu = 1;
buf++;
break;
@@ -244,7 +247,13 @@ void spuDoCommands(spu_state_t *state, spu_seq_t* seq, vo_overlay_t *ovl)
}
if (next_seq >= seq->buf + seq->seq_len)
seq->finished = 1; /* last sub-sequence */
+
state->next_pts = -1; /* invalidate timestamp */
+
+
+ state->cmd_ptr = next_seq;
+
+
}
static uint8_t *bit_ptr[2];
@@ -294,7 +303,7 @@ static int spu_next_line (vo_overlay_t *spu)
return 0;
}
-void spuDrawPicture (spu_state_t *state, spu_seq_t* seq, vo_overlay_t *ovl)
+void spu_draw_picture (spu_state_t *state, spu_seq_t* seq, vo_overlay_t *ovl)
{
rle_elem_t *rle;
@@ -304,26 +313,27 @@ void spuDrawPicture (spu_state_t *state, spu_seq_t* seq, vo_overlay_t *ovl)
put_x = put_y = 0;
get_bits (0); /* Reset/init bit code */
- ovl->x = state->o_left;
- ovl->y = state->o_top;
- ovl->width = state->o_right - state->o_left + 1;
- ovl->height = state->o_bottom - state->o_top + 1;
+/* ovl->x = state->o_left;
+ * ovl->y = state->o_top;
+ * ovl->width = state->o_right - state->o_left + 1;
+ * ovl->height = state->o_bottom - state->o_top + 1;
- ovl->clip_top = 0;
- ovl->clip_bottom = ovl->height - 1;
- ovl->clip_left = 0;
- ovl->clip_right = ovl->width - 1;
+ * ovl->clip_top = 0;
+ * ovl->clip_bottom = ovl->height - 1;
+ * ovl->clip_left = 0;
+ * ovl->clip_right = ovl->width - 1;
+ */
- spuUpdateMenu(state, ovl);
+/* spu_update_menu(state, ovl); FIXME: What is this for? */
/* buffer is believed to be sufficiently large
* with cmd_offs * 2 * sizeof(rle_elem_t), is that true? */
- if (seq->cmd_offs * 2 * sizeof(rle_elem_t) > ovl->data_size) {
- if (ovl->rle)
- free(ovl->rle);
+// if (seq->cmd_offs * 2 * sizeof(rle_elem_t) > ovl->data_size) {
+// if (ovl->rle)
+// free(ovl->rle);
ovl->data_size = seq->cmd_offs * 2 * sizeof(rle_elem_t);
ovl->rle = malloc(ovl->data_size);
- }
+// }
state->modified = 0; /* mark as already processed */
rle = ovl->rle;
@@ -371,7 +381,7 @@ void spuDrawPicture (spu_state_t *state, spu_seq_t* seq, vo_overlay_t *ovl)
MINFOUND is the number of ocurrences threshold.
*/
#define MINFOUND 25
-void spuDiscoverClut(spu_state_t *state, vo_overlay_t *ovl)
+void spu_discover_clut(spu_state_t *state, vo_overlay_t *ovl)
{
int bg,c;
int seqcolor[10];
@@ -448,7 +458,7 @@ void spuDiscoverClut(spu_state_t *state, vo_overlay_t *ovl)
}
-void spuUpdateMenu (spu_state_t *state, vo_overlay_t *ovl) {
+void spu_update_menu (spu_state_t *state, vo_overlay_t *ovl) {
if (!state->menu)
return;
diff --git a/src/libspudec/spu.h b/src/libspudec/spu.h
index 95145d1b3..e86adfde8 100644
--- a/src/libspudec/spu.h
+++ b/src/libspudec/spu.h
@@ -19,7 +19,7 @@
* 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.5 2001/09/27 02:11:16 miguelfreitas Exp $
+ * $Id: spu.h,v 1.6 2001/10/20 17:51:59 jcdutton Exp $
*
* This file was originally part of the OMS program.
*
@@ -80,6 +80,7 @@ typedef struct {
int modified; /* Was the sub-picture modified? */
int visible; /* Must the sub-picture be shown? */
int menu; /* This overlay is a menu */
+ int delay; /* Delay in 90Khz / 1000 */
int b_show; /* is a button shown? */
int need_clut; /* doesn't have the right clut yet */
int cur_colors[4];/* current 4 colors been used */
@@ -87,11 +88,11 @@ typedef struct {
uint32_t clut[16];
} spu_state_t;
-int spuReassembly (spu_seq_t *seq, int start, uint8_t *pkt_data, u_int pkt_len);
-int spuNextEvent (spu_state_t *state, spu_seq_t* seq, int pts);
-void spuDoCommands (spu_state_t *state, spu_seq_t* seq, vo_overlay_t *ovl);
-void spuDrawPicture (spu_state_t *state, spu_seq_t* seq, vo_overlay_t *ovl);
-void spuDiscoverClut (spu_state_t *state, vo_overlay_t *ovl);
-void spuUpdateMenu (spu_state_t *state, vo_overlay_t *ovl);
+int spu_reassembly (spu_seq_t *seq, int start, uint8_t *pkt_data, u_int pkt_len);
+int spu_next_event (spu_state_t *state, spu_seq_t* seq, int pts);
+void spu_do_commands (spu_state_t *state, spu_seq_t* seq, vo_overlay_t *ovl);
+void spu_draw_picture (spu_state_t *state, spu_seq_t* seq, vo_overlay_t *ovl);
+void spu_discover_clut (spu_state_t *state, vo_overlay_t *ovl);
+void spu_update_menu (spu_state_t *state, vo_overlay_t *ovl);
#endif
diff --git a/src/libspudec/spu_decoder_api.h b/src/libspudec/spu_decoder_api.h
index c0c44834b..c2c4bf2f6 100644
--- a/src/libspudec/spu_decoder_api.h
+++ b/src/libspudec/spu_decoder_api.h
@@ -29,7 +29,7 @@
*
* for a dynamic plugin make sure you provide this function call:
* spu_decoder_t *init_spu_decoder_plugin (int iface_version,
- * xine_t *xine);
+ * xine_t *xine);
*/
typedef struct spu_decoder_s spu_decoder_t;
diff --git a/src/libspudec/xine_decoder.c b/src/libspudec/xine_decoder.c
index 6fba7372e..5e85f89a0 100644
--- a/src/libspudec/xine_decoder.c
+++ b/src/libspudec/xine_decoder.c
@@ -19,16 +19,11 @@
* 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.16 2001/10/20 02:01:51 guenter Exp $
+ * $Id: xine_decoder.c,v 1.17 2001/10/20 17:51:59 jcdutton 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>
@@ -43,6 +38,26 @@
#include "video_out/alphablend.h"
#include "xine-engine/bswap.h"
+#define LOG_DEBUG 1
+
+#ifdef DEBUG
+
+# ifdef __GNUC__
+# define LOG(lvl, fmt...) fprintf (stderr, fmt);
+# else
+# define LOG(lvl, ...) fprintf (stderr, __VA_ARGS__);
+# endif
+
+#else /* !DEBUG */
+
+# ifdef __GNUC__
+# define LOG(lvl, fmt...)
+# else
+# define LOG(lvl, ...)
+# endif
+
+#endif /* !DEBUG */
+
static clut_t __default_clut[] = {
CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
CLUT_Y_CR_CB_INIT(0xbf, 0x80, 0x80),
@@ -63,16 +78,75 @@ static clut_t __default_clut[] = {
CLUT_Y_CR_CB_INIT(0x28, 0x6d, 0xef)
};
-#define NUM_SEQ_BUFFERS 5
+#define NUM_SEQ_BUFFERS 50
+#define MAX_OBJECTS 50
+#define MAX_STREAMS 32
+#define MAX_EVENTS 50
+#define MAX_SHOWING 5
+
+#define EVENT_NULL 0
+#define EVENT_SHOW_SPU 1
+#define EVENT_HIDE_SPU 2
+#define EVENT_MENU_SPU 3
+#define EVENT_MENU_BUTTON 4
+#define EVENT_DELETE_RESOURCE 5 /* Maybe release handle will do this */
+#define EVENT_SHOW_OSD 6 /* Not yet implemented */
+
+typedef struct spu_object_s {
+ int32_t handle; /* Used to match Show and Hide events. */
+ uint32_t object_type; /* 0=Subtitle, 1=Menu */
+ uint32_t pts; /* Needed for Menu button compares */
+ vo_overlay_t *overlay; /* The image data. */
+ uint32_t palette_type; /* 1 Y'CrCB, 2 R'G'B' */
+ uint32_t *palette; /* If NULL, no palette contained in this event. */
+} spu_object_t;
+
+/* This will hold all details of an event item, needed for event queue to function */
+typedef struct spu_overlay_event_s {
+ uint32_t event_type; /* Show SPU, Show OSD, Hide etc. */
+ uint32_t vpts; /* Time when event will action. 0 means action now */
+/* Once video_out blend_yuv etc. can take rle_elem_t with Colour, blend and length information.
+ * we can remove clut and blend from this structure.
+ * This will allow for many more colours for OSD.
+ */
+ spu_object_t object; /* The image data. */
+} spu_overlay_event_t;
+
+typedef struct spu_overlay_events_s {
+ spu_overlay_event_t *event;
+ uint32_t next_event;
+} spu_overlay_events_t;
+
+typedef struct spu_showing_s {
+ int32_t handle; /* -1 means not allocated */
+} spu_showing_t;
+
+
+typedef struct spudec_stream_state_s {
+ spu_seq_t ra_seq;
+ uint32_t ra_complete;
+ uint32_t stream_filter;
+ spu_state_t state;
+ uint32_t vpts;
+ uint32_t pts;
+} spudec_stream_state_t;
typedef struct spudec_decoder_s {
spu_decoder_t spu_decoder;
ovl_src_t ovl_src;
xine_t *xine;
-
- spu_seq_t seq_list[NUM_SEQ_BUFFERS];
+/* spu_seq_t seq_list[NUM_SEQ_BUFFERS]; */
spu_seq_t *cur_seq;
+ spudec_stream_state_t spu_stream_state[MAX_STREAMS];
+ pthread_mutex_t spu_events_mutex;
+ spu_overlay_events_t spu_events[MAX_EVENTS];
+ spu_overlay_event_t event;
+ spu_object_t object;
+ pthread_mutex_t spu_objects_mutex;
+ spu_object_t spu_objects[MAX_OBJECTS];
+ pthread_mutex_t spu_showing_mutex; /* Probably not needed */
+ spu_showing_t spu_showing[MAX_SHOWING];
spu_seq_t *ra_seq;
int ra_complete;
@@ -81,7 +155,7 @@ typedef struct spudec_decoder_s {
spu_state_t state;
vo_instance_t *vo_out;
- vo_overlay_t ovl;
+ vo_overlay_t overlay;
int ovl_caps;
int output_open;
@@ -92,20 +166,45 @@ int spudec_can_handle (spu_decoder_t *this_gen, int buf_type) {
return (type == BUF_SPU_PACKAGE || type == BUF_SPU_CLUT) ;
}
+/* FIXME: This function needs checking */
static void spudec_reset (spudec_decoder_t *this) {
int i;
-
this->ovl_pts = 0;
this->buf_pts = 0;
this->state.visible = 0;
- this->seq_list[0].finished = 1; /* mark as cur_seq */
- for (i = 1; i < NUM_SEQ_BUFFERS; i++) {
- this->seq_list[i].finished = 2; /* free for reassembly */
+// this->seq_list[0].finished = 1; /* mark as cur_seq */
+// for (i = 1; i < NUM_SEQ_BUFFERS; i++) {
+// this->seq_list[i].finished = 2; /* free for reassembly */
+// }
+ for (i=0; i < MAX_STREAMS; i++) {
+ this->spu_stream_state[i].stream_filter = 1;
+ this->spu_stream_state[i].ra_complete = 1;
+ }
+// this->spu_events[i].next_event = 1;
+ for (i=0; i < MAX_EVENTS; i++) {
+ if (this->spu_events[i].event == NULL) {
+ this->spu_events[i].event = malloc (sizeof(spu_overlay_event_t));
+ this->spu_events[i].event->event_type = 0; /* Empty slot */
+ }
+ }
+ for (i=0; i < MAX_OBJECTS; i++) {
+ this->spu_objects[i].handle = -1;
}
- this->ra_complete = 1;
+ /* Initialise the menu object */
+ this->spu_objects[1].handle=1;
+ this->spu_objects[1].object_type=1;
+ this->spu_objects[1].pts=0;
+ this->spu_objects[1].overlay = malloc (sizeof(vo_overlay_t));
+
+ pthread_mutex_init (&this->spu_events_mutex,NULL);
+ pthread_mutex_init (&this->spu_objects_mutex,NULL);
+ pthread_mutex_init (&this->spu_showing_mutex,NULL);
+
+/* I don't think I need this.
this->cur_seq = this->ra_seq = this->seq_list;
+ */
}
@@ -118,14 +217,181 @@ void spudec_init (spu_decoder_t *this_gen, vo_instance_t *vo_out) {
this->output_open = 0;
spudec_reset(this);
+/* FIXME:Do we really need a default clut? */
memcpy(this->state.clut, __default_clut, sizeof(this->state.clut));
this->state.need_clut = 1;
vo_out->register_ovl_src(vo_out, &this->ovl_src);
}
-void spudec_decode_data (spu_decoder_t *this_gen, buf_element_t *buf) {
+/* allocate a handle from the object pool
+ */
+int32_t spu_get_handle(spudec_decoder_t *this) {
+ int n;
+ n=0;
+ do {
+ n++;
+ } while ( ( n<MAX_OBJECTS ) && ( this->spu_objects[n].handle > -1 ) );
+ if (n >= MAX_OBJECTS) return -1;
+ this->spu_objects[n].handle=n;
+ return n;
+}
+
+/* allocate a menu handle from the object pool
+ */
+int32_t spu_get_menu_handle(spudec_decoder_t *this) {
+ return 1; /* This might be dynamic later */
+}
+
+/* free a handle from the object pool
+ */
+void spu_free_handle(spudec_decoder_t *this, int32_t handle) {
+ this->spu_objects[handle].handle = -1;
+}
+
+/* add an event to the events queue, sort the queue based on vpts.
+ * This can be the API entry point for DVD subtitles.
+ * In future this could also be the entry point for OSD as well as other Subtitle formats.
+ * One calls this function with an event, the event contains an overlay and a vpts when to action/process it.
+ * vpts of 0 means action the event now.
+ * One also has a handle, so one can match show and hide events.
+ * FIXME: Implement Event queue locking. A different thread calls spu_get_overlay, which removes events from the queue.
+ */
+int32_t spu_add_event(spudec_decoder_t *this, spu_overlay_event_t *event) {
+ int found;
+ uint32_t last_event,this_event,new_event;
+ new_event=0;
+ /* We skip the 0 entry because that is used as a pointer to the first event.*/
+ /* Find a free event slot */
+ pthread_mutex_lock (&this->spu_events_mutex);
+ do {
+ new_event++;
+ } while ((new_event<MAX_EVENTS) && (this->spu_events[new_event].event->event_type > 0));
+ if (new_event >= MAX_EVENTS) {
+ pthread_mutex_unlock (&this->spu_events_mutex);
+ return -1;
+ }
+ /* Find position in event queue to be added. */
+ this_event=0;
+ found=0;
+ /* Find where in the current queue to insert the event. I.E. Sort it. */
+ do {
+ last_event=this_event;
+ this_event=this->spu_events[last_event].next_event;
+ if (this_event == 0) {
+ found=1;
+ break;
+ }
+ LOG (LOG_DEBUG, "this_event=%d vpts %d\n",this_event, this->spu_events[this_event].event->vpts);
+ if (this->spu_events[this_event].event->vpts > event->vpts ) {
+ found=2;
+ break;
+ }
+ } while ((this_event != 0) && (found == 0));
+ if (last_event >= MAX_EVENTS) {
+ pthread_mutex_unlock (&this->spu_events_mutex);
+ fprintf(stderr, "No spare subtitle event slots\n");
+ return -1;
+ }
+ /* memcpy everything except the actual image */
+ this->spu_events[last_event].next_event=new_event;
+ this->spu_events[new_event].next_event=this_event;
+ if ( this->spu_events[new_event].event == NULL ) {
+ fprintf(stderr,"COMPLAIN BIG TIME!\n");
+ }
+ this->spu_events[new_event].event->event_type=event->event_type;
+ this->spu_events[new_event].event->vpts=event->vpts;
+ this->spu_events[new_event].event->object.handle=event->object.handle;
+ this->spu_events[new_event].event->object.overlay = malloc (sizeof(vo_overlay_t));
+ memcpy(this->spu_events[new_event].event->object.overlay,
+ event->object.overlay, sizeof(vo_overlay_t));
+
+ pthread_mutex_unlock (&this->spu_events_mutex);
+
+ return new_event;
+}
+
+/* empty the object queue
+ * release all handles currently allocated.
+ * IMPLEMENT ME.
+ */
+void spu_free_all_handles(spudec_decoder_t *this) {
+return;
+}
+
+void spu_process (spudec_decoder_t *this, uint32_t stream_id) {
+// spu_overlay_event_t *event;
+// spu_object_t *object;
+// vo_overlay_t *overlay;
+ int handle;
+ int pending = 1;
+ this->cur_seq = &this->spu_stream_state[stream_id].ra_seq;
+
+/* FIXME:Get Handle after we have found if "Forced display" is set or not.
+ */
+
+ LOG (LOG_DEBUG, "Found SPU from stream %d pts=%d vpts=%d\n",stream_id,
+ this->spu_stream_state[stream_id].pts,
+ this->spu_stream_state[stream_id].vpts);
+ this->state.cmd_ptr = this->cur_seq->buf + this->cur_seq->cmd_offs;
+ this->state.next_pts = -1; /* invalidate timestamp */
+ this->state.modified = 1; /* Only draw picture if = 1 on first event of SPU */
+ this->state.visible = 0; /* 0 - No value, 1 - Show, 2 - Hide. */
+ this->state.menu = 0; /* 0 - No value, 1 - Forced Display. */
+ this->state.delay = 0;
+ this->cur_seq->finished=0;
+ handle=spu_get_handle(this);
+ if (handle < 0) {
+ printf("No SPU Handles left\n");
+ return;
+ }
+ do {
+ if (!this->spu_stream_state[stream_id].ra_seq.finished) {
+ //spudec_nextseq(this);
+/* Get do commands to build the event. */
+ spu_do_commands(&this->state, this->cur_seq, &this->overlay);
+ /* FIXME: Check for Forced-display or subtitle stream
+ * For subtitles, open event.
+ * For menus, store it for later.
+ */
+ if ((this->state.modified) ) {
+ spu_draw_picture(&this->state, this->cur_seq, &this->overlay);
+ }
+/* spu_discover_clut probably goes here */
+/* Not sure where to put clut discovery */
+/* if (this->state.need_clut)
+ spu_discover_clut(&this->state, &this->overlay);
+ return ;
+ }
+ */
+ if (this->state.menu == 0) {
+ /* Subtitle */
+ this->event.object.handle = handle;
+ this->event.object.overlay = &this->overlay;
+ this->event.event_type = this->state.visible;
+ this->event.vpts = this->spu_stream_state[stream_id].vpts+(this->state.delay*1000);
+ } else {
+ /* Menu */
+ spu_free_handle(this, handle);
+ this->event.object.handle = spu_get_menu_handle(this);
+ this->event.object.overlay = &this->overlay;
+ this->event.event_type = EVENT_MENU_SPU;
+ this->event.vpts = 0; /* Activate it NOW */
+ }
+ spu_add_event(this, &this->event);
+ } else {
+ pending = 0;
+ }
+ } while (pending);
+
+}
+
+void spudec_decode_data (spu_decoder_t *this_gen, buf_element_t *buf) {
+ uint32_t stream_id;
+ spu_seq_t *cur_seq;
spudec_decoder_t *this = (spudec_decoder_t *) this_gen;
+ stream_id = buf->type & 0x1f ;
+ cur_seq = &this->spu_stream_state[stream_id].ra_seq;
if (buf->type == BUF_SPU_CLUT) {
if (buf->content[0]) { /* cheap endianess detection */
@@ -145,25 +411,33 @@ void spudec_decode_data (spu_decoder_t *this_gen, buf_element_t *buf) {
if (buf->PTS) {
metronom_t *metronom = this->ovl_src.metronom;
- uint32_t pts = metronom->got_spu_packet(metronom, buf->PTS, 0);
- if (pts < this->buf_pts)
+ uint32_t vpts = metronom->got_spu_packet(metronom, buf->PTS, 0);
+ if (vpts < this->buf_pts)
spudec_reset(this);
- this->buf_pts = pts;
+ this->spu_stream_state[stream_id].vpts = vpts; /* Show timer */
+ this->spu_stream_state[stream_id].pts = buf->PTS; /* Required to match up with NAV packets */
}
- if (this->ra_complete) {
+/* if (this->ra_complete) {
spu_seq_t *tmp_seq = this->ra_seq + 1;
if (tmp_seq >= this->seq_list + NUM_SEQ_BUFFERS)
tmp_seq = this->seq_list;
-
if (tmp_seq->finished > 1) {
this->ra_seq = tmp_seq;
- this->ra_seq->PTS = this->buf_pts;
+ this->ra_seq->PTS = this->buf_pts;
}
}
- this->ra_complete =
- spuReassembly(this->ra_seq, this->ra_complete, buf->content, buf->size);
+ */
+ stream_id = buf->type & 0x1f ;
+ this->spu_stream_state[stream_id].ra_complete =
+ spu_reassembly(&this->spu_stream_state[stream_id].ra_seq,
+ this->spu_stream_state[stream_id].ra_complete,
+ buf->content,
+ buf->size);
+ if(this->spu_stream_state[stream_id].ra_complete == 1) {
+ spu_process(this,stream_id);
+ }
}
void spudec_close (spu_decoder_t *this_gen) {
@@ -171,12 +445,13 @@ void spudec_close (spu_decoder_t *this_gen) {
this->vo_out->unregister_ovl_src(this->vo_out, &this->ovl_src);
}
-
+/* This function is probably not needed now */
static void spudec_nextseq(spudec_decoder_t* this) {
spu_seq_t *tmp_seq = this->cur_seq + 1;
- if (tmp_seq >= this->seq_list + NUM_SEQ_BUFFERS)
+/* if (tmp_seq >= this->seq_list + NUM_SEQ_BUFFERS)
tmp_seq = this->seq_list;
-
+ */
+
if (!tmp_seq->finished) { /* is the next seq ready for process? */
this->cur_seq->finished = 2; /* ready for reassembly */
this->cur_seq = tmp_seq;
@@ -188,90 +463,234 @@ static void spudec_nextseq(spudec_decoder_t* this) {
}
}
-static vo_overlay_t* spudec_get_overlay(ovl_src_t *ovl_src, int pts) {
- spudec_decoder_t *this = (spudec_decoder_t*) ovl_src->src_gen;
- int pending = 0;
-
- if (this->ovl_pts > pts)
- spudec_reset(this);
-
- this->ovl_pts = pts;
-
- do {
- if (this->cur_seq->finished)
- spudec_nextseq(this);
-
- if (!this->cur_seq->finished) {
- pending = spuNextEvent(&this->state, this->cur_seq, pts);
+/* FIXME:Some optimization needs to happen here. */
+void spu_process_event( spudec_decoder_t *this, int vpts ) {
+ int32_t handle;
+ uint32_t this_event;
+// uint32_t vpts;
+// uint32_t pts;
+// int i;
+// vo_overlay_t overlay;
+ pthread_mutex_lock (&this->spu_events_mutex);
+ this_event=this->spu_events[0].next_event;
+ if ((!this_event) || (vpts < this->spu_events[this_event].event->vpts) ) {
+ pthread_mutex_unlock (&this->spu_events_mutex);
+ return;
+ }
- if (pending)
- spuDoCommands(&this->state, this->cur_seq, &this->ovl);
- } else
- pending = 0;
+ printf("show event: event_vpts=%d actual_vpts=%d\n", this->spu_events[this_event].event->vpts,vpts );
+ printf("Process_event called\n");
- } while (pending);
-
- if (this->state.visible) {
- if (this->state.modified) {
- spuDrawPicture(&this->state, this->cur_seq, &this->ovl);
- }
+ handle=this->spu_events[this_event].event->object.handle;
+ switch( this->spu_events[this_event].event->event_type ) {
+ case EVENT_SHOW_SPU:
+ LOG (LOG_DEBUG, "SHOW SPU NOW\n");
+ if (this->spu_events[this_event].event->object.overlay != NULL) {
+ this->spu_objects[handle].handle = handle;
+ this->spu_objects[handle].overlay = this->spu_events[this_event].event->object.overlay;
+ }
+ this->spu_showing[1].handle = handle;
+ break;
+
+ case EVENT_HIDE_SPU:
+ LOG (LOG_DEBUG, "HIDE SPU NOW\n");
+ this->spu_showing[1].handle = -1;
+ spu_free_handle( this, handle );
+ break;
+
+ case EVENT_MENU_SPU:
+ LOG (LOG_DEBUG, "MENU SPU NOW\n");
+ if (this->spu_events[this_event].event->object.overlay != NULL) {
+ vo_overlay_t *overlay = this->spu_objects[handle].overlay;
+ vo_overlay_t *event_overlay = this->spu_events[this_event].event->object.overlay;
+ this->spu_objects[handle].handle = handle; /* This should not change for menus */
+ overlay->rle = event_overlay->rle;
+ overlay->data_size = event_overlay->data_size;
+ overlay->num_rle = event_overlay->num_rle;
+ overlay->x = event_overlay->x;
+ overlay->y = event_overlay->y;
+ overlay->width = event_overlay->width;
+ overlay->height = event_overlay->height;
+ overlay->rgb_clut = event_overlay->rgb_clut;
+ if((event_overlay->color[0] |
+ event_overlay->color[1] |
+ event_overlay->color[2] |
+ event_overlay->color[3]) > 0 ) {
+ overlay->color[0] = event_overlay->color[0];
+ overlay->color[1] = event_overlay->color[1];
+ overlay->color[2] = event_overlay->color[2];
+ overlay->color[3] = event_overlay->color[3];
+ }
+ if((event_overlay->trans[0] |
+ event_overlay->trans[1] |
+ event_overlay->trans[2] |
+ event_overlay->trans[3]) > 0 ) {
+ overlay->trans[0] = event_overlay->trans[0];
+ overlay->trans[1] = event_overlay->trans[1];
+ overlay->trans[2] = event_overlay->trans[2];
+ overlay->trans[3] = event_overlay->trans[3];
+ }
+ this->spu_showing[1].handle = handle;
+ }
+ break;
+
+ case EVENT_MENU_BUTTON:
+ LOG (LOG_DEBUG, "MENU BUTTON NOW\n");
+ if (this->spu_events[this_event].event->object.overlay != NULL) {
+ vo_overlay_t *overlay = this->spu_objects[handle].overlay;
+ vo_overlay_t *event_overlay = this->spu_events[this_event].event->object.overlay;
+ this->spu_objects[handle].handle = handle; /* This should not change for menus */
+ overlay->clip_top = event_overlay->clip_top;
+ overlay->clip_bottom = event_overlay->clip_bottom;
+ overlay->clip_left = event_overlay->clip_left;
+ overlay->clip_right = event_overlay->clip_right;
+ //overlay->rgb_clut = event_overlay->rgb_clut; /* May needed later for OSD */
+ if((event_overlay->color[0] |
+ event_overlay->color[1] |
+ event_overlay->color[2] |
+ event_overlay->color[3]) > 0 ) {
+ overlay->color[0] = event_overlay->color[0];
+ overlay->color[1] = event_overlay->color[1];
+ overlay->color[2] = event_overlay->color[2];
+ overlay->color[3] = event_overlay->color[3];
+ }
+ if((event_overlay->trans[0] |
+ event_overlay->trans[1] |
+ event_overlay->trans[2] |
+ event_overlay->trans[3]) > 0 ) {
+ overlay->trans[0] = event_overlay->trans[0];
+ overlay->trans[1] = event_overlay->trans[1];
+ overlay->trans[2] = event_overlay->trans[2];
+ overlay->trans[3] = event_overlay->trans[3];
+ }
+ this->spu_showing[1].handle = handle;
+ }
+ break;
- if (this->state.need_clut)
- spuDiscoverClut(&this->state, &this->ovl);
+ default:
+ LOG (LOG_DEBUG, "Unhandled event type\n");
+ break;
- return &this->ovl;
}
+ this->spu_events[0].next_event = this->spu_events[this_event].next_event;
+ this->spu_events[this_event].next_event = 0;
+ this->spu_events[this_event].event->event_type = 0;
+ pthread_mutex_unlock (&this->spu_events_mutex);
+}
+
+/* This is called from video_out and should return one image.
+ * Repeated calls will display the next image.
+ * until the last image is reached, when a NULL is returned
+ * and the pointer starts from the beginning again.
+ * For now, a max of 5 diffent images can be displayed at once.
+ * Maybe we should add a callback instead of calling the function all the time.
+ * We could rename this then to "Render overlay"
+ * This function needs an API change, to add a callback function to do the actual overlay.
+ * In this way we can get multiple objects displayed at the same time.
+ * i.e. Subtitles and OSD.
+ * Currently, only one object can be displayed at the same time.
+ * The first checkin of this code should add no more functionality than the current code.
+ * It was just be checked in so others can test it.
+ */
+
+static vo_overlay_t* spudec_get_overlay(ovl_src_t *ovl_src, int vpts) {
+ int32_t handle;
+ spudec_decoder_t *this = (spudec_decoder_t*) ovl_src->src_gen;
- return NULL;
+ /* Look at next event, if current video vpts > first event on queue, process the event
+ * else just continue
+ */
+ spu_process_event( this, vpts );
+ /* Scan through 5 entries and display any present.
+ * Currently, only 1 entry is scanned, until API can change.
+ */
+ handle=this->spu_showing[1].handle; /* handle is only valid if the object is currently visable. */
+ if (handle < 0) return NULL;
+ return this->spu_objects[handle].overlay;
}
-static void spudec_event_listener (void *this_gen, xine_event_t *event_gen) {
+static void spudec_event_listener(void *this_gen, xine_event_t *event_gen) {
spudec_decoder_t *this = (spudec_decoder_t *) this_gen;
xine_spu_event_t *event = (xine_spu_event_t *) event_gen;
if((!this) || (!event)) {
return;
}
-
+
switch (event->event.type) {
case XINE_EVENT_SPU_BUTTON:
{
- spu_button_t *but = event->data;
+ spu_overlay_event_t *overlay_event;
+ vo_overlay_t *overlay;
+ spu_button_t *but = event->data;
+ overlay_event = malloc (sizeof(spu_overlay_event_t));
+ overlay = malloc (sizeof(vo_overlay_t));
+ overlay_event->object.overlay=overlay;
+
+ LOG (LOG_DEBUG, "BUTTON\n");
+ LOG (LOG_DEBUG, "\tshow=%d\n",but->show);
+ LOG (LOG_DEBUG, "\tclut [%x %x %x %x]\n",
+ but->color[0], but->color[1], but->color[2], but->color[3]);
+ LOG (LOG_DEBUG, "\ttrans [%d %d %d %d]\n",
+ but->trans[0], but->trans[1], but->trans[2], but->trans[3]);
+ LOG (LOG_DEBUG, "\tleft = %d right = %d top = %d bottom = %d\n",
+ but->left, but->right, but->top, but->bottom );
if (!this->state.menu) return;
-
+
if (but->show) {
- int i;
- for (i = 0; i < 4; i++) {
- this->ovl.color[i] = this->state.clut[but->color[i]];
- this->ovl.trans[i] = but->trans[i];
- }
-
- this->state.b_left = but->left;
- this->state.b_right = but->right;
- this->state.b_top = but->top;
- this->state.b_bottom = but->bottom;
+ overlay_event->object.handle = spu_get_menu_handle(this);
+ overlay_event->object.overlay=overlay;
+ overlay_event->event_type = EVENT_MENU_BUTTON;
+ overlay_event->vpts = 0; /* Activate it NOW */
+ overlay->clip_top = but->top;
+ overlay->clip_bottom = but->bottom;
+ overlay->clip_left = but->left;
+ overlay->clip_right = but->right;
+ if((but->color[0] |
+ but->color[1] |
+ but->color[2] |
+ but->color[3]) > 0 ) {
+ overlay->color[0] = but->color[0];
+ overlay->color[1] = but->color[1];
+ overlay->color[2] = but->color[2];
+ overlay->color[3] = but->color[3];
+ }
+ if((but->trans[0] |
+ but->trans[1] |
+ but->trans[2] |
+ but->trans[3]) > 0 ) {
+ overlay->trans[0] = but->trans[0];
+ overlay->trans[1] = but->trans[1];
+ overlay->trans[2] = but->trans[2];
+ overlay->trans[3] = but->trans[3];
+ }
+ spu_add_event(this, overlay_event);
}
-
- this->state.b_show = but->show;
- spuUpdateMenu(&this->state, &this->ovl);
}
break;
case XINE_EVENT_SPU_CLUT:
{
+ /* FIXME: This function will need checking before it works. */
spu_cltbl_t *clut = event->data;
- if (clut){
- memcpy(this->state.clut, clut->clut, sizeof(int32_t)*16);
- this->state.need_clut = 0;
+ if (clut) {
+ memcpy(this->state.clut, clut->clut, sizeof(int32_t)*16);
+ this->state.need_clut = 0;
}
}
break;
- /* FIXME
+ /* What is this for?
+ * This event is for GUI -> NAVDVD plugin
+ * SPUDEC will have to use a different EVENT
+ * if it needs this for CLUT auto detect.
+ */
+ /* FIXME
case XINE_UI_GET_SPU_LANG:
{
this->state.need_clut = 1;
}
break;
- */
+ */
+
}
}
@@ -305,9 +724,9 @@ spu_decoder_t *init_spu_decoder_plugin (int iface_version, xine_t *xine) {
this->ovl_src.src_gen = this;
this->ovl_src.get_overlay = spudec_get_overlay;
this->xine = xine;
-
+
xine_register_event_listener(xine, spudec_event_listener, this);
-
+
return (spu_decoder_t *) this;
}