[MPlayer-dev-eng] [PATCH]: reduce vsync wait in VDPAU
Dan Oscarsson
Dan.Oscarsson at tietoenator.com
Wed Feb 25 11:09:09 CET 2009
Hi
Since I got a TV handling 23,976 hz I have seen the problems mplayer
have in handling syncronisation when the screen update frequency is same
as the video's. Probably some of you have noted that mplayer spends a
long time in the "update frame" time on the status line, when using
vdpau. This can be seen even with a 50/60 hz screen update.
The same can be seen using -vo sdl (at least with nvida graphics card).
Both are due to mplayer waiting for vsync (in draw routine in vdpau and
in flip page routine in sdl). Using -vo xv you instead sometimes get
tearing due to mplayer overwriting a shared buffer during screen update.
When mplayer waits for vsync it easily get out of time to do
syncronisation with audio.
In vdpau, the draw routine wait for an output surface to be idle. With
just two output surfaces, vdpau will have one displayed and one waiting
to be displayed. At next vsync, the displayed get idle and can be
reused, and the waiting one gets displayed.
This patch changes so vdpau uses 3 output surfaces, so one can be drawn
into, one can be queued and one displayed. If mplayer get to far ahead,
vo_vdpau will drop a frame.
This patch also adds one variable that contans the number of frames
dropped by vo, and so that it is displayed in the status line (if frames
are dropped). That can be removed easily if you do not want that, but it
is nice to be able to see number of frames drop in the vo layer.
After this patch you will se the time to draw a frame in the status line
drops a lot. With hardware decoding I get mplayer to nearly use no time
at all for video decoding and displaying, audio takes most of the time.
As there is now plenty of free time, audio keeps in sync much better.
-
I also have patches to vo_xv.c that drops frames when mplayer get to far
ahead and risks tearing, if you want them?
Also, I am experimenting on ways to handle the problem mplayer have in
aligning audio with the vsyncs of the screen that now and then results
in frames missed or displayed at wrong time. This is easily be seen when
movie frame rate is the same (or nearly the same) as screen refresh
rate. But this will have to wait until later.
Regards,
Dan
-------------- next part --------------
--- mplayer.c.org 2009-02-24 19:21:52.000000000 +0100
+++ mplayer.c 2009-02-24 19:22:21.000000000 +0100
@@ -1253,6 +1253,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)
--- libvo/video_out.c.org 2009-02-24 18:28:52.000000000 +0100
+++ libvo/video_out.c 2009-02-24 18:29:45.000000000 +0100
@@ -79,6 +79,8 @@
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
+
//
// Externally visible list of all vo drivers
//
--- libvo/video_out.h.org 2009-02-24 18:28:58.000000000 +0100
+++ libvo/video_out.h 2009-02-24 18:30:21.000000000 +0100
@@ -250,6 +250,8 @@
extern int vo_colorkey;
+extern int vo_drop_frame_cnt;
+
extern int WinID;
typedef struct {
--- libvo/vo_vdpau.c.org 2009-02-24 17:59:29.000000000 +0100
+++ libvo/vo_vdpau.c 2009-02-24 19:23:34.000000000 +0100
@@ -121,8 +121,10 @@
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;
-/* output_surfaces[2] is used in composite-picture. */
+
+/* composite_surface is used in composite-picture. */
static VdpOutputSurfaceRenderOutputSurface *vdp_output_surface_render_output_surface;
static VdpOutputSurfacePutBitsIndexed *vdp_output_surface_put_bits_indexed;
@@ -133,6 +135,8 @@
static void *vdpau_lib_handle;
static VdpOutputSurface output_surfaces[NUM_OUTPUT_SURFACES];
static int output_surface_width, output_surface_height;
+static int skip_output_surface[NUM_OUTPUT_SURFACES];
+static VdpOutputSurface composite_surface;
static VdpVideoMixer video_mixer;
static int deint;
@@ -231,7 +235,15 @@
&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]);
+ skip_output_surface[i] = 0;
}
+ if (composite_surface != VDP_INVALID_HANDLE)
+ vdp_output_surface_destroy(composite_surface);
+ vdp_st = vdp_output_surface_create(vdp_device, VDP_RGBA_FORMAT_B8G8R8A8,
+ output_surface_width, output_surface_height,
+ &composite_surface);
+ CHECK_ST_WARNING("Error when calling vdp_output_surface_create")
+ mp_msg(MSGT_VO, MSGL_DBG2, "OUT CREATE: %u\n", composite_surface);
}
video_to_output_surface();
if (visible_buf)
@@ -279,6 +291,8 @@
&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_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE,
&vdp_output_surface_render_output_surface},
{VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED,
@@ -535,8 +549,8 @@
pitch = w*2;
- // write source_data to output_surfaces[2].
- vdp_st = vdp_output_surface_put_bits_indexed(output_surfaces[2],
+ // write source_data to composite_surface.
+ vdp_st = vdp_output_surface_put_bits_indexed(composite_surface,
VDP_INDEXED_FORMAT_I8A8,
(const void *const*)&index_data,
&pitch,
@@ -555,7 +569,7 @@
vdp_st = vdp_output_surface_render_output_surface(output_surface,
&output_indexed_rect_vid,
- output_surfaces[2],
+ composite_surface,
&output_indexed_rect_vid,
NULL,
&blend_state,
@@ -577,12 +591,16 @@
mp_msg(MSGT_VO, MSGL_DBG2, "\nFLIP_PAGE VID:%u -> OUT:%u\n",
surface_render[vid_surface_num].surface, output_surfaces[surface_num]);
+ if (skip_output_surface[surface_num]) { // as it is not ready due to not idle in time
+ vo_drop_frame_cnt++;
+ return;
+ }
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")
- surface_num = !surface_num;
+ surface_num = (surface_num+1) % NUM_OUTPUT_SURFACES;
visible_buf = 1;
}
@@ -650,11 +668,26 @@
static uint32_t draw_image(mp_image_t *mpi)
{
+ VdpStatus vdp_st;
+ VdpTime dummy;
+ VdpPresentationQueueStatus out_status;
+
+ vdp_st = vdp_presentation_queue_query_surface_status(vdp_flip_queue,
+ output_surfaces[surface_num],
+ &out_status,
+ &dummy);
+ CHECK_ST_ERROR("Error when calling vdp_presentation_queue_query_surface_status")
+ if (out_status != VDP_PRESENTATION_QUEUE_STATUS_IDLE) {
+ skip_output_surface[surface_num] = 1;
+ return VO_TRUE;
+ } else {
+ skip_output_surface[surface_num] = 0;
+ }
+
if (IMGFMT_IS_VDPAU(image_format)) {
struct vdpau_render_state *rndr = mpi->priv;
vid_surface_num = rndr - surface_render;
} else if (!(mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)) {
- VdpStatus vdp_st;
void *destdata[3] = {mpi->planes[0], mpi->planes[2], mpi->planes[1]};
struct vdpau_render_state *rndr = get_surface(0);
vid_surface_num = rndr - surface_render;
@@ -727,6 +760,9 @@
output_surfaces[i] = VDP_INVALID_HANDLE;
CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy")
}
+ vdp_st = vdp_output_surface_destroy(composite_surface);
+ composite_surface = VDP_INVALID_HANDLE;
+ CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy")
vdp_st = vdp_device_destroy(vdp_device);
CHECK_ST_WARNING("Error when calling vdp_device_destroy")
@@ -812,6 +848,7 @@
video_mixer = VDP_INVALID_HANDLE;
for (i = 0; i < NUM_OUTPUT_SURFACES; i++)
output_surfaces[i] = VDP_INVALID_HANDLE;
+ composite_surface = VDP_INVALID_HANDLE;
vdp_flip_queue = VDP_INVALID_HANDLE;
output_surface_width = output_surface_height = -1;
More information about the MPlayer-dev-eng
mailing list