summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUoti Urpala <uau@glyph.nonexistent.invalid>2009-09-18 16:27:55 +0300
committerUoti Urpala <uau@glyph.nonexistent.invalid>2009-09-18 17:12:53 +0300
commit350fc4f5a2f6f4fdf9cc689d786d525f6397df5d (patch)
tree4f133589230adc4d87d296d5b7300b811c941bdd
parent6847e5e297821bdb56ec978100243bc452f508f4 (diff)
downloadmpv-350fc4f5a2f6f4fdf9cc689d786d525f6397df5d.tar.bz2
mpv-350fc4f5a2f6f4fdf9cc689d786d525f6397df5d.tar.xz
core/VO: Allow VO drivers to add/modify frames
Add interfaces to allow VO drivers to add or remove frames from the video stream and to alter timestamps. Currently this functionality only works with in correct-pts mode. Use the new functionality in vo_vdpau to properly support frame-adding deinterlace modes. Frames added by the VDPAU deinterlacing code are now properly timed. Before every second frame was always shown immediately (probably next monitor refresh) after the previous one, even if you were watching things in slow motion, and framestepping didn't stop at them at all. When seeking the deinterlace algorithm is no longer fed a mix of frames from old and new positions. As a side effect of the changes a problem with resize events was also fixed. Resizing calls video_to_output_surface() to render the frame at the new resolution, but before this function also changed the list of history frames, so resizing could give an image different from the original one, and also corrupt next frames due to them seeing the wrong history. Now the function has no such side effects. There are more resize-related problems though that will be fixed in a later commit. The deint_mpi[] list of reserved frames is increased from 2 to 3 entries for reasons related to the above. Having 2 entries is enough when you initially get a new frame in draw_image() because then you'll have those two entries plus the new one for a total of 3 (the code relied on the oldest mpi implicitly staying reserved for the duration of the call even after usage count was decreased). However if you want to be able to reproduce the rendering outside draw_image(), relying on the explicitly reserved list only, then it needs to store 3 entries.
-rw-r--r--libmpcodecs/vf.h1
-rw-r--r--libmpcodecs/vf_vo.c13
-rw-r--r--libvo/video_out.c40
-rw-r--r--libvo/video_out.h21
-rw-r--r--libvo/vo_vdpau.c189
-rw-r--r--mencoder.c1
-rw-r--r--mp_core.h4
-rw-r--r--mplayer.c27
8 files changed, 195 insertions, 101 deletions
diff --git a/libmpcodecs/vf.h b/libmpcodecs/vf.h
index 99321b3afa..099135c5da 100644
--- a/libmpcodecs/vf.h
+++ b/libmpcodecs/vf.h
@@ -88,7 +88,6 @@ typedef struct vf_seteq_s
#define VFCTRL_SCREENSHOT 14 /* Make a screenshot */
#define VFCTRL_INIT_EOSD 15 /* Select EOSD renderer */
#define VFCTRL_DRAW_EOSD 16 /* Render EOSD */
-#define VFCTRL_GET_PTS 17 /* Return last pts value that reached vf_vo*/
#define VFCTRL_SET_DEINTERLACE 18 /* Set deinterlacing status */
#define VFCTRL_GET_DEINTERLACE 19 /* Get deinterlacing status */
/* Hack to make the OSD state object available to vf_expand which accesses
diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c
index 7b3e16224f..53dc8267b6 100644
--- a/libmpcodecs/vf_vo.c
+++ b/libmpcodecs/vf_vo.c
@@ -22,7 +22,6 @@ extern int sub_visibility;
extern float sub_delay;
struct vf_priv_s {
- double pts;
struct vo *vo;
#ifdef CONFIG_ASS
ASS_Renderer *ass_priv;
@@ -127,7 +126,7 @@ static int control(struct vf_instance* vf, int request, void* data)
case VFCTRL_DRAW_EOSD:
{
mp_eosd_images_t images = {NULL, 2};
- double pts = vf->priv->pts;
+ double pts = video_out->next_pts;
if (!video_out->config_ok || !vf->priv->ass_priv) return CONTROL_FALSE;
if (sub_visibility && vf->priv->ass_priv && ass_track && (pts != MP_NOPTS_VALUE)) {
mp_eosd_res_t res;
@@ -148,11 +147,6 @@ static int control(struct vf_instance* vf, int request, void* data)
return vo_control(video_out, VOCTRL_DRAW_EOSD, &images) == VO_TRUE;
}
#endif
- case VFCTRL_GET_PTS:
- {
- *(double *)data = vf->priv->pts;
- return CONTROL_TRUE;
- }
}
return CONTROL_UNKNOWN;
}
@@ -179,10 +173,9 @@ static void get_image(struct vf_instance* vf,
static int put_image(struct vf_instance* vf,
mp_image_t *mpi, double pts){
if(!video_out->config_ok) return 0; // vo not configured?
- // record pts (potentially modified by filters) for main loop
- vf->priv->pts = pts;
// first check, maybe the vo/vf plugin implements draw_image using mpi:
- if (vo_control(video_out, VOCTRL_DRAW_IMAGE,mpi)==VO_TRUE) return 1; // done.
+ if (vo_draw_image(video_out, mpi, pts) >= 0)
+ return 1;
// nope, fallback to old draw_frame/draw_slice:
if(!(mpi->flags&(MP_IMGFLAG_DIRECT|MP_IMGFLAG_DRAW_CALLBACK))){
// blit frame:
diff --git a/libvo/video_out.c b/libvo/video_out.c
index 9224212b35..b6506406c3 100644
--- a/libvo/video_out.c
+++ b/libvo/video_out.c
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
+#include <stdbool.h>
#include <unistd.h>
//#include <sys/mman.h>
@@ -278,6 +279,35 @@ int vo_control(struct vo *vo, uint32_t request, void *data)
return vo->driver->control(vo, request, data);
}
+// Return -1 if driver appears not to support a draw_image interface,
+// 0 otherwise (whether the driver actually drew something or not).
+int vo_draw_image(struct vo *vo, struct mp_image *mpi, double pts)
+{
+ if (!vo->config_ok)
+ return 0;
+ if (vo->driver->buffer_frames) {
+ vo->driver->draw_image(vo, mpi, pts);
+ return 0;
+ }
+ vo->frame_loaded = true;
+ vo->next_pts = pts;
+ if (vo_control(vo, VOCTRL_DRAW_IMAGE, mpi) == VO_NOTIMPL)
+ return -1;
+ return 0;
+}
+
+int vo_get_buffered_frame(struct vo *vo, bool eof)
+{
+ if (!vo->config_ok)
+ return -1;
+ if (vo->frame_loaded)
+ return 0;
+ if (!vo->driver->buffer_frames)
+ return -1;
+ vo->driver->get_buffered_frame(vo, eof);
+ return vo->frame_loaded ? 0 : -1;
+}
+
int vo_draw_frame(struct vo *vo, uint8_t *src[])
{
assert(!vo->driver->is_new);
@@ -302,6 +332,8 @@ 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->driver->flip_page(vo);
}
@@ -312,6 +344,14 @@ void vo_check_events(struct vo *vo)
vo->driver->check_events(vo);
}
+void vo_seek_reset(struct vo *vo)
+{
+ if (!vo->config_ok)
+ return;
+ vo_control(vo, VOCTRL_RESET, NULL);
+ vo->frame_loaded = false;
+}
+
void vo_destroy(struct vo *vo)
{
vo->driver->uninit(vo);
diff --git a/libvo/video_out.h b/libvo/video_out.h
index a911bfdd03..4ddeaa827e 100644
--- a/libvo/video_out.h
+++ b/libvo/video_out.h
@@ -129,10 +129,14 @@ typedef struct vo_info_s
struct vo;
struct osd_state;
+struct mp_image;
struct vo_driver {
// Driver uses new API
bool is_new;
+ // Driver buffers or adds (deinterlace) frames and will keep track
+ // of pts values itself
+ bool buffer_frames;
// This is set if the driver is not new and contains pointers to
// old-API functions to be used instead of the ones below.
@@ -164,6 +168,16 @@ struct vo_driver {
*/
int (*control)(struct vo *vo, uint32_t request, void *data);
+ void (*draw_image)(struct vo *vo, struct mp_image *mpi, double pts);
+
+ /*
+ * Get extra frames from the VO, such as those added by VDPAU
+ * deinterlace. Preparing the next such frame if any could be done
+ * automatically by the VO after a previous flip_page(), but having
+ * it as a separate step seems to allow making code more robust.
+ */
+ void (*get_buffered_frame)(struct vo *vo, bool eof);
+
/*
* Draw a planar YUV slice to the buffer:
* params:
@@ -214,6 +228,10 @@ struct vo_old_functions {
struct vo {
int config_ok; // Last config call was successful?
int config_count; // Total number of successful config calls
+
+ bool frame_loaded; // Is there a next frame the VO could flip to?
+ double next_pts; // pts value of the next frame if any
+
const struct vo_driver *driver;
void *priv;
struct MPOpts *opts;
@@ -251,11 +269,14 @@ int vo_config(struct vo *vo, uint32_t width, uint32_t height,
void list_video_out(void);
int vo_control(struct vo *vo, uint32_t request, void *data);
+int vo_draw_image(struct vo *vo, struct mp_image *mpi, double pts);
+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_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 dcd2a7092e..bf760750cc 100644
--- a/libvo/vo_vdpau.c
+++ b/libvo/vo_vdpau.c
@@ -28,6 +28,7 @@
*/
#include <stdio.h>
+#include <stdlib.h>
#include <dlfcn.h>
#include <stdint.h>
#include <stdbool.h>
@@ -110,14 +111,15 @@ struct vdpctx {
#define osd_surface vc->output_surfaces[NUM_OUTPUT_SURFACES]
VdpOutputSurface output_surfaces[NUM_OUTPUT_SURFACES + 1];
VdpVideoSurface deint_surfaces[3];
- mp_image_t *deint_mpi[2];
+ double deint_pts[3];
+ int deint_queue_pos;
+ mp_image_t *deint_mpi[3];
int output_surface_width, output_surface_height;
VdpVideoMixer video_mixer;
int deint;
int deint_type;
int deint_counter;
- int deint_buffer_past_frames;
int pullup;
float denoise;
float sharpen;
@@ -133,7 +135,6 @@ struct vdpctx {
struct vdpau_render_state surface_render[MAX_VIDEO_SURFACES];
int surface_num;
- int vid_surface_num;
uint32_t vid_width, vid_height;
uint32_t image_format;
VdpChromaType vdp_chroma_type;
@@ -176,14 +177,6 @@ struct vdpctx {
};
-static void push_deint_surface(struct vo *vo, VdpVideoSurface surface)
-{
- struct vdpctx *vc = vo->priv;
- vc->deint_surfaces[2] = vc->deint_surfaces[1];
- vc->deint_surfaces[1] = vc->deint_surfaces[0];
- vc->deint_surfaces[0] = surface;
-}
-
static void flip_page(struct vo *vo);
static void video_to_output_surface(struct vo *vo)
{
@@ -191,41 +184,81 @@ static void video_to_output_surface(struct vo *vo)
struct vdp_functions *vdp = vc->vdp;
VdpTime dummy;
VdpStatus vdp_st;
- int i;
- if (vc->vid_surface_num < 0)
+ if (vc->deint_queue_pos < 0)
return;
- if (vc->deint < 2 || vc->deint_surfaces[0] == VDP_INVALID_HANDLE)
- push_deint_surface(vo, vc->surface_render[vc->vid_surface_num].surface);
+ 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,
+ // 2 last field of previous frame and so on
+ if (vc->deint) {
+ field = vc->top_field_first ^ (dp & 1) ?
+ 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]};
+ const VdpVideoSurface *future_fields = (const VdpVideoSurface []){
+ q[(dp-1)/2]};
+ VdpOutputSurface output_surface = vc->output_surfaces[vc->surface_num];
+ vdp_st = vdp->presentation_queue_block_until_surface_idle(vc->flip_queue,
+ output_surface,
+ &dummy);
+ CHECK_ST_WARNING("Error when calling "
+ "vdp_presentation_queue_block_until_surface_idle");
+
+ 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,
+ &vc->src_rect_vid, output_surface,
+ NULL, &vc->out_rect_vid, 0, NULL);
+ CHECK_ST_WARNING("Error when calling vdp_video_mixer_render");
+}
- for (i = 0; i <= (vc->deint > 1); i++) {
- int field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
- VdpOutputSurface output_surface;
- if (i) {
- // draw_eosd()
- // draw_osd()
- flip_page(vo);
- }
- if (vc->deint)
- field = (vc->top_field_first == i) ^ (vc->deint > 1) ?
- VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD:
- VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
- output_surface = vc->output_surfaces[vc->surface_num];
- vdp_st = vdp->
- presentation_queue_block_until_surface_idle(vc->flip_queue,
- output_surface,
- &dummy);
- CHECK_ST_WARNING("Error when calling "
- "vdp_presentation_queue_block_until_surface_idle");
-
- vdp_st = vdp->video_mixer_render(vc->video_mixer, VDP_INVALID_HANDLE,
- 0, field, 2, vc->deint_surfaces + 1,
- vc->deint_surfaces[0], 1,
- &vc->surface_render[vc->vid_surface_num].surface,
- &vc->src_rect_vid, output_surface,
- NULL, &vc->out_rect_vid, 0, NULL);
- CHECK_ST_WARNING("Error when calling vdp_video_mixer_render");
- push_deint_surface(vo, vc->surface_render[vc->vid_surface_num].surface);
+static void add_new_video_surface(struct vo *vo, VdpVideoSurface surface,
+ struct mp_image *reserved_mpi, double pts)
+{
+ 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;
+
+ 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];
+ if (diff > 0 && diff < 0.5)
+ vo->next_pts = (vc->deint_pts[0] + vc->deint_pts[1]) / 2;
+ else
+ vo->next_pts = vc->deint_pts[1];
+ } else
+ vc->deint_queue_pos = 1;
+ video_to_output_surface(vo);
+}
+
+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;
}
}
@@ -563,7 +596,7 @@ int initialize_vdpau_objects(struct vo *vo)
&vc->eosd_surface.max_height);
CHECK_ST_WARNING("Query to get max EOSD surface size failed");
vc->surface_num = 0;
- vc->vid_surface_num = -1;
+ forget_frames(vo);
resize(vo);
return 0;
}
@@ -575,8 +608,7 @@ static void mark_vdpau_objects_uninitialized(struct vo *vo)
vc->decoder = VDP_INVALID_HANDLE;
for (int i = 0; i < MAX_VIDEO_SURFACES; i++)
vc->surface_render[i].surface = VDP_INVALID_HANDLE;
- for (int i = 0; i < 3; i++)
- vc->deint_surfaces[i] = VDP_INVALID_HANDLE;
+ forget_frames(vo);
vc->video_mixer = VDP_INVALID_HANDLE;
vc->flip_queue = VDP_INVALID_HANDLE;
vc->flip_target = VDP_INVALID_HANDLE;
@@ -1033,10 +1065,6 @@ static void flip_page(struct vo *vo)
if (handle_preemption(vo) < 0)
return;
- mp_msg(MSGT_VO, MSGL_DBG2, "\nFLIP_PAGE VID:%u -> OUT:%u\n",
- vc->surface_render[vc->vid_surface_num].surface,
- vc->output_surfaces[vc->surface_num]);
-
vdp_st =
vdp->presentation_queue_display(vc->flip_queue,
vc->output_surfaces[vc->surface_num],
@@ -1095,27 +1123,26 @@ static struct vdpau_render_state *get_surface(struct vo *vo, int number)
return &vc->surface_render[number];
}
-static uint32_t draw_image(struct vo *vo, mp_image_t *mpi)
+static void draw_image(struct vo *vo, mp_image_t *mpi, double pts)
{
struct vdpctx *vc = vo->priv;
struct vdp_functions *vdp = vc->vdp;
+ struct mp_image *reserved_mpi = NULL;
+ struct vdpau_render_state *rndr;
+
+ if (vc->is_preempted) {
+ vo->frame_loaded = true;
+ return;
+ }
if (IMGFMT_IS_VDPAU(vc->image_format)) {
- struct vdpau_render_state *rndr = mpi->priv;
- vc->vid_surface_num = rndr - vc->surface_render;
- if (vc->deint_buffer_past_frames) {
- mpi->usage_count++;
- if (vc->deint_mpi[1])
- vc->deint_mpi[1]->usage_count--;
- vc->deint_mpi[1] = vc->deint_mpi[0];
- vc->deint_mpi[0] = mpi;
- }
+ rndr = mpi->priv;
+ reserved_mpi = mpi;
} else if (!(mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)) {
VdpStatus vdp_st;
void *destdata[3] = {mpi->planes[0], mpi->planes[2], mpi->planes[1]};
- struct vdpau_render_state *rndr = get_surface(vo, vc->deint_counter);
+ rndr = get_surface(vo, vc->deint_counter);
vc->deint_counter = (vc->deint_counter + 1) % 3;
- vc->vid_surface_num = rndr - vc->surface_render;
if (vc->image_format == IMGFMT_NV12)
destdata[1] = destdata[2];
vdp_st =
@@ -1123,16 +1150,33 @@ static uint32_t draw_image(struct vo *vo, mp_image_t *mpi)
vc->vdp_pixel_format,
(const void *const*)destdata,
mpi->stride); // pitch
- CHECK_ST_ERROR("Error when calling "
+ CHECK_ST_WARNING("Error when calling "
"vdp_video_surface_put_bits_y_cb_cr");
- }
+ } else
+ // We don't support slice callbacks so this shouldn't occur -
+ // I think the flags test above in pointless, but I'm adding
+ // this instead of removing it just in case.
+ abort();
if (mpi->fields & MP_IMGFIELD_ORDERED)
vc->top_field_first = !!(mpi->fields & MP_IMGFIELD_TOP_FIRST);
else
vc->top_field_first = 1;
+ add_new_video_surface(vo, rndr->surface, mpi, 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);
- return VO_TRUE;
+ vo->next_pts = vc->deint_pts[0];
+ vo->frame_loaded = true;
}
static uint32_t get_image(struct vo *vo, mp_image_t *mpi)
@@ -1287,8 +1331,6 @@ static int preinit(struct vo *vo, const char *arg)
}
if (vc->deint)
vc->deint_type = vc->deint;
- if (vc->deint > 1)
- vc->deint_buffer_past_frames = 1;
char *vdpaulibrary = "libvdpau.so.1";
char *vdpau_device_create = "vdp_device_create_x11";
@@ -1408,7 +1450,6 @@ static int control(struct vo *vo, uint32_t request, void *data)
1, features,
feature_enables);
CHECK_ST_WARNING("Error changing deinterlacing settings");
- vc->deint_buffer_past_frames = 1;
}
return VO_TRUE;
case VOCTRL_PAUSE:
@@ -1420,9 +1461,7 @@ static int control(struct vo *vo, uint32_t request, void *data)
case VOCTRL_GET_IMAGE:
return get_image(vo, data);
case VOCTRL_DRAW_IMAGE:
- if (vc->is_preempted)
- return true;
- return draw_image(vo, data);
+ abort(); // draw_image() should get called directly
case VOCTRL_BORDER:
vo_x11_border(vo);
resize(vo);
@@ -1476,12 +1515,16 @@ static int control(struct vo *vo, uint32_t request, void *data)
draw_osd(vo, data);
flip_page(vo);
return true;
+ case VOCTRL_RESET:
+ forget_frames(vo);
+ return true;
}
return VO_NOTIMPL;
}
const struct vo_driver video_out_vdpau = {
- .is_new = 1,
+ .is_new = true,
+ .buffer_frames = true,
.info = &(const struct vo_info_s){
"VDPAU with X11",
"vdpau",
@@ -1491,6 +1534,8 @@ const struct vo_driver video_out_vdpau = {
.preinit = preinit,
.config = config,
.control = control,
+ .draw_image = draw_image,
+ .get_buffered_frame = get_buffered_frame,
.draw_slice = draw_slice,
.draw_osd = draw_osd,
.flip_page = flip_page,
diff --git a/mencoder.c b/mencoder.c
index de862fac48..d1472a0568 100644
--- a/mencoder.c
+++ b/mencoder.c
@@ -204,6 +204,7 @@ int vo_config(struct vo *vo, uint32_t width, uint32_t height,
uint32_t d_width, uint32_t d_height, uint32_t flags,
char *title, uint32_t format) { abort(); }
int vo_control(struct vo *vo, uint32_t request, void *data) { abort(); }
+int vo_draw_image(struct vo *vo, struct mp_image *mpi, double pts) { abort(); }
int vo_draw_frame(struct vo *vo, uint8_t *src[]) { abort(); }
int vo_draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h, int x, int y) { abort(); }
void vo_draw_osd(struct vo *vo, struct osd_state *osd) { abort(); }
diff --git a/mp_core.h b/mp_core.h
index 4092e49efb..a5c7e70c8a 100644
--- a/mp_core.h
+++ b/mp_core.h
@@ -103,10 +103,6 @@ typedef struct MPContext {
struct demux_stream *d_sub;
mixer_t mixer;
struct vo *video_out;
- // Frames buffered in the vo ready to flip. Currently always 0 or 1.
- // This is really a vo variable but currently there's no suitable vo
- // struct.
- int num_buffered_frames;
// Show a video frame as quickly as possible without trying to adjust
// for AV sync. Used when starting a file or after seeking.
diff --git a/mplayer.c b/mplayer.c
index 7553621f9a..52731c7e4b 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -2240,6 +2240,7 @@ static double update_video_nocorrect_pts(struct MPContext *mpctx,
static double update_video(struct MPContext *mpctx, int *blit_frame)
{
struct sh_video *sh_video = mpctx->sh_video;
+ struct vo *video_out = mpctx->video_out;
*blit_frame = 0;
sh_video->vfilter->control(sh_video->vfilter, VFCTRL_SET_OSD_OBJ,
mpctx->osd); // hack for vf_expand
@@ -2248,14 +2249,18 @@ static double update_video(struct MPContext *mpctx, int *blit_frame)
double pts;
- while (1) {
+ bool hit_eof = false;
+ while (!video_out->frame_loaded) {
current_module = "filter_video";
+ if (vo_get_buffered_frame(video_out, hit_eof) >= 0)
+ break;
+ if (hit_eof)
+ return -1;
// XXX Time used in this call is not counted in any performance
// timer now, OSD time is not updated correctly for filter-added frames
if (vf_output_queued_frame(sh_video->vfilter))
break;
unsigned char *packet = NULL;
- bool hit_eof = false;
int in_size = ds_get_packet_pts(mpctx->d_video, &packet, &pts);
if (pts != MP_NOPTS_VALUE)
pts += mpctx->video_offset;
@@ -2278,12 +2283,12 @@ static double update_video(struct MPContext *mpctx, int *blit_frame)
update_osd_msg(mpctx);
current_module = "filter video";
if (filter_video(sh_video, decoded_frame, sh_video->pts))
- break;
- } else if (hit_eof)
- return -1;
+ if (!video_out->config_ok)
+ break; // We'd likely hang in this loop otherwise
+ }
}
- sh_video->vfilter->control(sh_video->vfilter, VFCTRL_GET_PTS, &pts);
+ pts = video_out->next_pts;
if (pts == MP_NOPTS_VALUE) {
mp_msg(MSGT_CPLAYER, MSGL_ERR, "Video pts after filters MISSING\n");
// Try to use decoder pts from before filters
@@ -2539,11 +2544,9 @@ static int seek(MPContext *mpctx, double amount, int style)
if (mpctx->sh_video) {
current_module = "seek_video_reset";
resync_video_stream(mpctx->sh_video);
- if (mpctx->video_out->config_ok)
- vo_control(mpctx->video_out, VOCTRL_RESET, NULL);
+ vo_seek_reset(mpctx->video_out);
mpctx->sh_video->num_buffered_pts = 0;
mpctx->sh_video->last_pts = MP_NOPTS_VALUE;
- mpctx->num_buffered_frames = 0;
mpctx->delay = 0;
mpctx->time_frame = 0;
mpctx->update_video_immediately = true;
@@ -3762,7 +3765,6 @@ if(verbose) term_osd = 0;
int frame_time_remaining=0; // flag
int blit_frame=0;
-mpctx->num_buffered_frames=0;
// Make sure old OSD does not stay around,
// e.g. with -fixed-vo and same-resolution files
@@ -3911,7 +3913,7 @@ if(!mpctx->sh_video) {
vo_pts=mpctx->sh_video->timer*90000.0;
vo_fps=mpctx->sh_video->fps;
- if (!mpctx->num_buffered_frames) {
+ if (!mpctx->video_out->frame_loaded) {
double frame_time = update_video(mpctx, &blit_frame);
mp_dbg(MSGT_AVSYNC,MSGL_DBG2,"*** ftime=%5.3f ***\n",frame_time);
if (mpctx->sh_video->vf_initialized < 0) {
@@ -3928,8 +3930,6 @@ if(!mpctx->sh_video) {
if (frame_time < 0)
mpctx->stop_play = AT_END_OF_FILE;
else {
- // might return with !eof && !blit_frame if !correct_pts
- mpctx->num_buffered_frames += blit_frame;
if (mpctx->update_video_immediately) {
// Show this frame immediately, rest normally
mpctx->update_video_immediately = false;
@@ -3981,7 +3981,6 @@ if(!mpctx->sh_video) {
unsigned int t2=GetTimer();
vo_flip_page(mpctx->video_out);
- mpctx->num_buffered_frames--;
mpctx->last_vo_flip_duration = (GetTimer() - t2) * 0.000001;
vout_time_usage += mpctx->last_vo_flip_duration;