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