[MPlayer-dev-eng] [PATCH] patch 1: vdpau
Dan Oscarsson
Dan.Oscarsson at tietoenator.com
Sun Apr 26 17:22:06 CEST 2009
Hi
I have now split my patch into two: one for vdpau fixes and one for
syncing video to display rate.
Attached is the one for vdpau.
It now contains just one option: max-delay (if you have a better name we
can change to that).
If contains fixes so mplayer works better on displays having a rate
nearly equal to movie rate. Included are also minor fixes to flashing
during resizing.
max-delay can be set by direct suboption to -vo vdpau or as an option to
-vdpauopts.
Set it to 0 if you want old behaviour, otherwise it defines when to
start dropping frames to keep in sync, given in vsync intervals.
In some ways it works like -framedrop but smoother and user definable.
Default are the values that works fine for me.
Two small changes to mplayer.c is also included.
- Display on status line of frames dropped in vo layer
- Video decoding is done before audio decoding to reduce
initial delay in video frames.
tabs included in moved lines and one following its use
in cfg-mplayer.h
-------------- next part --------------
--- mplayer.c.org 2009-04-26 16:34:40.000000000 +0200
+++ mplayer.c 2009-04-26 16:40:49.000000000 +0200
@@ -1255,6 +1255,9 @@
if (sh_video)
saddf(line, &pos, width, "%d %d ", drop_frame_cnt, output_quality);
+ if (sh_video && vo_drop_frame_cnt)
+ saddf(line, &pos, width, "%d ", vo_drop_frame_cnt);
+
#ifdef CONFIG_STREAM_CACHE
// cache stats
if (stream_cache_size > 0)
@@ -3656,6 +3659,30 @@
reinit_audio_chain();
}
+
+/*========================== PLAY VIDEO ============================*/
+
+if(mpctx->sh_video) {
+ vo_pts=mpctx->sh_video->timer*90000.0;
+ vo_fps=mpctx->sh_video->fps;
+
+ if (!mpctx->num_buffered_frames) {
+ double frame_time = update_video(&blit_frame);
+ mp_dbg(MSGT_AVSYNC,MSGL_DBG2,"*** ftime=%5.3f ***\n",frame_time);
+ if (mpctx->sh_video->vf_initialized < 0) {
+ mp_msg(MSGT_CPLAYER,MSGL_FATAL, MSGTR_NotInitializeVOPorVO);
+ mpctx->eof = 1; goto goto_next_file;
+ }
+ if (frame_time < 0)
+ mpctx->eof = 1;
+ else {
+ // might return with !eof && !blit_frame if !correct_pts
+ mpctx->num_buffered_frames += blit_frame;
+ time_frame += frame_time / playback_speed; // for nosound
+ }
+ }
+}
+
/*========================== PLAY AUDIO ============================*/
if (mpctx->sh_audio)
@@ -3681,28 +3708,6 @@
update_osd_msg();
} else {
-
-/*========================== PLAY VIDEO ============================*/
-
- vo_pts=mpctx->sh_video->timer*90000.0;
- vo_fps=mpctx->sh_video->fps;
-
- if (!mpctx->num_buffered_frames) {
- double frame_time = update_video(&blit_frame);
- mp_dbg(MSGT_AVSYNC,MSGL_DBG2,"*** ftime=%5.3f ***\n",frame_time);
- if (mpctx->sh_video->vf_initialized < 0) {
- mp_msg(MSGT_CPLAYER,MSGL_FATAL, MSGTR_NotInitializeVOPorVO);
- mpctx->eof = 1; goto goto_next_file;
- }
- if (frame_time < 0)
- mpctx->eof = 1;
- else {
- // might return with !eof && !blit_frame if !correct_pts
- mpctx->num_buffered_frames += blit_frame;
- time_frame += frame_time / playback_speed; // for nosound
- }
- }
-
// ==========================================================================
// current_module="draw_osd";
--- libvo/video_out.c.org 2009-04-26 16:34:48.000000000 +0200
+++ libvo/video_out.c 2009-04-26 16:35:55.000000000 +0200
@@ -79,6 +79,11 @@
int vo_colorkey = 0x0000ff00; // default colorkey is green
// (0xff000000 means that colorkey has been disabled)
+int vo_drop_frame_cnt = 0; // frames dropped by vo driver
+unsigned int vo_vsync_offset = 0; // last displayed frame was queued micro sec before vsync
+unsigned int vo_vsync_interval = 0; // interval between vsync in nanosec
+
+
//
// Externally visible list of all vo drivers
//
--- libvo/video_out.h.org 2009-04-26 16:34:54.000000000 +0200
+++ libvo/video_out.h 2009-04-26 16:35:55.000000000 +0200
@@ -250,6 +250,10 @@
extern int vo_colorkey;
+extern int vo_drop_frame_cnt;
+extern unsigned int vo_vsync_offset;
+extern unsigned int vo_vsync_interval;
+
extern int64_t WinID;
typedef struct {
--- libvo/vo_vdpau.c.org 2009-04-26 16:34:59.000000000 +0200
+++ libvo/vo_vdpau.c 2009-04-26 16:56:07.000000000 +0200
@@ -43,6 +43,7 @@
#include "aspect.h"
#include "sub.h"
#include "subopt-helper.h"
+#include "get_path.h"
#include "libavcodec/vdpau.h"
@@ -76,7 +77,8 @@
message, vdp_get_error_string(vdp_st));
/* number of video and output surfaces */
-#define NUM_OUTPUT_SURFACES 2
+/** number of output surfaces is set in preinit */
+static int num_output_surfaces;
#define MAX_VIDEO_SURFACES 50
/* number of palette entries */
@@ -128,6 +130,9 @@
static VdpPresentationQueueDisplay *vdp_presentation_queue_display;
static VdpPresentationQueueBlockUntilSurfaceIdle *vdp_presentation_queue_block_until_surface_idle;
static VdpPresentationQueueTargetCreateX11 *vdp_presentation_queue_target_create_x11;
+static VdpPresentationQueueQuerySurfaceStatus *vdp_presentation_queue_query_surface_status;
+static VdpPresentationQueueGetTime *vdp_presentation_queue_get_time;
+static VdpPresentationQueueSetBackgroundColor *vdp_presentation_queue_set_background_color;
static VdpOutputSurfaceRenderOutputSurface *vdp_output_surface_render_output_surface;
static VdpOutputSurfacePutBitsIndexed *vdp_output_surface_put_bits_indexed;
@@ -144,9 +149,19 @@
static VdpGenerateCSCMatrix *vdp_generate_csc_matrix;
static void *vdpau_lib_handle;
-/* output_surfaces[NUM_OUTPUT_SURFACES] is misused for OSD. */
-#define osd_surface output_surfaces[NUM_OUTPUT_SURFACES]
-static VdpOutputSurface output_surfaces[NUM_OUTPUT_SURFACES + 1];
+
+typedef struct {
+ VdpOutputSurface surface;
+ int width;
+ int height;
+ int dwidth;
+ int dheight;
+ VdpTime queued;
+} output_surface_info;
+
+/* output_surfaces[num_output_surfaces] is misused for OSD. */
+#define osd_surface output_surfaces[num_output_surfaces].surface
+static output_surface_info *output_surfaces;
static VdpVideoSurface deint_surfaces[3];
static mp_image_t *deint_mpi[2];
static int output_surface_width, output_surface_height;
@@ -162,6 +177,12 @@
static int chroma_deint;
static int top_field_first;
+static float max_delay = -1;
+static unsigned int max_delay_interval;
+static double time_correction = 0;
+static int time_measured_over;
+static VdpTime vsync_interval = 0;
+
static VdpDecoder decoder;
static int decoder_max_refs;
@@ -205,12 +226,70 @@
// Video equalizer
static VdpProcamp procamp;
+static u_int64_t reference_system_time;
+static VdpTime reference_vdpau_time;
+
+#include "m_option.h"
+m_option_t vdpauopts_conf[]={
+ {"max-delay", &max_delay, CONF_TYPE_FLOAT, CONF_RANGE, 0.0, 4.0, NULL},
+ {NULL, NULL, 0, 0, 0, 0, NULL}
+};
+
+
+// Returns current time in micro seconds in 64 bit quantity so it does not wrap
+uint64_t get_time(void){
+ struct timeval tv;
+ gettimeofday(&tv,NULL);
+ return (uint64_t)(tv.tv_sec)*1000000+tv.tv_usec;
+}
+
/*
* X11 specific
*/
static int visible_buf;
static int int_pause;
+static void create_output_surface(int no) {
+ VdpStatus vdp_st;
+
+ vdp_st = vdp_output_surface_create(vdp_device, VDP_RGBA_FORMAT_B8G8R8A8,
+ output_surface_width, output_surface_height,
+ &output_surfaces[no].surface);
+ CHECK_ST_WARNING("Error when calling vdp_output_surface_create")
+ output_surfaces[no].width = output_surface_width;
+ output_surfaces[no].height = output_surface_height;
+}
+
+static VdpOutputSurface get_output_surface(void) {
+ VdpStatus vdp_st;
+
+ if (output_surfaces[surface_num].surface == VDP_INVALID_HANDLE) {
+ create_output_surface(surface_num);
+ mp_msg(MSGT_VO, MSGL_DBG2, "OUT CREATE: %u\n", output_surfaces[surface_num].surface);
+ } else if (output_surfaces[surface_num].width != output_surface_width ||
+ output_surfaces[surface_num].height != output_surface_height) {
+ vdp_st = vdp_output_surface_destroy(output_surfaces[surface_num].surface);
+ CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy")
+ mp_msg(MSGT_VO, MSGL_DBG2, "OUT DELETE - to small: %u\n", output_surfaces[surface_num].surface);
+ create_output_surface(surface_num);
+ mp_msg(MSGT_VO, MSGL_DBG2, "OUT CREATE - new size: %u %d %d\n",
+ output_surfaces[surface_num].surface,
+ output_surfaces[surface_num].width,
+ output_surfaces[surface_num].height);
+ }
+ if(!max_delay_interval) {
+ VdpTime visible_time;
+ vdp_st = vdp_presentation_queue_block_until_surface_idle(vdp_flip_queue,
+ output_surfaces[surface_num].surface,
+ &visible_time);
+ CHECK_ST_WARNING("Error when calling vdp_presentation_queue_block_until_surface_idle")
+ }
+ output_surfaces[surface_num].dwidth = vo_dwidth;
+ output_surfaces[surface_num].dheight = vo_dheight;
+ return output_surfaces[surface_num].surface;
+}
+
+
static void draw_eosd(void);
static void push_deint_surface(VdpVideoSurface surface)
@@ -222,7 +301,6 @@
static void video_to_output_surface(void)
{
- VdpTime dummy;
VdpStatus vdp_st;
int i;
if (vid_surface_num < 0)
@@ -243,12 +321,7 @@
field = (top_field_first == i) ^ (deint > 1) ?
VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD:
VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
- output_surface = output_surfaces[surface_num];
- vdp_st = vdp_presentation_queue_block_until_surface_idle(vdp_flip_queue,
- output_surface,
- &dummy);
- CHECK_ST_WARNING("Error when calling vdp_presentation_queue_block_until_surface_idle")
-
+ output_surface = get_output_surface();
vdp_st = vdp_video_mixer_render(video_mixer, VDP_INVALID_HANDLE, 0,
field, 2, deint_surfaces + 1,
deint_surfaces[0],
@@ -264,7 +337,6 @@
static void resize(void)
{
VdpStatus vdp_st;
- int i;
struct vo_rect src_rect;
struct vo_rect dst_rect;
struct vo_rect borders;
@@ -288,26 +360,21 @@
if (output_surface_width < vo_dwidth || output_surface_height < vo_dheight) {
if (output_surface_width < vo_dwidth) {
output_surface_width += output_surface_width >> 1;
- output_surface_width = FFMAX(output_surface_width, vo_dwidth);
+ output_surface_width = FFMIN(vo_screenwidth,FFMAX(output_surface_width, vo_dwidth));
}
if (output_surface_height < vo_dheight) {
output_surface_height += output_surface_height >> 1;
- output_surface_height = FFMAX(output_surface_height, vo_dheight);
- }
- // Creation of output_surfaces
- for (i = 0; i <= NUM_OUTPUT_SURFACES; i++) {
- if (output_surfaces[i] != VDP_INVALID_HANDLE)
- vdp_output_surface_destroy(output_surfaces[i]);
- vdp_st = vdp_output_surface_create(vdp_device, VDP_RGBA_FORMAT_B8G8R8A8,
- output_surface_width, output_surface_height,
- &output_surfaces[i]);
- CHECK_ST_WARNING("Error when calling vdp_output_surface_create")
- mp_msg(MSGT_VO, MSGL_DBG2, "OUT CREATE: %u\n", output_surfaces[i]);
+ output_surface_height = FFMIN(vo_screenheight,FFMAX(output_surface_height, vo_dheight));
}
+ // Creation of osd surface
+ if (osd_surface != VDP_INVALID_HANDLE)
+ vdp_output_surface_destroy(osd_surface);
+ vdp_st = vdp_output_surface_create(vdp_device, VDP_RGBA_FORMAT_B8G8R8A8,
+ output_surface_width, output_surface_height,
+ &osd_surface);
+ CHECK_ST_WARNING("Error when calling vdp_output_surface_create")
+ mp_msg(MSGT_VO, MSGL_DBG2, "OUT CREATE OSD: %u\n", osd_surface);
}
- video_to_output_surface();
- if (visible_buf)
- flip_page();
}
/* Initialize vdp_get_proc_address, called from preinit() */
@@ -351,6 +418,12 @@
&vdp_presentation_queue_block_until_surface_idle},
{VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11,
&vdp_presentation_queue_target_create_x11},
+ {VDP_FUNC_ID_PRESENTATION_QUEUE_QUERY_SURFACE_STATUS,
+ &vdp_presentation_queue_query_surface_status},
+ {VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME,
+ &vdp_presentation_queue_get_time},
+ {VDP_FUNC_ID_PRESENTATION_QUEUE_SET_BACKGROUND_COLOR,
+ &vdp_presentation_queue_set_background_color},
{VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE,
&vdp_output_surface_render_output_surface},
{VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED,
@@ -390,6 +463,7 @@
static int win_x11_init_vdpau_flip_queue(void)
{
VdpStatus vdp_st;
+ VdpColor vdp_black = { 0, 0, 0, 0 };
vdp_st = vdp_presentation_queue_target_create_x11(vdp_device, vo_window,
&vdp_flip_target);
@@ -399,6 +473,9 @@
&vdp_flip_queue);
CHECK_ST_ERROR("Error when calling vdp_presentation_queue_create")
+ vdp_st = vdp_presentation_queue_set_background_color(vdp_flip_queue, &vdp_black);
+ CHECK_ST_ERROR("Error when calling vdp_presentation_queue_set_background_color")
+
return 0;
}
@@ -528,6 +605,114 @@
return 1;
}
+static void get_vdpau_timing(void)
+{
+ VdpTime time1;
+ VdpTime time2;
+ VdpTime time3;
+ VdpTime td1,td2,td3;
+ VdpPresentationQueueStatus out_status;
+
+ VdpOutputSurface surface1;
+ VdpOutputSurface surface2;
+ VdpOutputSurface surface3;
+ VdpStatus vdp_st;
+
+ if (vsync_interval) return;
+
+ if (time_correction >= 0) {
+ // get relation between vdpau time and system time
+ vdp_st = vdp_presentation_queue_get_time(vdp_flip_queue, &reference_vdpau_time);
+ CHECK_ST_WARNING("Error when calling vdp_presentation_queue_get_time")
+ reference_system_time = get_time();
+ }
+
+ // create timing surfaces
+ vdp_st = vdp_output_surface_create(vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, 16, 16, &surface1);
+ CHECK_ST_WARNING("Error when calling vdp_output_surface_create")
+ vdp_st = vdp_output_surface_create(vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, 16, 16, &surface2);
+ CHECK_ST_WARNING("Error when calling vdp_output_surface_create")
+ vdp_st = vdp_output_surface_create(vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, 16, 16, &surface3);
+ CHECK_ST_WARNING("Error when calling vdp_output_surface_create")
+
+ // queue surfaces and check time for display
+ vdp_st = vdp_presentation_queue_display(vdp_flip_queue, surface1, 1, 1,0);
+ CHECK_ST_WARNING("Error when calling vdp_presentation_queue_display")
+ vdp_st = vdp_presentation_queue_display(vdp_flip_queue, surface2, 1, 1,0);
+ CHECK_ST_WARNING("Error when calling vdp_presentation_queue_display")
+ vdp_st = vdp_presentation_queue_display(vdp_flip_queue, surface3, 1, 1,0);
+ CHECK_ST_WARNING("Error when calling vdp_presentation_queue_display")
+
+ vdp_st = vdp_presentation_queue_block_until_surface_idle(vdp_flip_queue, surface1, &time1);
+ CHECK_ST_WARNING("Error when calling vdp_presentation_queue_block_until_surface_idle")
+ vdp_st = vdp_presentation_queue_block_until_surface_idle(vdp_flip_queue, surface2, &time2);
+ CHECK_ST_WARNING("Error when calling vdp_presentation_queue_block_until_surface_idle")
+
+ vdp_st = vdp_presentation_queue_query_surface_status(vdp_flip_queue, surface3, &out_status, &time3);
+ CHECK_ST_WARNING("Error when calling vdp_presentation_queue_query_surface_status")
+
+ if (out_status != 2) {
+ mp_msg(MSGT_VO, MSGL_V, "[vdpau] Surface not visible as it should\n");
+ return;
+ }
+ td1 = time2-time1;
+ td2 = time3-time2;
+ if (td1 != td2) {
+ // time one frame more to get more accurate data
+ vdp_st = vdp_presentation_queue_display(vdp_flip_queue, surface2, 1, 1, 0);
+ CHECK_ST_WARNING("Error when calling vdp_presentation_queue_display")
+ vdp_st = vdp_presentation_queue_block_until_surface_idle(vdp_flip_queue, surface3, &time2);
+ CHECK_ST_WARNING("Error when calling vdp_presentation_queue_block_until_surface_idle")
+ vdp_st = vdp_presentation_queue_query_surface_status(vdp_flip_queue, surface2, &out_status, &time2);
+ CHECK_ST_WARNING("Error when calling vdp_presentation_queue_query_surface_status")
+ if (out_status != 2) {
+ mp_msg(MSGT_VO, MSGL_V, "[vdpau] Surface not visible as it should (accuracy test)\n");
+ return;
+ }
+ td3 = time2-time3;
+ if (td3 == td2) {
+ td1 = td3;
+ } else if (td3 != td1) {
+ VdpTime tdv;
+ VdpTime tdmax,tdmin;
+
+ tdmax = FFMAX(td1,FFMAX(td2,td3));
+ tdmin = FFMIN(td1,FFMIN(td2,td3));
+ td1 = (time2-time1)/3;
+ tdv = td1/10000;
+ if (tdv != td2/10000 || tdv != td3/10000) {
+ mp_msg(MSGT_VO, MSGL_V, "[vdpau] Timing unaccurate at 10 microsecond level - assume blit engine\n");
+ if (tdmax-tdmin < 3000000) { // 3 ms (about 3 ms have been seen)
+ mp_msg(MSGT_VO, MSGL_V, "[vdpau] Timing unaccurate at millisecond level - acceptible for blit engine\n");
+ } else {
+ mp_msg(MSGT_VO, MSGL_V, "[vdpau] Timing very unaccurate at millisecond level - assume assume no vsync alignment\n");
+ return;
+ }
+ }
+ }
+ }
+ if (td1 < 5000000) {
+ mp_msg(MSGT_VO, MSGL_V, "[vdpau] To small vsync value - assume no vsync alignment\n");
+ return;
+ }
+ vsync_interval = td1;
+ if (time_correction > 0.9 && time_correction < 1.1) {
+ mp_msg(MSGT_VO, MSGL_V, "[vdpau] correcting vsync interval by timing correction %ld\n",time_correction);
+ vo_vsync_interval = vsync_interval*time_correction;
+ } else {
+ vo_vsync_interval = vsync_interval;
+ }
+
+ vdp_st = vdp_output_surface_destroy(surface1);
+ vdp_st = vdp_output_surface_destroy(surface2);
+ vdp_st = vdp_output_surface_destroy(surface3);
+
+ if (max_delay) {
+ max_delay_interval = vsync_interval*max_delay;
+ }
+}
+
+
/*
* connect to X server, create and map window, initialize all
* VDPAU objects, create different surfaces etc.
@@ -625,6 +810,10 @@
vid_surface_num = -1;
resize();
+ if (max_delay) {
+ get_vdpau_timing();
+ }
+
return 0;
}
@@ -636,23 +825,16 @@
resize();
if ((e & VO_EVENT_EXPOSE || e & VO_EVENT_RESIZE) && int_pause) {
- /* did we already draw a buffer */
- if (visible_buf) {
- /* redraw the last visible buffer */
- VdpStatus vdp_st;
- vdp_st = vdp_presentation_queue_display(vdp_flip_queue,
- output_surfaces[surface_num],
- vo_dwidth, vo_dheight,
- 0);
- CHECK_ST_WARNING("Error when calling vdp_presentation_queue_display")
- }
+ video_to_output_surface();
+ if (visible_buf)
+ flip_page();
}
}
static void draw_osd_I8A8(int x0,int y0, int w,int h, unsigned char *src,
unsigned char *srca, int stride)
{
- VdpOutputSurface output_surface = output_surfaces[surface_num];
+ VdpOutputSurface output_surface = get_output_surface();
VdpStatus vdp_st;
int i, j;
int pitch;
@@ -713,7 +895,7 @@
static void draw_eosd(void) {
VdpStatus vdp_st;
- VdpOutputSurface output_surface = output_surfaces[surface_num];
+ VdpOutputSurface output_surface = get_output_surface();
VdpOutputSurfaceRenderBlendState blend_state;
int i;
@@ -836,15 +1018,67 @@
static void flip_page(void)
{
VdpStatus vdp_st;
+ VdpPresentationQueueStatus next_status = VDP_PRESENTATION_QUEUE_STATUS_IDLE;
+ VdpTime show_time;
+ VdpTime next_show,now;
+ int q,s;
+ VdpTime time_to_next_vsync;
+ int next_surface = (surface_num + 1) % num_output_surfaces;
+
+ if (output_surfaces[next_surface].surface == VDP_INVALID_HANDLE) {
+ create_output_surface(next_surface);
+ mp_msg(MSGT_VO, MSGL_DBG2, "OUT at flip_page CREATE: %u\n", output_surfaces[next_surface].surface);
+ } else {
+ vdp_st = vdp_presentation_queue_query_surface_status(vdp_flip_queue,
+ output_surfaces[next_surface].surface, &next_status, &show_time);
+ if (num_output_surfaces > 2 && vdp_st == VDP_STATUS_OK &&
+ next_status != VDP_PRESENTATION_QUEUE_STATUS_IDLE) {
+ mp_msg(MSGT_VO, MSGL_V, "[vdpau] dropping frame\n");
+ vo_drop_frame_cnt++;
+ return;
+ }
+ }
+ vo_vsync_offset = (show_time-output_surfaces[next_surface].queued)/1000;
+
+ if (max_delay_interval && vsync_interval) {
+ // find queued surfaces and the visible one
+ for (q=0,s = surface_num-1 < 0 ? num_output_surfaces-1 : surface_num-1;
+ s != surface_num; s = s-1 < 0 ? num_output_surfaces-1 : s-1) {
+ vdp_st = vdp_presentation_queue_query_surface_status(vdp_flip_queue,
+ output_surfaces[s].surface, &next_status, &show_time);
+ if (next_status == VDP_PRESENTATION_QUEUE_STATUS_QUEUED) q++;
+ if (next_status == VDP_PRESENTATION_QUEUE_STATUS_VISIBLE) break;
+ }
+ vdp_st = vdp_presentation_queue_get_time(vdp_flip_queue, &now);
+ CHECK_ST_WARNING("Error when calling vdp_presentation_queue_get_time")
+
+ if (next_status == VDP_PRESENTATION_QUEUE_STATUS_VISIBLE) {
+ q++;
+ next_show = show_time+q*vsync_interval;
+ if (next_show > now) {
+ time_to_next_vsync = next_show-now;
+ if (time_to_next_vsync > max_delay_interval) {
+ mp_msg(MSGT_VO, MSGL_V, "[vdpau] dropping frame - delay to large\n");
+ vo_drop_frame_cnt++;
+ return;
+ }
+ }
+ }
+ output_surfaces[surface_num].queued = now;
+ } else {
+ vdp_st = vdp_presentation_queue_get_time(vdp_flip_queue, &output_surfaces[surface_num].queued);
+ CHECK_ST_WARNING("Error when calling vdp_presentation_queue_get_time")
+ }
+
mp_msg(MSGT_VO, MSGL_DBG2, "\nFLIP_PAGE VID:%u -> OUT:%u\n",
- surface_render[vid_surface_num].surface, output_surfaces[surface_num]);
+ surface_render[vid_surface_num].surface, output_surfaces[surface_num].surface);
- vdp_st = vdp_presentation_queue_display(vdp_flip_queue, output_surfaces[surface_num],
- vo_dwidth, vo_dheight,
+ vdp_st = vdp_presentation_queue_display(vdp_flip_queue, output_surfaces[surface_num].surface,
+ output_surfaces[surface_num].dwidth, output_surfaces[surface_num].dheight,
0);
CHECK_ST_WARNING("Error when calling vdp_presentation_queue_display")
- surface_num = (surface_num + 1) % NUM_OUTPUT_SURFACES;
+ surface_num = next_surface;
visible_buf = 1;
}
@@ -968,11 +1202,61 @@
return 0;
}
+static void load_time_correction(void)
+{
+ char * path = get_path("vdpau.tcorr");
+ FILE * fd;
+
+ time_correction = 0;
+ time_measured_over = 0;
+ fd = fopen(path, "r");
+ if (fd != NULL) {
+ fscanf(fd, "%lf %d\n", &time_correction, &time_measured_over);
+ fclose(fd);
+ }
+}
+
+static void save_time_correction(void)
+{
+ char * path = get_path("vdpau.tcorr");
+ FILE * fd;
+
+ fd = fopen(path, "w");
+ if (fd != NULL) {
+ fprintf(fd, "%lf %d\n", time_correction, time_measured_over);
+ fclose(fd);
+ } else {
+ mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Unable to save timing correction value to %s (%s)\n",path,strerror(errno));
+ }
+}
+
static void DestroyVdpauObjects(void)
{
int i;
VdpStatus vdp_st;
+ if (time_correction >= 0) {
+ VdpTime now;
+ uint64_t systime;
+ VdpTime nvtime;
+ double corr;
+
+ systime = get_time();
+ vdp_st = vdp_presentation_queue_get_time(vdp_flip_queue, &now);
+ CHECK_ST_WARNING("Error when calling vdp_presentation_queue_get_time")
+
+ nvtime = now-reference_vdpau_time;
+ systime = systime-reference_system_time;
+ corr = systime/(nvtime/1000.0f);
+ mp_msg(MSGT_VO,MSGL_V,"[vdpau] Card time correction=%2.10f\n",corr);
+
+ if (systime/1000000 > time_measured_over) {
+ time_correction = corr;
+ time_measured_over = systime/1000000;
+ save_time_correction();
+ }
+ }
+
free_video_specific();
vdp_st = vdp_presentation_queue_destroy(vdp_flip_queue);
@@ -981,11 +1265,15 @@
vdp_st = vdp_presentation_queue_target_destroy(vdp_flip_target);
CHECK_ST_WARNING("Error when calling vdp_presentation_queue_target_destroy")
- for (i = 0; i <= NUM_OUTPUT_SURFACES; i++) {
- vdp_st = vdp_output_surface_destroy(output_surfaces[i]);
- output_surfaces[i] = VDP_INVALID_HANDLE;
- CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy")
+ for (i = 0; i <= num_output_surfaces; i++) {
+ if (output_surfaces[i].surface != VDP_INVALID_HANDLE) {
+ vdp_st = vdp_output_surface_destroy(output_surfaces[i].surface);
+ output_surfaces[i].surface = VDP_INVALID_HANDLE;
+ CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy")
+ }
}
+ free(output_surfaces);
+ output_surfaces = NULL;
for (i = 0; i<eosd_surface_count; i++) {
if (eosd_surfaces[i].surface != VDP_INVALID_HANDLE) {
@@ -1030,6 +1318,7 @@
{"pullup", OPT_ARG_BOOL, &pullup, NULL},
{"denoise", OPT_ARG_FLOAT, &denoise, NULL},
{"sharpen", OPT_ARG_FLOAT, &sharpen, NULL},
+ {"max-delay",OPT_ARG_FLOAT,&max_delay, NULL},
{NULL}
};
@@ -1052,6 +1341,10 @@
" Apply denoising, argument is strength from 0.0 to 1.0\n"
" sharpen\n"
" Apply sharpening or softening, argument is strength from -1.0 to 1.0\n"
+ " max-delay=delay\n"
+ " Maximum delay before frames are dropped, argument is in vsyncs. Do not use\n"
+ " an integer value to avoid jitter (default is 1.3 (1.5 with deint)),\n"
+ " set to 0 for no dropping\n"
;
static int preinit(const char *arg)
@@ -1077,6 +1370,19 @@
deint_type = deint;
if (deint > 1)
deint_buffer_past_frames = 1;
+ if (max_delay < 0) {
+ if (deint) {
+ max_delay = 1.8;
+ } else {
+ max_delay = 1.3;
+ }
+ }
+ if (max_delay) {
+ num_output_surfaces = 3+((int)(max_delay+0.05));
+ } else {
+ num_output_surfaces = 2;
+ }
+ mp_msg(MSGT_VO, MSGL_DBG2, "[vdpau] max delay %f, output surfaces: %d\n", max_delay, num_output_surfaces);
vdpau_lib_handle = dlopen(vdpaulibrary, RTLD_LAZY);
if (!vdpau_lib_handle) {
@@ -1097,8 +1403,9 @@
for (i = 0; i < MAX_VIDEO_SURFACES; i++)
surface_render[i].surface = VDP_INVALID_HANDLE;
video_mixer = VDP_INVALID_HANDLE;
- for (i = 0; i <= NUM_OUTPUT_SURFACES; i++)
- output_surfaces[i] = VDP_INVALID_HANDLE;
+ output_surfaces = (output_surface_info *)calloc(num_output_surfaces+1,sizeof(output_surface_info));
+ for (i = 0; i <= num_output_surfaces; i++)
+ output_surfaces[i].surface = VDP_INVALID_HANDLE;
vdp_flip_queue = VDP_INVALID_HANDLE;
output_surface_width = output_surface_height = -1;
@@ -1118,6 +1425,8 @@
procamp.saturation = 1.0;
procamp.hue = 0.0;
+ load_time_correction();
+
return 0;
}
--- cfg-mplayer.h.org 2009-04-26 16:35:11.000000000 +0200
+++ cfg-mplayer.h 2009-04-26 16:38:24.000000000 +0200
@@ -71,6 +71,9 @@
{NULL, NULL, 0, 0, 0, 0, NULL}
};
#endif
+
+extern m_option_t vdpauopts_conf[];
+
/*
* CONF_TYPE_FUNC_FULL :
* allows own implementations for passing the params
@@ -241,6 +244,9 @@
{"dxr2", &dxr2_opts, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
#endif
+#ifdef CONFIG_VDPAU
+ {"vdpauopts", vdpauopts_conf, CONF_TYPE_SUBCONFIG, CONF_GLOBAL, 0, 0, NULL},
+#endif
//---------------------- mplayer-only options ------------------------
More information about the MPlayer-dev-eng
mailing list