From 37713cb3ec2ad1c05dbc828ad94e12cd4ea4f574 Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Thu, 22 Oct 2009 04:21:14 +0300 Subject: cosmetics: Add two missing "static" Add missing 'static' to internal functions in vo_xv.c and vo_vdpau.c. --- libvo/vo_vdpau.c | 2 +- libvo/vo_xv.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'libvo') diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index e613205834..286015176c 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -559,7 +559,7 @@ static int create_vdp_decoder(struct vo *vo, int max_refs) return 1; } -int initialize_vdpau_objects(struct vo *vo) +static int initialize_vdpau_objects(struct vo *vo) { struct vdpctx *vc = vo->priv; struct vdp_functions *vdp = vc->vdp; diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c index f9579c1e19..886fd0a0d7 100644 --- a/libvo/vo_xv.c +++ b/libvo/vo_xv.c @@ -400,7 +400,7 @@ static inline void put_xvimage(struct vo *vo, XvImage *xvi) } // Only copies luma for planar formats as draw_alpha doesn't change others */ -void copy_backup_image(struct vo *vo, int dest, int src) +static void copy_backup_image(struct vo *vo, int dest, int src) { struct xvctx *ctx = vo->priv; -- cgit v1.2.3 From b87ce8bc96657c0b2d9b7fc51ed4bc1661d53270 Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Wed, 14 Oct 2009 04:12:10 +0300 Subject: vo_vdpau: Modify frame buffering code Clean up code related to frame buffering and generate pts information also for the next frame in the output queue. The timing information will be used in a following framedrop patch. This commit adds one frame of buffering delay in vo_vdpau and increases the number of buffered vdpau video surfaces from 3 to 4. The delay increase makes it more important to fix remaining code in MPlayer that doesn't deal well with filter/VO delay; OTOH it should help any decoding/filtering parallelism in the underlying VDPAU implementation as now filtering a frame for display can happen while the next one is being decoded. --- libvo/video_out.c | 2 +- libvo/video_out.h | 3 ++ libvo/vo_vdpau.c | 131 ++++++++++++++++++++++++++++++++---------------------- 3 files changed, 81 insertions(+), 55 deletions(-) (limited to 'libvo') diff --git a/libvo/video_out.c b/libvo/video_out.c index 7a41fcf1d4..615cfe57f4 100644 --- a/libvo/video_out.c +++ b/libvo/video_out.c @@ -333,7 +333,7 @@ void vo_flip_page(struct vo *vo) if (!vo->config_ok) return; vo->frame_loaded = false; - vo->next_pts = (-1LL<<63); // MP_NOPTS_VALUE + vo->next_pts = MP_NOPTS_VALUE; vo->driver->flip_page(vo); } diff --git a/libvo/video_out.h b/libvo/video_out.h index 9bbfd3dc41..9e6de0842e 100644 --- a/libvo/video_out.h +++ b/libvo/video_out.h @@ -30,6 +30,8 @@ #include "libmpcodecs/img_format.h" //#include "vidix/vidix.h" +#define MP_NOPTS_VALUE (-1LL<<63) + #define VO_EVENT_EXPOSE 1 #define VO_EVENT_RESIZE 2 #define VO_EVENT_KEYPRESS 4 @@ -231,6 +233,7 @@ struct vo { bool frame_loaded; // Is there a next frame the VO could flip to? double next_pts; // pts value of the next frame if any + double next_pts2; // optional pts of frame after that const struct vo_driver *driver; void *priv; diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index 286015176c..2f45003f21 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -74,6 +74,7 @@ /* number of video and output surfaces */ #define NUM_OUTPUT_SURFACES 2 #define MAX_VIDEO_SURFACES 50 +#define NUM_BUFFERED_VIDEO 4 /* number of palette entries */ #define PALETTE_SIZE 256 @@ -110,10 +111,12 @@ struct vdpctx { /* output_surfaces[NUM_OUTPUT_SURFACES] is misused for OSD. */ #define osd_surface vc->output_surfaces[NUM_OUTPUT_SURFACES] VdpOutputSurface output_surfaces[NUM_OUTPUT_SURFACES + 1]; - VdpVideoSurface deint_surfaces[3]; - double deint_pts[3]; + struct buffered_video_surface { + VdpVideoSurface surface; + double pts; + mp_image_t *mpi; + } buffered_video[NUM_BUFFERED_VIDEO]; int deint_queue_pos; - mp_image_t *deint_mpi[3]; int output_surface_width, output_surface_height; VdpVideoMixer video_mixer; @@ -187,6 +190,7 @@ static int video_to_output_surface(struct vo *vo) if (vc->deint_queue_pos < 0) return -1; + struct buffered_video_surface *bv = vc->buffered_video; int field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; unsigned int dp = vc->deint_queue_pos; // dp==0 means last field of latest frame, 1 earlier field of latest frame, @@ -196,11 +200,10 @@ static int video_to_output_surface(struct vo *vo) VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD: VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; } - VdpVideoSurface *q = vc->deint_surfaces; const VdpVideoSurface *past_fields = (const VdpVideoSurface []){ - q[(dp+1)/2], q[(dp+2)/2]}; + bv[(dp+1)/2].surface, bv[(dp+2)/2].surface}; const VdpVideoSurface *future_fields = (const VdpVideoSurface []){ - q[(dp-1)/2]}; + dp >= 1 ? bv[(dp-1)/2].surface : VDP_INVALID_HANDLE}; VdpOutputSurface output_surface = vc->output_surfaces[vc->surface_num]; vdp_st = vdp->presentation_queue_block_until_surface_idle(vc->flip_queue, output_surface, @@ -210,56 +213,92 @@ static int video_to_output_surface(struct vo *vo) vdp_st = vdp->video_mixer_render(vc->video_mixer, VDP_INVALID_HANDLE, 0, field, 2, past_fields, - vc->deint_surfaces[dp/2], 1, future_fields, + bv[dp/2].surface, 1, future_fields, &vc->src_rect_vid, output_surface, NULL, &vc->out_rect_vid, 0, NULL); CHECK_ST_WARNING("Error when calling vdp_video_mixer_render"); return 0; } -static void add_new_video_surface(struct vo *vo, VdpVideoSurface surface, - struct mp_image *reserved_mpi, double pts) +static void get_buffered_frame(struct vo *vo, bool eof) { struct vdpctx *vc = vo->priv; - if (reserved_mpi) - reserved_mpi->usage_count++; - if (vc->deint_mpi[2]) - vc->deint_mpi[2]->usage_count--; - - for (int i = 2; i > 0; i--) { - vc->deint_mpi[i] = vc->deint_mpi[i - 1]; - vc->deint_surfaces[i] = vc->deint_surfaces[i - 1]; - vc->deint_pts[i] = vc->deint_pts[i - 1]; - } - vc->deint_mpi[0] = reserved_mpi; - vc->deint_surfaces[0] = surface; - vc->deint_pts[0] = pts; + int dqp = vc->deint_queue_pos; + if (dqp < 0) + dqp += 1000; + else + dqp = vc->deint >= 2 ? dqp - 1 : dqp - 2 | 1; + if (dqp < (eof ? 0 : 3)) + return; + dqp = FFMIN(dqp, 4); + vc->deint_queue_pos = dqp; vo->frame_loaded = true; - vo->next_pts = pts; - if (vc->deint >= 2 && vc->deint_queue_pos >= 0) { - vc->deint_queue_pos = 2; - double diff = vc->deint_pts[0] - vc->deint_pts[1]; + + // Set pts values + struct buffered_video_surface *bv = vc->buffered_video; + int idx = vc->deint_queue_pos >> 1; + if (idx == 0) { // no future frame/pts available + vo->next_pts = bv[0].pts; + vo->next_pts2 = MP_NOPTS_VALUE; + } else if (!(vc->deint >= 2)) { // no field-splitting deinterlace + vo->next_pts = bv[idx].pts; + vo->next_pts2 = bv[idx - 1].pts; + } else { // deinterlace with separate fields + double intermediate_pts; + double diff = bv[idx - 1].pts - bv[idx].pts; if (diff > 0 && diff < 0.5) - vo->next_pts = (vc->deint_pts[0] + vc->deint_pts[1]) / 2; + intermediate_pts = (bv[idx].pts + bv[idx - 1].pts) / 2; else - vo->next_pts = vc->deint_pts[1]; - } else - vc->deint_queue_pos = 1; + intermediate_pts = bv[idx].pts; + if (vc->deint_queue_pos & 1) { // first field + vo->next_pts = bv[idx].pts; + vo->next_pts2 = intermediate_pts; + } else { + vo->next_pts = intermediate_pts; + vo->next_pts2 = bv[idx - 1].pts; + } + } + video_to_output_surface(vo); } +static void add_new_video_surface(struct vo *vo, VdpVideoSurface surface, + struct mp_image *reserved_mpi, double pts) +{ + struct vdpctx *vc = vo->priv; + struct buffered_video_surface *bv = vc->buffered_video; + + if (reserved_mpi) + reserved_mpi->usage_count++; + if (bv[NUM_BUFFERED_VIDEO - 1].mpi) + bv[NUM_BUFFERED_VIDEO - 1].mpi->usage_count--; + + for (int i = NUM_BUFFERED_VIDEO - 1; i > 0; i--) + bv[i] = bv[i - 1]; + bv[0] = (struct buffered_video_surface){ + .mpi = reserved_mpi, + .surface = surface, + .pts = pts, + }; + + vc->deint_queue_pos += 2; + get_buffered_frame(vo, false); +} + static void forget_frames(struct vo *vo) { struct vdpctx *vc = vo->priv; - vc->deint_queue_pos = -1; - for (int i = 0; i < 3; i++) { - vc->deint_surfaces[i] = VDP_INVALID_HANDLE; - if (vc->deint_mpi[i]) - vc->deint_mpi[i]->usage_count--; - vc->deint_mpi[i] = NULL; + vc->deint_queue_pos = -1001; + for (int i = 0; i < NUM_BUFFERED_VIDEO; i++) { + struct buffered_video_surface *p = vc->buffered_video + i; + if (p->mpi) + p->mpi->usage_count--; + *p = (struct buffered_video_surface){ + .surface = VDP_INVALID_HANDLE, + }; } } @@ -498,11 +537,7 @@ static void free_video_specific(struct vo *vo) vc->decoder = VDP_INVALID_HANDLE; vc->decoder_max_refs = -1; - for (i = 0; i < 2; i++) - if (vc->deint_mpi[i]) { - vc->deint_mpi[i]->usage_count--; - vc->deint_mpi[i] = NULL; - } + forget_frames(vo); for (i = 0; i < MAX_VIDEO_SURFACES; i++) { if (vc->surface_render[i].surface != VDP_INVALID_HANDLE) { @@ -1144,7 +1179,7 @@ static void draw_image(struct vo *vo, mp_image_t *mpi, double pts) VdpStatus vdp_st; void *destdata[3] = {mpi->planes[0], mpi->planes[2], mpi->planes[1]}; rndr = get_surface(vo, vc->deint_counter); - vc->deint_counter = (vc->deint_counter + 1) % 3; + vc->deint_counter = (vc->deint_counter + 1) % NUM_BUFFERED_VIDEO; if (vc->image_format == IMGFMT_NV12) destdata[1] = destdata[2]; vdp_st = @@ -1169,18 +1204,6 @@ static void draw_image(struct vo *vo, mp_image_t *mpi, double pts) return; } -static void get_buffered_frame(struct vo *vo, bool eof) -{ - struct vdpctx *vc = vo->priv; - - if (vc->deint_queue_pos < 2) - return; - vc->deint_queue_pos = 1; - video_to_output_surface(vo); - vo->next_pts = vc->deint_pts[0]; - vo->frame_loaded = true; -} - static uint32_t get_image(struct vo *vo, mp_image_t *mpi) { struct vdpctx *vc = vo->priv; -- cgit v1.2.3 From 201bef7ee150f9d852996b379c926ba0c47320d5 Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Sun, 15 Nov 2009 04:39:22 +0200 Subject: Implement vsync-aware frame timing for VDPAU Main things added are custom frame dropping for VDPAU to work around the display FPS limit, frame timing adjustment to avoid jitter when video frame times keep falling near vsyncs, and use of VDPAU's timing feature to keep one future frame queued in advance. NVIDIA's VDPAU implementation refuses to change the displayed frame more than once per vsync. This set a limit on how much video could be sped up, and caused problems for nearly all videos on low-FPS video projectors (playing 24 FPS video on a 24 FPS projector would not work reliably as MPlayer may need to slightly speed up the video for AV sync). This commit adds a framedrop mechanism that drops some frames so that no more than one is sent for display per vsync. The code tries to select the dropped frames smartly, selecting the best one to show for each vsync. Because of the timing features needed the drop functionality currently does not work if the correct-pts option is disabled. The code also adjusts frame timing slightly to avoid jitter. If you for example play 24 FPS video content on a 72 FPS display then normally a frame would be shown for 3 vsyncs, but if the frame times happen to fall near vsyncs and change between just before and just after then there could be frames alternating between 2 and 4 vsyncs. The code changes frame timing by up to one quarter vsync interval to avoid this. The above functionality depends on having reliable vsync timing information available. The display refresh rate is not directly provided by the VDPAU API. The current code uses information from the XF86VidMode extension if available; I'm not sure how common cases where that is inaccurate are. The refresh rate can be specified manually if necessary. After the changes in this commit MPlayer now always tries to keep one frame queued for future display using VDPAU's internal timing mechanism (however no more than 50 ms to the future). This should make video playback somewhat more robust against timing inaccuracies caused by system load. --- libvo/vdpau_template.c | 2 + libvo/video_out.c | 7 +- libvo/video_out.h | 3 +- libvo/vo_vdpau.c | 230 ++++++++++++++++++++++++++++++++++++++++++++++--- libvo/x11_common.c | 12 +++ libvo/x11_common.h | 1 + 6 files changed, 239 insertions(+), 16 deletions(-) (limited to 'libvo') diff --git a/libvo/vdpau_template.c b/libvo/vdpau_template.c index ca1a6f6056..1b8d354316 100644 --- a/libvo/vdpau_template.c +++ b/libvo/vdpau_template.c @@ -27,6 +27,8 @@ VDP_FUNCTION(VdpPresentationQueueBlockUntilSurfaceIdle, VDP_FUNC_ID_PRESENTATION VDP_FUNCTION(VdpPresentationQueueCreate, VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE, presentation_queue_create) VDP_FUNCTION(VdpPresentationQueueDestroy, VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY, presentation_queue_destroy) VDP_FUNCTION(VdpPresentationQueueDisplay, VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY, presentation_queue_display) +VDP_FUNCTION(VdpPresentationQueueGetTime, VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME, presentation_queue_get_time) +VDP_FUNCTION(VdpPresentationQueueQuerySurfaceStatus, VDP_FUNC_ID_PRESENTATION_QUEUE_QUERY_SURFACE_STATUS, presentation_queue_query_surface_status) VDP_FUNCTION(VdpPresentationQueueTargetCreateX11, VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11, presentation_queue_target_create_x11) VDP_FUNCTION(VdpPresentationQueueTargetDestroy, VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY, presentation_queue_target_destroy) VDP_FUNCTION(VdpVideoMixerCreate, VDP_FUNC_ID_VIDEO_MIXER_CREATE, video_mixer_create) diff --git a/libvo/video_out.c b/libvo/video_out.c index 615cfe57f4..eb3d0183d6 100644 --- a/libvo/video_out.c +++ b/libvo/video_out.c @@ -328,13 +328,16 @@ void vo_draw_osd(struct vo *vo, struct osd_state *osd) vo->driver->draw_osd(vo, osd); } -void vo_flip_page(struct vo *vo) +void vo_flip_page(struct vo *vo, unsigned int pts_us, int duration) { if (!vo->config_ok) return; vo->frame_loaded = false; vo->next_pts = MP_NOPTS_VALUE; - vo->driver->flip_page(vo); + if (vo->driver->flip_page_timed) + vo->driver->flip_page_timed(vo, pts_us, duration); + else + vo->driver->flip_page(vo); } void vo_check_events(struct vo *vo) diff --git a/libvo/video_out.h b/libvo/video_out.h index 9e6de0842e..50602e83a4 100644 --- a/libvo/video_out.h +++ b/libvo/video_out.h @@ -200,6 +200,7 @@ struct vo_driver { * Blit/Flip buffer to the screen. Must be called after each frame! */ void (*flip_page)(struct vo *vo); + void (*flip_page_timed)(struct vo *vo, unsigned int pts_us, int duration); /* * This func is called after every frames to handle keyboard and @@ -277,7 +278,7 @@ int vo_get_buffered_frame(struct vo *vo, bool eof); int vo_draw_frame(struct vo *vo, uint8_t *src[]); int vo_draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h, int x, int y); void vo_draw_osd(struct vo *vo, struct osd_state *osd); -void vo_flip_page(struct vo *vo); +void vo_flip_page(struct vo *vo, unsigned int pts_us, int duration); void vo_check_events(struct vo *vo); void vo_seek_reset(struct vo *vo); void vo_destroy(struct vo *vo); diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index 2f45003f21..6eef93842f 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -2,6 +2,7 @@ * VDPAU video output driver * * Copyright (C) 2008 NVIDIA + * Copyright (C) 2009 Uoti Urpala * * This file is part of MPlayer. * @@ -32,6 +33,7 @@ #include #include #include +#include #include "config.h" #include "mp_msg.h" @@ -72,7 +74,7 @@ } while (0) /* number of video and output surfaces */ -#define NUM_OUTPUT_SURFACES 2 +#define NUM_OUTPUT_SURFACES 3 #define MAX_VIDEO_SURFACES 50 #define NUM_BUFFERED_VIDEO 4 @@ -105,6 +107,8 @@ struct vdpctx { VdpPresentationQueueTarget flip_target; VdpPresentationQueue flip_queue; + uint64_t last_vdp_time; + unsigned int last_sync_update; void *vdpau_lib_handle; @@ -138,6 +142,13 @@ struct vdpctx { struct vdpau_render_state surface_render[MAX_VIDEO_SURFACES]; int surface_num; + VdpTime recent_vsync_time; + float user_fps; + unsigned int vsync_interval; + uint64_t last_queue_time; + uint64_t last_ideal_time; + bool dropped_frame; + uint64_t dropped_time; uint32_t vid_width, vid_height; uint32_t image_format; VdpChromaType vdp_chroma_type; @@ -172,15 +183,57 @@ struct vdpctx { // Video equalizer VdpProcamp procamp; - bool visible_buf; + int num_shown_frames; bool paused; // These tell what's been initialized and uninit() should free/uninitialize bool mode_switched; }; +static int change_vdptime_sync(struct vdpctx *vc, unsigned int *t) +{ + struct vdp_functions *vdp = vc->vdp; + VdpStatus vdp_st; + VdpTime vdp_time; + vdp_st = vdp->presentation_queue_get_time(vc->flip_queue, &vdp_time); + CHECK_ST_ERROR("Error when calling vdp_presentation_queue_get_time"); + unsigned int t1 = *t; + unsigned int t2 = GetTimer(); + uint64_t old = vc->last_vdp_time + (t1 - vc->last_sync_update) * 1000ULL; + if (vdp_time > old) + if (vdp_time > old + (t2 - t1) * 1000ULL) + vdp_time -= (t2 - t1) * 1000ULL; + else + vdp_time = old; + mp_msg(MSGT_VO, MSGL_V, "[vdpau] adjusting VdpTime offset by %f µs\n", + (int64_t)(vdp_time - old) / 1000.); + vc->last_vdp_time = vdp_time; + vc->last_sync_update = t1; + *t = t2; + return 0; +} + +static uint64_t sync_vdptime(struct vo *vo) +{ + struct vdpctx *vc = vo->priv; + + unsigned int t = GetTimer(); + if (t - vc->last_sync_update > 5000000) + change_vdptime_sync(vc, &t); + uint64_t now = (t - vc->last_sync_update) * 1000ULL + vc->last_vdp_time; + // Make sure nanosecond inaccuracies don't make things inconsistent + now = FFMAX(now, vc->recent_vsync_time); + return now; +} + +static uint64_t convert_to_vdptime(struct vo *vo, unsigned int t) +{ + struct vdpctx *vc = vo->priv; + return (int)(t - vc->last_sync_update) * 1000LL + vc->last_vdp_time; +} + +static void flip_page_timed(struct vo *vo, unsigned int pts_us, int duration); -static void flip_page(struct vo *vo); static int video_to_output_surface(struct vo *vo) { struct vdpctx *vc = vo->priv; @@ -292,6 +345,7 @@ static void forget_frames(struct vo *vo) struct vdpctx *vc = vo->priv; vc->deint_queue_pos = -1001; + vc->dropped_frame = false; for (int i = 0; i < NUM_BUFFERED_VIDEO; i++) { struct buffered_video_surface *p = vc->buffered_video + i; if (p->mpi) @@ -329,6 +383,7 @@ static void resize(struct vo *vo) #endif vo_osd_changed(OSDTYPE_OSD); + bool had_frames = vc->num_shown_frames; if (vc->output_surface_width < vo->dwidth || vc->output_surface_height < vo->dheight) { if (vc->output_surface_width < vo->dwidth) { @@ -354,10 +409,11 @@ static void resize(struct vo *vo) mp_msg(MSGT_VO, MSGL_DBG2, "OUT CREATE: %u\n", vc->output_surfaces[i]); } + vc->num_shown_frames = 0; } - if (vc->paused && vc->visible_buf) + if (vc->paused && had_frames) if (video_to_output_surface(vo) >= 0) - flip_page(vo); + flip_page_timed(vo, 0, -1); } static void preemption_callback(VdpDevice device, void *context) @@ -448,6 +504,40 @@ static int win_x11_init_vdpau_flip_queue(struct vo *vo) CHECK_ST_ERROR("Error when calling vdp_presentation_queue_create"); } + VdpTime vdp_time; + vdp_st = vdp->presentation_queue_get_time(vc->flip_queue, &vdp_time); + CHECK_ST_ERROR("Error when calling vdp_presentation_queue_get_time"); + vc->last_vdp_time = vdp_time; + vc->last_sync_update = GetTimer(); + + vc->vsync_interval = 1; + if (vc->user_fps > 0) { + vc->vsync_interval = 1e9 / vc->user_fps; + mp_msg(MSGT_VO, MSGL_INFO, "[vdpau] Assuming user-specified display " + "refresh rate of %.3f Hz.\n", vc->user_fps); + } else if (vc->user_fps == 0) { +#ifdef CONFIG_XF86VM + double fps = vo_vm_get_fps(vo); + if (!fps) + mp_msg(MSGT_VO, MSGL_WARN, "[vdpau] Failed to get display FPS\n"); + else { + vc->vsync_interval = 1e9 / fps; + // This is verbose, but I'm not yet sure how common wrong values are + mp_msg(MSGT_VO, MSGL_INFO, + "[vdpau] Got display refresh rate %.3f Hz.\n" + "[vdpau] If that value looks wrong give the " + "-vo vdpau:fps=X suboption manually.\n", fps); + } +#else + mp_msg(MSGT_VO, MSGL_INFO, "[vdpau] This binary has been compiled " + "without XF86VidMode support.\n"); + mp_msg(MSGT_VO, MSGL_INFO, "[vdpau] Can't use vsync-aware timing " + "without manually provided -vo vdpau:fps=X suboption.\n"); +#endif + } else + mp_msg(MSGT_VO, MSGL_V, "[vdpau] framedrop/timing logic disabled by " + "user.\n"); + return 0; } @@ -631,7 +721,6 @@ static int initialize_vdpau_objects(struct vo *vo) &vc->eosd_surface.max_width, &vc->eosd_surface.max_height); CHECK_ST_WARNING("Query to get max EOSD surface size failed"); - vc->surface_num = 0; forget_frames(vo); resize(vo); return 0; @@ -656,7 +745,7 @@ static void mark_vdpau_objects_uninitialized(struct vo *vo) }; vc->output_surface_width = vc->output_surface_height = -1; vc->eosd_render_count = 0; - vc->visible_buf = false; + vc->num_shown_frames = 0; } static int handle_preemption(struct vo *vo) @@ -775,7 +864,7 @@ static void check_events(struct vo *vo) resize(vo); else if (e & VO_EVENT_EXPOSE && vc->paused) { /* did we already draw a buffer */ - if (vc->visible_buf) { + if (vc->num_shown_frames) { /* redraw the last visible buffer */ VdpStatus vdp_st; int last_surface = (vc->surface_num + NUM_OUTPUT_SURFACES - 1) @@ -1093,23 +1182,135 @@ static void draw_osd(struct vo *vo, struct osd_state *osd) vc->vid_height, draw_osd_I8A8, vo); } -static void flip_page(struct vo *vo) +static void wait_for_previous_frame(struct vo *vo) { struct vdpctx *vc = vo->priv; struct vdp_functions *vdp = vc->vdp; VdpStatus vdp_st; + if (vc->num_shown_frames < 2) + return; + + VdpTime vtime; + VdpOutputSurface visible_s, prev_s; + int base = vc->surface_num + NUM_OUTPUT_SURFACES; + visible_s = vc->output_surfaces[(base - 1) % NUM_OUTPUT_SURFACES]; + prev_s = vc->output_surfaces[(base - 2) % NUM_OUTPUT_SURFACES]; + vdp_st = vdp->presentation_queue_block_until_surface_idle(vc->flip_queue, + prev_s, &vtime); + CHECK_ST_WARNING("Error calling " + "presentation_queue_block_until_surface_idle"); + VdpPresentationQueueStatus status; + vdp_st = vdp->presentation_queue_query_surface_status(vc->flip_queue, + visible_s, + &status, &vtime); + CHECK_ST_WARNING("Error calling presentation_queue_query_surface_status"); + vc->recent_vsync_time = vtime; +} + +static inline uint64_t prev_vs2(struct vdpctx *vc, uint64_t ts, int shift) +{ + uint64_t offset = ts - vc->recent_vsync_time; + // Fix negative values for 1<recent_vsync_time + offset += (uint64_t)vc->vsync_interval << shift; + offset %= vc->vsync_interval; + return ts - offset; +} + +static void flip_page_timed(struct vo *vo, unsigned int pts_us, int duration) +{ + struct vdpctx *vc = vo->priv; + struct vdp_functions *vdp = vc->vdp; + VdpStatus vdp_st; + uint32_t vsync_interval = vc->vsync_interval; + if (handle_preemption(vo) < 0) return; + if (duration > INT_MAX / 1000) + duration = -1; + else + duration *= 1000; + + if (vc->user_fps < 0) + duration = -1; // Make sure drop logic is disabled + + uint64_t now = sync_vdptime(vo); + uint64_t pts = pts_us ? convert_to_vdptime(vo, pts_us) : now; + uint64_t ideal_pts = pts; + uint64_t npts = duration >= 0 ? pts + duration : UINT64_MAX; + +#define PREV_VS2(ts, shift) prev_vs2(vc, ts, shift) + // Only gives accurate results for ts >= vc->recent_vsync_time +#define PREV_VSYNC(ts) PREV_VS2(ts, 0) + + /* We hope to be here at least one vsync before the frame should be shown. + * If we are running late then don't drop the frame unless there is + * already one queued for the next vsync; even if we _hope_ to show the + * next frame soon enough to mean this one should be dropped we might + * not make the target time in reality. Without this check we could drop + * every frame, freezing the display completely if video lags behind. + */ + if (now > PREV_VSYNC(FFMAX(pts, + vc->last_queue_time + vsync_interval))) + npts = UINT64_MAX; + + /* Allow flipping a frame at a vsync if its presentation time is a + * bit after that vsync and the change makes the flip time delta + * from previous frame better match the target timestamp delta. + * This avoids instability with frame timestamps falling near vsyncs. + * For example if the frame timestamps were (with vsyncs at + * integer values) 0.01, 1.99, 4.01, 5.99, 8.01, ... then + * straightforward timing at next vsync would flip the frames at + * 1, 2, 5, 6, 9; this changes it to 1, 2, 4, 6, 8 and so on with + * regular 2-vsync intervals. + * + * Also allow moving the frame forward if it looks like we dropped + * the previous frame incorrectly (now that we know better after + * having final exact timestamp information for this frame) and + * there would unnecessarily be a vsync without a frame change. + */ + uint64_t vsync = PREV_VSYNC(pts); + if (pts < vsync + vsync_interval / 4 + && (vsync - PREV_VS2(vc->last_queue_time, 16) + > pts - vc->last_ideal_time + vsync_interval / 2 + || vc->dropped_frame && vsync > vc->dropped_time)) + pts -= vsync_interval / 2; + + vc->dropped_frame = true; // changed at end if false + vc->dropped_time = ideal_pts; + + pts = FFMAX(pts, vc->last_queue_time + vsync_interval); + pts = FFMAX(pts, now); + if (npts < PREV_VSYNC(pts) + vsync_interval) + return; + + /* At least on my NVIDIA 9500GT with driver versions 185.18.36 and 190.42 + * trying to queue two unshown frames simultaneously caused bad behavior + * (high CPU use in _other_ VDPAU functions called later). Avoiding + * longer queues also makes things simpler. So currently we always + * try to keep exactly one frame queued for the future, queuing the + * current frame immediately after the previous one is shown. + */ + wait_for_previous_frame(vo); + + now = sync_vdptime(vo); + pts = FFMAX(pts, now); + vsync = PREV_VSYNC(pts); + if (npts < vsync + vsync_interval) + return; + pts = vsync + (vsync_interval >> 2); vdp_st = vdp->presentation_queue_display(vc->flip_queue, vc->output_surfaces[vc->surface_num], - vo->dwidth, vo->dheight, 0); + vo->dwidth, vo->dheight, pts); CHECK_ST_WARNING("Error when calling vdp_presentation_queue_display"); + vc->last_queue_time = pts; + vc->last_ideal_time = ideal_pts; + vc->dropped_frame = false; vc->surface_num = (vc->surface_num + 1) % NUM_OUTPUT_SURFACES; - vc->visible_buf = true; + vc->num_shown_frames = FFMIN(vc->num_shown_frames + 1, 1000); } static int draw_slice(struct vo *vo, uint8_t *image[], int stride[], int w, @@ -1348,6 +1549,7 @@ static int preinit(struct vo *vo, const char *arg) {"pullup", OPT_ARG_BOOL, &vc->pullup, NULL}, {"denoise", OPT_ARG_FLOAT, &vc->denoise, NULL}, {"sharpen", OPT_ARG_FLOAT, &vc->sharpen, NULL}, + {"fps", OPT_ARG_FLOAT, &vc->user_fps, NULL}, {NULL} }; if (subopt_parse(arg, subopts) != 0) { @@ -1478,6 +1680,8 @@ static int control(struct vo *vo, uint32_t request, void *data) } return VO_TRUE; case VOCTRL_PAUSE: + if (vc->dropped_frame) + flip_page_timed(vo, 0, -1); return (vc->paused = true); case VOCTRL_RESUME: return (vc->paused = false); @@ -1538,7 +1742,7 @@ static int control(struct vo *vo, uint32_t request, void *data) video_to_output_surface(vo); draw_eosd(vo); draw_osd(vo, data); - flip_page(vo); + flip_page_timed(vo, 0, -1); return true; case VOCTRL_RESET: forget_frames(vo); @@ -1563,7 +1767,7 @@ const struct vo_driver video_out_vdpau = { .get_buffered_frame = get_buffered_frame, .draw_slice = draw_slice, .draw_osd = draw_osd, - .flip_page = flip_page, + .flip_page_timed = flip_page_timed, .check_events = check_events, .uninit = uninit, }; diff --git a/libvo/x11_common.c b/libvo/x11_common.c index a9de90d350..621880e137 100644 --- a/libvo/x11_common.c +++ b/libvo/x11_common.c @@ -1642,6 +1642,18 @@ void vo_vm_close(struct vo *vo) vidmodes = NULL; } } + +double vo_vm_get_fps(struct vo *vo) +{ + struct vo_x11_state *x11 = vo->x11; + int clock; + XF86VidModeModeLine modeline; + if (!XF86VidModeGetModeLine(x11->display, x11->screen, &clock, &modeline)) + return 0; + if (modeline.privsize) + Xfree(modeline.private); + return 1e3 * clock / modeline.htotal / modeline.vtotal; +} #endif #endif /* X11_FULLSCREEN */ diff --git a/libvo/x11_common.h b/libvo/x11_common.h index a610f813bb..fccad90ced 100644 --- a/libvo/x11_common.h +++ b/libvo/x11_common.h @@ -164,6 +164,7 @@ void vo_x11_putkey(struct vo *vo, int key); #ifdef CONFIG_XF86VM void vo_vm_switch(struct vo *vo); void vo_vm_close(struct vo *vo); +double vo_vm_get_fps(struct vo *vo); #endif void update_xinerama_info(struct vo *vo); -- cgit v1.2.3 From 98ee8dd15976501157c894ec385c4c551c6614ad Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Sun, 15 Nov 2009 15:21:40 +0200 Subject: Add yuv_colorspace property, implemented in vo_vdpau and vo_xv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a property to select YUV colorspace. Currently implemented only in vo_vdpau and vo_xv. Allows switching between BT.601, BT.709 and SMPTE-240M (vdpau only). The xv support uses the "XV_ITURBT_709" attribute. At least my NVIDIA card supports that; I don't know whether other xv implementations do. Bind the colorspace switch to the 'c' key by default. 'c' is currently used by vo_sdl for some fullscreen mode change thing, but at the moment that does not conflict and if it will in the future then vo_sdl can change. VDPAU part based on a patch from Lauri Mylläri --- libvo/video_out.h | 3 +++ libvo/vo_vdpau.c | 59 +++++++++++++++++++++++++++++++++++++++++------------- libvo/vo_xv.c | 9 +++++++++ libvo/x11_common.c | 8 +++++++- 4 files changed, 64 insertions(+), 15 deletions(-) (limited to 'libvo') diff --git a/libvo/video_out.h b/libvo/video_out.h index 50602e83a4..17c387a320 100644 --- a/libvo/video_out.h +++ b/libvo/video_out.h @@ -88,6 +88,9 @@ typedef struct { #define VOCTRL_UPDATE_SCREENINFO 32 +#define VOCTRL_SET_YUV_COLORSPACE 33 +#define VOCTRL_GET_YUV_COLORSPACE 34 + // Vo can be used by xover #define VOCTRL_XOVERLAY_SUPPORT 22 diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index 6eef93842f..a228b00787 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -124,6 +124,8 @@ struct vdpctx { int output_surface_width, output_surface_height; VdpVideoMixer video_mixer; + int user_colorspace; + int colorspace; int deint; int deint_type; int deint_counter; @@ -541,6 +543,33 @@ static int win_x11_init_vdpau_flip_queue(struct vo *vo) return 0; } +static void update_csc_matrix(struct vo *vo) +{ + struct vdpctx *vc = vo->priv; + struct vdp_functions *vdp = vc->vdp; + VdpStatus vdp_st; + + const VdpColorStandard vdp_colors[] = {VDP_COLOR_STANDARD_ITUR_BT_601, + VDP_COLOR_STANDARD_ITUR_BT_709, + VDP_COLOR_STANDARD_SMPTE_240M}; + char * const vdp_names[] = {"BT.601", "BT.709", "SMPTE-240M"}; + int csp = vc->colorspace; + mp_msg(MSGT_VO, MSGL_V, "[vdpau] Updating CSC matrix for %s\n", + vdp_names[csp]); + + VdpCSCMatrix matrix; + vdp_st = vdp->generate_csc_matrix(&vc->procamp, vdp_colors[csp], &matrix); + CHECK_ST_WARNING("Error when generating CSC matrix"); + + const VdpVideoMixerAttribute attributes[] = + {VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX}; + const void *attribute_values[] = {&matrix}; + vdp_st = vdp->video_mixer_set_attribute_values(vc->video_mixer, 1, + attributes, + attribute_values); + CHECK_ST_WARNING("Error when setting CSC matrix"); +} + static int create_vdp_mixer(struct vo *vo, VdpChromaType vdp_chroma_type) { struct vdpctx *vc = vo->priv; @@ -611,6 +640,7 @@ static int create_vdp_mixer(struct vo *vo, VdpChromaType vdp_chroma_type) skip_chroma_attrib, skip_chroma_value_ptr); + update_csc_matrix(vo); return 0; } @@ -803,6 +833,10 @@ static int config(struct vo *vo, uint32_t width, uint32_t height, vc->image_format = format; vc->vid_width = width; vc->vid_height = height; + if (vc->user_colorspace == 0) + vc->colorspace = width >= 1280 || height > 576 ? 1 : 0; + else + vc->colorspace = vc->user_colorspace - 1; free_video_specific(vo); if (IMGFMT_IS_VDPAU(vc->image_format) && !create_vdp_decoder(vo, 2)) return -1; @@ -1543,12 +1577,14 @@ static int preinit(struct vo *vo, const char *arg) vc->deint_type = 3; vc->chroma_deint = 1; + vc->user_colorspace = 1; const opt_t subopts[] = { {"deint", OPT_ARG_INT, &vc->deint, (opt_test_f)int_non_neg}, {"chroma-deint", OPT_ARG_BOOL, &vc->chroma_deint, NULL}, {"pullup", OPT_ARG_BOOL, &vc->pullup, NULL}, {"denoise", OPT_ARG_FLOAT, &vc->denoise, NULL}, {"sharpen", OPT_ARG_FLOAT, &vc->sharpen, NULL}, + {"colorspace", OPT_ARG_INT, &vc->user_colorspace, NULL}, {"fps", OPT_ARG_FLOAT, &vc->user_fps, NULL}, {NULL} }; @@ -1623,11 +1659,6 @@ static int set_equalizer(struct vo *vo, const char *name, int value) { struct vdpctx *vc = vo->priv; struct vdp_functions *vdp = vc->vdp; - VdpStatus vdp_st; - VdpCSCMatrix matrix; - static const VdpVideoMixerAttribute attributes[] = - {VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX}; - const void *attribute_values[] = {&matrix}; if (!strcasecmp(name, "brightness")) vc->procamp.brightness = value / 100.0; @@ -1640,15 +1671,8 @@ static int set_equalizer(struct vo *vo, const char *name, int value) else return VO_NOTIMPL; - vdp_st = vdp->generate_csc_matrix(&vc->procamp, - VDP_COLOR_STANDARD_ITUR_BT_601, - &matrix); - CHECK_ST_WARNING("Error when generating CSC matrix"); - vdp_st = vdp->video_mixer_set_attribute_values(vc->video_mixer, 1, - attributes, - attribute_values); - CHECK_ST_WARNING("Error when setting CSC matrix"); - return VO_TRUE; + update_csc_matrix(vo); + return true; } static int control(struct vo *vo, uint32_t request, void *data) @@ -1712,6 +1736,13 @@ static int control(struct vo *vo, uint32_t request, void *data) struct voctrl_get_equalizer_args *args = data; return get_equalizer(vo, args->name, args->valueptr); } + case VOCTRL_SET_YUV_COLORSPACE: + vc->colorspace = *(int *)data % 3; + update_csc_matrix(vo); + return true; + case VOCTRL_GET_YUV_COLORSPACE: + *(int *)data = vc->colorspace; + return true; case VOCTRL_ONTOP: vo_x11_ontop(vo); return VO_TRUE; diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c index 886fd0a0d7..9a030ac71c 100644 --- a/libvo/vo_xv.c +++ b/libvo/vo_xv.c @@ -817,6 +817,15 @@ static int control(struct vo *vo, uint32_t request, void *data) struct voctrl_get_equalizer_args *args = data; return vo_xv_get_eq(vo, x11->xv_port, args->name, args->valueptr); } + case VOCTRL_SET_YUV_COLORSPACE:; + int given_cspc = *(int *)data % 2; + return vo_xv_set_eq(vo, x11->xv_port, "bt_709", given_cspc * 200 - 100); + case VOCTRL_GET_YUV_COLORSPACE:; + int bt709_enabled; + if (!vo_xv_get_eq(vo, x11->xv_port, "bt_709", &bt709_enabled)) + return false; + *(int *)data = bt709_enabled == 100; + return true; case VOCTRL_ONTOP: vo_x11_ontop(vo); return VO_TRUE; diff --git a/libvo/x11_common.c b/libvo/x11_common.c index 621880e137..e617aad082 100644 --- a/libvo/x11_common.c +++ b/libvo/x11_common.c @@ -1651,7 +1651,7 @@ double vo_vm_get_fps(struct vo *vo) if (!XF86VidModeGetModeLine(x11->display, x11->screen, &clock, &modeline)) return 0; if (modeline.privsize) - Xfree(modeline.private); + XFree(modeline.private); return 1e3 * clock / modeline.htotal / modeline.vtotal; } #endif @@ -1906,6 +1906,9 @@ int vo_xv_set_eq(struct vo *vo, uint32_t xv_port, char *name, int value) else if (!strcmp(attributes[i].name, "XV_BLUE_INTENSITY") && (!strcasecmp(name, "blue_intensity"))) port_value = value; + else if (!strcmp(attributes[i].name, "XV_ITURBT_709") + && (!strcasecmp(name, "bt_709"))) + port_value = value; else continue; @@ -1987,6 +1990,9 @@ int vo_xv_get_eq(struct vo *vo, uint32_t xv_port, char *name, int *value) else if (!strcmp(attributes[i].name, "XV_BLUE_INTENSITY") && (!strcasecmp(name, "blue_intensity"))) *value = val; + else if (!strcmp(attributes[i].name, "XV_ITURBT_709") + && (!strcasecmp(name, "bt_709"))) + *value = val; else continue; -- cgit v1.2.3 From 7038c57a0c9a037f7f697dbecc656fc2b81f4651 Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Sun, 15 Nov 2009 15:41:25 +0200 Subject: vo_vdpau: Free buffers allocated by FFmpeg on uninit --- libvo/vo_vdpau.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'libvo') diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index a228b00787..4da410b028 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -1540,6 +1540,10 @@ static void uninit(struct vo *vo) #endif vo_x11_uninit(vo); + // Free bitstream buffers allocated by FFmpeg + for (int i = 0; i < MAX_VIDEO_SURFACES; i++) + av_freep(&vc->surface_render[i].bitstream_buffers); + dlclose(vc->vdpau_lib_handle); } -- cgit v1.2.3 From 82ee2e217f8f9ec67bcbd3b6b60f49a003da9300 Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Sun, 15 Nov 2009 15:50:28 +0200 Subject: vo_vdpau: add support for VFCAP_FLIP Patch by Carl Eugen Hoyos. --- libvo/vo_vdpau.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'libvo') diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index 4da410b028..26314a948a 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -134,6 +134,7 @@ struct vdpctx { float sharpen; int chroma_deint; int top_field_first; + bool flip; VdpDecoder decoder; int decoder_max_refs; @@ -375,8 +376,8 @@ static void resize(struct vo *vo) vc->out_rect_vid.y1 = dst_rect.bottom; vc->src_rect_vid.x0 = src_rect.left; vc->src_rect_vid.x1 = src_rect.right; - vc->src_rect_vid.y0 = src_rect.top; - vc->src_rect_vid.y1 = src_rect.bottom; + vc->src_rect_vid.y0 = vc->flip ? src_rect.bottom : src_rect.top; + vc->src_rect_vid.y1 = vc->flip ? src_rect.top : src_rect.bottom; vc->border_x = borders.left; vc->border_y = borders.top; #ifdef CONFIG_FREETYPE @@ -830,6 +831,8 @@ static int config(struct vo *vo, uint32_t width, uint32_t height, if (handle_preemption(vo) < 0) return -1; + + vc->flip = flags & VOFLAG_FLIPPING; vc->image_format = format; vc->vid_width = width; vc->vid_height = height; @@ -1471,7 +1474,7 @@ static int query_format(uint32_t format) { int default_flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD | VFCAP_EOSD - | VFCAP_EOSD_UNSCALED; + | VFCAP_EOSD_UNSCALED | VFCAP_FLIP; switch (format) { case IMGFMT_YV12: case IMGFMT_I420: -- cgit v1.2.3 From 14bb3416c735e99cbf0507548d3f3fcbba0fba7f Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Sun, 15 Nov 2009 18:39:48 +0200 Subject: vo_vdpau: Add support for high-quality scaling feature Part of the code is currently under #ifdef to allow compilation with older VDPAU library versions; that can be removed later. Partially based on a patch by Carl Eugen Hoyos. --- libvo/vdpau_template.c | 1 + libvo/vo_vdpau.c | 26 ++++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) (limited to 'libvo') diff --git a/libvo/vdpau_template.c b/libvo/vdpau_template.c index 1b8d354316..3f9b26c5d8 100644 --- a/libvo/vdpau_template.c +++ b/libvo/vdpau_template.c @@ -33,6 +33,7 @@ VDP_FUNCTION(VdpPresentationQueueTargetCreateX11, VDP_FUNC_ID_PRESENTATION_QUEUE VDP_FUNCTION(VdpPresentationQueueTargetDestroy, VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY, presentation_queue_target_destroy) VDP_FUNCTION(VdpVideoMixerCreate, VDP_FUNC_ID_VIDEO_MIXER_CREATE, video_mixer_create) VDP_FUNCTION(VdpVideoMixerDestroy, VDP_FUNC_ID_VIDEO_MIXER_DESTROY, video_mixer_destroy) +VDP_FUNCTION(VdpVideoMixerQueryFeatureSupport, VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT, video_mixer_query_feature_support) VDP_FUNCTION(VdpVideoMixerRender, VDP_FUNC_ID_VIDEO_MIXER_RENDER, video_mixer_render) VDP_FUNCTION(VdpVideoMixerSetAttributeValues, VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES, video_mixer_set_attribute_values) VDP_FUNCTION(VdpVideoMixerSetFeatureEnables, VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES, video_mixer_set_feature_enables) diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index 26314a948a..b48f44052a 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -132,6 +132,7 @@ struct vdpctx { int pullup; float denoise; float sharpen; + int hqscaling; int chroma_deint; int top_field_first; bool flip; @@ -576,7 +577,7 @@ static int create_vdp_mixer(struct vo *vo, VdpChromaType vdp_chroma_type) struct vdpctx *vc = vo->priv; struct vdp_functions *vdp = vc->vdp; #define VDP_NUM_MIXER_PARAMETER 3 -#define MAX_NUM_FEATURES 5 +#define MAX_NUM_FEATURES 6 int i; VdpStatus vdp_st; @@ -616,6 +617,25 @@ static int create_vdp_mixer(struct vo *vo, VdpChromaType vdp_chroma_type) features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION; if (vc->sharpen) features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_SHARPNESS; + if (vc->hqscaling) { +#ifndef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 + mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] MPlayer was compiled with (old?)" + "libvdpau headers with no support for requested hqscaling.\n"); +#else + VdpVideoMixerFeature hqscaling_feature = + VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 + vc->hqscaling-1; + VdpBool hqscaling_available; + vdp_st = vdp->video_mixer_query_feature_support(vc->vdp_device, + hqscaling_feature, + &hqscaling_available); + CHECK_ST_ERROR("Error when calling video_mixer_query_feature_support"); + if (hqscaling_available) + features[feature_count++] = hqscaling_feature; + else + mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Your hardware or VDPAU " + "library does not support requested hqscaling.\n"); + } +#endif vdp_st = vdp->video_mixer_create(vc->vdp_device, feature_count, features, VDP_NUM_MIXER_PARAMETER, @@ -1592,10 +1612,12 @@ static int preinit(struct vo *vo, const char *arg) {"denoise", OPT_ARG_FLOAT, &vc->denoise, NULL}, {"sharpen", OPT_ARG_FLOAT, &vc->sharpen, NULL}, {"colorspace", OPT_ARG_INT, &vc->user_colorspace, NULL}, + {"hqscaling", OPT_ARG_INT, &vc->hqscaling, NULL}, {"fps", OPT_ARG_FLOAT, &vc->user_fps, NULL}, {NULL} }; - if (subopt_parse(arg, subopts) != 0) { + if (subopt_parse(arg, subopts) != 0 || vc->hqscaling < 0 + || vc->hqscaling > 9) { mp_msg(MSGT_VO, MSGL_FATAL, help_msg); return -1; } -- cgit v1.2.3 From 19b4d70e01ca2fd963b4ca599e0377e109a6881f Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Mon, 16 Nov 2009 00:50:01 +0200 Subject: vo_vdpau: Remove custom help message Remove the help text explaining -vo vdpau suboptions that was printed in case of parsing errors. It did perhaps have some value, but there are also reasons to remove it: it was printed in an ugly manner in the middle of output, most other MPlayer options do not have such internal help texts either, and it was detailed enough that it required maintaining documentation about the options in two separate places (the man page and the help message). --- libvo/vo_vdpau.c | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) (limited to 'libvo') diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index b48f44052a..2bd0eec3c4 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -1570,27 +1570,6 @@ static void uninit(struct vo *vo) dlclose(vc->vdpau_lib_handle); } -static const char help_msg[] = - "\n-vo vdpau command line help:\n" - "Example: mplayer -vo vdpau:deint=2\n" - "\nOptions:\n" - " deint (all modes > 0 respect -field-dominance)\n" - " 0: no deinterlacing\n" - " 1: only show first field\n" - " 2: bob deinterlacing\n" - " 3: temporal deinterlacing (resource-hungry)\n" - " 4: temporal-spatial deinterlacing (very resource-hungry)\n" - " chroma-deint\n" - " Operate on luma and chroma when using temporal deinterlacing (default)\n" - " Use nochroma-deint to speed up temporal deinterlacing\n" - " pullup\n" - " Try to apply inverse-telecine (needs temporal deinterlacing)\n" - " denoise\n" - " 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" - ; - static int preinit(struct vo *vo, const char *arg) { int i; @@ -1616,9 +1595,13 @@ static int preinit(struct vo *vo, const char *arg) {"fps", OPT_ARG_FLOAT, &vc->user_fps, NULL}, {NULL} }; - if (subopt_parse(arg, subopts) != 0 || vc->hqscaling < 0 - || vc->hqscaling > 9) { - mp_msg(MSGT_VO, MSGL_FATAL, help_msg); + if (subopt_parse(arg, subopts) != 0) { + mp_msg(MSGT_VO, MSGL_FATAL, "[vdpau] Could not parse suboptions.\n"); + return -1; + } + if (vc->hqscaling < 0 || vc->hqscaling > 9) { + mp_msg(MSGT_VO, MSGL_FATAL, "[vdpau] Invalid value for suboption " + "hqscaling\n"); return -1; } if (vc->deint) -- cgit v1.2.3 From b8861ce8e28080b151467827f65bdc3707a74511 Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Mon, 16 Nov 2009 02:45:59 +0200 Subject: Support VDPAU MPEG4 hardware decoding Original patch by NVIDIA. --- libvo/vo_vdpau.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'libvo') diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index 2bd0eec3c4..484b5fc87d 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -721,6 +721,11 @@ static int create_vdp_decoder(struct vo *vo, int max_refs) case IMGFMT_VDPAU_VC1: vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED; break; +#ifdef VDP_DECODER_PROFILE_MPEG4_PART2_ASP + case IMGFMT_VDPAU_MPEG4: + vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP; + break; +#endif } vdp_st = vdp->decoder_create(vc->vdp_device, vdp_decoder_profile, vc->vid_width, vc->vid_height, max_refs, @@ -1508,6 +1513,7 @@ static int query_format(uint32_t format) case IMGFMT_VDPAU_H264: case IMGFMT_VDPAU_WMV3: case IMGFMT_VDPAU_VC1: + case IMGFMT_VDPAU_MPEG4: return default_flags; } return 0; -- cgit v1.2.3