summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich J Wareham <richwareham@users.sourceforge.net>2001-06-18 15:43:00 +0000
committerRich J Wareham <richwareham@users.sourceforge.net>2001-06-18 15:43:00 +0000
commita2c0482e17a5d1d0ea99d06b81e94c0e7b5cb4e2 (patch)
treec064d151203dd381e7606b570e8910cce018d449
parent7e7483472eb410396ff7890577ac49bce9afab7a (diff)
downloadxine-lib-a2c0482e17a5d1d0ea99d06b81e94c0e7b5cb4e2.tar.gz
xine-lib-a2c0482e17a5d1d0ea99d06b81e94c0e7b5cb4e2.tar.bz2
Added very primitive overlay capacity (white line now appears if subtitles are enabled.)
CVS patchset: 210 CVS date: 2001/06/18 15:43:00
-rw-r--r--src/libspudec/Makefile.am2
-rw-r--r--src/libspudec/spudec.c644
-rw-r--r--src/libspudec/spudec.h44
-rw-r--r--src/libspudec/spudec_old.c612
-rw-r--r--src/video_out/video_out_xv.c4
-rw-r--r--src/xine-engine/Makefile.am2
-rw-r--r--src/xine-engine/spu_decoder.c30
-rw-r--r--src/xine-engine/video_out.c11
-rw-r--r--src/xine-engine/video_out.h7
-rw-r--r--src/xine-engine/xine.c26
-rw-r--r--src/xine-engine/xine_internal.h3
11 files changed, 745 insertions, 640 deletions
diff --git a/src/libspudec/Makefile.am b/src/libspudec/Makefile.am
index 0951814c2..c96adda1d 100644
--- a/src/libspudec/Makefile.am
+++ b/src/libspudec/Makefile.am
@@ -4,7 +4,7 @@ EXTRA_DIST =
noinst_LTLIBRARIES = libspudec.la
-libspudec_la_SOURCES = #spudec.c
+libspudec_la_SOURCES = spudec.c spudec.h
noinst_HEADERS = spudec.h
diff --git a/src/libspudec/spudec.c b/src/libspudec/spudec.c
index 45d9f9dff..5ee33f988 100644
--- a/src/libspudec/spudec.c
+++ b/src/libspudec/spudec.c
@@ -34,43 +34,16 @@
#include <fcntl.h>
#include <unistd.h>
-typedef struct _spudec_globals {
- vo_image_buffer_t *overlay;
- vo_image_buffer_t *mask;
- int width, height;
- int format;
+struct spudec_priv_s {
+ uint32_t *clut;
+ xine_t *xine;
- int bInitialised;
-
- int state;
-
- spudec_geometry geom;
-
- /* The current packet we are assembling, not decoding */
- unsigned char *packet;
- int packet_size;
- uint32_t pts; /* PTS of packet */
-
- uint32_t lifetime; /* Lifetime of currently displayed SPU in pts */
- uint32_t displayPTS; /* The PTS when the last SPU was displayed. */
-
- uint32_t lastPTS;
-
- clut_t *clut;
-} spudec_globals;
-
-static spudec_globals gSpudec;
-
-clut_t *palette[4] = {
- NULL, NULL, NULL, NULL
-};
-
-uint8_t alpha[4] = {
- 0xff, 0x00, 0x00, 0x00
+ uint8_t *overlay;
+ uint8_t *mask;
};
#ifdef BIG_ENDIAN
-static uint32_t default_palette[32] = {
+static uint32_t _default_clut[32] = {
0x80801000, 0x80801000, 0x80808400, 0x8080eb00,
0x80801000, 0x80801000, 0x80808400, 0x8080eb00,
0x80801000, 0x80801000, 0x80808400, 0x8080eb00,
@@ -79,7 +52,7 @@ static uint32_t default_palette[32] = {
#else
-static uint32_t default_palette[32] = {
+static uint32_t _default_clut[32] = {
0x00108080, 0x00108080, 0x00848080, 0x00eb8080,
0x00108080, 0x00108080, 0x00848080, 0x00eb8080,
0x00108080, 0x00108080, 0x00848080, 0x00eb8080,
@@ -87,602 +60,69 @@ static uint32_t default_palette[32] = {
};
#endif
-static clut_t* default_clut = (clut_t*) default_palette;
-
-/* Maximum packets we can keep in the queue. Should be fine */
-#define MAX_PACKETS 200
-
-typedef struct {
- unsigned char *packet; /* The actual packet of data */
- uint32_t pts; /* The PTS of the packet */
- uint16_t size; /* The packet size */
-} spudec_packet;
-
-/* Implement the SPU packet queue as a ring queuefer */
-spudec_packet* spudec_packet_queue[MAX_PACKETS];
-int16_t spudec_queue_size = 0; /* Queue length (items) */
-int16_t spudec_queue_pos = 0; /* Start of queue position */
-
-/* Forward declarations */
-void spudec_process_packet(unsigned char *packet, int size);
-
-/* Pushes a packet on the end of the queue */
-void spudec_queue_packet(spudec_packet *packet) {
- if(spudec_queue_size + 1 > MAX_PACKETS) {
- /* Too many packets */
- printf("spudec: Too many packets.\n");
- return;
- }
-
- spudec_packet_queue[(spudec_queue_pos + spudec_queue_size) % MAX_PACKETS] = packet;
- spudec_queue_size++;
-}
-
-/* Gets the next packet but does /not/ remove it */
-spudec_packet* spudec_peek_next_packet() {
- if(spudec_queue_size <= 0) {
- /* No packet in queue */
- printf("spudec: No more packets.\n");
- return NULL;
- }
-
- return spudec_packet_queue[spudec_queue_pos];
-}
-
-/* Like peek_next but removes the packet from the queue */
-spudec_packet* spudec_get_next_packet() {
- spudec_packet *packet;
-
- if((packet = spudec_peek_next_packet()) != NULL) {
- spudec_queue_pos = (spudec_queue_pos + 1) % MAX_PACKETS;
- spudec_queue_size --;
- }
-
- return packet;
-}
-
-void spudec_init(clut_t *clut) {
- gSpudec.bInitialised = 1;
-
- spudec_reset();
-
+void spudec_change_clut (spudec_t *this, uint32_t *clut)
+{
if(clut == NULL) {
- gSpudec.clut = default_clut;
+ this->private->clut = _default_clut;
} else {
- gSpudec.clut = clut;
+ this->private->clut = clut;
}
-
- palette[0] = palette[1] = palette[2] = palette[3] = &(gSpudec.clut[0]);
}
-void spudec_tick()
+void spudec_start (spudec_t *this, clut_t *clut)
{
- uint32_t pts;
- if(!gSpudec.bInitialised)
- return;
-
- pts = metronom_got_spu_packet(0);
+ /* initialise overlay and mask buffers. */
+ this->private->mask = this->private->overlay = NULL;
- /* See if we have any SPUs queued */
- if(spudec_queue_size != 0) {
- spudec_packet *p;
-
- p = spudec_peek_next_packet();
- if(pts >= p->pts) {
- /* Process */
- p = spudec_get_next_packet();
-
- spudec_process_packet(p->packet, p->size);
- /* Assume it was displayed correctly */
- gSpudec.displayPTS = p->pts;
-
- free(p->packet);
- free(p);
- }
- }
-
- if((gSpudec.geom.bIsVisible) && (pts - gSpudec.lifetime >= gSpudec.displayPTS)) {
- gSpudec.geom.bIsVisible = 0;
- gSpudec.lifetime = 0;
- gSpudec.lastPTS = pts;
- return;
- }
-
- if(pts < gSpudec.lastPTS) {
- /* Something screwey. */
- gSpudec.lastPTS = pts;
- return;
- }
-
- gSpudec.lastPTS = pts;
+ spudec_change_clut(this, clut);
}
-spudec_geometry* spudec_get_geometry()
+void spudec_overlay_yuv (spudec_t *this, uint32_t vpts,
+ uint8_t *y, uint8_t *u, uint8_t *v)
{
- return &(gSpudec.geom);
+ if(this->private->xine->spu_channel != -1)
+ memset(y+102400, 255, 2048);
}
-int spudec_set_images(vo_image_buffer_t* overlay,
- vo_image_buffer_t* mask,
- int width, int height,
- int format)
+void spudec_overlay_rgb (spudec_t *this, uint32_t vpts,
+ uint8_t *rgb_data, int mode)
{
- if(format != IMGFMT_YV12) {
- printf("Error, SPUDEC only supports YV12 overlays.\n");
- gSpudec.bInitialised = 0;
-
- return 0;
- }
-
- gSpudec.overlay = overlay;
- gSpudec.mask = mask;
- gSpudec.width = width;
- gSpudec.height = height;
- gSpudec.format = format;
- gSpudec.geom.bIsVisible = 0;
-
- /* Clear images initially */
- if(gSpudec.format == IMGFMT_YV12) {
- /* Set initial image to empty & clear mask */
- memset(mask->mem[0], 0xff, (gSpudec.width*gSpudec.height));
- memset(overlay->mem[0], 0x00, (gSpudec.width*gSpudec.height));
- memset(mask->mem[1], 0xff, (gSpudec.width*gSpudec.height) >> 2);
- memset(overlay->mem[1], 0x00, (gSpudec.width >> 1)*(gSpudec.height >> 1));
- memset(mask->mem[2], 0xff, (gSpudec.width >> 1)*(gSpudec.height >> 1));
- memset(overlay->mem[2], 0x00, (gSpudec.width >> 1)*(gSpudec.height >> 1));
- }
-
- gSpudec.geom.start_col = 0;
- gSpudec.geom.end_col = gSpudec.width-1;
- gSpudec.geom.start_row = 0;
- gSpudec.geom.end_row = gSpudec.height-1;
-
- return gSpudec.bInitialised = 1;
}
-#define nibble(data, index) ((index & 1) ? data[index >> 1] & 0xf : (data[index >> 1] >> 4) & 0xf)
-
-void spudec_process_data(unsigned char *data, int size, int d1, int d2)
+void spudec_push_packet (spudec_t *this, buf_element_t *buf)
{
- /* This does the 'hard' work of processing the image data */
-
- long off,line_base, line_base2,y,na,nb;
- int n; /* The code word */
-
- na = d1<<1;
- nb = d2<<1;
-
- /* Align on even row */
- if (gSpudec.geom.start_row & 1) {
- gSpudec.geom.start_row--;
- gSpudec.geom.end_row--;
- }
- if (gSpudec.geom.start_col & 1) {
- gSpudec.geom.start_col--;
- gSpudec.geom.end_col--;
- }
- y = gSpudec.geom.start_row;
-
- while(y <= gSpudec.geom.end_row) {
- line_base = gSpudec.width * y + gSpudec.geom.start_col;
- line_base2 = (gSpudec.width>>1) * (y>>1) + (gSpudec.geom.start_col >> 1);
-
- off = 0;
- do {
- int num;
- clut_t *col;
-
- n = nibble(data, na);
- na++;
- if(n < 0x4) {
- n = (n<<4) | nibble(data, na);
- na++;
- if(n < 0x10) {
- n = (n<<4) | nibble(data, na);
- na++;
- if(n < 0x40) {
- n = (n<<4) | nibble(data, na);
- na++;
- if(n < 0x100)
- n = 0; /* Carriage return */
- }
- }
- }
- // printf("Code: 0x%04x\n",n);
-
- num = n >> 2; col = palette[n & 0x3];
- if(col == NULL) {
- printf("Error in palette\n");
- }
-
- if(num != 0) {
- if(alpha[n & 0x3] & 0x80) {
- memset(&(gSpudec.mask->mem[0][line_base + off]), 0x00, num);
- memset(&(gSpudec.overlay->mem[0][line_base + off]), col->y, num);
- memset(&(gSpudec.mask->mem[1][line_base2 + (off>>1)]), 0x00, num>>1);
- memset(&(gSpudec.overlay->mem[1][line_base2 + (off>>1)]), col->cr, num>>1);
- memset(&(gSpudec.mask->mem[2][line_base2 + (off>>1)]), 0x00, num>>1);
- memset(&(gSpudec.overlay->mem[2][line_base2 + (off>>1)]), col->cb, num>>1);
- } else {
- memset(&(gSpudec.mask->mem[0][line_base + off]), 0xff, num);
- memset(&(gSpudec.overlay->mem[0][line_base + off]), 0x00, num);
- memset(&(gSpudec.mask->mem[1][line_base2 + (off>>1)]), 0xff, num>>1);
- memset(&(gSpudec.overlay->mem[1][line_base2 + (off>>1)]), 0x00, num>>1);
- memset(&(gSpudec.mask->mem[2][line_base2 + (off>>1)]), 0xff, num>>1);
- memset(&(gSpudec.overlay->mem[2][line_base2 + (off>>1)]), 0x00, num>>1);
- }
- }
- off+=num;
- } while((n != 0) && (off <= gSpudec.geom.end_col - gSpudec.geom.start_col));
-
- if((n == 0) && (off <= gSpudec.geom.end_col - gSpudec.geom.start_col)) {
- /* Clear to end of line if carriage return */
- int len = gSpudec.geom.start_col + gSpudec.geom.end_col - off;
- memset(&(gSpudec.mask->mem[0][line_base + off]), 0xff, len);
- memset(&(gSpudec.overlay->mem[0][line_base + off]), 0x00, len);
- memset(&(gSpudec.mask->mem[0][line_base + off]) + gSpudec.width, 0xff, len);
- memset(&(gSpudec.overlay->mem[0][line_base + off]) + gSpudec.width, 0x00, len);
- memset(&(gSpudec.mask->mem[1][line_base2 + (off>>1)]), 0xff, len>>1);
- memset(&(gSpudec.overlay->mem[1][line_base2 + (off>>1)]), 0x00, len>>1);
- memset(&(gSpudec.mask->mem[2][line_base2 + (off>>1)]), 0xff, len>>1);
- memset(&(gSpudec.overlay->mem[2][line_base2 + (off>>1)]), 0x00, len>>1);
- }
-
- if((na & 1))
- na ++; /* Re-align */
-
- line_base += gSpudec.width;
- y++;
- if (y > gSpudec.geom.end_row)
- break;
-
- off = 0;
- do {
- int num;
- clut_t *col;
-
- n = nibble(data, nb);
- nb++;
- if(n < 0x4) {
- n = (n<<4) | nibble(data, nb);
- nb++;
- if(n < 0x10) {
- n = (n<<4) | nibble(data, nb);
- nb++;
- if(n < 0x40) {
- n = (n<<4) | nibble(data, nb);
- nb++;
- if(n < 0x100)
- n = 0; /* Carriage return */
- }
- }
- }
- // printf("Code: 0x%04x\n",n);
-
- num = n >> 2; col = palette[n & 0x3];
- if(col == NULL) {
- printf("Error in palette\n");
- }
-
- if(num != 0) {
- if(alpha[n & 0x3] & 0x80) {
- memset(&(gSpudec.mask->mem[0][line_base + off]), 0x00, num);
- memset(&(gSpudec.overlay->mem[0][line_base + off]), col->y, num);
- } else {
- memset(&(gSpudec.mask->mem[0][line_base + off]), 0xff, num);
- memset(&(gSpudec.overlay->mem[0][line_base + off]), 0x00, num);
- }
- }
- off+=num;
- } while((n != 0) && (off <= gSpudec.geom.end_col - gSpudec.geom.start_col));
-
- if((n == 0) && (off <= gSpudec.geom.end_col - gSpudec.geom.start_col)) {
- /* Clear to end of line if carriage return */
- int len = gSpudec.geom.start_col + gSpudec.geom.end_col - off;
- memset(&(gSpudec.mask->mem[0][line_base + off]), 0xff, len);
- memset(&(gSpudec.overlay->mem[0][line_base + off]), 0x00, len);
- }
-
- if((nb & 1))
- nb ++; /* Re-align */
-
- y++;
- }
}
-void spudec_process_control(unsigned char *control, int size, int* d1, int* d2)
+spudec_t *spudec_init (xine_t *xine)
{
- int off = 2;
- int a,b; /* Temporary vars */
+ spudec_t *decoder;
- do {
- int type = control[off];
- off++;
+ printf("spudec: Creating decoder.\n");
- switch(type) {
- case 0x00:
- /* Menu ID, 1 byte */
- break;
- case 0x01:
- /* Start display */
- gSpudec.geom.bIsVisible = 1;
- break;
- case 0x03:
- /* Palette */
- palette[3] = &(gSpudec.clut[(control[off] >> 4)]);
- palette[2] = &(gSpudec.clut[control[off] & 0xf]);
- palette[1] = &(gSpudec.clut[(control[off+1] >> 4)]);
- palette[0] = &(gSpudec.clut[control[off+1] & 0xf]);
- off+=2;
- break;
- case 0x04:
- /* Alpha */
- alpha[3] = control[off] & 0xf0;
- alpha[2] = (control[off] & 0xf) << 4;
- alpha[1] = control[off+1] & 0xf0;
- alpha[0] = (control[off+1] & 0xf) << 4;
- off+=2;
- break;
- case 0x05:
- /* Co-ords */
- a = (control[off] << 16) + (control[off+1] << 8) + control[off+2];
- b = (control[off+3] << 16) + (control[off+4] << 8) + control[off+5];
+ decoder = xmalloc(sizeof(struct spudec_s));
+ decoder->private = xmalloc(sizeof(struct spudec_priv_s));
+ decoder->private->clut = _default_clut;
+ decoder->private->xine = xine;
- gSpudec.geom.start_col = a >> 12;
- gSpudec.geom.end_col = a & 0xfff;
- gSpudec.geom.start_row = b >> 12;
- gSpudec.geom.end_row = b & 0xfff;
+ decoder->start = spudec_start;
+ decoder->change_clut = spudec_change_clut;
+ decoder->push_packet = spudec_push_packet;
+ decoder->overlay_yuv = spudec_overlay_yuv;
+ decoder->overlay_rgb = spudec_overlay_rgb;
- off+=6;
- break;
- case 0x06:
- /* Graphic lines */
- *(d1) = (control[off] << 8) + control[off+1];
- *(d2) = (control[off+2] << 8) + control[off+3];
- off+=4;
- break;
- case 0xff:
- /* All done, bye-bye */
- return;
- break;
- default:
- printf("spudec: Error determining control type 0x%02x.\n",type);
- return;
- break;
- }
-
- /* printf("spudec: Processsed control type 0x%02x.\n",type); */
- } while(off < size);
+ return decoder;
}
-void spudec_process_packet(unsigned char *packet, int size)
+void spudec_close (spudec_t *decoder)
{
- int x0, x1;
- int d1, d2;
-
- /* Check packet */
- if((packet[0] << 8) + packet[1] != size) {
- printf("Packet size mismatch:\n");
- printf("Packet reports size 0x%04x\n", (packet[0] << 8) + packet[1]);
- printf("I reckon 0x%04x\n", size);
- return;
- }
-
- x0 = (packet[2] << 8) + packet[3];
- x1 = (packet[x0+2] << 8) + packet[x0+3];
-
- /* /Another/ sanity check. */
- if((packet[x1+2]<<8) + packet[x1+3] != x1) {
- printf("spudec: Incorrect packet.\n");
- return;
- }
-
- /* End sequence, FIXME: why do we need the division by 2? */
- gSpudec.lifetime = (metronom_get_video_rate() >> 1)* ((packet[x1]<<8) + packet[x1+1]);
-
- d1 = d2 = -1;
- spudec_process_control(packet + x0 + 2, x1-x0-2, &d1, &d2);
-
- if((d1 != -1) && (d2 != -1)) {
- spudec_process_data(packet, x0, d1, d2);
- }
-}
-
-void spudec_decode(unsigned char *data, int size, uint32_t pts) {
- if(!gSpudec.bInitialised)
+ if(!decoder) {
+ /* If some naughty person passed a NULL pointer, don't
+ * do silly things. */
return;
-
- if(gSpudec.packet == NULL) {
- if(pts != 0) {
- /* Allocate a packet buffer */
- gSpudec.packet = xmalloc((data[0] << 8) + data[1]);
- gSpudec.pts = pts;
-
- if(gSpudec.packet == NULL) {
- printf("Error allocating packet buffer.\n");
- return;
- }
-
- gSpudec.packet_size = 0;
- } else {
- printf("spudec: Error, we are half way through a packet I don't know\n");
- }
- }
-
- /* Prevent buffer overruns */
- if(gSpudec.packet_size >= 2) { /* If the /packet/ knows how big it is */
- if((gSpudec.packet_size + size) >
- (gSpudec.packet[0]<<8) + gSpudec.packet[1]) {
- printf("spudec: Mismatched buffer size (0x%04x to big), truncating.\n",
- (gSpudec.packet_size + size) -
- ((gSpudec.packet[0]<<8) + gSpudec.packet[1]));
- size = (gSpudec.packet[0]<<8) + gSpudec.packet[1] - gSpudec.packet_size;
- }
- }
-
-
- memcpy(gSpudec.packet + gSpudec.packet_size, data, size);
- gSpudec.packet_size += size;
-
- if(gSpudec.packet_size >= (gSpudec.packet[0]<<8) + gSpudec.packet[1]) {
- /* If packet complete then queue */
- spudec_packet *p;
-
- p = xmalloc(sizeof(spudec_packet));
- p->packet = gSpudec.packet;
- p->size = gSpudec.packet_size;
- p->pts = gSpudec.pts;
-
- spudec_queue_packet(p);
-
- gSpudec.packet = NULL;
- gSpudec.packet_size = -1;
- gSpudec.pts = 0;
}
-}
-
-void spudec_reset() {
- /* Clear any packet being assembled */
- if(gSpudec.packet != NULL) {
- gSpudec.packet_size = 0;
- free(gSpudec.packet);
- gSpudec.packet = NULL;
- gSpudec.pts = 0;
- }
-
- /* Remove any current subtitle */
- gSpudec.geom.bIsVisible = 0;
- gSpudec.lifetime = 0;
- /* Clear packet queue */
- while(spudec_queue_size > 0) {
- spudec_packet *p = spudec_get_next_packet();
+ printf("spudec: Closing decoder.\n");
- free(p->packet);
- free(p);
- }
-}
-
-void spudec_overlay_yuv (uint8_t *y, uint8_t *u, uint8_t *v) {
-
- /*
- * Mix in SPU
- */
-
- /* Tick SPUdec */
- spudec_tick();
-
- if(gVO.bOverlayImage) {
- /* This code is pretty nasty but quite quick which is important here! */
- /* APPROACH: Since 32bit processors hande data, well 32bits at a time,
- * we overlay the image word by word rather than byte by byte and then
- * tidy up the odd bytes at the end. This effectively cuts the number of
- * loop itterations by a factor of 4. */
-
- /* FIXME: Optimise for 64bit machines as well? */
-
- if((gVO.spu_geom->bIsVisible) &&
- (gVO.format == IMGFMT_YV12)) {
- /* Overlay the image. */
- long i, off;
- uint8_t *img_l_8, *ovl_l_8, *msk_l_8;
- uint32_t *img_l_32, *ovl_l_32, *msk_l_32;
- uint8_t *img_y_8, *ovl_y_8, *msk_y_8;
- uint32_t *img_y_32, *ovl_y_32, *msk_y_32;
- uint8_t *img_v_8, *ovl_v_8, *msk_v_8;
- uint32_t *img_v_32, *ovl_v_32, *msk_v_32;
-
- img_l_8 = img->mem[0];
- ovl_l_8 = gVO.overlay_image->mem[0];
- msk_l_8 = gVO.mask_image->mem[0];
- img_l_32 = ((uint32_t*)img->mem[0]);
- ovl_l_32 = ((uint32_t*)gVO.overlay_image->mem[0]);
- msk_l_32 = ((uint32_t*)gVO.mask_image->mem[0]);
- img_y_8 = img->mem[1];
- ovl_y_8 = gVO.overlay_image->mem[1];
- msk_y_8 = gVO.mask_image->mem[1];
- img_y_32 = ((uint32_t*)img->mem[1]);
- ovl_y_32 = ((uint32_t*)gVO.overlay_image->mem[1]);
- msk_y_32 = ((uint32_t*)gVO.mask_image->mem[1]);
- img_v_8 = img->mem[2];
- ovl_v_8 = gVO.overlay_image->mem[2];
- msk_v_8 = gVO.mask_image->mem[2];
- img_v_32 = ((uint32_t*)img->mem[2]);
- ovl_v_32 = ((uint32_t*)gVO.overlay_image->mem[2]);
- msk_v_32 = ((uint32_t*)gVO.mask_image->mem[2]);
-
- /* luminance */
- for(i=gVO.width*gVO.spu_geom->start_row;
- i<=gVO.width*gVO.spu_geom->end_row; i+=gVO.width) {
- /* i is address of begining of line. */
-
- /* Firstly, draw the start odd bytes. */
- for(off = i+gVO.spu_geom->start_col; (off & 3) != 0; off++) {
- if(msk_l_8[off] != 0xff) {
- img_l_8[off] &= msk_l_8[off];
- img_l_8[off] |= ovl_l_8[off];
- }
- }
-
- /* Now words */
- for(; off<=i+gVO.spu_geom->end_col-3; off+=4) {
- if(msk_l_32[off>>2] != 0xffffffff) {
- img_l_32[off>>2] &= msk_l_32[off>>2];
- img_l_32[off>>2] |= ovl_l_32[off>>2];
- }
- }
- off -= 4;
-
- /* Now end odd bytes */
- for(; off<=i+gVO.spu_geom->end_col; off++) {
- if(msk_l_8[off] != 0xff) {
- img_l_8[off] &= msk_l_8[off];
- img_l_8[off] |= ovl_l_8[off];
- }
- }
- }
- /* colour */
- for(i=(gVO.width>>1)*(gVO.spu_geom->start_row>>1);
- i<=(gVO.width>>1)*(gVO.spu_geom->end_row>>1); i+=(gVO.width)>>1) {
- /* i is address of begining of line. */
-
- /* Firstly, draw the start odd bytes. */
- for(off = i+((gVO.spu_geom->start_col)>>1); (off & 3) != 0; off++) {
- if(msk_y_8[off] != 0xff) {
- img_y_8[off] &= msk_y_8[off];
- img_y_8[off] |= ovl_y_8[off];
- }
- if(msk_v_8[off] != 0xff) {
- img_v_8[off] &= msk_v_8[off];
- img_v_8[off] |= ovl_v_8[off];
- }
- }
-
- /* Now words */
- for(; off<=i+((gVO.spu_geom->end_col)>>1)-3; off+=4) {
- if(msk_y_32[off>>2] != 0xffffffff) {
- img_y_32[off>>2] &= msk_y_32[off>>2];
- img_y_32[off>>2] |= ovl_y_32[off>>2];
- }
- if(msk_v_32[off>>2] != 0xffffffff) {
- img_v_32[off>>2] &= msk_v_32[off>>2];
- img_v_32[off>>2] |= ovl_v_32[off>>2];
- }
- }
- off -= 4;
-
- /* Final end odd bytes */
- for(; off<=i+((gVO.spu_geom->end_col)>>1); off++) {
- if(msk_y_8[off] != 0xff) {
- img_y_8[off] &= msk_y_8[off];
- img_y_8[off] |= ovl_y_8[off];
- }
- if(msk_v_8[off] != 0xff) {
- img_v_8[off] &= msk_v_8[off];
- img_v_8[off] |= ovl_v_8[off];
- }
- }
- }
- }
- }
+ free(decoder->private);
+ free(decoder);
}
diff --git a/src/libspudec/spudec.h b/src/libspudec/spudec.h
index e4ce15741..a79516a01 100644
--- a/src/libspudec/spudec.h
+++ b/src/libspudec/spudec.h
@@ -26,8 +26,10 @@
#include "metronom.h"
#include "input/input_plugin.h"
+#include "xine_internal.h"
-typedef struct spudec_s spudec_t;
+/* typedef struct spudec_s spudec_t; */
+typedef struct spudec_priv_s spudec_priv_t;
struct spudec_s {
@@ -35,19 +37,40 @@ struct spudec_s {
* reset spudec for a new stream
*
* clut : pointer to array of 16 cluts for palette info
+ * or NULL to use default (not recommended!).
*/
- void (*spudec_start) (spudec_t *this, clut_t *clut);
+ void (*start) (spudec_t *this, clut_t *clut);
+
+ /*
+ * change the colour lookup table (clut) used by the decoder.
+ *
+ * clut : pointer to array of 16 cluts for palette info
+ * or NULL to use default (not recommended!).
+ */
+
+ void (*change_clut) (spudec_t *this, clut_t *clut);
+
+ /*
+ * pass a packet demux-ed from the MPEG2 stream to the decoder.
+ * (the buffer is copied so may be 'free'-ed).
+ *
+ * buf : a buf_element_t containing the packet.
+ */
+ void (*push_packet) (spudec_t *this, buf_element_t *buf);
/*
* overlay functions: spudec decodes all subpicture data until
* it reaches the given vpts, then overlays the subpicture
*/
- void (*spudec_overlay_yuv) (spudec_t *this, uint32_t vpts,
- uint8_t *y, uint8_t *u, uint8_t *v);
- void (*spudec_overlay_rgb) (spudec_t *this, uint32_t vpts,
- uint8_t *rgb_data, int mode);
+ void (*overlay_yuv) (spudec_t *this, uint32_t vpts,
+ uint8_t *y, uint8_t *u, uint8_t *v);
+ void (*overlay_rgb) (spudec_t *this, uint32_t vpts,
+ uint8_t *rgb_data, int mode);
+
+ /* PRIVATE DATA -- Not to be touched. */
+ spudec_priv_t *private;
};
/*
@@ -57,6 +80,13 @@ struct spudec_s {
* spu_fifo : fifo buffer where subpicture packages arrive
*/
-spudec_t *spudec_init (metronom_t *metronom, fifo_buffer_t *spu_fifo);
+extern spudec_t *spudec_init (xine_t *xine);
+
+/*
+ * close a given subpicture decoder
+ *
+ * decoder : The decoder previously returned by spudec_init
+ */
+extern void spudec_close (spudec_t *decoder);
#endif /* HAVE_SPUDEC_H */
diff --git a/src/libspudec/spudec_old.c b/src/libspudec/spudec_old.c
new file mode 100644
index 000000000..9b61d0e01
--- /dev/null
+++ b/src/libspudec/spudec_old.c
@@ -0,0 +1,612 @@
+
+static spudec_globals gSpudec;
+
+clut_t *palette[4] = {
+ NULL, NULL, NULL, NULL
+};
+
+uint8_t alpha[4] = {
+ 0xff, 0x00, 0x00, 0x00
+};
+
+static clut_t* default_clut = (clut_t*) default_palette;
+
+/* Maximum packets we can keep in the queue. Should be fine */
+#define MAX_PACKETS 200
+
+typedef struct {
+ unsigned char *packet; /* The actual packet of data */
+ uint32_t pts; /* The PTS of the packet */
+ uint16_t size; /* The packet size */
+} spudec_packet;
+
+/* Implement the SPU packet queue as a ring queuefer */
+spudec_packet* spudec_packet_queue[MAX_PACKETS];
+int16_t spudec_queue_size = 0; /* Queue length (items) */
+int16_t spudec_queue_pos = 0; /* Start of queue position */
+
+/* Forward declarations */
+void spudec_process_packet(unsigned char *packet, int size);
+
+/* Pushes a packet on the end of the queue */
+void spudec_queue_packet(spudec_packet *packet) {
+ if(spudec_queue_size + 1 > MAX_PACKETS) {
+ /* Too many packets */
+ printf("spudec: Too many packets.\n");
+ return;
+ }
+
+ spudec_packet_queue[(spudec_queue_pos + spudec_queue_size) % MAX_PACKETS] = packet;
+ spudec_queue_size++;
+}
+
+/* Gets the next packet but does /not/ remove it */
+spudec_packet* spudec_peek_next_packet() {
+ if(spudec_queue_size <= 0) {
+ /* No packet in queue */
+ printf("spudec: No more packets.\n");
+ return NULL;
+ }
+
+ return spudec_packet_queue[spudec_queue_pos];
+}
+
+/* Like peek_next but removes the packet from the queue */
+spudec_packet* spudec_get_next_packet() {
+ spudec_packet *packet;
+
+ if((packet = spudec_peek_next_packet()) != NULL) {
+ spudec_queue_pos = (spudec_queue_pos + 1) % MAX_PACKETS;
+ spudec_queue_size --;
+ }
+
+ return packet;
+}
+
+#if 0
+void spudec_init(clut_t *clut) {
+ gSpudec.bInitialised = 1;
+
+ spudec_reset();
+
+ if(clut == NULL) {
+ gSpudec.clut = default_clut;
+ } else {
+ gSpudec.clut = clut;
+ }
+
+ palette[0] = palette[1] = palette[2] = palette[3] = &(gSpudec.clut[0]);
+}
+#endif
+
+void spudec_tick()
+{
+ uint32_t pts;
+ if(!gSpudec.bInitialised)
+ return;
+
+ pts = metronom_got_spu_packet(0);
+
+ /* See if we have any SPUs queued */
+ if(spudec_queue_size != 0) {
+ spudec_packet *p;
+
+ p = spudec_peek_next_packet();
+ if(pts >= p->pts) {
+ /* Process */
+ p = spudec_get_next_packet();
+
+ spudec_process_packet(p->packet, p->size);
+ /* Assume it was displayed correctly */
+ gSpudec.displayPTS = p->pts;
+
+ free(p->packet);
+ free(p);
+ }
+ }
+
+ if((gSpudec.geom.bIsVisible) && (pts - gSpudec.lifetime >= gSpudec.displayPTS)) {
+ gSpudec.geom.bIsVisible = 0;
+ gSpudec.lifetime = 0;
+ gSpudec.lastPTS = pts;
+ return;
+ }
+
+ if(pts < gSpudec.lastPTS) {
+ /* Something screwey. */
+ gSpudec.lastPTS = pts;
+ return;
+ }
+
+ gSpudec.lastPTS = pts;
+}
+
+spudec_geometry* spudec_get_geometry()
+{
+ return &(gSpudec.geom);
+}
+
+int spudec_set_images(vo_image_buffer_t* overlay,
+ vo_image_buffer_t* mask,
+ int width, int height,
+ int format)
+{
+ if(format != IMGFMT_YV12) {
+ printf("Error, SPUDEC only supports YV12 overlays.\n");
+ gSpudec.bInitialised = 0;
+
+ return 0;
+ }
+
+ gSpudec.overlay = overlay;
+ gSpudec.mask = mask;
+ gSpudec.width = width;
+ gSpudec.height = height;
+ gSpudec.format = format;
+ gSpudec.geom.bIsVisible = 0;
+
+ /* Clear images initially */
+ if(gSpudec.format == IMGFMT_YV12) {
+ /* Set initial image to empty & clear mask */
+ memset(mask->mem[0], 0xff, (gSpudec.width*gSpudec.height));
+ memset(overlay->mem[0], 0x00, (gSpudec.width*gSpudec.height));
+ memset(mask->mem[1], 0xff, (gSpudec.width*gSpudec.height) >> 2);
+ memset(overlay->mem[1], 0x00, (gSpudec.width >> 1)*(gSpudec.height >> 1));
+ memset(mask->mem[2], 0xff, (gSpudec.width >> 1)*(gSpudec.height >> 1));
+ memset(overlay->mem[2], 0x00, (gSpudec.width >> 1)*(gSpudec.height >> 1));
+ }
+
+ gSpudec.geom.start_col = 0;
+ gSpudec.geom.end_col = gSpudec.width-1;
+ gSpudec.geom.start_row = 0;
+ gSpudec.geom.end_row = gSpudec.height-1;
+
+ return gSpudec.bInitialised = 1;
+}
+
+#define nibble(data, index) ((index & 1) ? data[index >> 1] & 0xf : (data[index >> 1] >> 4) & 0xf)
+
+void spudec_process_data(unsigned char *data, int size, int d1, int d2)
+{
+ /* This does the 'hard' work of processing the image data */
+
+ long off,line_base, line_base2,y,na,nb;
+ int n; /* The code word */
+
+ na = d1<<1;
+ nb = d2<<1;
+
+ /* Align on even row */
+ if (gSpudec.geom.start_row & 1) {
+ gSpudec.geom.start_row--;
+ gSpudec.geom.end_row--;
+ }
+ if (gSpudec.geom.start_col & 1) {
+ gSpudec.geom.start_col--;
+ gSpudec.geom.end_col--;
+ }
+ y = gSpudec.geom.start_row;
+
+ while(y <= gSpudec.geom.end_row) {
+ line_base = gSpudec.width * y + gSpudec.geom.start_col;
+ line_base2 = (gSpudec.width>>1) * (y>>1) + (gSpudec.geom.start_col >> 1);
+
+ off = 0;
+ do {
+ int num;
+ clut_t *col;
+
+ n = nibble(data, na);
+ na++;
+ if(n < 0x4) {
+ n = (n<<4) | nibble(data, na);
+ na++;
+ if(n < 0x10) {
+ n = (n<<4) | nibble(data, na);
+ na++;
+ if(n < 0x40) {
+ n = (n<<4) | nibble(data, na);
+ na++;
+ if(n < 0x100)
+ n = 0; /* Carriage return */
+ }
+ }
+ }
+ // printf("Code: 0x%04x\n",n);
+
+ num = n >> 2; col = palette[n & 0x3];
+ if(col == NULL) {
+ printf("Error in palette\n");
+ }
+
+ if(num != 0) {
+ if(alpha[n & 0x3] & 0x80) {
+ memset(&(gSpudec.mask->mem[0][line_base + off]), 0x00, num);
+ memset(&(gSpudec.overlay->mem[0][line_base + off]), col->y, num);
+ memset(&(gSpudec.mask->mem[1][line_base2 + (off>>1)]), 0x00, num>>1);
+ memset(&(gSpudec.overlay->mem[1][line_base2 + (off>>1)]), col->cr, num>>1);
+ memset(&(gSpudec.mask->mem[2][line_base2 + (off>>1)]), 0x00, num>>1);
+ memset(&(gSpudec.overlay->mem[2][line_base2 + (off>>1)]), col->cb, num>>1);
+ } else {
+ memset(&(gSpudec.mask->mem[0][line_base + off]), 0xff, num);
+ memset(&(gSpudec.overlay->mem[0][line_base + off]), 0x00, num);
+ memset(&(gSpudec.mask->mem[1][line_base2 + (off>>1)]), 0xff, num>>1);
+ memset(&(gSpudec.overlay->mem[1][line_base2 + (off>>1)]), 0x00, num>>1);
+ memset(&(gSpudec.mask->mem[2][line_base2 + (off>>1)]), 0xff, num>>1);
+ memset(&(gSpudec.overlay->mem[2][line_base2 + (off>>1)]), 0x00, num>>1);
+ }
+ }
+ off+=num;
+ } while((n != 0) && (off <= gSpudec.geom.end_col - gSpudec.geom.start_col));
+
+ if((n == 0) && (off <= gSpudec.geom.end_col - gSpudec.geom.start_col)) {
+ /* Clear to end of line if carriage return */
+ int len = gSpudec.geom.start_col + gSpudec.geom.end_col - off;
+ memset(&(gSpudec.mask->mem[0][line_base + off]), 0xff, len);
+ memset(&(gSpudec.overlay->mem[0][line_base + off]), 0x00, len);
+ memset(&(gSpudec.mask->mem[0][line_base + off]) + gSpudec.width, 0xff, len);
+ memset(&(gSpudec.overlay->mem[0][line_base + off]) + gSpudec.width, 0x00, len);
+ memset(&(gSpudec.mask->mem[1][line_base2 + (off>>1)]), 0xff, len>>1);
+ memset(&(gSpudec.overlay->mem[1][line_base2 + (off>>1)]), 0x00, len>>1);
+ memset(&(gSpudec.mask->mem[2][line_base2 + (off>>1)]), 0xff, len>>1);
+ memset(&(gSpudec.overlay->mem[2][line_base2 + (off>>1)]), 0x00, len>>1);
+ }
+
+ if((na & 1))
+ na ++; /* Re-align */
+
+ line_base += gSpudec.width;
+ y++;
+ if (y > gSpudec.geom.end_row)
+ break;
+
+ off = 0;
+ do {
+ int num;
+ clut_t *col;
+
+ n = nibble(data, nb);
+ nb++;
+ if(n < 0x4) {
+ n = (n<<4) | nibble(data, nb);
+ nb++;
+ if(n < 0x10) {
+ n = (n<<4) | nibble(data, nb);
+ nb++;
+ if(n < 0x40) {
+ n = (n<<4) | nibble(data, nb);
+ nb++;
+ if(n < 0x100)
+ n = 0; /* Carriage return */
+ }
+ }
+ }
+ // printf("Code: 0x%04x\n",n);
+
+ num = n >> 2; col = palette[n & 0x3];
+ if(col == NULL) {
+ printf("Error in palette\n");
+ }
+
+ if(num != 0) {
+ if(alpha[n & 0x3] & 0x80) {
+ memset(&(gSpudec.mask->mem[0][line_base + off]), 0x00, num);
+ memset(&(gSpudec.overlay->mem[0][line_base + off]), col->y, num);
+ } else {
+ memset(&(gSpudec.mask->mem[0][line_base + off]), 0xff, num);
+ memset(&(gSpudec.overlay->mem[0][line_base + off]), 0x00, num);
+ }
+ }
+ off+=num;
+ } while((n != 0) && (off <= gSpudec.geom.end_col - gSpudec.geom.start_col));
+
+ if((n == 0) && (off <= gSpudec.geom.end_col - gSpudec.geom.start_col)) {
+ /* Clear to end of line if carriage return */
+ int len = gSpudec.geom.start_col + gSpudec.geom.end_col - off;
+ memset(&(gSpudec.mask->mem[0][line_base + off]), 0xff, len);
+ memset(&(gSpudec.overlay->mem[0][line_base + off]), 0x00, len);
+ }
+
+ if((nb & 1))
+ nb ++; /* Re-align */
+
+ y++;
+ }
+}
+
+void spudec_process_control(unsigned char *control, int size, int* d1, int* d2)
+{
+ int off = 2;
+ int a,b; /* Temporary vars */
+
+ do {
+ int type = control[off];
+ off++;
+
+ switch(type) {
+ case 0x00:
+ /* Menu ID, 1 byte */
+ break;
+ case 0x01:
+ /* Start display */
+ gSpudec.geom.bIsVisible = 1;
+ break;
+ case 0x03:
+ /* Palette */
+ palette[3] = &(gSpudec.clut[(control[off] >> 4)]);
+ palette[2] = &(gSpudec.clut[control[off] & 0xf]);
+ palette[1] = &(gSpudec.clut[(control[off+1] >> 4)]);
+ palette[0] = &(gSpudec.clut[control[off+1] & 0xf]);
+ off+=2;
+ break;
+ case 0x04:
+ /* Alpha */
+ alpha[3] = control[off] & 0xf0;
+ alpha[2] = (control[off] & 0xf) << 4;
+ alpha[1] = control[off+1] & 0xf0;
+ alpha[0] = (control[off+1] & 0xf) << 4;
+ off+=2;
+ break;
+ case 0x05:
+ /* Co-ords */
+ a = (control[off] << 16) + (control[off+1] << 8) + control[off+2];
+ b = (control[off+3] << 16) + (control[off+4] << 8) + control[off+5];
+
+ gSpudec.geom.start_col = a >> 12;
+ gSpudec.geom.end_col = a & 0xfff;
+ gSpudec.geom.start_row = b >> 12;
+ gSpudec.geom.end_row = b & 0xfff;
+
+ off+=6;
+ break;
+ case 0x06:
+ /* Graphic lines */
+ *(d1) = (control[off] << 8) + control[off+1];
+ *(d2) = (control[off+2] << 8) + control[off+3];
+ off+=4;
+ break;
+ case 0xff:
+ /* All done, bye-bye */
+ return;
+ break;
+ default:
+ printf("spudec: Error determining control type 0x%02x.\n",type);
+ return;
+ break;
+ }
+
+ /* printf("spudec: Processsed control type 0x%02x.\n",type); */
+ } while(off < size);
+}
+
+void spudec_process_packet(unsigned char *packet, int size)
+{
+ int x0, x1;
+ int d1, d2;
+
+ /* Check packet */
+ if((packet[0] << 8) + packet[1] != size) {
+ printf("Packet size mismatch:\n");
+ printf("Packet reports size 0x%04x\n", (packet[0] << 8) + packet[1]);
+ printf("I reckon 0x%04x\n", size);
+ return;
+ }
+
+ x0 = (packet[2] << 8) + packet[3];
+ x1 = (packet[x0+2] << 8) + packet[x0+3];
+
+ /* /Another/ sanity check. */
+ if((packet[x1+2]<<8) + packet[x1+3] != x1) {
+ printf("spudec: Incorrect packet.\n");
+ return;
+ }
+
+ /* End sequence, FIXME: why do we need the division by 2? */
+ gSpudec.lifetime = (metronom_get_video_rate() >> 1)* ((packet[x1]<<8) + packet[x1+1]);
+
+ d1 = d2 = -1;
+ spudec_process_control(packet + x0 + 2, x1-x0-2, &d1, &d2);
+
+ if((d1 != -1) && (d2 != -1)) {
+ spudec_process_data(packet, x0, d1, d2);
+ }
+}
+
+void spudec_decode(unsigned char *data, int size, uint32_t pts) {
+ if(!gSpudec.bInitialised)
+ return;
+
+ if(gSpudec.packet == NULL) {
+ if(pts != 0) {
+ /* Allocate a packet buffer */
+ gSpudec.packet = xmalloc((data[0] << 8) + data[1]);
+ gSpudec.pts = pts;
+
+ if(gSpudec.packet == NULL) {
+ printf("Error allocating packet buffer.\n");
+ return;
+ }
+
+ gSpudec.packet_size = 0;
+ } else {
+ printf("spudec: Error, we are half way through a packet I don't know\n");
+ }
+ }
+
+ /* Prevent buffer overruns */
+ if(gSpudec.packet_size >= 2) { /* If the /packet/ knows how big it is */
+ if((gSpudec.packet_size + size) >
+ (gSpudec.packet[0]<<8) + gSpudec.packet[1]) {
+ printf("spudec: Mismatched buffer size (0x%04x to big), truncating.\n",
+ (gSpudec.packet_size + size) -
+ ((gSpudec.packet[0]<<8) + gSpudec.packet[1]));
+ size = (gSpudec.packet[0]<<8) + gSpudec.packet[1] - gSpudec.packet_size;
+ }
+ }
+
+
+ memcpy(gSpudec.packet + gSpudec.packet_size, data, size);
+ gSpudec.packet_size += size;
+
+ if(gSpudec.packet_size >= (gSpudec.packet[0]<<8) + gSpudec.packet[1]) {
+ /* If packet complete then queue */
+ spudec_packet *p;
+
+ p = xmalloc(sizeof(spudec_packet));
+ p->packet = gSpudec.packet;
+ p->size = gSpudec.packet_size;
+ p->pts = gSpudec.pts;
+
+ spudec_queue_packet(p);
+
+ gSpudec.packet = NULL;
+ gSpudec.packet_size = -1;
+ gSpudec.pts = 0;
+ }
+}
+
+void spudec_reset() {
+ /* Clear any packet being assembled */
+ if(gSpudec.packet != NULL) {
+ gSpudec.packet_size = 0;
+ free(gSpudec.packet);
+ gSpudec.packet = NULL;
+ gSpudec.pts = 0;
+ }
+
+ /* Remove any current subtitle */
+ gSpudec.geom.bIsVisible = 0;
+ gSpudec.lifetime = 0;
+
+ /* Clear packet queue */
+ while(spudec_queue_size > 0) {
+ spudec_packet *p = spudec_get_next_packet();
+
+ free(p->packet);
+ free(p);
+ }
+}
+
+void spudec_overlay_yuv (uint8_t *y, uint8_t *u, uint8_t *v) {
+
+ /*
+ * Mix in SPU
+ */
+
+ /* Tick SPUdec */
+ spudec_tick();
+
+ if(gVO.bOverlayImage) {
+ /* This code is pretty nasty but quite quick which is important here! */
+ /* APPROACH: Since 32bit processors hande data, well 32bits at a time,
+ * we overlay the image word by word rather than byte by byte and then
+ * tidy up the odd bytes at the end. This effectively cuts the number of
+ * loop itterations by a factor of 4. */
+
+ /* FIXME: Optimise for 64bit machines as well? */
+
+ if((gVO.spu_geom->bIsVisible) &&
+ (gVO.format == IMGFMT_YV12)) {
+ /* Overlay the image. */
+ long i, off;
+ uint8_t *img_l_8, *ovl_l_8, *msk_l_8;
+ uint32_t *img_l_32, *ovl_l_32, *msk_l_32;
+ uint8_t *img_y_8, *ovl_y_8, *msk_y_8;
+ uint32_t *img_y_32, *ovl_y_32, *msk_y_32;
+ uint8_t *img_v_8, *ovl_v_8, *msk_v_8;
+ uint32_t *img_v_32, *ovl_v_32, *msk_v_32;
+
+ img_l_8 = img->mem[0];
+ ovl_l_8 = gVO.overlay_image->mem[0];
+ msk_l_8 = gVO.mask_image->mem[0];
+ img_l_32 = ((uint32_t*)img->mem[0]);
+ ovl_l_32 = ((uint32_t*)gVO.overlay_image->mem[0]);
+ msk_l_32 = ((uint32_t*)gVO.mask_image->mem[0]);
+ img_y_8 = img->mem[1];
+ ovl_y_8 = gVO.overlay_image->mem[1];
+ msk_y_8 = gVO.mask_image->mem[1];
+ img_y_32 = ((uint32_t*)img->mem[1]);
+ ovl_y_32 = ((uint32_t*)gVO.overlay_image->mem[1]);
+ msk_y_32 = ((uint32_t*)gVO.mask_image->mem[1]);
+ img_v_8 = img->mem[2];
+ ovl_v_8 = gVO.overlay_image->mem[2];
+ msk_v_8 = gVO.mask_image->mem[2];
+ img_v_32 = ((uint32_t*)img->mem[2]);
+ ovl_v_32 = ((uint32_t*)gVO.overlay_image->mem[2]);
+ msk_v_32 = ((uint32_t*)gVO.mask_image->mem[2]);
+
+ /* luminance */
+ for(i=gVO.width*gVO.spu_geom->start_row;
+ i<=gVO.width*gVO.spu_geom->end_row; i+=gVO.width) {
+ /* i is address of begining of line. */
+
+ /* Firstly, draw the start odd bytes. */
+ for(off = i+gVO.spu_geom->start_col; (off & 3) != 0; off++) {
+ if(msk_l_8[off] != 0xff) {
+ img_l_8[off] &= msk_l_8[off];
+ img_l_8[off] |= ovl_l_8[off];
+ }
+ }
+
+ /* Now words */
+ for(; off<=i+gVO.spu_geom->end_col-3; off+=4) {
+ if(msk_l_32[off>>2] != 0xffffffff) {
+ img_l_32[off>>2] &= msk_l_32[off>>2];
+ img_l_32[off>>2] |= ovl_l_32[off>>2];
+ }
+ }
+ off -= 4;
+
+ /* Now end odd bytes */
+ for(; off<=i+gVO.spu_geom->end_col; off++) {
+ if(msk_l_8[off] != 0xff) {
+ img_l_8[off] &= msk_l_8[off];
+ img_l_8[off] |= ovl_l_8[off];
+ }
+ }
+ }
+ /* colour */
+ for(i=(gVO.width>>1)*(gVO.spu_geom->start_row>>1);
+ i<=(gVO.width>>1)*(gVO.spu_geom->end_row>>1); i+=(gVO.width)>>1) {
+ /* i is address of begining of line. */
+
+ /* Firstly, draw the start odd bytes. */
+ for(off = i+((gVO.spu_geom->start_col)>>1); (off & 3) != 0; off++) {
+ if(msk_y_8[off] != 0xff) {
+ img_y_8[off] &= msk_y_8[off];
+ img_y_8[off] |= ovl_y_8[off];
+ }
+ if(msk_v_8[off] != 0xff) {
+ img_v_8[off] &= msk_v_8[off];
+ img_v_8[off] |= ovl_v_8[off];
+ }
+ }
+
+ /* Now words */
+ for(; off<=i+((gVO.spu_geom->end_col)>>1)-3; off+=4) {
+ if(msk_y_32[off>>2] != 0xffffffff) {
+ img_y_32[off>>2] &= msk_y_32[off>>2];
+ img_y_32[off>>2] |= ovl_y_32[off>>2];
+ }
+ if(msk_v_32[off>>2] != 0xffffffff) {
+ img_v_32[off>>2] &= msk_v_32[off>>2];
+ img_v_32[off>>2] |= ovl_v_32[off>>2];
+ }
+ }
+ off -= 4;
+
+ /* Final end odd bytes */
+ for(; off<=i+((gVO.spu_geom->end_col)>>1); off++) {
+ if(msk_y_8[off] != 0xff) {
+ img_y_8[off] &= msk_y_8[off];
+ img_y_8[off] |= ovl_y_8[off];
+ }
+ if(msk_v_8[off] != 0xff) {
+ img_v_8[off] &= msk_v_8[off];
+ img_v_8[off] |= ovl_v_8[off];
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/video_out/video_out_xv.c b/src/video_out/video_out_xv.c
index e48fcf103..eb9d0bb5c 100644
--- a/src/video_out/video_out_xv.c
+++ b/src/video_out/video_out_xv.c
@@ -17,7 +17,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: video_out_xv.c,v 1.43 2001/06/17 22:34:36 guenter Exp $
+ * $Id: video_out_xv.c,v 1.44 2001/06/18 15:43:00 richwareham Exp $
*
* video_out_xv.c, X11 video extension interface for xine
*
@@ -466,7 +466,7 @@ static void xv_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) {
xv_calc_format (this, frame->width, frame->height, frame->ratio_code);
}
-
+
XLockDisplay (this->display);
this->cur_frame = frame;
diff --git a/src/xine-engine/Makefile.am b/src/xine-engine/Makefile.am
index 3444d2833..17558fdd2 100644
--- a/src/xine-engine/Makefile.am
+++ b/src/xine-engine/Makefile.am
@@ -12,7 +12,7 @@ libxine_la_SOURCES = xine.c metronom.c configfile.c buffer.c monitor.c \
utils.c load_plugins.c video_decoder.c spu_decoder.c \
audio_decoder.c video_out.c
libxine_la_LIBADD = cpu_accel.lo \
-## $(top_srcdir)/src/libspudec/libspudec.la \
+ $(top_srcdir)/src/libspudec/libspudec.la \
$(THREAD_LIBS) \
$(DYNAMIC_LD_LIBS)
-lm
diff --git a/src/xine-engine/spu_decoder.c b/src/xine-engine/spu_decoder.c
index a1af8045a..03f008367 100644
--- a/src/xine-engine/spu_decoder.c
+++ b/src/xine-engine/spu_decoder.c
@@ -17,7 +17,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_decoder.c,v 1.1 2001/06/18 09:39:05 richwareham Exp $
+ * $Id: spu_decoder.c,v 1.2 2001/06/18 15:43:01 richwareham Exp $
*
*/
@@ -27,18 +27,22 @@
#include "xine_internal.h"
+#include "libspudec/spudec.h"
+
void *spu_decoder_loop (void *this_gen) {
buf_element_t *buf;
xine_t *this = (xine_t *) this_gen;
int running = 1;
int streamtype;
+ spudec_t *decoder;
+ decoder = this->spu_decoder;
while (running) {
/* printf ("video_decoder: getting buffer...\n"); */
- buf = this->video_fifo->get (this->spu_fifo);
+ buf = this->spu_fifo->get (this->spu_fifo);
if (buf->input_pos)
this->cur_input_pos = buf->input_pos;
@@ -55,6 +59,18 @@ void *spu_decoder_loop (void *this_gen) {
running = 0;
break;
+ default:
+ if ( (buf->type & 0xFF000000) == BUF_SPU_BASE ) {
+ int stream_id;
+
+ printf ("spu_decoder: got an SPU buffer, type %08x\n", buf->type);
+
+ stream_id = buf->type & 0xFF;
+
+ if(decoder) {
+ decoder->push_packet(decoder, buf);
+ }
+ }
}
buf->free_buffer (buf);
@@ -64,9 +80,16 @@ void *spu_decoder_loop (void *this_gen) {
}
void spu_decoder_init (xine_t *this) {
+ buf_element_t *buf;
+
+ this->spu_decoder = spudec_init(this);
this->spu_fifo = fifo_buffer_new (1500, 4096);
+ buf = this->spu_fifo->buffer_pool_alloc (this->spu_fifo);
+ buf->type = BUF_CONTROL_START;
+ this->spu_fifo->put (this->spu_fifo, buf);
+
pthread_create (&this->spu_thread, NULL, spu_decoder_loop, this) ;
}
@@ -81,6 +104,9 @@ void spu_decoder_shutdown (xine_t *this) {
buf->type = BUF_CONTROL_QUIT;
this->spu_fifo->put (this->spu_fifo, buf);
+ spudec_close(this->spu_decoder);
+ this->spu_decoder = NULL;
+
pthread_join (this->spu_thread, &p);
}
diff --git a/src/xine-engine/video_out.c b/src/xine-engine/video_out.c
index 22dd0fe81..2c624b94d 100644
--- a/src/xine-engine/video_out.c
+++ b/src/xine-engine/video_out.c
@@ -17,7 +17,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: video_out.c,v 1.23 2001/06/17 02:22:30 guenter Exp $
+ * $Id: video_out.c,v 1.24 2001/06/18 15:43:01 richwareham Exp $
*
*/
@@ -35,6 +35,7 @@
#include "utils.h"
#include "monitor.h"
+#include "libspudec/spudec.h"
#define NUM_FRAME_BUFFERS 20
@@ -266,9 +267,10 @@ static void *video_out_loop (void *this_gen) {
img->bDisplayLock = 0;
pthread_mutex_unlock (&img->mutex);
- /* FIXME: spudec_overlay_yuv (img->mem[0], img->mem[1], img->mem[2]) */
+ /* Overlay SPU FIXME: Check image format */
+ this->spu_decoder->overlay_yuv (this->spu_decoder, pts,
+ img->base[0], img->base[1], img->base[2]);
-
xprintf (VERBOSE|VIDEO, "video_out : passing to video driver, image with pts = %d\n", pts);
this->driver->display_frame (this->driver, img);
}
@@ -461,7 +463,7 @@ static int vo_frame_draw (vo_frame_t *img) {
return frames_to_skip;
}
-vo_instance_t *vo_new_instance (vo_driver_t *driver, metronom_t *metronom) {
+vo_instance_t *vo_new_instance (vo_driver_t *driver, metronom_t *metronom, spudec_t *spu_decoder) {
vo_instance_t *this;
int i;
@@ -470,6 +472,7 @@ vo_instance_t *vo_new_instance (vo_driver_t *driver, metronom_t *metronom) {
this->driver = driver;
this->metronom = metronom;
+ this->spu_decoder = spu_decoder;
this->open = vo_open;
this->get_frame = vo_get_frame;
diff --git a/src/xine-engine/video_out.h b/src/xine-engine/video_out.h
index f49464c77..becfba058 100644
--- a/src/xine-engine/video_out.h
+++ b/src/xine-engine/video_out.h
@@ -17,7 +17,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: video_out.h,v 1.7 2001/06/09 11:34:01 heikos Exp $
+ * $Id: video_out.h,v 1.8 2001/06/18 15:43:01 richwareham Exp $
*
*
* xine version of video_out.h
@@ -49,6 +49,8 @@ typedef struct vo_driver_s vo_driver_t ;
typedef struct vo_instance_s vo_instance_t;
typedef struct img_buf_fifo_s img_buf_fifo_t;
+typedef struct spudec_s spudec_t;
+
/* public part, video drivers may add private fields */
struct vo_frame_s {
struct vo_frame_s *next;
@@ -120,6 +122,7 @@ struct vo_instance_s {
vo_driver_t *driver;
metronom_t *metronom;
+ spudec_t *spu_decoder;
img_buf_fifo_t *free_img_buf_queue;
img_buf_fifo_t *display_img_buf_queue;
@@ -239,7 +242,7 @@ struct vo_driver_s {
* a given video driver
*/
-vo_instance_t *vo_new_instance (vo_driver_t *driver, metronom_t *metronom) ;
+vo_instance_t *vo_new_instance (vo_driver_t *driver, metronom_t *metronom, spudec_t *spu_decoder) ;
/*
* to build a dynamic video output plugin
diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c
index 142a29452..d2aef0dc4 100644
--- a/src/xine-engine/xine.c
+++ b/src/xine-engine/xine.c
@@ -17,7 +17,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.c,v 1.27 2001/06/18 09:39:05 richwareham Exp $
+ * $Id: xine.c,v 1.28 2001/06/18 15:43:01 richwareham Exp $
*
* top-level xine functions
*
@@ -219,17 +219,6 @@ static void xine_play_internal (xine_t *this, char *mrl,
this->cur_demuxer_plugin->get_identifier());
/*
- * Init SPU decoder with colour lookup table.
- */
-
- /* FIXME
- if(this->cur_input_plugin->get_clut)
- spudec_init(this->cur_input_plugin->get_clut());
- else
- spudec_init(NULL);
- */
-
- /*
* metronom
*/
@@ -417,12 +406,18 @@ xine_t *xine_init (vo_driver_t *vo,
this->cur_input_pos = 0;
/*
+ * init SPU decoder (must be done before video decoder
+ * so that this->spu_decoder is valid).
+ */
+ spu_decoder_init (this);
+
+ /*
* init and start decoder threads
*/
load_decoder_plugins (this, config, DECODER_PLUGIN_IFACE_VERSION);
- this->video_out = vo_new_instance (vo, this->metronom);
+ this->video_out = vo_new_instance (vo, this->metronom, this->spu_decoder);
video_decoder_init (this);
if(ao) {
@@ -431,11 +426,6 @@ xine_t *xine_init (vo_driver_t *vo,
}
audio_decoder_init (this);
- /*
- * init SPU decoder
- */
- spu_decoder_init (this);
-
return this;
}
diff --git a/src/xine-engine/xine_internal.h b/src/xine-engine/xine_internal.h
index a6e44b2a8..716377b04 100644
--- a/src/xine-engine/xine_internal.h
+++ b/src/xine-engine/xine_internal.h
@@ -17,7 +17,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_internal.h,v 1.24 2001/06/18 09:39:05 richwareham Exp $
+ * $Id: xine_internal.h,v 1.25 2001/06/18 15:43:01 richwareham Exp $
*
*/
@@ -130,6 +130,7 @@ typedef struct xine_s {
fifo_buffer_t *spu_fifo;
pthread_t spu_thread;
+ spudec_t *spu_decoder;
int audio_channel;
int spu_channel;