diff options
author | Rich J Wareham <richwareham@users.sourceforge.net> | 2001-06-18 15:43:00 +0000 |
---|---|---|
committer | Rich J Wareham <richwareham@users.sourceforge.net> | 2001-06-18 15:43:00 +0000 |
commit | a2c0482e17a5d1d0ea99d06b81e94c0e7b5cb4e2 (patch) | |
tree | c064d151203dd381e7606b570e8910cce018d449 | |
parent | 7e7483472eb410396ff7890577ac49bce9afab7a (diff) | |
download | xine-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.am | 2 | ||||
-rw-r--r-- | src/libspudec/spudec.c | 644 | ||||
-rw-r--r-- | src/libspudec/spudec.h | 44 | ||||
-rw-r--r-- | src/libspudec/spudec_old.c | 612 | ||||
-rw-r--r-- | src/video_out/video_out_xv.c | 4 | ||||
-rw-r--r-- | src/xine-engine/Makefile.am | 2 | ||||
-rw-r--r-- | src/xine-engine/spu_decoder.c | 30 | ||||
-rw-r--r-- | src/xine-engine/video_out.c | 11 | ||||
-rw-r--r-- | src/xine-engine/video_out.h | 7 | ||||
-rw-r--r-- | src/xine-engine/xine.c | 26 | ||||
-rw-r--r-- | src/xine-engine/xine_internal.h | 3 |
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; |