diff options
author | James Courtier-Dutton <jcdutton@users.sourceforge.net> | 2001-10-20 17:51:58 +0000 |
---|---|---|
committer | James Courtier-Dutton <jcdutton@users.sourceforge.net> | 2001-10-20 17:51:58 +0000 |
commit | 7391de8e6a14274fb7368aa4f1e71d091dc5c73c (patch) | |
tree | ca9f39e44be131b2003d19dbf84a81231ceb5b04 | |
parent | e3eb18aa6868ad17f01cfffafb001a95aa1ffb71 (diff) | |
download | xine-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.c | 142 | ||||
-rw-r--r-- | src/libspudec/spu.h | 15 | ||||
-rw-r--r-- | src/libspudec/spu_decoder_api.h | 2 | ||||
-rw-r--r-- | src/libspudec/xine_decoder.c | 579 |
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; } |