[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