[MPlayer-dev-eng] [PATCH] vdpau fixes and timing enhancements
Dan Oscarsson
Dan.Oscarsson at tietoenator.com
Sat Apr 18 16:02:30 CEST 2009
Hi
Here is a patch for my current version of fixes and enhancements to
using vdpau.
I have been using them for many weeks using the overlay engine for
display without problems. As I only have two systems (of which one is
using a lcd tv for display) to test on, there may be things working
differently on other systems with other graphic cards.
I have not included documentation updates. I will do that if you think
my fixes/enhancements are ok.
The patches include:
- an option to vdpau: max-delay
which if set to 0 results in 2 output surfaces and working
like current code.
if set will drop frames if a frame would be delayed longer
then given value. the number of output surfaces will be adjusted to
match.
by default will select suitable delay (will be larger if
de-interlacing is used).
- an option to vdpau: time-corr
which measures card time and prints correction value at end of
movie. To be used with option: card-time-correction
- a global option: vdpauopts
that can be used to set max-delay or time-corr for use when
vo vdpau is selected. This what you can change the default
for vdpau without having to select -vo vdpau
Useful to have in your .mplayer/config
- fixes so resizing window do not flash a lot. Though there are
some when using blit engine still, none with overlay.
- a global option: match-vsync-speed
that will change speed of movie to vsync speed (if nearly the same).
this allows movies to be shown with less frame dropping.
- a global option: card-time-correction
that gives correction that is needed to correct that graphics card
have a time that have a different speed then system time.
- on status line, info about dropped frames by vo is added if that
occur. Like this:
A: 7.8 V: 7.8 A-V: -0.000 ct: 0.000 0/ 0 5% 1% 1.9% 0 0 7
where the 7 at the end shows frames dropped by vo.
The defaults are:
max-delay = 1.3 if normal, 1.5 if de-interlacing
mplayer -vo vdpau:max-delay=0
gives same handling as before (2 output surfaces, waiting for idle
surface).
The default mplayer -vo vdpau:max-delay=1.3
gives 4 output surfaces and frames will be dropped if more than 1.3
vsync intervals are needed before the frame will be shown.
You will probably only notice a difference when running a movie
at same rate or higher then screen refresh rate.
To avoid frame drops when rate is nearly the same as display,
like running a 24hz movie on a lcd tv at 24hz, you can have
mplayer adjust speed to match display rate.
mplayer -match-vsync-speed
In this case, if movie fps is near (about 5%) of vsync rate,
playback speed will be adjusted to match vsync rate.
Pressing backspace to adjust speed to 1.0 will change speed
back to adjusted speed.
Have not tested this with blit engine, works fine with overlay.
Measuring vsync interval when blit engine is used is less
accurate so may not be good enough.
My tests show that time speed is different on graphics card
compared to system time. To fix this, you run a full movie
with -vo vdpau:time-corr and records the value printed
when movie ends. You then add
mplayer -card-time-correction printed-value (or in your
config-file) which corrects the speed matching.
Using this I can view a movie without frame drops.
Notes on my changes to the code:
In mplayer.c I have changed order of audio decode and video decode
so that video decode is done first. This is due to when starting
decoding of video it takes some time (especially when needing to
measure vsync interval) and that will make audio start out of
sync unless video decode is done first.
In osdep I have added a get_timer call (only for linux for now)
that returns current time in 64-bit value. You cannot use the
GetTimer call for timing over long time, as it is only 32-bit and
will wrap around.
In vo_vdpau.c the code includes code to:
- time the vsync interval
- flashing fixes
- variable number of output surfaces
- card time correction calculation
Hope they are interesting enough to include now.
Dan
-------------- next part --------------
--- mplayer.c.org 2009-04-18 15:13:38.000000000 +0200
+++ mplayer.c 2009-04-18 15:14:50.000000000 +0200
@@ -216,6 +216,8 @@
static int output_quality=0;
float playback_speed=1.0;
+float matched_playback_speed=0;
+float card_time_correction=0;
int use_gui=0;
@@ -302,6 +304,8 @@
static int play_n_frames=-1;
static int play_n_frames_mf=-1;
+ int match_vsync_speed=0; // match speed to vsync speed
+
// screen info:
char** video_driver_list=NULL;
char** audio_driver_list=NULL;
@@ -1255,6 +1259,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)
@@ -2514,6 +2521,7 @@
int i;
int gui_no_filename=0;
+int vsynced_speed = 0;
InitTimer();
srand(GetTimerMS());
@@ -3656,6 +3664,55 @@
reinit_audio_chain();
}
+if (match_vsync_speed && vo_vsync_interval > 0) {
+ if (!vsynced_speed) {
+ float fps_interval, vo_interval;
+
+ fps_interval = 1000000.0f/vo_fps;
+ vo_interval = vo_vsync_interval/1000.0f;
+ if (fps_interval*0.95 < vo_interval && vo_interval < fps_interval*1.05) {
+ matched_playback_speed = fps_interval/vo_interval;
+ mp_msg(MSGT_CPLAYER,MSGL_INFO,"Matching speed to vsync %3.10f\n",matched_playback_speed);
+ } else if (fps_interval/2*0.95 < vo_interval && vo_interval < fps_interval/2*1.05) {
+ matched_playback_speed = fps_interval/2/vo_interval;
+ mp_msg(MSGT_CPLAYER,MSGL_INFO,"Matching speed to double vsync rate %3.10f\n",matched_playback_speed);
+ } else {
+ mp_msg(MSGT_CPLAYER,MSGL_INFO,"Vsync rate to far from video rate, no matching of speed\n");
+ }
+ if (matched_playback_speed) {
+ if (card_time_correction) matched_playback_speed *= card_time_correction;
+ playback_speed = matched_playback_speed;
+ build_afilter_chain(mpctx->sh_audio, &ao_data);
+ }
+ vsynced_speed = 1;
+ }
+}
+
+
+
+/*========================== 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 +3738,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-18 15:13:47.000000000 +0200
+++ libvo/video_out.c 2009-04-18 15:14:50.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;
+unsigned int vo_vsync_interval = 0;
+
+
//
// Externally visible list of all vo drivers
//
--- libvo/video_out.h.org 2009-04-18 15:13:53.000000000 +0200
+++ libvo/video_out.h 2009-04-18 15:14:50.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-18 15:14:00.000000000 +0200
+++ libvo/vo_vdpau.c 2009-04-18 15:14:50.000000000 +0200
@@ -43,6 +43,7 @@
#include "aspect.h"
#include "sub.h"
#include "subopt-helper.h"
+#include "osdep/timer.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_t;
+
+/* output_surfaces[num_output_surfaces] is misused for OSD. */
+#define osd_surface output_surfaces[num_output_surfaces].surface
+static output_surface_t *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,10 @@
static int chroma_deint;
static int top_field_first;
+static float max_delay = -1;
+static unsigned int max_delay_interval;
+static int time_corr;
+
static VdpDecoder decoder;
static int decoder_max_refs;
@@ -205,12 +224,64 @@
// 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},
+ {"time-corr", &time_corr, CONF_TYPE_FLAG, 0, 0, 1, NULL},
+ {NULL, NULL, 0, 0, 0, 0, NULL}
+};
+
+
/*
* 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 +293,6 @@
static void video_to_output_surface(void)
{
- VdpTime dummy;
VdpStatus vdp_st;
int i;
if (vid_surface_num < 0)
@@ -243,12 +313,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 +329,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 +352,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 +410,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 +455,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 +465,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 +597,108 @@
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 (vo_vsync_interval) return;
+
+ if (time_corr) {
+ // 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;
+ }
+ }
+ } else { // td1 == td3
+ }
+ }
+ if (td1 < 5000000) {
+ mp_msg(MSGT_VO, MSGL_V, "[vdpau] To small vsync value - assume no vsync alignment\n");
+ return;
+ }
+ vo_vsync_interval = td1;
+
+ 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 = vo_vsync_interval*max_delay;
+ }
+}
+
+
/*
* connect to X server, create and map window, initialize all
* VDPAU objects, create different surfaces etc.
@@ -625,6 +796,8 @@
vid_surface_num = -1;
resize();
+ if (max_delay) get_vdpau_timing();
+
return 0;
}
@@ -636,23 +809,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 +879,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 +1002,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 && vo_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*vo_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;
}
@@ -973,6 +1191,22 @@
int i;
VdpStatus vdp_st;
+ if (time_corr) {
+ VdpTime now;
+ u_int64_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_INFO,"[vdpau] Card time correction=%2.10f\n",corr);
+ }
+
free_video_specific();
vdp_st = vdp_presentation_queue_destroy(vdp_flip_queue);
@@ -981,11 +1215,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 +1268,8 @@
{"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},
+ {"time-corr",OPT_ARG_BOOL, &time_corr, NULL},
{NULL}
};
@@ -1052,6 +1292,14 @@
" 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"
+ " time-corr\n"
+ " Turns on card time correction calculation (unless max_delay=0).\n"
+ " Printed at exit, to get best value, and can be used as input to\n"
+ " the -card-time-correction option\n"
;
static int preinit(const char *arg)
@@ -1077,6 +1325,19 @@
deint_type = deint;
if (deint > 1)
deint_buffer_past_frames = 1;
+ if (max_delay < 0) {
+ if (deint) {
+ max_delay = 1.5;
+ } 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 +1358,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_t *)calloc(num_output_surfaces+1,sizeof(output_surface_t));
+ 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;
--- osdep/timer.h.org 2009-04-18 15:14:05.000000000 +0200
+++ osdep/timer.h 2009-04-18 15:14:50.000000000 +0200
@@ -21,6 +21,8 @@
extern const char *timer_name;
+u_int64_t get_time(void);
+
void InitTimer(void);
unsigned int GetTimer(void);
unsigned int GetTimerMS(void);
--- osdep/timer-linux.c.org 2009-04-18 15:14:12.000000000 +0200
+++ osdep/timer-linux.c 2009-04-18 15:14:50.000000000 +0200
@@ -26,6 +26,7 @@
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
+#include <sys/types.h>
#include "config.h"
const char *timer_name =
@@ -47,6 +48,13 @@
#endif
}
+// Returns current time in microseconds in 64 bit quantity so it does not wrap
+u_int64_t get_time(void){
+ struct timeval tv;
+ gettimeofday(&tv,NULL);
+ return (u_int64_t)(tv.tv_sec)*1000000+tv.tv_usec;
+}
+
// Returns current time in microseconds
unsigned int GetTimer(void){
struct timeval tv;
--- mp_core.h.org 2009-04-18 15:14:18.000000000 +0200
+++ mp_core.h 2009-04-18 15:14:50.000000000 +0200
@@ -124,6 +124,10 @@
extern int fixed_vo;
extern int forced_subs_only;
+extern float matched_playback_speed; // matched with vsync speed, use instead of 1.0
+extern int match_vsync_speed; // enable speed matching
+extern float card_time_correction; // speed correction due to different clock on card
+
int build_afilter_chain(sh_audio_t *sh_audio, ao_data_t *ao_data);
void uninit_player(unsigned int mask);
--- cfg-mplayer.h.org 2009-04-18 15:14:23.000000000 +0200
+++ cfg-mplayer.h 2009-04-18 15:14:50.000000000 +0200
@@ -71,6 +71,11 @@
{NULL, NULL, 0, 0, 0, 0, NULL}
};
#endif
+
+#ifdef CONFIG_VDPAU
+extern m_option_t vdpauopts_conf[];
+#endif
+
/*
* CONF_TYPE_FUNC_FULL :
* allows own implementations for passing the params
@@ -241,6 +246,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 ------------------------
@@ -326,6 +334,8 @@
{"autosync", &autosync, CONF_TYPE_INT, CONF_RANGE, 0, 10000, NULL},
// {"dapsync", &dapsync, CONF_TYPE_FLAG, 0, 0, 1, NULL},
// {"nodapsync", &dapsync, CONF_TYPE_FLAG, 0, 1, 0, NULL},
+ {"match-vsync-speed", &match_vsync_speed, CONF_TYPE_FLAG, 0, 0, 1, NULL},
+ {"card-time-correction", &card_time_correction, CONF_TYPE_FLOAT, CONF_RANGE, 0.8, 1.2, NULL},
{"softsleep", &softsleep, CONF_TYPE_FLAG, 0, 0, 1, NULL},
#ifdef HAVE_RTC
--- command.c.org 2009-04-18 15:14:29.000000000 +0200
+++ command.c 2009-04-18 15:14:50.000000000 +0200
@@ -198,6 +198,9 @@
return M_PROPERTY_ERROR;
M_PROPERTY_CLAMP(prop, *(float *) arg);
playback_speed = *(float *) arg;
+ if (playback_speed == 1.0 && matched_playback_speed) {
+ playback_speed = matched_playback_speed;
+ }
build_afilter_chain(mpctx->sh_audio, &ao_data);
return M_PROPERTY_OK;
case M_PROPERTY_STEP_UP:
@@ -2491,6 +2494,9 @@
case MP_CMD_SPEED_SET:{
float v = cmd->args[0].v.f;
playback_speed = v;
+ if (playback_speed == 1.0 && matched_playback_speed) {
+ playback_speed = matched_playback_speed;
+ }
build_afilter_chain(sh_audio, &ao_data);
set_osd_msg(OSD_MSG_SPEED, 1, osd_duration, MSGTR_OSDSpeed,
playback_speed);
More information about the MPlayer-dev-eng
mailing list