From 8b7b18f012709ff905c5664d2ec2695cae5b3e9e Mon Sep 17 00:00:00 2001 From: Harm van der Heijden Date: Sun, 23 Dec 2001 02:36:54 +0000 Subject: 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 --- src/dxr3/dxr3_decoder.c | 230 +++++++++++++++++++++++++++++++++++----------- src/dxr3/dxr3_video_out.c | 87 ++++++++++++++---- src/dxr3/dxr3_video_out.h | 8 +- src/dxr3/dxr3_vo_core.c | 64 ++++++++++--- src/dxr3/mpeg_encoders.c | 74 +++++++-------- 5 files changed, 333 insertions(+), 130 deletions(-) (limited to 'src') 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; iheight; i+=2) { for (j=0; jreal_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; -- cgit v1.2.3