summaryrefslogtreecommitdiff
path: root/src/libspudec/spu.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libspudec/spu.c')
-rw-r--r--src/libspudec/spu.c485
1 files changed, 240 insertions, 245 deletions
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;
+ }
}