summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHarm van der Heijden <hrm@users.sourceforge.net>2001-12-23 02:36:54 +0000
committerHarm van der Heijden <hrm@users.sourceforge.net>2001-12-23 02:36:54 +0000
commit8b7b18f012709ff905c5664d2ec2695cae5b3e9e (patch)
tree724ef7ec89c30692bdc3138b1ccac9a448fb52dc /src
parente1627a68149cd386acee5ed28356ae03fe814da3 (diff)
downloadxine-lib-8b7b18f012709ff905c5664d2ec2695cae5b3e9e.tar.gz
xine-lib-8b7b18f012709ff905c5664d2ec2695cae5b3e9e.tar.bz2
lots of dxr3 tweaks and fixes
- mpeg playback optionally syncs (SETPTS) every frame; works only for constant frame duration (PAL movie) not most NTSC movies. metronom doesn't seem to dig varying durations, gives pts values that upset the dxr3 hardware. - detect repeat first field in mpeg, disable sync every frame if found. - small dxr3 encoder fixes - moved fame encoding from copy to display method; should help with frame skip. - added callback functions for some config/dxr3* variables (those callbacks are cool BTW; only wish the xine-ui setup screen would show which vars have callbacks) - added Dan Hollis field swapping trick; not sure if it really does what he wants; I don't have an NTSC tv, so his 720x480 test video will look interlaced no matter what. - merry xmas CVS patchset: 1287 CVS date: 2001/12/23 02:36:54
Diffstat (limited to 'src')
-rw-r--r--src/dxr3/dxr3_decoder.c230
-rw-r--r--src/dxr3/dxr3_video_out.c87
-rw-r--r--src/dxr3/dxr3_video_out.h8
-rw-r--r--src/dxr3/dxr3_vo_core.c64
-rw-r--r--src/dxr3/mpeg_encoders.c74
5 files changed, 333 insertions, 130 deletions
diff --git a/src/dxr3/dxr3_decoder.c b/src/dxr3/dxr3_decoder.c
index 5997c1196..023140bfb 100644
--- a/src/dxr3/dxr3_decoder.c
+++ b/src/dxr3/dxr3_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: dxr3_decoder.c,v 1.47 2001/12/19 01:53:43 hrm Exp $
+ * $Id: dxr3_decoder.c,v 1.48 2001/12/23 02:36:54 hrm Exp $
*
* dxr3 video and spu decoder plugin. Accepts the video and spu data
* from XINE and sends it directly to the corresponding dxr3 devices.
@@ -45,6 +45,10 @@
* get a lot of "throwing away frame..." messages, especially just
* after start/seek, but those are relatively harmless. (I guess we
* call img->draw a tad too often).
+ *
+ * update 21/12/01 by Harm
+ * many revisions, but I've been too lazy to document them here.
+ * read the cvs log, that's what it's for anyways.
*/
@@ -72,7 +76,8 @@
#define DEFAULT_DEV "/dev/em8300"
static char *devname;
-#define METRONOM_HACK 0
+/* lots of poohaa about pts things */
+#define LOG_PTS 0
#define MV_COMMAND 0
#define MV_STATUS 1
@@ -94,7 +99,13 @@ typedef struct dxr3_decoder_s {
int width;
int height;
int aspect;
- int duration;
+ int frame_rate_code;
+ int repeat_first_field;
+ /* try to sync PTS every frame. will be disabled if non-progessive
+ video is detected via repeat first field */
+ int sync_every_frame;
+ /* if disabled by repeat first field, retry after 500 frames */
+ int sync_retry;
int enhanced_mode;
int have_header_info;
int in_buffer_fill;
@@ -230,14 +241,14 @@ static int dxr3scr_set_speed (scr_plugin_t *scr, int speed) {
Adjusts the SCR value of the card to match that given.
This function is only called if the dxr3 SCR plugin is
_NOT_ master...
+ Harm: wish that were so. It's called by audio_out
+ (those adjusting master clock x->y messages)
*/
static void dxr3scr_adjust (scr_plugin_t *scr, uint32_t vpts) {
dxr3scr_t *self = (dxr3scr_t*) scr;
vpts >>= 1;
-
if (ioctl(self->fd_control, EM8300_IOCTL_SCR_SET, &vpts))
printf("dxr3scr: adjust failed (%s)\n", strerror(errno));
-
}
/* *** dxr3scr_start ***
@@ -314,18 +325,10 @@ static int dxr3_can_handle (video_decoder_t *this_gen, int buf_type)
static void dxr3_init (video_decoder_t *this_gen, vo_instance_t *video_out)
{
dxr3_decoder_t *this = (dxr3_decoder_t *) this_gen;
- char tmpstr[100];
printf("dxr3: Entering video init, devname=%s.\n",devname);
-
- /* open video device */
- snprintf (tmpstr, sizeof(tmpstr), "%s_mv", devname);
- if ((this->fd_video = open (tmpstr, O_WRONLY)) < 0) {
- /* printf("dxr3: Failed to open video device %s (%s)\n",
- tmpstr, strerror(errno)); */
- /* it's possible that the dxr3 video out plugin still
- * has it. We try again before writing */
- }
+
+ this->fd_video = -1; /* open later */
if ((this->fd_control = open (devname, O_WRONLY)) < 0) {
printf("dxr3: Failed to open control device %s (%s)\n",
@@ -337,7 +340,6 @@ static void dxr3_init (video_decoder_t *this_gen, vo_instance_t *video_out)
this->video_out = video_out;
this->last_pts = 0;
-
this->scr = dxr3scr_init(this);
this->video_decoder.metronom->register_scr(
this->video_decoder.metronom, this->scr);
@@ -363,7 +365,7 @@ static void dxr3_init (video_decoder_t *this_gen, vo_instance_t *video_out)
static void parse_mpeg_header(dxr3_decoder_t *this, uint8_t * buffer)
{
/* framerate code... needed for metronom */
- int framecode = buffer[HEADER_OFFSET+3] & 15;
+ this->frame_rate_code = buffer[HEADER_OFFSET+3] & 15;
/* grab video resolution and aspect ratio from the stream */
this->height = (buffer[HEADER_OFFSET+0] << 16) |
@@ -372,45 +374,48 @@ static void parse_mpeg_header(dxr3_decoder_t *this, uint8_t * buffer)
this->width = ((this->height >> 12) + 15) & ~15;
this->height = ((this->height & 0xfff) + 15) & ~15;
this->aspect = buffer[HEADER_OFFSET+3] >> 4;
+
+ this->have_header_info = 1;
+}
+static int get_duration(int framecode, int repeat_first_field)
+{
+ int duration;
switch (framecode){
case 1: /* 23.976 */
- this->duration=3913;
+ duration=3913;
break;
case 2: /* 24.000 */
- this->duration=3750;
+ duration=3750;
break;
case 3: /* 25.000 */
- this->duration=3600;
+ duration=repeat_first_field ? 5400 : 3600;
+ /*duration=3600;*/
break;
case 4: /* 29.970 */
- this->duration=3003;
+ duration=repeat_first_field ? 3754 : 3003;
+ /*duration=3003;*/
break;
case 5: /* 30.000 */
- this->duration=3000;
+ duration=3000;
break;
case 6: /* 50.000 */
- this->duration=1800;
+ duration=1800;
break;
case 7: /* 59.940 */
- this->duration=1525;
+ duration=1525;
break;
case 8: /* 60.000 */
- this->duration=1509;
+ duration=1509;
break;
default:
- /* only print this warning once */
- if (this->duration != 3600) {
- printf("dxr3: warning: unknown frame rate code %d: using PAL\n", framecode);
- }
- this->duration=3600; /* PAL 25fps */
+ printf("dxr3: warning: unknown frame rate code %d: using PAL\n", framecode);
+ duration=3600; /* PAL 25fps */
break;
}
-
- this->have_header_info = 1;
+ return duration;
}
-
/* *** dxr3_flush ***
flush the dxr3's onboard buffers - but I'm not sure that this is
doing that - more testing is required.
@@ -430,7 +435,7 @@ static void dxr3_decode_data (video_decoder_t *this_gen, buf_element_t *buf)
{
dxr3_decoder_t *this = (dxr3_decoder_t *) this_gen;
ssize_t written;
- int vpts, i;
+ int vpts, i, duration, skip;
vo_frame_t *img;
uint8_t *buffer, byte;
uint32_t shift;
@@ -445,6 +450,7 @@ static void dxr3_decode_data (video_decoder_t *this_gen, buf_element_t *buf)
/* FIXME What are we supposed to do with this? */
if (buf->type == BUF_VIDEO_FILL && this->have_header_info) {
+ duration = get_duration(this->frame_rate_code, 0);
/* printf("dxr3enc: BUF_VIDEO_FILL\n"); */
/* require have_header_info, otherwise width and height
* settings may be random */
@@ -453,13 +459,14 @@ static void dxr3_decode_data (video_decoder_t *this_gen, buf_element_t *buf)
this->height,
this->aspect,
IMGFMT_YV12,
- this->duration,
+ duration,
DXR3_VO_UPDATE_FLAG);
img->PTS=0;
img->bad_frame = 0;
img->draw(img);
vpts = img->PTS;
img->free(img);
+ this->last_pts += duration; /* predict vpts */
return;
}
@@ -485,8 +492,28 @@ static void dxr3_decode_data (video_decoder_t *this_gen, buf_element_t *buf)
parse_mpeg_header(this, buffer);
continue;
}
+ if (byte == 0xb5) {
+ /* extension data */
+ if ((buffer[0] & 0xf0) == 0x80) {
+ /* picture coding extension */
+ this->repeat_first_field = (buffer[3] >> 1) & 1;
+ }
+ /* check if we can keep syncing */
+ if (this->repeat_first_field && this->sync_every_frame) {
+ /* metronom can't handle variable duration */
+ printf("dxr3: non-progressive video detected. "
+ "disabling sync_every_frame.\n");
+ this->sync_every_frame = 0;
+ this->sync_retry = 500; /* see you later */
+ }
+ if (this->repeat_first_field && this->sync_retry) {
+ /* reset counter */
+ this->sync_retry = 500;
+ }
+ continue;
+ }
if (byte != 0x00) {
- /* not a new frame */
+ /* Don't care what it is. It's not a new frame */
continue;
}
/* we have a code for a new frame */
@@ -494,13 +521,15 @@ static void dxr3_decode_data (video_decoder_t *this_gen, buf_element_t *buf)
/* this->width et al may still be undefined */
continue;
}
+ duration = get_duration(this->frame_rate_code,
+ this->repeat_first_field);
/* pretend like we have decoded a frame */
img = this->video_out->get_frame (this->video_out,
this->width,
this->height,
this->aspect,
IMGFMT_YV12,
- this->duration,
+ duration,
DXR3_VO_UPDATE_FLAG);
img->PTS=buf->PTS;
img->bad_frame = 0;
@@ -508,10 +537,28 @@ static void dxr3_decode_data (video_decoder_t *this_gen, buf_element_t *buf)
and stores the return value back in img->PTS
Calling draw with buf->PTS==0 is okay; metronome will
extrapolate a value. */
- img->draw(img);
- vpts = img->PTS; /* copy so we can free img */
- /* store at what time we called draw last */
+ skip = img->draw(img);
+ if (skip <= 0) { /* don't skip */
+ vpts = img->PTS; /* copy so we can free img */
+ }
+ else { /* metronom says skip, so don't set PTS */
+ printf("dxr3: skip = %d\n", skip);
+ vpts = 0;
+ }
img->free(img);
+ this->last_pts += duration; /* predict vpts */
+
+ /* if sync_every_frame was disabled, decrease the counter
+ * for a retry
+ * (it might be due to crappy studio logos and stuff
+ * so we should give the main movie a chance) */
+ if (this->sync_retry) {
+ this->sync_retry--;
+ if (!this->sync_retry) {
+ printf("dxr3: retrying sync_every_frame");
+ this->sync_every_frame = 1;
+ }
+ }
}
@@ -521,7 +568,7 @@ static void dxr3_decode_data (video_decoder_t *this_gen, buf_element_t *buf)
if (this->fd_video < 0) {
char tmpstr[128];
snprintf (tmpstr, sizeof(tmpstr), "%s_mv", devname);
- if ((this->fd_video = open (tmpstr, O_WRONLY)) < 0) {
+ if ((this->fd_video = open (tmpstr, O_WRONLY | O_NONBLOCK)) < 0) {
printf("dxr3: Failed to open video device %s (%s)\n",
tmpstr, strerror(errno));
return;
@@ -530,16 +577,40 @@ static void dxr3_decode_data (video_decoder_t *this_gen, buf_element_t *buf)
/* From time to time, update the pts value
* FIXME: the exact conditions here are a bit uncertain... */
- if (buf->PTS && vpts && this->last_pts < vpts)
+ if (vpts)
{
+ int delay;
+ delay = vpts - this->video_decoder.metronom->get_current_time(
+ this->video_decoder.metronom);
+#if LOG_PTS
+ printf("dxr3: SETPTS got %d expected = %d (delta %d) delay = %d\n",
+ vpts, this->last_pts, vpts-this->last_pts, delay);
+#endif
this->last_pts = vpts;
- /* update the dxr3's current pts value */
- if (this->fd_video >= 0 &&
- ioctl(this->fd_video, EM8300_IOCTL_VIDEO_SETPTS, &vpts)) {
+ /* SETPTS only if less then one second in the future and
+ * either buffer has PTS or sync_every_frame is set */
+ if ((delay > 0) && (delay < 90000) &&
+ (this->sync_every_frame || buf->PTS)) {
+ /* update the dxr3's current pts value */
+ if (ioctl(this->fd_video, EM8300_IOCTL_VIDEO_SETPTS, &vpts))
printf("dxr3: set video pts failed (%s)\n",
- strerror(errno));
+ strerror(errno));
+ }
+ if (delay >= 90000) {
+ /* frame more than 1 sec ahead */
+ printf("dxr3: WARNING: vpts %d is %.02f seconds ahead of time!\n",
+ vpts, delay/90000.0);
+ }
+ if (delay < 0) {
+ printf("dxr3: WARNING: overdue frame.\n");
}
}
+#if LOG_PTS
+ else if (buf->PTS) {
+ printf("dxr3: skip buf->PTS = %d (no vpts) last_vpts = %d\n",
+ buf->PTS, this->last_pts);
+ }
+#endif
/* if the dxr3_alt_play option is used, change the dxr3 playmode */
if(this->enhanced_mode && !scanning_mode)
dxr3_mvcommand(this->fd_control, 6);
@@ -548,8 +619,14 @@ static void dxr3_decode_data (video_decoder_t *this_gen, buf_element_t *buf)
break with open source tradition, check the return value */
written = write(this->fd_video, buf->content, buf->size);
if (written < 0) {
- printf("dxr3: video device write failed (%s)\n",
- strerror(errno));
+ if (errno == EAGAIN) {
+ printf("dxr3: write to device would block. flushing\n");
+ dxr3_flush(this_gen);
+ }
+ else {
+ printf("dxr3: video device write failed (%s)\n",
+ strerror(errno));
+ }
return;
}
if (written != buf->size)
@@ -562,8 +639,10 @@ static void dxr3_close (video_decoder_t *this_gen)
{
dxr3_decoder_t *this = (dxr3_decoder_t *) this_gen;
- this->video_decoder.metronom->unregister_scr(
- this->video_decoder.metronom, this->scr);
+ if (this->scr) {
+ this->video_decoder.metronom->unregister_scr(
+ this->video_decoder.metronom, this->scr);
+ }
if (this->fd_video >= 0)
close(this->fd_video);
@@ -577,6 +656,28 @@ static char *dxr3_get_id(void) {
return "dxr3-mpeg2";
}
+static void dxr3_update_enhanced_mode(void *this_gen, cfg_entry_t *entry)
+{
+ ((dxr3_decoder_t*)this_gen)->enhanced_mode = entry->num_value;
+ printf("dxr3: mpeg playback: set enhanced mode to %s\n",
+ (entry->num_value ? "on" : "off"));
+}
+
+static void dxr3_update_sync_mode(void *this_gen, cfg_entry_t *entry)
+{
+ ((dxr3_decoder_t*)this_gen)->sync_every_frame = entry->num_value;
+ printf("dxr3: set sync_every_frame to %s\n",
+ (entry->num_value ? "on" : "off"));
+}
+
+static void dxr3_flush_decoder(void *this_gen, cfg_entry_t *entry)
+{
+ printf("dxr3: flush requested\n");
+ dxr3_flush(this_gen);
+ /* reset to false, so it'll look like a button in the gui :-) */
+ entry->num_value = 0;
+}
+
video_decoder_t *init_video_decoder_plugin (int iface_version,
config_values_t *cfg)
{
@@ -607,12 +708,35 @@ video_decoder_t *init_video_decoder_plugin (int iface_version,
this->video_decoder.priority = 10;
this->config = cfg;
+ this->frame_rate_code = 0;
+ this->repeat_first_field = 0;
+ this->sync_every_frame = 1;
+
this->scr_prio = cfg->register_num(cfg, "dxr3.scr_priority", 10, "Dxr3: SCR plugin priority",NULL,NULL,NULL);
- this->enhanced_mode = cfg->register_bool(cfg,"dxr3.alt_play_mode", 0, "Dxr3: use alternate Play mode","Enabling this option will utilise a slightly different play mode",NULL,NULL);
-
+ this->sync_every_frame = cfg->register_bool(cfg,
+ "dxr3.sync_every_frame",
+ 1,
+ "Try to sync video every frame",
+ "This is relevant for progressive video only (most PAL films)",
+ dxr3_update_sync_mode, this);
+
+ this->sync_retry = 0;
+
+ this->enhanced_mode = cfg->register_bool(cfg,
+ "dxr3.alt_play_mode",
+ 0,
+ "Use alternate Play mode",
+ "Enabling this option will utilise a slightly different play mode",
+ dxr3_update_enhanced_mode, this);
+
+ /* a boolean that's really a button; request a decoder flush */
+ cfg->register_bool(cfg, "dxr3.flush", 0, "Flush decoder now",
+ "Flushing the decoder might unfreeze playback or restore sync",
+ dxr3_flush_decoder, this);
+
if(this->enhanced_mode)
- printf("Dxr3: Using Mode 6 for playback\n");
+ printf("dxr3: Using Mode 6 for playback\n");
this->have_header_info = 0;
this->in_buffer_fill = 0;
return (video_decoder_t *) this;
diff --git a/src/dxr3/dxr3_video_out.c b/src/dxr3/dxr3_video_out.c
index 7621d46b3..be13d239b 100644
--- a/src/dxr3/dxr3_video_out.c
+++ b/src/dxr3/dxr3_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: dxr3_video_out.c,v 1.1 2001/12/16 19:05:44 hrm Exp $
+ * $Id: dxr3_video_out.c,v 1.2 2001/12/23 02:36:55 hrm Exp $
*
* mpeg1 encoding video out plugin for the dxr3.
*
@@ -200,8 +200,6 @@ static void dxr3_frame_dispose (vo_frame_t *frame_gen)
dxr3_frame_t *frame = (dxr3_frame_t *) frame_gen;
if (frame->mem)
free (frame->mem);
- if (frame->mpeg)
- free(frame->mpeg);
free(frame);
}
@@ -222,8 +220,6 @@ static vo_frame_t *dxr3_alloc_frame (vo_driver_t *this_gen)
frame->vo_frame.field = dummy_frame_field;
frame->vo_frame.dispose = dxr3_frame_dispose;
- frame->mpeg = 0;
-
return (vo_frame_t*) frame;
}
@@ -235,7 +231,7 @@ static void dxr3_update_frame_format (vo_driver_t *this_gen,
dxr3_driver_t *this = (dxr3_driver_t *) this_gen;
int aspect,i;
dxr3_frame_t *frame = (dxr3_frame_t *) frame_gen;
- int image_size, oheight, top_bar;
+ int image_size, oheight;
/* reset the copy calls counter (number of calls to dxr3_frame_copy) */
frame->copy_calls = 0;
@@ -244,8 +240,6 @@ static void dxr3_update_frame_format (vo_driver_t *this_gen,
aspect = this->aspectratio;
oheight = this->oheight;
- frame->mpeg_size = 0;
-
if (flags == DXR3_VO_UPDATE_FLAG) { /* talking to dxr3 decoder */
this->mpeg_source = 1;
/* a bit of a hack. we must release the em8300_mv fd for
@@ -290,6 +284,11 @@ static void dxr3_update_frame_format (vo_driver_t *this_gen,
/* the following is for the mpeg encoding part only */
+ if (this->add_bars == 0) {
+ /* don't add black bars; assume source is in 4:3 */
+ ratio_code = XINE_ASPECT_RATIO_4_3;
+ }
+
/* check aspect ratio, see if we need to add black borders */
if ((this->video_width != width) || (this->video_iheight != height) ||
(this->video_aspect != ratio_code)) {
@@ -349,23 +348,27 @@ static void dxr3_update_frame_format (vo_driver_t *this_gen,
/* if dimensions changed, we need to re-allocate frame memory */
- if ((frame->width != width) || (frame->height != height)) {
+ if ((frame->width != width) || (frame->height != height) ||
+ (frame->oheight != oheight)) {
if (frame->mem) {
free (frame->mem);
frame->mem = NULL;
}
/* make top black bar multiple of 16,
* so old and new macroblocks overlap */
- top_bar = ((oheight - height) / 32) * 16;
-
+ this->top_bar = ((oheight - height) / 32) * 16;
if (format == IMGFMT_YUY2) {
image_size = width * oheight; /* includes black bars */
/* planar format, only base[0] */
- frame->real_base[0] = malloc_aligned(16, image_size*2, (void**)&frame->mem);
+ /* add one extra line for field swap stuff */
+ frame->real_base[0] = malloc_aligned(16, (image_size+width)*2,
+ (void**)&frame->mem);
+ /* don't use first line */
+ frame->real_base[0] += width * 2;
frame->real_base[1] = frame->real_base[2] = 0;
/* fix offset, so the decoder does not see the top black bar */
- frame->vo_frame.base[0] = frame->real_base[0] + width * 2 * top_bar;
+ frame->vo_frame.base[0] = frame->real_base[0] + width * 2 * this->top_bar;
frame->vo_frame.base[1] = frame->vo_frame.base[2] = 0;
/* fill with black (yuy2 16,128,16,128,...) */
@@ -375,8 +378,11 @@ static void dxr3_update_frame_format (vo_driver_t *this_gen,
}
else { /* IMGFMT_YV12 */
image_size = width * oheight; /* includes black bars */
- frame->real_base[0] = malloc_aligned(16, image_size * 3/2,
+ /* add one extra line for field swap stuff */
+ frame->real_base[0] = malloc_aligned(16, (image_size + width) * 3/2,
(void**) &frame->mem);
+ /* don't use first line */
+ frame->real_base[0] += width;
frame->real_base[1] = frame->real_base[0] + image_size;
frame->real_base[2] = frame->real_base[1] + image_size/4;
@@ -386,16 +392,32 @@ static void dxr3_update_frame_format (vo_driver_t *this_gen,
memset(frame->real_base[2], 128, image_size/4);
/* fix offsets, so the decoder does not see the top black bar */
- frame->vo_frame.base[0] = frame->real_base[0] + width * top_bar;
- frame->vo_frame.base[1] = frame->real_base[1] + width * top_bar/4;
- frame->vo_frame.base[2] = frame->real_base[2] + width * top_bar/4;
+ frame->vo_frame.base[0] = frame->real_base[0] + width * this->top_bar;
+ frame->vo_frame.base[1] = frame->real_base[1] + width * this->top_bar/4;
+ frame->vo_frame.base[2] = frame->real_base[2] + width * this->top_bar/4;
}
}
-
+
+ if (this->swap_fields != frame->swap_fields) {
+ if (format == IMGFMT_YUY2) {
+ if (this->swap_fields)
+ frame->vo_frame.base[0] -= width *2;
+ else
+ frame->vo_frame.base[0] += width *2;
+ }
+ else {
+ if (this->swap_fields)
+ frame->vo_frame.base[0] -= width;
+ else
+ frame->vo_frame.base[0] += width;
+ }
+ }
+
frame->width = width;
frame->height = height;
frame->oheight = oheight;
frame->format = format;
+ frame->swap_fields = this->swap_fields;
if(this->aspectratio!=aspect)
dxr3_set_property (this_gen,VO_PROP_ASPECT_RATIO, aspect);
@@ -450,6 +472,29 @@ void dxr3_exit (vo_driver_t *this_gen)
dxr3_set_vo(this, 0);
}
+void dxr3_update_add_bars(void *data, cfg_entry_t* entry)
+{
+ dxr3_driver_t* this = (dxr3_driver_t*)data;
+ this->add_bars = entry->num_value;
+ printf("dxr3: add bars to correct a.r. is %s\n",
+ (this->add_bars ? "on" : "off"));
+}
+
+void dxr3_update_swap_fields(void *data, cfg_entry_t* entry)
+{
+ dxr3_driver_t* this = (dxr3_driver_t*)data;
+ this->swap_fields = entry->num_value;
+ printf("dxr3: set swap field to %s\n",
+ (this->swap_fields ? "on" : "off"));
+}
+
+static void dxr3_update_enhanced_mode(void *this_gen, cfg_entry_t *entry)
+{
+ ((dxr3_driver_t*)this_gen)->enhanced_mode = entry->num_value;
+ printf("dxr3: encode: set enhanced mode to %s\n",
+ (entry->num_value ? "on" : "off"));
+}
+
vo_driver_t *init_video_out_plugin (config_values_t *config, void *visual_gen)
{
dxr3_driver_t *this;
@@ -482,8 +527,12 @@ vo_driver_t *init_video_out_plugin (config_values_t *config, void *visual_gen)
this->vo_driver.exit = dxr3_exit;
this->config=config;
this->mpeg_source = 0; /* set by update_frame, by checking the flag */
+
+ this->swap_fields = config->register_bool(config, "dxr3.enc_swap_fields", 0, "swap odd and even lines", NULL, dxr3_update_swap_fields, this);
+
+ this->add_bars = config->register_bool(config, "dxr3.enc_add_bars", 1, "Add black bars to correct aspect ratio", "If disabled, will assume source has 4:3 a.r.", dxr3_update_add_bars, this);
- this->enhanced_mode = config->register_bool(config,"dxr3.enc_alt_play_mode", 1, "dxr3: use alternate play mode for mpeg encoder playback","Enabling this option will utilise a slightly different play mode",NULL,NULL);
+ this->enhanced_mode = config->register_bool(config,"dxr3.enc_alt_play_mode", 1, "dxr3: use alternate play mode for mpeg encoder playback","Enabling this option will utilise a slightly different play mode",dxr3_update_enhanced_mode,this);
/* open control device */
this->devname = config->register_string (config, LOOKUP_DEV, DEFAULT_DEV,NULL,NULL,NULL,NULL);
diff --git a/src/dxr3/dxr3_video_out.h b/src/dxr3/dxr3_video_out.h
index f62f9d57e..d3fa1c6b5 100644
--- a/src/dxr3/dxr3_video_out.h
+++ b/src/dxr3/dxr3_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: dxr3_video_out.h,v 1.11 2001/12/16 19:05:44 hrm Exp $
+ * $Id: dxr3_video_out.h,v 1.12 2001/12/23 02:36:55 hrm Exp $
*
*/
@@ -100,8 +100,11 @@ typedef struct dxr3_driver_s {
double fps; /* frames per second */
int format; /* color format */
const char *file_out;
+ int swap_fields; /* swap fields */
+ int add_bars; /* add black bars to correct a.r. */
/* height after adding black bars to correct a.r. */
int oheight;
+ int top_bar; /* number of lines in top black bar */
/* input height (before adding black bars) */
int video_iheight;
/* output height (after adding bars) */
@@ -140,8 +143,7 @@ typedef struct dxr3_frame_s {
int format;
dxr3_driver_t *vo_instance; /* points to self, for use in dxr3_frame_copy */
int copy_calls; /* counts calls to dxr3_frame_copy function */
- unsigned char *mpeg; /* encoded mpeg data */
- unsigned int mpeg_size; /* length of data */
+ int swap_fields; /* shifts Y buffer one line to exchange odd/even lines*/
} dxr3_frame_t;
struct encoder_data_s {
diff --git a/src/dxr3/dxr3_vo_core.c b/src/dxr3/dxr3_vo_core.c
index 0c218f130..84092955a 100644
--- a/src/dxr3/dxr3_vo_core.c
+++ b/src/dxr3/dxr3_vo_core.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_vo_core.c,v 1.11 2001/11/29 07:17:08 mlampard Exp $
+ * $Id: dxr3_vo_core.c,v 1.12 2001/12/23 02:36:55 hrm Exp $
*
*************************************************************************
* core functions common to both Standard and RT-Encoding vo plugins *
@@ -41,6 +41,8 @@
#include "dxr3_video_out.h"
+#define OVERLAY_LOG 0
+
void *malloc_aligned (size_t alignment, size_t size, void **mem) {
char *aligned;
@@ -536,13 +538,18 @@ static int lookup_parameter(struct lut_entry *lut, char *name,
void **ptr, int *type)
{
int i;
-
for(i=0; lut[i].name; i++)
if(!strcmp(name,lut[i].name)) {
*ptr = lut[i].ptr;
*type = lut[i].type;
+#if OVERLAY_LOG
+ printf("dxr3: found parameter \"%s\"\n", name);
+#endif
return 1;
}
+#if OVERLAY_LOG
+ printf("dxr3: WARNING: unknown parameter \"%s\"\n", name);
+#endif
return 0;
}
@@ -562,7 +569,9 @@ int dxr3_overlay_read_state(dxr3_overlay_t *this)
sprintf(tmp,"/res_%dx%dx%d",
this->screen_xres,this->screen_yres,this->screen_depth);
strcat(fname,tmp);
-
+#if OVERLAY_LOG
+ printf("dxr3: attempting to open %s\n", fname);
+#endif
if(!(fp=fopen(fname,"r"))){
printf("ERRROR Reading overlay init file!! run autocal !!!\n");
return -1;
@@ -575,23 +584,38 @@ int dxr3_overlay_read_state(dxr3_overlay_t *this)
break;
tok=strtok(line," ");
if(lookup_parameter(lut,tok,&ptr,&type)) {
- tok=strtok(NULL," ");
+ tok=strtok(NULL," \n");
switch(type) {
case TYPE_INT:
sscanf(tok,"%d",(int *)ptr);
+#if OVERLAY_LOG
+ printf("dxr3: value \"%s\" -> %d\n", tok, *(int*)ptr);
+#endif
break;
case TYPE_XINT:
sscanf(tok,"%x",(int *)ptr);
+#if OVERLAY_LOG
+ printf("dxr3: value \"%s\" -> %d\n", tok, *(int*)ptr);
+#endif
break;
case TYPE_FLOAT:
sscanf(tok,"%f",(float *)ptr);
+#if OVERLAY_LOG
+ printf("dxr3: value \"%s\" -> %f\n", tok, *(float*)ptr);
+#endif
break;
case TYPE_COEFF:
for(j=0;j<3;j++) {
sscanf(tok,"%f",&((struct coeff *)ptr)[j].k);
- tok=strtok(NULL," ");
+#if OVERLAY_LOG
+ printf("dxr3: value (%d,k) \"%s\" -> %f\n", j, tok, ((struct coeff*)ptr)[j].k);
+#endif
+ tok=strtok(NULL," \n");
sscanf(tok,"%f",&((struct coeff *)ptr)[j].m);
- tok=strtok(NULL," ");
+#if OVERLAY_LOG
+ printf("dxr3: value (%d,m) \"%s\" -> %f\n", j, tok, ((struct coeff*)ptr)[j].m);
+#endif
+ tok=strtok(NULL," \n");
}
break;
}
@@ -621,24 +645,40 @@ int dxr3_overlay_set_keycolor(dxr3_overlay_t *this)
int32_t overlay_limit;
em8300_attribute_t attr;
+#if OVERLAY_LOG
+ printf("dxr3: set_keycolor: r=%f g=%f b=%f, interval = %f\n",
+ r,g,b,interval);
+#endif
overlay_limit = /* lower limit */
- col_interp(r - interval, this->colcal_upper[0]) << 16 |
- col_interp(g - interval, this->colcal_upper[1]) << 8 |
- col_interp(b - interval, this->colcal_upper[2]);
+ col_interp(r - interval, this->colcal_lower[0]) << 16 |
+ col_interp(g - interval, this->colcal_lower[1]) << 8 |
+ col_interp(b - interval, this->colcal_lower[2]);
+#if OVERLAY_LOG
+ printf("dxr3: lower overlay_limit = %d\n", overlay_limit);
+#endif
attr.attribute = EM9010_ATTRIBUTE_KEYCOLOR_LOWER;
attr.value = overlay_limit;
ret = ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SET_ATTRIBUTE, &attr);
- if (ret < 0) return ret;
+ if (ret < 0) {
+ printf("dxr3: WARNING: error setting overlay upperl limit attribute\n");
+ return ret;
+ }
overlay_limit = /* upper limit */
col_interp(r + interval, this->colcal_upper[0]) << 16 |
col_interp(g + interval, this->colcal_upper[1]) << 8 |
col_interp(b + interval, this->colcal_upper[2]);
-
+#if OVERLAY_LOG
+ printf("dxr3: upper overlay_limit = %d\n", overlay_limit);
+#endif
attr.attribute = EM9010_ATTRIBUTE_KEYCOLOR_UPPER;
attr.value = overlay_limit;
- return ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SET_ATTRIBUTE, &attr);
+ ret = ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SET_ATTRIBUTE, &attr);
+ if (ret < 0) {
+ printf("dxr3: WARNING: error setting overlay upperl limit attribute\n");
+ }
+ return ret;
}
diff --git a/src/dxr3/mpeg_encoders.c b/src/dxr3/mpeg_encoders.c
index 2e7a7b0ad..6370bf446 100644
--- a/src/dxr3/mpeg_encoders.c
+++ b/src/dxr3/mpeg_encoders.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: mpeg_encoders.c,v 1.2 2001/12/16 22:34:21 hrm Exp $
+ * $Id: mpeg_encoders.c,v 1.3 2001/12/23 02:36:55 hrm Exp $
*
* mpeg encoders for the dxr3 video out plugin.
*/
@@ -45,6 +45,7 @@
#ifdef HAVE_LIBRTE
typedef struct {
encoder_data_t encoder_data;
+ int width, height;
rte_context* context; /* handle for encoding */
void* rte_ptr; /* buffer maintened by librte */
double rte_time; /* frame time (s) */
@@ -92,6 +93,8 @@ static int rte_on_update_format(dxr3_driver_t *drv)
rte_context_delete(this->context);
this->context = 0;
}
+ this->width = width;
+ this->height = height;
this->context = rte_context_new (width, height, "mp1e", drv);
if (! this->context) {
@@ -169,6 +172,11 @@ static int rte_on_display_frame( dxr3_driver_t* drv, dxr3_frame_t* frame )
{
int size;
rte_data_t* this = (rte_data_t*)drv->enc;
+
+ if ( (this->width != frame->width) || (this->height != frame->height)){
+ /* maybe we were reinitialized and get an old frame. */
+ return 0;
+ }
size = frame->width * frame->oheight;
if (frame->format == IMGFMT_YV12)
xine_fast_memcpy(this->rte_ptr, frame->real_base[0], size*3/2);
@@ -319,23 +327,15 @@ static int fame_on_update_format(dxr3_driver_t *drv)
return 0;
}
-static int fame_on_frame_copy(dxr3_driver_t *drv, dxr3_frame_t *frame,
- uint8_t **src)
+static int fame_prepare_frame(fame_data_t* this, dxr3_driver_t *drv,
+ dxr3_frame_t *frame)
{
- int size, i, j, hoffset, w2;
+ int i, j, w2;
uint8_t *y, *u, *v, *yuy2;
- fame_data_t *this = (fame_data_t*)drv->enc;
if (frame->vo_frame.bad_frame)
return 0;
- if (frame->copy_calls == frame->height/16) {
- /* shouldn't happen */
- printf("dxr3: Internal error. Too many calls to dxr3_frame_copy (%d)\n",
- frame->copy_calls);
- return 1;
- }
-
if (frame->vo_frame.format == IMGFMT_YUY2) {
/* need YUY2->YV12 conversion */
if (! (this->out[0] && this->out[1] && this->out[2]) ) {
@@ -343,14 +343,12 @@ static int fame_on_frame_copy(dxr3_driver_t *drv, dxr3_frame_t *frame,
return 1;
}
/* need conversion */
- hoffset = ((frame->oheight - frame->height)/32)*16;
- y = this->out[0] + frame->width*(hoffset + frame->copy_calls*16);
- u = this->out[1] + frame->width/2*(hoffset/2 + frame->copy_calls*8);
- v = this->out[2] + frame->width/2*(hoffset/2 + frame->copy_calls*8);
- yuy2 = src[0];
+ y = this->out[0] + frame->width*drv->top_bar;
+ u = this->out[1] + frame->width/2*(drv->top_bar/2);
+ v = this->out[2] + frame->width/2*(drv->top_bar/2);
+ yuy2 = frame->vo_frame.base[0];
w2 = frame->width/2;
- /* we get 16 lines each time */
- for (i=0; i<16; i+=2) {
+ for (i=0; i<frame->height; i+=2) {
for (j=0; j<w2; j++) {
/* packed YUV 422 is: Y[i] U[i] Y[i+1] V[i] */
*(y++) = *(yuy2++);
@@ -378,31 +376,9 @@ static int fame_on_frame_copy(dxr3_driver_t *drv, dxr3_frame_t *frame,
v = frame->real_base[2];
}
- frame->copy_calls++;
-
- /* frame complete yet? */
- if (frame->copy_calls != frame->height/16)
- return 0;
- /* frame is complete: encode */
this->yuv.y=y;
this->yuv.u=u;
this->yuv.v=v;
- size = fame_encode_frame(this->fc, &this->yuv, NULL);
- if (size >= DEFAULT_BUFFER_SIZE) {
- printf("dxr3: warning, mpeg buffer too small!\n");
- size = DEFAULT_BUFFER_SIZE;
- }
- /* alloc frame does not allocate the mpeg buffer. do this now */
- if (! frame->mpeg) {
- frame->mpeg = (unsigned char *) malloc (DEFAULT_BUFFER_SIZE);
- }
- if (! frame->mpeg) {
- printf("dxr3: error, could not allocate mpeg buffer!\n");
- return 1;
- }
- /* copy mpeg data to frame */
- xine_fast_memcpy(frame->mpeg, this->buffer, size);
- frame->mpeg_size = size;
return 0;
}
@@ -411,6 +387,17 @@ static int fame_on_display_frame( dxr3_driver_t* drv, dxr3_frame_t* frame)
{
char tmpstr[128];
em8300_register_t regs;
+ int size;
+ fame_data_t *this = (fame_data_t*)drv->enc;
+
+ if ((frame->width != this->fp.width) || (frame->oheight != this->fp.height)) {
+ /* probably an old frame for a previous context. ignore it */
+ return 0;
+ }
+
+ fame_prepare_frame(this, drv, frame);
+ size = fame_encode_frame(this->fc, &this->yuv, NULL);
+
if (drv->enhanced_mode)
{
regs.microcode_register=1; /* Yes, this is a MC Reg */
@@ -423,7 +410,8 @@ static int fame_on_display_frame( dxr3_driver_t* drv, dxr3_frame_t* frame)
snprintf (tmpstr, sizeof(tmpstr), "%s_mv", drv->devname);
drv->fd_video = open(tmpstr, O_WRONLY);
}
- if (write(drv->fd_video, frame->mpeg, frame->mpeg_size) < 0)
+ //if (write(drv->fd_video, frame->mpeg, frame->mpeg_size) < 0)
+ if (write(drv->fd_video, this->buffer, size) < 0)
perror("dxr3: writing to video device");
frame->vo_frame.displayed(&frame->vo_frame);
return 0;
@@ -451,7 +439,7 @@ int dxr3_fame_init( dxr3_driver_t *drv )
/* fame context */
this->fc = 0;
this->encoder_data.on_update_format = fame_on_update_format;
- this->encoder_data.on_frame_copy = fame_on_frame_copy;
+ this->encoder_data.on_frame_copy = NULL;
this->encoder_data.on_display_frame = fame_on_display_frame;
this->encoder_data.on_close = fame_on_close;
drv->enc = (encoder_data_t*)this;