summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dxr3/Makefile.am2
-rw-r--r--src/dxr3/dxr3_decode_spu.c56
-rw-r--r--src/dxr3/dxr3_spu_encoder.c493
-rw-r--r--src/dxr3/video_out_dxr3.c113
-rw-r--r--src/dxr3/video_out_dxr3.h31
5 files changed, 677 insertions, 18 deletions
diff --git a/src/dxr3/Makefile.am b/src/dxr3/Makefile.am
index f3db2f562..92fd08ab5 100644
--- a/src/dxr3/Makefile.am
+++ b/src/dxr3/Makefile.am
@@ -22,7 +22,7 @@ xineplug_decode_dxr3_video_la_LDFLAGS = -avoid-version -module
xineplug_decode_dxr3_spu_la_SOURCES = dxr3_decode_spu.c nav_read.c
xineplug_decode_dxr3_spu_la_LDFLAGS = -avoid-version -module
-xineplug_vo_out_dxr3_la_SOURCES = video_out_dxr3.c dxr3_mpeg_encoders.c alphablend.c
+xineplug_vo_out_dxr3_la_SOURCES = video_out_dxr3.c dxr3_mpeg_encoders.c alphablend.c dxr3_spu_encoder.c
if HAVE_X11
xineplug_vo_out_dxr3_la_LIBADD = $(X_LIBS) -lXext
xineplug_vo_out_dxr3_la_LDFLAGS = -avoid-version -module $(link_fame) $(link_rte) $(X_LIBS)
diff --git a/src/dxr3/dxr3_decode_spu.c b/src/dxr3/dxr3_decode_spu.c
index cc35ed734..b1d61c7e6 100644
--- a/src/dxr3/dxr3_decode_spu.c
+++ b/src/dxr3/dxr3_decode_spu.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: dxr3_decode_spu.c,v 1.14 2002/07/21 10:02:35 mroi Exp $
+ * $Id: dxr3_decode_spu.c,v 1.15 2002/08/17 14:30:09 mroi Exp $
*/
/* dxr3 spu decoder plugin.
@@ -42,6 +42,7 @@
#include "xine-engine/bswap.h"
#include "nav_types.h"
#include "nav_read.h"
+#include "video_out_dxr3.h"
#include "dxr3.h"
#define LOG_PTS 0
@@ -76,14 +77,15 @@ typedef struct dxr3_spu_stream_state_s {
typedef struct dxr3_spudec_s {
spu_decoder_t spu_decoder;
- vo_instance_t *vo_out;
xine_t *xine;
+ dxr3_driver_t *dxr3_vo; /* we need to talk to the video out */
char devname[128];
char devnum[3];
int fd_spu; /* to access the dxr3 spu device */
dxr3_spu_stream_state_t spu_stream_state[MAX_SPU_STREAMS];
+ uint32_t clut[16]; /* the current color lookup table */
int menu; /* are we in a menu? */
int button_filter;
pci_t pci;
@@ -145,6 +147,9 @@ spu_decoder_t *init_spu_decoder_plugin(int iface_version, xine_t *xine)
this->spu_decoder.priority = 10;
this->xine = xine;
+ /* We need to talk to dxr3 video out to coordinate spus and overlays */
+ this->dxr3_vo = (dxr3_driver_t *)xine->video_driver;
+
this->fd_spu = 0;
this->menu = 0;
this->button_filter = 1;
@@ -176,8 +181,7 @@ static void dxr3_spudec_init(spu_decoder_t *this_gen, vo_instance_t *vo_out)
char tmpstr[128];
int i;
- this->vo_out = vo_out;
-
+ pthread_mutex_lock(&this->dxr3_vo->spu_device_lock);
/* open dxr3 spu device */
snprintf(tmpstr, sizeof(tmpstr), "%s_sp%s", this->devname, this->devnum);
if ((this->fd_spu = open(tmpstr, O_WRONLY)) < 0) {
@@ -188,6 +192,11 @@ static void dxr3_spudec_init(spu_decoder_t *this_gen, vo_instance_t *vo_out)
#if LOG_SPU
printf ("dxr3_decode_spu: init: SPU_FD = %i\n",this->fd_spu);
#endif
+ /* We are talking directly to the dxr3 video out to allow concurrent
+ * access to the same spu device */
+ this->dxr3_vo->fd_spu = this->fd_spu;
+ pthread_mutex_unlock(&this->dxr3_vo->spu_device_lock);
+
for (i=0; i < MAX_SPU_STREAMS; i++) {
this->spu_stream_state[i].stream_filter = 1;
this->spu_stream_state[i].spu_length = 0;
@@ -208,8 +217,13 @@ static void dxr3_spudec_decode_data(spu_decoder_t *this_gen, buf_element_t *buf)
#endif
if (buf->content[0] == 0) /* cheap endianess detection */
dxr3_swab_clut((int *)buf->content);
+ pthread_mutex_lock(&this->dxr3_vo->spu_device_lock);
if (ioctl(this->fd_spu, EM8300_IOCTL_SPU_SETPALETTE, buf->content))
printf("dxr3_decode_spu: failed to set CLUT (%s)\n", strerror(errno));
+ /* remember clut, when video out places some overlay we may need to restore it */
+ memcpy(this->clut, buf->content, 16 * sizeof(uint32_t));
+ this->dxr3_vo->clut_cluttered = 0;
+ pthread_mutex_unlock(&this->dxr3_vo->spu_device_lock);
return;
}
if(buf->type == BUF_SPU_SUBP_CONTROL) {
@@ -252,10 +266,13 @@ static void dxr3_spudec_decode_data(spu_decoder_t *this_gen, buf_element_t *buf)
spu_button.buttonN = this->buttonN;
xine_send_event(this->xine, &spu_event.event);
}
- if ((dxr3_spudec_copy_nav_to_btn(this, 0, &btn ) > 0))
+ if ((dxr3_spudec_copy_nav_to_btn(this, 0, &btn ) > 0)) {
+ pthread_mutex_lock(&this->dxr3_vo->spu_device_lock);
if (ioctl(this->fd_spu, EM8300_IOCTL_SPU_BUTTON, &btn))
printf("dxr3_decode_spu: failed to set spu button (%s)\n",
strerror(errno));
+ pthread_mutex_unlock(&this->dxr3_vo->spu_device_lock);
+ }
}
if ((pci.hli.hl_gi.hli_ss == 0) && (this->pci.hli.hl_gi.hli_ss == 1)) {
@@ -271,8 +288,10 @@ static void dxr3_spudec_decode_data(spu_decoder_t *this_gen, buf_element_t *buf)
this->pci.hli.hl_gi.hli_ss = 0;
this->menu = 0;
this->button_filter = 1;
+ pthread_mutex_lock(&this->dxr3_vo->spu_device_lock);
ioctl(this->fd_spu, EM8300_IOCTL_SPU_BUTTON, NULL);
write(this->fd_spu, empty_spu, sizeof(empty_spu));
+ pthread_mutex_unlock(&this->dxr3_vo->spu_device_lock);
}
}
return;
@@ -350,6 +369,8 @@ static void dxr3_spudec_decode_data(spu_decoder_t *this_gen, buf_element_t *buf)
return;
}
+ pthread_mutex_lock(&this->dxr3_vo->spu_device_lock);
+
/* write sync timestamp to the card */
if (buf->pts) {
int64_t vpts;
@@ -367,6 +388,13 @@ static void dxr3_spudec_decode_data(spu_decoder_t *this_gen, buf_element_t *buf)
printf("dxr3_decode_spu: spu setpts failed (%s)\n", strerror(errno));
}
+ /* has video out tampered with our palette */
+ if (this->dxr3_vo->clut_cluttered) {
+ if (ioctl(this->fd_spu, EM8300_IOCTL_SPU_SETPALETTE, this->clut))
+ printf("dxr3_decode_spu: failed to set CLUT (%s)\n", strerror(errno));
+ this->dxr3_vo->clut_cluttered = 0;
+ }
+
/* write spu data to the card */
#if LOG_SPU
printf ("dxr3_decode_spu: write: SPU_FD = %i\n",this->fd_spu);
@@ -375,11 +403,14 @@ static void dxr3_spudec_decode_data(spu_decoder_t *this_gen, buf_element_t *buf)
if (written < 0) {
printf("dxr3_decode_spu: spu device write failed (%s)\n",
strerror(errno));
+ pthread_mutex_unlock(&this->dxr3_vo->spu_device_lock);
return;
}
if (written != buf->size)
printf("dxr3_decode_spu: Could only write %d of %d spu bytes.\n",
written, buf->size);
+
+ pthread_mutex_unlock(&this->dxr3_vo->spu_device_lock);
}
static void dxr3_spudec_reset(spu_decoder_t *this_gen)
@@ -397,8 +428,11 @@ static void dxr3_spudec_close(spu_decoder_t *this_gen)
#if LOG_SPU
printf("dxr3_decode_spu: close: SPU_FD = %i\n",this->fd_spu);
#endif
+ pthread_mutex_lock(&this->dxr3_vo->spu_device_lock);
close(this->fd_spu);
this->fd_spu = 0;
+ this->dxr3_vo->fd_spu = 0;
+ pthread_mutex_unlock(&this->dxr3_vo->spu_device_lock);
}
static void dxr3_spudec_dispose(spu_decoder_t *this_gen)
@@ -444,10 +478,13 @@ static void dxr3_spudec_event_listener(void *this_gen, xine_event_t *event_gen)
#endif
this->buttonN = but->buttonN;
if ((but->show > 0) && !this->button_filter &&
- (dxr3_spudec_copy_nav_to_btn(this, but->show - 1, &btn) > 0))
+ (dxr3_spudec_copy_nav_to_btn(this, but->show - 1, &btn) > 0)) {
+ pthread_mutex_lock(&this->dxr3_vo->spu_device_lock);
if (ioctl(this->fd_spu, EM8300_IOCTL_SPU_BUTTON, &btn))
printf("dxr3_decode_spu: failed to set spu button (%s)\n",
strerror(errno));
+ pthread_mutex_unlock(&this->dxr3_vo->spu_device_lock);
+ }
if (but->show == 2) this->button_filter = 1;
#if LOG_BTN
printf("dxr3_decode_spu: buttonN = %u\n",but->buttonN);
@@ -464,9 +501,14 @@ static void dxr3_spudec_event_listener(void *this_gen, xine_event_t *event_gen)
#ifdef WORDS_BIGENDIAN
dxr3_swab_clut(clut->clut);
#endif
+ pthread_mutex_lock(&this->dxr3_vo->spu_device_lock);
if (ioctl(this->fd_spu, EM8300_IOCTL_SPU_SETPALETTE, clut->clut))
printf("dxr3_decode_spu: failed to set CLUT (%s)\n",
strerror(errno));
+ /* remember clut, when video out places some overlay we may need to restore it */
+ memcpy(this->clut, clut->clut, 16 * sizeof(uint32_t));
+ this->dxr3_vo->clut_cluttered = 0;
+ pthread_mutex_unlock(&this->dxr3_vo->spu_device_lock);
}
break;
case XINE_EVENT_FRAME_CHANGE:
@@ -476,7 +518,7 @@ static void dxr3_spudec_event_listener(void *this_gen, xine_event_t *event_gen)
printf("dxr3_decode_spu: aspect changed to %d\n", this->aspect);
#endif
break;
- }
+ }
}
static int dxr3_spudec_copy_nav_to_btn(dxr3_spudec_t *this, int32_t mode, em8300_button_t *btn)
diff --git a/src/dxr3/dxr3_spu_encoder.c b/src/dxr3/dxr3_spu_encoder.c
new file mode 100644
index 000000000..c2cfe64a6
--- /dev/null
+++ b/src/dxr3/dxr3_spu_encoder.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) 2000-2002 the xine project
+ *
+ * This file is part of xine, a free video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: dxr3_spu_encoder.c,v 1.1 2002/08/17 14:30:10 mroi Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <float.h>
+
+#include "video_out_dxr3.h"
+
+/* We use the following algorithm to reduce the given overlay palette
+ * to a spu palette with only four distinct colours:
+ * - create a histogram on the overlay palette
+ * - the color with the maximum histogram value becomes one spu color
+ * - modify the histogram so that the counts for colors very near to the
+ * chosen one are lowered; this is done by multiplying with a penalty
+ * function 1-1/(dist/DIST_COEFF + 1) where dist is the squared spatial
+ * distance between current color and chosen spu color
+ * - continue with the next maximum
+ * The used histogram modification function from above looks like that:
+ * ^
+ * 1 + ********
+ * | ******
+ * | ****
+ * | **
+ * | *
+ * 0 **--------------------> dist
+ */
+#define DIST_COEFF 1024.0
+
+#define LOG_ENC 1
+
+/* spu encoder function */
+spu_encoder_t *dxr3_spu_encoder_init(void);
+void dxr3_spu_encode(spu_encoder_t *this);
+
+/* helper functions */
+static void convert_palette(spu_encoder_t *this);
+static void create_histogram(spu_encoder_t *this);
+static void generate_clut(spu_encoder_t *this);
+static void map_colors(spu_encoder_t *this);
+static void convert_clut(spu_encoder_t *this);
+static void convert_overlay(spu_encoder_t *this);
+static void write_rle(spu_encoder_t *this, int *offset, int *higher_nibble, int length, int color);
+static void write_byte(spu_encoder_t *this, int *offset, uint8_t byte);
+static void write_nibble(spu_encoder_t *this, int *offset, int *higher_nibble, uint8_t nibble);
+
+
+spu_encoder_t *dxr3_spu_encoder_init(void)
+{
+ spu_encoder_t *this;
+
+ this = (spu_encoder_t *)malloc(sizeof(spu_encoder_t));
+ this->target = NULL;
+ this->need_reencode = 0;
+ this->malloc_size = 0;
+#if LOG_ENC
+ printf("dxr3_spu_encoder: initialized\n");
+#endif
+ return this;
+}
+
+void dxr3_spu_encode(spu_encoder_t *this)
+{
+ if (!this->need_reencode || !this->overlay) return;
+#if LOG_ENC
+ printf("dxr3_spu_encoder: overlay for encoding arrived.\n");
+#endif
+ convert_palette(this);
+ create_histogram(this);
+ generate_clut(this);
+ map_colors(this);
+ convert_clut(this);
+ convert_overlay(this);
+#if LOG_ENC
+ printf("dxr3_spu_encoder: overlay encoding completed\n");
+#endif
+}
+
+
+static void convert_palette(spu_encoder_t *this)
+{
+ int i, y, cb, cr, r, g, b;
+
+ if (!this->overlay->rgb_clut) {
+ for (i = 0; i < OVL_PALETTE_SIZE; i++) {
+ y = (this->overlay->color[i] >> 16) & 0xff;
+ cr = (this->overlay->color[i] >> 8) & 0xff;
+ cb = (this->overlay->color[i] ) & 0xff;
+ r = 1.164 * y + 1.596 * (cr - 128);
+ g = 1.164 * y - 0.813 * (cr - 128) - 0.392 * (cb - 128);
+ b = 1.164 * y + 2.017 * (cb - 128);
+ if (r < 0) r = 0;
+ if (g < 0) g = 0;
+ if (b < 0) b = 0;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ this->overlay->color[i] = (r << 16) | (g << 8) | b;
+ }
+ this->overlay->rgb_clut = 1;
+ }
+ if (!this->overlay->clip_rgb_clut) {
+ for (i = 0; i < OVL_PALETTE_SIZE; i++) {
+ y = (this->overlay->clip_color[i] >> 16) & 0xff;
+ cr = (this->overlay->clip_color[i] >> 8) & 0xff;
+ cb = (this->overlay->clip_color[i] ) & 0xff;
+ r = 1.164 * y + 1.596 * (cr - 128);
+ g = 1.164 * y - 0.813 * (cr - 128) - 0.392 * (cb - 128);
+ b = 1.164 * y + 2.017 * (cb - 128);
+ if (r < 0) r = 0;
+ if (g < 0) g = 0;
+ if (b < 0) b = 0;
+ if (r > 0xff) r = 0xff;
+ if (g > 0xff) g = 0xff;
+ if (b > 0xff) b = 0xff;
+ this->overlay->clip_color[i] = (r << 16) | (g << 8) | b;
+ }
+ this->overlay->clip_rgb_clut = 1;
+ }
+}
+
+static void create_histogram(spu_encoder_t *this)
+{
+ rle_elem_t *rle;
+ int i, x, y, len, part;
+
+ for (i = 0; i < OVL_PALETTE_SIZE; i++)
+ this->map[i] = this->clip_map[i] = 0;
+ x = y = 0;
+ for (i = 0, rle = this->overlay->rle; i < this->overlay->num_rle; i++, rle++) {
+ len = rle->len;
+ if (y >= this->overlay->clip_top && y < this->overlay->clip_bottom) {
+ if (x < this->overlay->clip_left) {
+ part = (this->overlay->clip_left - x < len) ? (this->overlay->clip_left - x) : len;
+ this->map[rle->color] += part;
+ len -= part;
+ x += part;
+ }
+ if (x >= this->overlay->clip_left && x < this->overlay->clip_right) {
+ part = (this->overlay->clip_right - x < len) ? (this->overlay->clip_right - x) : len;
+ this->clip_map[rle->color] += part;
+ len -= part;
+ x += part;
+ }
+ }
+ this->map[rle->color] += len;
+ x += len;
+ if (x >= this->overlay->width) {
+ x = 0;
+ y++;
+ }
+ }
+#if LOG_ENC
+ for (i = 0; i < OVL_PALETTE_SIZE; i++)
+ if (this->map[i])
+ printf("dxr3_spu_encoder: histogram: color #%d 0x%.8x appears %d times\n",
+ i, this->overlay->color[i], this->map[i]);
+ for (i = 0; i < OVL_PALETTE_SIZE; i++)
+ if (this->clip_map[i])
+ printf("dxr3_spu_encoder: histogram: clip color #%d 0x%.8x appears %d times\n",
+ i, this->overlay->clip_color[i], this->clip_map[i]);
+#endif
+}
+
+static void generate_clut(spu_encoder_t *this)
+{
+ int i, max, spu_color;
+ double dist, diff;
+
+ /* find first maximum -> first spu color */
+ max = 0;
+ for (i = 1; i < OVL_PALETTE_SIZE; i++)
+ if (this->map[i] > this->map[max]) max = i;
+ this->color[0] = this->overlay->color[max];
+ this->trans[0] = this->overlay->trans[max];
+
+ for (spu_color = 1; spu_color < 4; spu_color++) {
+ /* modify histogram and find next maximum -> next spu color */
+ max = 0;
+ for (i = 0; i < OVL_PALETTE_SIZE; i++) {
+ /* subtract a correction based on the distance to the last spu color */
+ diff = ((this->overlay->color[i] ) & 0xff) - ((this->color[spu_color - 1] ) & 0xff);
+ dist = diff * diff;
+ diff = ((this->overlay->color[i] >> 8) & 0xff) - ((this->color[spu_color - 1] >> 8) & 0xff);
+ dist += diff * diff;
+ diff = ((this->overlay->color[i] >> 16) & 0xff) - ((this->color[spu_color - 1] >> 16) & 0xff);
+ dist += diff * diff;
+ diff = ((this->overlay->trans[i] ) ) - ((this->trans[spu_color - 1] ) );
+ dist += diff * diff;
+ this->map[i] *= 1 - 1.0 / (dist / DIST_COEFF + 1.0);
+ if (this->map[i] > this->map[max]) max = i;
+ }
+ this->color[spu_color] = this->overlay->color[max];
+ this->trans[spu_color] = this->overlay->trans[max];
+ }
+#if LOG_ENC
+ for (spu_color = 0; spu_color < 4; spu_color++)
+ printf("dxr3_spu_encoder: spu color %d: 0x%.8x, trans: %d\n", spu_color,
+ this->color[spu_color], this->trans[spu_color]);
+#endif
+
+ /* now the same stuff again, this time for the palette of the clipping area */
+
+ /* find first maximum -> first spu color */
+ max = 0;
+ for (i = 1; i < OVL_PALETTE_SIZE; i++)
+ if (this->clip_map[i] > this->clip_map[max]) max = i;
+ this->clip_color[0] = this->overlay->clip_color[max];
+ this->clip_trans[0] = this->overlay->clip_trans[max];
+
+ for (spu_color = 1; spu_color < 4; spu_color++) {
+ /* modify histogram and find next maximum -> next spu color */
+ max = 0;
+ for (i = 0; i < OVL_PALETTE_SIZE; i++) {
+ /* subtract a correction based on the distance to the last spu color */
+ diff = ((this->overlay->clip_color[i] ) & 0xff) - ((this->clip_color[spu_color - 1] ) & 0xff);
+ dist = diff * diff;
+ diff = ((this->overlay->clip_color[i] >> 8) & 0xff) - ((this->clip_color[spu_color - 1] >> 8) & 0xff);
+ dist += diff * diff;
+ diff = ((this->overlay->clip_color[i] >> 16) & 0xff) - ((this->clip_color[spu_color - 1] >> 16) & 0xff);
+ dist += diff * diff;
+ diff = ((this->overlay->clip_trans[i] ) ) - ((this->clip_trans[spu_color - 1] ) );
+ dist += diff * diff;
+ this->clip_map[i] *= 1 - 1.0 / (dist / DIST_COEFF + 1.0);
+ if (this->clip_map[i] > this->clip_map[max]) max = i;
+ }
+ this->clip_color[spu_color] = this->overlay->clip_color[max];
+ this->clip_trans[spu_color] = this->overlay->clip_trans[max];
+ }
+#if LOG_ENC
+ for (spu_color = 0; spu_color < 4; spu_color++)
+ printf("dxr3_spu_encoder: spu clip color %d: 0x%.8x, trans: %d\n", spu_color,
+ this->clip_color[spu_color], this->clip_trans[spu_color]);
+#endif
+}
+
+static void map_colors(spu_encoder_t *this)
+{
+ int i, min, spu_color;
+ double dist, diff, min_dist;
+
+ /* for all colors in overlay palette find closest spu color */
+ for (i = 0; i < OVL_PALETTE_SIZE; i++) {
+ min = 0;
+ min_dist = DBL_MAX;
+ for (spu_color = 0; spu_color < 4; spu_color++) {
+ diff = ((this->overlay->color[i] ) & 0xff) - ((this->color[spu_color] ) & 0xff);
+ dist = diff * diff;
+ diff = ((this->overlay->color[i] >> 8) & 0xff) - ((this->color[spu_color] >> 8) & 0xff);
+ dist += diff * diff;
+ diff = ((this->overlay->color[i] >> 16) & 0xff) - ((this->color[spu_color] >> 16) & 0xff);
+ dist += diff * diff;
+ diff = ((this->overlay->trans[i] ) ) - ((this->trans[spu_color] ) );
+ dist += diff * diff;
+ if (dist < min_dist) {
+ min_dist = dist;
+ min = spu_color;
+ }
+ }
+ this->map[i] = min;
+ }
+
+ /* for all colors in overlay clip palette find closest spu color */
+ for (i = 0; i < OVL_PALETTE_SIZE; i++) {
+ min = 0;
+ min_dist = DBL_MAX;
+ for (spu_color = 0; spu_color < 4; spu_color++) {
+ diff = ((this->overlay->clip_color[i] ) & 0xff) - ((this->clip_color[spu_color] ) & 0xff);
+ dist = diff * diff;
+ diff = ((this->overlay->clip_color[i] >> 8) & 0xff) - ((this->clip_color[spu_color] >> 8) & 0xff);
+ dist += diff * diff;
+ diff = ((this->overlay->clip_color[i] >> 16) & 0xff) - ((this->clip_color[spu_color] >> 16) & 0xff);
+ dist += diff * diff;
+ diff = ((this->overlay->clip_trans[i] ) ) - ((this->clip_trans[spu_color] ) );
+ dist += diff * diff;
+ if (dist < min_dist) {
+ min_dist = dist;
+ min = spu_color;
+ }
+ }
+ this->clip_map[i] = min;
+ }
+}
+
+static void convert_clut(spu_encoder_t *this)
+{
+ int i, r, g, b, y, cb, cr;
+
+ for (i = 0; i < 4; i++) {
+ r = (this->color[i] >> 16) & 0xff;
+ g = (this->color[i] >> 8) & 0xff;
+ b = (this->color[i] ) & 0xff;
+ y = 0.257 * r + 0.504 * g + 0.098 * b;
+ cr = 0.439 * r - 0.368 * g - 0.071 * b + 128;
+ cb = -0.148 * r - 0.291 * g + 0.439 * b + 128;
+ this->color[i] = (y << 16) | (cr << 8) | cb;
+ }
+ for (i = 4; i < 16; i++)
+ this->color[i] = 0x00008080;
+
+ for (i = 0; i < 4; i++) {
+ r = (this->clip_color[i] >> 16) & 0xff;
+ g = (this->clip_color[i] >> 8) & 0xff;
+ b = (this->clip_color[i] ) & 0xff;
+ y = 0.257 * r + 0.504 * g + 0.098 * b;
+ cr = 0.439 * r - 0.368 * g - 0.071 * b + 128;
+ cb = -0.148 * r - 0.291 * g + 0.439 * b + 128;
+ this->clip_color[i] = (y << 16) | (cr << 8) | cb;
+ }
+ for (i = 4; i < 16; i++)
+ this->clip_color[i] = 0x00008080;
+}
+
+static void convert_overlay(spu_encoder_t *this)
+{
+ int offset = 0, field_start[2];
+ rle_elem_t *rle;
+ int field, i, len, part, x, y, higher_nibble = 1;
+
+ /* size will be determined later */
+ write_byte(this, &offset, 0x00);
+ write_byte(this, &offset, 0x00);
+
+ /* control sequence pointer will be determined later */
+ write_byte(this, &offset, 0x00);
+ write_byte(this, &offset, 0x00);
+
+ for (field = 0; field < 2; field++) {
+ write_byte(this, &offset, 0x00);
+ write_byte(this, &offset, 0x00);
+#if LOG_ENC
+ printf("dxr3_spu_encoder: encoding field %d\n", field);
+#endif
+ field_start[field] = offset;
+ x = y = 0;
+ for (i = 0, rle = this->overlay->rle; i < this->overlay->num_rle; i++, rle++) {
+ len = rle->len;
+ if ((y & 1) == field) {
+ if (y >= this->overlay->clip_top && y < this->overlay->clip_bottom) {
+ if (x < this->overlay->clip_left) {
+ part = (this->overlay->clip_left - x < len) ? (this->overlay->clip_left - x) : len;
+ write_rle(this, &offset, &higher_nibble, part, this->map[rle->color]);
+ len -= part;
+ x += part;
+ }
+ if (x >= this->overlay->clip_left && x < this->overlay->clip_right) {
+ part = (this->overlay->clip_right - x < len) ? (this->overlay->clip_right - x) : len;
+ write_rle(this, &offset, &higher_nibble, part, this->clip_map[rle->color]);
+ len -= part;
+ x += part;
+ }
+ }
+ write_rle(this, &offset, &higher_nibble, len, this->map[rle->color]);
+ }
+ x += len;
+ if (x >= this->overlay->width) {
+ if ((y & 1) == field && !higher_nibble)
+ write_nibble(this, &offset, &higher_nibble, 0);
+ x = 0;
+ y++;
+ }
+ }
+ }
+
+ /* we should be byte aligned here */
+ assert(higher_nibble);
+
+ /* control sequence starts here */
+ this->target[2] = offset >> 8;
+ this->target[3] = offset & 0xff;
+ write_byte(this, &offset, 0x00);
+ write_byte(this, &offset, 0x00);
+ /* write pointer to end sequence */
+ write_byte(this, &offset, this->target[2]);
+ write_byte(this, &offset, this->target[3]);
+ /* write control sequence */
+ write_byte(this, &offset, 0x00);
+ /* clut indices */
+ write_byte(this, &offset, 0x03);
+ write_byte(this, &offset, 0x32);
+ write_byte(this, &offset, 0x10);
+ /* alpha information */
+ write_byte(this, &offset, 0x04);
+ write_nibble(this, &offset, &higher_nibble, this->trans[3] & 0xf);
+ write_nibble(this, &offset, &higher_nibble, this->trans[2] & 0xf);
+ write_nibble(this, &offset, &higher_nibble, this->trans[1] & 0xf);
+ write_nibble(this, &offset, &higher_nibble, this->trans[0] & 0xf);
+ /* on screen position */
+#if LOG_ENC
+ printf("dxr3_spu_encoder: overlay position: x %d, y %d, width %d, height %d\n",
+ this->overlay->x, this->overlay->y, this->overlay->width, this->overlay->height);
+#endif
+ write_byte(this, &offset, 0x05);
+ write_byte(this, &offset, this->overlay->x >> 4);
+ write_nibble(this, &offset, &higher_nibble, this->overlay->x & 0xf);
+ write_nibble(this, &offset, &higher_nibble, (this->overlay->x + this->overlay->width - 1) >> 8);
+ write_byte(this, &offset, (this->overlay->x + this->overlay->width - 1) & 0xff);
+ write_byte(this, &offset, this->overlay->y >> 4);
+ write_nibble(this, &offset, &higher_nibble, this->overlay->y & 0xf);
+ write_nibble(this, &offset, &higher_nibble, (this->overlay->y + this->overlay->height - 1) >> 8);
+ write_byte(this, &offset, (this->overlay->y + this->overlay->height - 1) & 0xff);
+ /* field pointers */
+ write_byte(this, &offset, 0x06);
+ write_byte(this, &offset, field_start[0] >> 8);
+ write_byte(this, &offset, field_start[0] & 0xff);
+ write_byte(this, &offset, field_start[1] >> 8);
+ write_byte(this, &offset, field_start[1] & 0xff);
+ /* end marker */
+ write_byte(this, &offset, 0xff);
+ if (offset & 1)
+ write_byte(this, &offset, 0xff);
+ /* write size information */
+ this->size = offset;
+ this->target[0] = offset >> 8;
+ this->target[1] = offset & 0xff;
+}
+
+static void write_rle(spu_encoder_t *this, int *offset, int *higher_nibble, int length, int color)
+{
+ if (!length) return;
+ length <<= 2;
+ while (length > 0x03fc) {
+ write_nibble(this, offset, higher_nibble, 0x0);
+ write_nibble(this, offset, higher_nibble, 0x3);
+ write_nibble(this, offset, higher_nibble, 0xf);
+ write_nibble(this, offset, higher_nibble, 0xc | color);
+ length -= 0x03fc;
+ }
+ if ((length & ~0xc) == 0) {
+ write_nibble(this, offset, higher_nibble, length | color);
+ return;
+ }
+ if ((length & ~0x3c) == 0) {
+ write_nibble(this, offset, higher_nibble, length >> 4);
+ write_nibble(this, offset, higher_nibble, (length & 0xc) | color);
+ return;
+ }
+ if ((length & ~0xfc) == 0) {
+ write_nibble(this, offset, higher_nibble, 0x0);
+ write_nibble(this, offset, higher_nibble, length >> 4);
+ write_nibble(this, offset, higher_nibble, (length & 0xc) | color);
+ return;
+ }
+ if ((length & ~0x3fc) == 0) {
+ write_nibble(this, offset, higher_nibble, 0x0);
+ write_nibble(this, offset, higher_nibble, length >> 8);
+ write_nibble(this, offset, higher_nibble, (length >> 4) & 0xf);
+ write_nibble(this, offset, higher_nibble, (length & 0xc) | color);
+ return;
+ }
+ assert(0);
+}
+
+static void write_byte(spu_encoder_t *this, int *offset, uint8_t byte)
+{
+ if (*offset >= this->malloc_size)
+ this->target = realloc(this->target, this->malloc_size += 2048);
+ this->target[(*offset)++] = byte;
+}
+
+static void write_nibble(spu_encoder_t *this, int *offset, int *higher_nibble, uint8_t nibble)
+{
+ if (*offset >= this->malloc_size)
+ this->target = realloc(this->target, this->malloc_size += 2048);
+ if (*higher_nibble) {
+ this->target[*offset] &= 0x0f;
+ this->target[*offset] |= nibble << 4;
+ *higher_nibble = 0;
+ } else {
+ this->target[*offset] &= 0xf0;
+ this->target[(*offset)++] |= nibble;
+ *higher_nibble = 1;
+ }
+}
diff --git a/src/dxr3/video_out_dxr3.c b/src/dxr3/video_out_dxr3.c
index e5204f0c2..7650eaab4 100644
--- a/src/dxr3/video_out_dxr3.c
+++ b/src/dxr3/video_out_dxr3.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_dxr3.c,v 1.50 2002/08/15 13:35:12 mroi Exp $
+ * $Id: video_out_dxr3.c,v 1.51 2002/08/17 14:30:10 mroi Exp $
*/
/* mpeg1 encoding video out plugin for the dxr3.
@@ -79,8 +79,10 @@ static void dxr3_frame_dispose(vo_frame_t *frame_gen);
static void dxr3_update_frame_format(vo_driver_t *this_gen, vo_frame_t *frame_gen,
uint32_t width, uint32_t height,
int ratio_code, int format, int flags);
+static void dxr3_overlay_begin(vo_driver_t *this_gen, vo_frame_t *frame_gen, int changed);
static void dxr3_overlay_blend(vo_driver_t *this_gen, vo_frame_t *frame_gen,
vo_overlay_t *overlay);
+static void dxr3_overlay_end(vo_driver_t *this_gen, vo_frame_t *frame_gen);
static void dxr3_display_frame(vo_driver_t *this_gen, vo_frame_t *frame_gen);
static int dxr3_redraw_needed(vo_driver_t *this_gen);
static int dxr3_get_property(vo_driver_t *this_gen, int property);
@@ -145,9 +147,9 @@ vo_driver_t *init_video_out_plugin(config_values_t *config, void *visual_gen)
this->vo_driver.get_capabilities = dxr3_get_capabilities;
this->vo_driver.alloc_frame = dxr3_alloc_frame;
this->vo_driver.update_frame_format = dxr3_update_frame_format;
- this->vo_driver.overlay_begin = NULL; /* not used */
+ this->vo_driver.overlay_begin = dxr3_overlay_begin;
this->vo_driver.overlay_blend = dxr3_overlay_blend;
- this->vo_driver.overlay_end = NULL; /* not used */
+ this->vo_driver.overlay_end = dxr3_overlay_end;
this->vo_driver.display_frame = dxr3_display_frame;
this->vo_driver.redraw_needed = dxr3_redraw_needed;
this->vo_driver.get_property = dxr3_get_property;
@@ -156,6 +158,8 @@ vo_driver_t *init_video_out_plugin(config_values_t *config, void *visual_gen)
this->vo_driver.gui_data_exchange = dxr3_gui_data_exchange;
this->vo_driver.exit = dxr3_exit;
+ pthread_mutex_init(&this->spu_device_lock, NULL);
+
this->config = config;
this->swap_fields = config->register_bool(config,
"dxr3.enc_swap_fields", 0, _("swap odd and even lines"),
@@ -610,11 +614,27 @@ static void dxr3_update_frame_format(vo_driver_t *this_gen, vo_frame_t *frame_ge
frame->swap_fields = this->swap_fields;
}
+static void dxr3_overlay_begin(vo_driver_t *this_gen, vo_frame_t *frame_gen, int changed)
+{
+ dxr3_driver_t *this = (dxr3_driver_t *)this_gen;
+
+ /* special treatment is only necessary for mpeg frames */
+ if (frame_gen->format != IMGFMT_MPEG) return;
+
+ if (!this->spu_enc) this->spu_enc = dxr3_spu_encoder_init();
+
+ if (!changed) {
+ this->spu_enc->need_reencode = 0;
+ return;
+ }
+
+ this->spu_enc->need_reencode = 1;
+ this->spu_enc->overlay = NULL;
+}
+
static void dxr3_overlay_blend(vo_driver_t *this_gen, vo_frame_t *frame_gen,
vo_overlay_t *overlay)
{
- /* FIXME: We only blend non-mpeg frames here.
- Is there any way to provide overlays for mpeg content? Subpictures? */
if (frame_gen->format != IMGFMT_MPEG) {
dxr3_frame_t *frame = (dxr3_frame_t *)frame_gen;
@@ -624,7 +644,86 @@ static void dxr3_overlay_blend(vo_driver_t *this_gen, vo_frame_t *frame_gen,
else
blend_yuy2(frame->vo_frame.base[0], overlay, frame->vo_frame.width, frame->vo_frame.height);
}
+ } else { /* IMGFMT_MPEG */
+ dxr3_driver_t *this = (dxr3_driver_t *)this_gen;
+ if (!this->spu_enc->need_reencode) return;
+ /* FIXME: we only handle the last overlay because previous ones are simply overwritten */
+ this->spu_enc->overlay = overlay;
+ }
+}
+
+static void dxr3_overlay_end(vo_driver_t *this_gen, vo_frame_t *frame_gen)
+{
+ dxr3_driver_t *this = (dxr3_driver_t *)this_gen;
+ em8300_button_t btn;
+ char tmpstr[128];
+ ssize_t written;
+
+ if (frame_gen->format != IMGFMT_MPEG) return;
+ if (!this->spu_enc->need_reencode) return;
+
+ dxr3_spu_encode(this->spu_enc);
+
+ /* try to open the dxr3 spu device */
+ if (!this->fd_spu) {
+ snprintf (tmpstr, sizeof(tmpstr), "%s_sp%s", this->devname, this->devnum);
+ if ((this->fd_spu = open (tmpstr, O_WRONLY)) < 0) {
+ printf("video_out_dxr3: Failed to open spu device %s (%s)\n",
+ tmpstr, strerror(errno));
+ printf("video_out_dxr3: Overlays are not available\n");
+ return;
+ }
+ }
+
+ pthread_mutex_lock(&this->spu_device_lock);
+
+ if (!this->spu_enc->overlay) {
+ uint8_t empty_spu[] = {
+ 0x00, 0x26, 0x00, 0x08, 0x80, 0x00, 0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x20, 0x01, 0x03, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x05, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x01, 0x06, 0x00, 0x04, 0x00, 0x07, 0xFF,
+ 0x00, 0x01, 0x00, 0x20, 0x02, 0xFF };
+ /* just clear any previous spu */
+ ioctl(this->fd_spu, EM8300_IOCTL_SPU_BUTTON, NULL);
+ write(this->fd_spu, empty_spu, sizeof(empty_spu));
+ pthread_mutex_unlock(&this->spu_device_lock);
+ return;
}
+
+ /* copy clip palette */
+ this->spu_enc->color[4] = this->spu_enc->clip_color[0];
+ this->spu_enc->color[5] = this->spu_enc->clip_color[1];
+ this->spu_enc->color[6] = this->spu_enc->clip_color[2];
+ this->spu_enc->color[7] = this->spu_enc->clip_color[3];
+ /* set palette */
+ if (ioctl(this->fd_spu, EM8300_IOCTL_SPU_SETPALETTE, this->spu_enc->color))
+ printf("video_out_dxr3: failed to set CLUT (%s)\n", strerror(errno));
+ this->clut_cluttered = 1;
+ /* write spu */
+ written = write(this->fd_spu, this->spu_enc->target, this->spu_enc->size);
+ if (written < 0)
+ printf("video_out_dxr3: spu device write failed (%s)\n",
+ strerror(errno));
+ else if (written != this->spu_enc->size)
+ printf("video_out_dxr3: Could only write %d of %d spu bytes.\n",
+ written, this->spu_enc->size);
+ /* set clipping */
+ btn.color = 0x7654;
+ btn.contrast =
+ ((this->spu_enc->clip_trans[3] << 12) & 0xf000) |
+ ((this->spu_enc->clip_trans[2] << 8) & 0x0f00) |
+ ((this->spu_enc->clip_trans[1] << 4) & 0x00f0) |
+ ((this->spu_enc->clip_trans[0] ) & 0x000f);
+ btn.left = this->spu_enc->overlay->x + this->spu_enc->overlay->clip_left;
+ btn.right = this->spu_enc->overlay->x + this->spu_enc->overlay->clip_right - 1;
+ btn.top = this->spu_enc->overlay->y + this->spu_enc->overlay->clip_top;
+ btn.bottom = this->spu_enc->overlay->y + this->spu_enc->overlay->clip_bottom - 2;
+ if (ioctl(this->fd_spu, EM8300_IOCTL_SPU_BUTTON, &btn))
+ printf("dxr3_decode_spu: failed to set spu button (%s)\n",
+ strerror(errno));
+
+ pthread_mutex_unlock(&this->spu_device_lock);
}
static void dxr3_display_frame(vo_driver_t *this_gen, vo_frame_t *frame_gen)
@@ -902,7 +1001,9 @@ static void dxr3_exit(vo_driver_t *this_gen)
this->enc->on_close(this);
if(this->overlay_enabled)
ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SETMODE, &val);
-
+ close(this->fd_control);
+ if (this->fd_spu) close(this->fd_spu);
+ pthread_mutex_destroy(&this->spu_device_lock);
free(this);
}
diff --git a/src/dxr3/video_out_dxr3.h b/src/dxr3/video_out_dxr3.h
index d930363a5..ae6e7f6a1 100644
--- a/src/dxr3/video_out_dxr3.h
+++ b/src/dxr3/video_out_dxr3.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_dxr3.h,v 1.8 2002/08/11 13:22:55 mroi Exp $
+ * $Id: video_out_dxr3.h,v 1.9 2002/08/17 14:30:10 mroi Exp $
*/
#ifdef HAVE_CONFIG_H
@@ -41,6 +41,7 @@
/* plugin structures */
typedef struct encoder_data_s encoder_data_t;
+typedef struct spu_encoder_s spu_encoder_t;
typedef enum { ENC_FAME, ENC_RTE } encoder_type;
@@ -74,7 +75,10 @@ typedef struct dxr3_driver_s {
char devname[128];
char devnum[3];
int fd_control;
- int fd_video; /* to access the relevant dxr3 devices */
+ int fd_video;
+ pthread_mutex_t spu_device_lock;
+ int fd_spu; /* to access the relevant dxr3 devices */
+ int clut_cluttered;/* to tell spu decoder that it has to restore the palette */
int enhanced_mode;
int swap_fields; /* swap fields */
@@ -88,7 +92,8 @@ typedef struct dxr3_driver_s {
int widescreen_enabled;
em8300_bcs_t bcs;
- encoder_data_t *enc; /* encoder data */
+ encoder_data_t *enc; /* mpeg encoder data */
+ spu_encoder_t *spu_enc; /* spu encoder */
int video_iheight; /* input height (before adding black bars) */
int video_oheight; /* output height (after adding bars) */
int video_width;
@@ -133,10 +138,28 @@ struct encoder_data_s {
int (*on_close)(dxr3_driver_t *);
};
-/* encoder plugins initialization functions */
+struct spu_encoder_s {
+ vo_overlay_t *overlay;
+ int need_reencode;
+ uint8_t *target;
+ int size;
+ int malloc_size;
+ uint32_t color[16];
+ uint8_t trans[4];
+ int map[OVL_PALETTE_SIZE];
+ uint32_t clip_color[16];
+ uint8_t clip_trans[4];
+ int clip_map[OVL_PALETTE_SIZE];
+};
+
+/* mpeg encoder plugins initialization functions */
#ifdef HAVE_LIBRTE
int dxr3_rte_init(dxr3_driver_t *);
#endif
#ifdef HAVE_LIBFAME
int dxr3_fame_init(dxr3_driver_t *);
#endif
+
+/* spu encoder functions */
+spu_encoder_t *dxr3_spu_encoder_init(void);
+void dxr3_spu_encode(spu_encoder_t *);