diff options
Diffstat (limited to 'src/libspudec')
-rw-r--r-- | src/libspudec/Makefile.am | 3 | ||||
-rw-r--r-- | src/libspudec/spu.c | 485 | ||||
-rw-r--r-- | src/libspudec/spu.h | 41 | ||||
-rw-r--r-- | src/libspudec/spu_decoder_api.h | 18 | ||||
-rw-r--r-- | src/libspudec/xine_decoder.c | 259 |
5 files changed, 462 insertions, 344 deletions
diff --git a/src/libspudec/Makefile.am b/src/libspudec/Makefile.am index 578f038d4..9e5d8ca4b 100644 --- a/src/libspudec/Makefile.am +++ b/src/libspudec/Makefile.am @@ -9,7 +9,8 @@ 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 +noinst_HEADERS = spu.h +include_HEADERS = spu_decoder_api.h ## ## Install header files (default=$includedir/xine) diff --git a/src/libspudec/spu.c b/src/libspudec/spu.c index f28e74884..8c572bf54 100644 --- a/src/libspudec/spu.c +++ b/src/libspudec/spu.c @@ -65,26 +65,8 @@ #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 @@ -93,8 +75,168 @@ struct reassembly_s { #define LOG(lvl, fmt...) #endif +void spuInit (void) +{ +} + +/* Return value: reassembly complete = 1 */ +int spuReassembly (spu_seq_t *seq, int start, uint8_t *pkt_data, u_int pkt_len) +{ + LOG (LOG_DEBUG, "pkt_len: %d", pkt_len); + + if (start) { + seq->seq_len = (((u_int)pkt_data[0])<<8) | pkt_data[1]; + seq->cmd_offs = (((u_int)pkt_data[2])<<8) | pkt_data[3]; + + if (seq->buf_len < seq->seq_len) { + if (seq->buf) + free(seq->buf); + + seq->buf_len = seq->seq_len; + seq->buf = malloc(seq->buf_len); + } + seq->ra_offs = 0; + + LOG (LOG_DEBUG, "buf_len: %d", seq->buf_len); + LOG (LOG_DEBUG, "cmd_off: %d", seq->cmd_offs); + } + + if (seq->ra_offs < seq->buf_len) { + if (seq->ra_offs + pkt_len > seq->seq_len) + pkt_len = seq->seq_len - seq->ra_offs; + + memcpy (seq->buf + seq->ra_offs, pkt_data, pkt_len); + seq->ra_offs += pkt_len; + } + + if (seq->ra_offs == seq->seq_len) { + seq->finished = 0; + return 1; /* sequence ready */ + } + + return 0; +} + +int spuNextEvent(spu_state_t *state, spu_seq_t* seq, int pts) +{ + uint8_t *buf = state->cmd_ptr; + + if (state->next_pts == -1) { /* timestamp valid? */ + state->next_pts = seq->PTS + ((buf[0] << 8) + buf[1]) * 1100; + buf += 2; + state->cmd_ptr = buf; + } + + return state->next_pts <= pts; +} + +#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 + +void spuDoCommands(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; + + if (state->cmd_ptr >= next_seq) + next_seq = seq->buf + seq->seq_len; /* allow to run until end */ + + state->cmd_ptr = next_seq; + + while (buf < next_seq && *buf != CMD_SPU_EOF) { + switch (*buf) { + case CMD_SPU_SHOW: /* show subpicture */ + LOG (LOG_DEBUG, "\tshow subpicture"); + state->visible = 1; + buf++; + break; + + case CMD_SPU_HIDE: /* hide subpicture */ + LOG (LOG_DEBUG, "\thide subpicture"); + state->visible = 0; + buf++; + break; + + case CMD_SPU_SET_PALETTE: { /* CLUT */ + spu_clut_t *clut = (spu_clut_t *) (buf+1); + + 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]", + ovl->color[0], ovl->color[1], ovl->color[2], ovl->color[3]); + state->modified = 1; + buf += 3; + break; + } + case CMD_SPU_SET_ALPHA: { /* transparency palette */ + spu_clut_t *trans = (spu_clut_t *) (buf+1); + + /* TODO: bswap32? */ + ovl->trans[3] = trans->entry0; + ovl->trans[2] = trans->entry1; + ovl->trans[1] = trans->entry2; + ovl->trans[0] = trans->entry3; + LOG (LOG_DEBUG, "\ttrans [%d %d %d %d]\n", + ovl->trans[0], ovl->trans[1], ovl->trans[2], ovl->trans[3]); + state->modified = 1; + buf += 3; + break; + } + + case CMD_SPU_SET_SIZE: /* image coordinates */ + 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); + state->modified = 1; + buf += 7; + break; + + case CMD_SPU_SET_PXD_OFFSET: /* image 1 / image 2 offsets */ + 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", + state->field_offs[0], state->field_offs[1]); + state->modified = 1; + buf += 5; + break; + + case CMD_SPU_MENU: + state->menu = 1; + buf++; + break; + + default: + fprintf(stderr, "libspudec: unknown seqence command (%02x)\n", buf[0]); + buf++; + break; + } + } + if (next_seq >= seq->buf + seq->seq_len) + seq->finished = 1; /* last sub-sequence */ + state->next_pts = -1; /* invalidate timestamp */ +} + +static uint8_t *bit_ptr[2]; +static int field; // which field we are currently decoding +static int put_x, put_y; -static u_int _get_bits (u_int bits, vo_overlay_t *spu) +static u_int get_bits (u_int bits) { static u_int data; static u_int bits_left; @@ -109,7 +251,7 @@ static u_int _get_bits (u_int bits, vo_overlay_t *spu) ret |= data << (bits - bits_left); bits -= bits_left; - data = reassembly.buf[spu->offset[field]++]; + data = *bit_ptr[field]++; bits_left = 8; } else { bits_left -= bits; @@ -122,236 +264,68 @@ static u_int _get_bits (u_int bits, vo_overlay_t *spu) return ret; } - -void spuInit (void) -{ -} - - -static inline void _spu_put_pixel (vo_overlay_t *spu, u_int len, uint8_t colorid) +static inline void spu_put_pixel (vo_overlay_t *spu, 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); + memset (spu->data + put_x + put_y * spu->width, colorid, len); + put_x += len; } - -static int _spu_next_line (vo_overlay_t *spu) +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 + get_bits (0); // byte align rle data - 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) { - reassembly.buf = pkt_data; - reassembly_flag = REASSEMBLY_UNNEEDED; - return &reassembly; - } else { - 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 { - 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; - } - } + put_x = 0; + put_y++; + field ^= 1; // Toggle fields - 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))) + if (put_y >= spu->height) { + LOG (LOG_DEBUG, "."); 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 = /* Frames + */ ((buf[i] << 8) + buf[i+1]) /* * TIME_UNIT */ ; - LOG (LOG_DEBUG, "duration = %d frames", 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[3] = clut->entry0; - spu->clut[2] = clut->entry1; - spu->clut[1] = clut->entry2; - spu->clut[0] = 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 */ - 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; - 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 */ - - if (spu->data) spu->data = (uint8_t *) realloc (spu->data,spu->width * spu->height * sizeof (uint8_t)); - else 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 - */ - 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) +void spuDrawPicture (spu_state_t *state, spu_seq_t* seq, vo_overlay_t *ovl) { field = 0; - _get_bits (0, spu); /* Reset/init bit code */ - - while ((spu->offset[1] < reassembly.cmd_offset)) { + bit_ptr[0] = seq->buf + state->field_offs[0]; + bit_ptr[1] = seq->buf + state->field_offs[1]; + 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; + ovl->height = state->o_bottom - state->o_top; + + ovl->clip_top = 0; + ovl->clip_bottom = ovl->height; + ovl->clip_left = 0; + ovl->clip_right = ovl->width; + + spuUpdateMenu(state, ovl); + + if (ovl->width * ovl->height > ovl->data_size) { + if (ovl->data) + free(ovl->data); + ovl->data_size = ovl->width * ovl->height; + ovl->data = malloc(ovl->data_size); + } + + state->modified = 0; /* mark as already processed */ + + while (bit_ptr[1] < seq->buf + seq->cmd_offs) { u_int len; u_int color; u_int vlc; - vlc = _get_bits (4, spu); + vlc = get_bits (4); if (vlc < 0x0004) { - vlc = (vlc << 4) | _get_bits (4, spu); + vlc = (vlc << 4) | get_bits (4); if (vlc < 0x0010) { - vlc = (vlc << 4) | _get_bits (4, spu); + vlc = (vlc << 4) | get_bits (4); if (vlc < 0x0040) { - vlc = (vlc << 4) | _get_bits (4, spu); + vlc = (vlc << 4) | get_bits (4); } } } @@ -360,26 +334,47 @@ void spuParseData (vo_overlay_t *spu) len = vlc>>2; /* if len == 0 -> end sequence - fill to end of line */ - len = len ? : spu->width - spu->_x; + if (!len) + len = ovl->width - put_x; - _spu_put_pixel (spu, len, color); + spu_put_pixel (ovl, len, color); - if (spu->_x >= spu->width) - if (_spu_next_line (spu) < 0) - goto clean_up; + if (put_x >= ovl->width) + if (spu_next_line (ovl) < 0) + return; } /* 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); - } + do { + spu_put_pixel (ovl, ovl->width, 0); + } while (!spu_next_line (ovl)); +} - clean_up: - if (reassembly_flag != REASSEMBLY_UNNEEDED) { - LOG (LOG_DEBUG, "freeing reassembly.buf"); - free (reassembly.buf); - } +void spuUpdateMenu (spu_state_t *state, vo_overlay_t *ovl) { + + if (!state->menu) + return; + + if (state->b_show) { + + int left = state->b_left; + int right = state->b_right; + int top = state->b_top; + int bottom = state->b_bottom; + + if (left < state->o_left) left = state->o_left; + if (right > state->o_right) right = state->o_right; + if (top < state->o_top) top = state->o_top; + if (bottom > state->o_bottom) bottom = state->o_bottom; + + ovl->clip_top = top - state->o_top; + ovl->clip_bottom = bottom - state->o_top; + ovl->clip_left = left - state->o_left; + ovl->clip_right = right - state->o_left; + + state->visible = 1; - reassembly_flag = REASSEMBLY_START; + } else { + state->visible = 0; + } } diff --git a/src/libspudec/spu.h b/src/libspudec/spu.h index 09cfd32ee..6899c7af8 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.2 2001/07/04 20:32:29 uid32519 Exp $ + * $Id: spu.h,v 1.3 2001/08/13 12:52:33 ehasenle Exp $ * * This file was originally part of the OMS program. * @@ -59,11 +59,40 @@ typedef struct spu_clut_struct { #endif } spu_clut_t; +typedef struct { + uint8_t *buf; + u_int ra_offs; /* reassembly offset */ + u_int seq_len; + u_int buf_len; -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); + u_int cmd_offs; + + u_int PTS; /* Base PTS of this sequence */ + int finished; /* Has this sequence been finished? */ +} spu_seq_t; + +typedef struct { + uint8_t *cmd_ptr; + + int field_offs[2]; + int b_top, o_top; + int b_bottom, o_bottom; + int b_left, o_left; + int b_right, o_right; + + u_int next_pts; /* pts of next sub-sequence */ + int modified; /* Was the sub-picture modified? */ + int visible; /* Must the sub-picture be shown? */ + int menu; /* This overlay is a menu */ + int b_show; /* is a button shown? */ + + 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 spuUpdateMenu (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 e30a4cd11..a7d75511a 100644 --- a/src/libspudec/spu_decoder_api.h +++ b/src/libspudec/spu_decoder_api.h @@ -44,6 +44,8 @@ struct spu_decoder_s { void (*decode_data) (spu_decoder_t *this, buf_element_t *buf); + void (*event) (spu_decoder_t *this, spu_event_t *event); + void (*close) (spu_decoder_t *this); char* (*get_identifier) (void); @@ -70,4 +72,20 @@ struct spudec_s { }; +#define SPU_EVENT_BUTTON 0x100 +typedef struct spu_button_s spu_button_t; +struct spu_button_s { + int show; + uint8_t color[4]; + uint8_t trans[4]; + int left, right; + int top, bottom; +}; + +#define SPU_EVENT_CLUT 0x101 +typedef struct spu_cltbl_s spu_cltbl_t; +struct spu_cltbl_s { + uint32_t clut[16]; +}; + #endif /* HAVE_SPUDEC_H */ diff --git a/src/libspudec/xine_decoder.c b/src/libspudec/xine_decoder.c index 406c0cc9d..0d3a0836d 100644 --- a/src/libspudec/xine_decoder.c +++ b/src/libspudec/xine_decoder.c @@ -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: xine_decoder.c,v 1.7 2001/08/05 08:24:56 ehasenle Exp $ + * $Id: xine_decoder.c,v 1.8 2001/08/13 12:52:33 ehasenle Exp $ * * stuff needed to turn libspu into a xine decoder plugin */ @@ -38,31 +38,48 @@ #include "spu.h" #include "buffer.h" +#include "events.h" #include "xine_internal.h" -#define FRAME_SIZE 4096 - +static clut_t __default_clut[] = { + {y: 0x00, cr: 0x80, cb:0x80}, + {y: 0xbf, cr: 0x80, cb:0x80}, + {y: 0x10, cr: 0x80, cb:0x80}, + {y: 0x28, cr: 0x6d, cb:0xef}, + {y: 0x51, cr: 0xef, cb:0x5a}, + {y: 0xbf, cr: 0x80, cb:0x80}, + {y: 0x36, cr: 0x80, cb:0x80}, + {y: 0x28, cr: 0x6d, cb:0xef}, + {y: 0xbf, cr: 0x80, cb:0x80}, + {y: 0x51, cr: 0x80, cb:0x80}, + {y: 0xbf, cr: 0x80, cb:0x80}, + {y: 0x10, cr: 0x80, cb:0x80}, + {y: 0x28, cr: 0x6d, cb:0xef}, + {y: 0x5c, cr: 0x80, cb:0x80}, + {y: 0xbf, cr: 0x80, cb:0x80}, + {y: 0x1c, cr: 0x80, cb:0x80}, + {y: 0x28, cr: 0x6d, cb:0xef} +}; + +#define NUM_SEQ_BUFFERS 5 typedef struct spudec_decoder_s { spu_decoder_t spu_decoder; + ovl_src_t ovl_src; - uint32_t pts; + spu_seq_t seq_list[NUM_SEQ_BUFFERS]; + spu_seq_t *cur_seq; + spu_seq_t *ra_seq; + int ra_complete; - uint8_t frame_buffer[FRAME_SIZE]; - uint8_t *frame_ptr; - int sync_todo; - int frame_length, frame_todo; - uint16_t syncword; + uint32_t ovl_pts; + uint32_t buf_pts; + spu_state_t state; vo_instance_t *vo_out; - vo_overlay_t *spu; - uint32_t *clut; - int spu_caps; - int bypass_mode; - int max_num_channels; - int output_sampling_rate; + vo_overlay_t ovl; + int ovl_caps; int output_open; - int output_mode; } spudec_decoder_t; @@ -71,107 +88,155 @@ int spudec_can_handle (spu_decoder_t *this_gen, int buf_type) { return (type == BUF_SPU_PACKAGE || type == BUF_SPU_CLUT) ; } +static void spudec_reset (spudec_decoder_t *this) { + int i; + + this->ovl_pts = 0; + this->buf_pts = 0; + + this->state.visible = 0; + + for (i = 0; i < NUM_SEQ_BUFFERS; i++) { + this->seq_list[i].finished = 1; + } + this->ra_complete = 1; + this->cur_seq = this->ra_seq = this->seq_list; +} + void spudec_init (spu_decoder_t *this_gen, vo_instance_t *vo_out) { spudec_decoder_t *this = (spudec_decoder_t *) this_gen; + this->vo_out = vo_out; - this->spu_caps = vo_out->get_capabilities(vo_out); - this->syncword = 0; - this->sync_todo = 6; + this->ovl_caps = vo_out->get_capabilities(vo_out); this->output_open = 0; -} - -/* overlay_txt is just for test purposes */ -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; + spudec_reset(this); + memcpy(this->state.clut, __default_clut, sizeof(this->state.clut)); + vo_out->register_ovl_src(vo_out, &this->ovl_src); } 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; - if (buf->type == BUF_SPU_CLUT) { - if (this->clut == NULL) - this->clut = malloc(sizeof(clut_t)*16); - - memcpy(this->clut, buf->content, sizeof(clut_t)*16); + memcpy(this->state.clut, buf->content, sizeof(int32_t)*16); return; } - - 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 (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) + spudec_reset(this); - this->spu->PTS = buf->PTS; - if (this->clut) - this->spu->clut_tbl = this->clut; - - if (!spuParseHdr (this->spu, current, buf->size)) { - spuParseData (this->spu); - /* overlay_txt(this->spu,1.0); Just for test purposes */ - this->vo_out->queue_overlay (this->vo_out, this->spu); - this->spu = NULL; - } else { - this->spu->data=NULL; - this->vo_out->queue_overlay (this->vo_out, this->spu); - this->spu = NULL; + this->buf_pts = pts; + } + + 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) { + this->ra_seq = tmp_seq; + this->ra_seq->PTS = this->buf_pts; + } } + this->ra_complete = + spuReassembly(this->ra_seq, this->ra_complete, buf->content, buf->size); } void spudec_close (spu_decoder_t *this_gen) { spudec_decoder_t *this = (spudec_decoder_t *) this_gen; + + this->vo_out->unregister_ovl_src(this->vo_out, &this->ovl_src); +} - if (this->clut) { - free(this->clut); - this->clut = 0; +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) + tmp_seq = this->seq_list; + + if (!tmp_seq->finished) { /* is the next seq ready for process? */ + this->cur_seq = tmp_seq; + this->state.cmd_ptr = this->cur_seq->buf + this->cur_seq->cmd_offs; + this->state.next_pts = -1; /* invalidate timestamp */ + this->state.modified = 1; + this->state.visible = 0; + this->state.menu = 0; } +} + +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; -/* FIXME not implemented */ -// if (this->output_open) -// this->spu_out->close (this->spu_out); + if (this->ovl_pts > pts) + spudec_reset(this); - /* close (spufile); */ + 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); + + if (pending) + spuDoCommands(&this->state, this->cur_seq, &this->ovl); + } else + pending = 0; + + } while (pending); + + if (this->state.visible) { + if (this->state.modified) { + spuDrawPicture(&this->state, this->cur_seq, &this->ovl); + } + + return &this->ovl; + } + + return NULL; +} + +static void spudec_event(spu_decoder_t *this_gen, spu_event_t *event) { + spudec_decoder_t *this = (spudec_decoder_t*) this_gen; + + switch (event->sub_type) { + case SPU_EVENT_BUTTON: + { + spu_button_t *but = event->data; + 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; + } + + this->state.b_show = but->show; + spuUpdateMenu(&this->state, &this->ovl); + } + break; + case SPU_EVENT_CLUT: + { + spu_cltbl_t *clut = event->data; + memcpy(this->state.clut, clut->clut, sizeof(int32_t)*16); + } + break; + } } static char *spudec_get_id(void) { @@ -182,18 +247,28 @@ spu_decoder_t *init_spu_decoder_plugin (int iface_version, config_values_t *cfg) spudec_decoder_t *this ; - if (iface_version != 2) + if (iface_version != 3) { + fprintf(stderr, + "libspudec: Doesn't support plugin API version %d.\n" + "libspudec: This means there is a version mismatch between XINE and\n" + "libspudec: this plugin.\n", iface_version); return NULL; + } this = (spudec_decoder_t *) malloc (sizeof (spudec_decoder_t)); + memset (this, 0, sizeof(*this)); - this->spu_decoder.interface_version = 2; + this->spu_decoder.interface_version = 3; 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.event = spudec_event; this->spu_decoder.close = spudec_close; this->spu_decoder.get_identifier = spudec_get_id; this->spu_decoder.priority = 1; + + this->ovl_src.src_gen = this; + this->ovl_src.get_overlay = spudec_get_overlay; return (spu_decoder_t *) this; } |