summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--video/out/opengl/video.c60
-rw-r--r--video/out/vo.h1
2 files changed, 39 insertions, 22 deletions
diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c
index dadfe705ff..17468ab9a5 100644
--- a/video/out/opengl/video.c
+++ b/video/out/opengl/video.c
@@ -104,6 +104,7 @@ struct texplane {
struct video_image {
struct texplane planes[4];
struct mp_image *mpi; // original input image
+ uint64_t id; // unique ID identifying mpi contents
bool hwdec_mapped;
};
@@ -153,6 +154,7 @@ struct tex_hook {
struct fbosurface {
struct fbotex fbotex;
+ uint64_t id;
double pts;
};
@@ -517,7 +519,8 @@ static void uninit_scaler(struct gl_video *p, struct scaler *scaler);
static void check_gl_features(struct gl_video *p);
static bool init_format(struct gl_video *p, int fmt, bool test_only);
static void init_image_desc(struct gl_video *p, int fmt);
-static bool gl_video_upload_image(struct gl_video *p, struct mp_image *mpi);
+static bool gl_video_upload_image(struct gl_video *p, struct mp_image *mpi,
+ uint64_t id);
static const char *handle_scaler_opt(const char *name, bool tscale);
static void reinit_from_options(struct gl_video *p);
static void get_scale_factors(struct gl_video *p, bool transpose_rot, double xy[2]);
@@ -565,8 +568,10 @@ void gl_video_set_debug(struct gl_video *p, bool enable)
static void gl_video_reset_surfaces(struct gl_video *p)
{
- for (int i = 0; i < FBOSURFACES_MAX; i++)
+ for (int i = 0; i < FBOSURFACES_MAX; i++) {
+ p->surfaces[i].id = 0;
p->surfaces[i].pts = MP_NOPTS_VALUE;
+ }
p->surface_idx = 0;
p->surface_now = 0;
p->frames_drawn = 0;
@@ -960,6 +965,7 @@ static void unref_current_image(struct gl_video *p)
{
unmap_current_image(p);
mp_image_unrefp(&p->image.mpi);
+ p->image.id = 0;
}
static void uninit_video(struct gl_video *p)
@@ -2552,22 +2558,23 @@ static void gl_video_interpolate_frame(struct gl_video *p, struct vo_frame *t,
// First of all, figure out if we have a frame available at all, and draw
// it manually + reset the queue if not
- if (p->surfaces[p->surface_now].pts == MP_NOPTS_VALUE) {
- if (!gl_video_upload_image(p, t->current))
+ if (p->surfaces[p->surface_now].id == 0) {
+ if (!gl_video_upload_image(p, t->current, t->frame_id))
return;
pass_render_frame(p);
finish_pass_fbo(p, &p->surfaces[p->surface_now].fbotex,
vp_w, vp_h, FBOTEX_FUZZY);
+ p->surfaces[p->surface_now].id = p->image.id;
p->surfaces[p->surface_now].pts = p->image.mpi->pts;
p->surface_idx = p->surface_now;
}
// Find the right frame for this instant
- if (t->current && t->current->pts != MP_NOPTS_VALUE) {
+ if (t->current) {
int next = fbosurface_wrap(p->surface_now + 1);
- while (p->surfaces[next].pts != MP_NOPTS_VALUE &&
- p->surfaces[next].pts > p->surfaces[p->surface_now].pts &&
- p->surfaces[p->surface_now].pts < t->current->pts)
+ while (p->surfaces[next].id &&
+ p->surfaces[next].id > p->surfaces[p->surface_now].id &&
+ p->surfaces[p->surface_now].id < t->frame_id)
{
p->surface_now = next;
next = fbosurface_wrap(next + 1);
@@ -2609,16 +2616,17 @@ static void gl_video_interpolate_frame(struct gl_video *p, struct vo_frame *t,
break;
struct mp_image *f = t->frames[i];
- if (!mp_image_params_equal(&f->params, &p->real_image_params) ||
- f->pts == MP_NOPTS_VALUE)
+ uint64_t f_id = t->frame_id + i;
+ if (!mp_image_params_equal(&f->params, &p->real_image_params))
continue;
- if (f->pts > p->surfaces[p->surface_idx].pts) {
- if (!gl_video_upload_image(p, f))
+ if (f_id > p->surfaces[p->surface_idx].id) {
+ if (!gl_video_upload_image(p, f, f_id))
return;
pass_render_frame(p);
finish_pass_fbo(p, &p->surfaces[surface_dst].fbotex,
vp_w, vp_h, FBOTEX_FUZZY);
+ p->surfaces[surface_dst].id = f_id;
p->surfaces[surface_dst].pts = f->pts;
p->surface_idx = surface_dst;
surface_dst = fbosurface_wrap(surface_dst + 1);
@@ -2633,11 +2641,9 @@ static void gl_video_interpolate_frame(struct gl_video *p, struct vo_frame *t,
bool valid = true;
for (int i = surface_bse, ii; valid && i != surface_end; i = ii) {
ii = fbosurface_wrap(i + 1);
- if (p->surfaces[i].pts == MP_NOPTS_VALUE ||
- p->surfaces[ii].pts == MP_NOPTS_VALUE)
- {
+ if (p->surfaces[i].id == 0 || p->surfaces[ii].id == 0) {
valid = false;
- } else if (p->surfaces[ii].pts < p->surfaces[i].pts) {
+ } else if (p->surfaces[ii].id < p->surfaces[i].id) {
valid = false;
MP_DBG(p, "interpolation queue underrun\n");
}
@@ -2658,8 +2664,8 @@ static void gl_video_interpolate_frame(struct gl_video *p, struct vo_frame *t,
// (which requires some extra checking to make sure it's valid)
if (mix < 0.0) {
int prev = fbosurface_wrap(surface_bse - 1);
- if (p->surfaces[prev].pts != MP_NOPTS_VALUE &&
- p->surfaces[prev].pts < p->surfaces[surface_bse].pts)
+ if (p->surfaces[prev].id != 0 &&
+ p->surfaces[prev].id < p->surfaces[surface_bse].id)
{
mix += 1.0;
surface_bse = prev;
@@ -2738,7 +2744,6 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo)
gl->BindFramebuffer(GL_FRAMEBUFFER, fbo);
bool has_frame = !!frame->current;
- bool is_new = has_frame && !frame->redraw && !frame->repeat;
if (!has_frame || p->dst_rect.x0 > 0 || p->dst_rect.y0 > 0 ||
p->dst_rect.x1 < p->vp_w || p->dst_rect.y1 < abs(p->vp_h))
@@ -2760,7 +2765,7 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo)
gl->Disable(GL_SCISSOR_TEST);
}
- if (is_new || !frame->current)
+ if (frame->frame_id != p->image.id || !frame->current)
p->hwdec->driver->overlay_frame(p->hwdec, frame->current);
if (frame->current)
@@ -2784,10 +2789,16 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo)
if (interpolate) {
gl_video_interpolate_frame(p, frame, fbo);
} else {
+ bool is_new = frame->frame_id != p->image.id;
+
+ // Redrawing a frame might update subtitles.
+ if (!frame->repeat && p->opts.blend_subs)
+ is_new = false;
+
if (is_new || !p->output_fbo_valid) {
p->output_fbo_valid = false;
- if (!gl_video_upload_image(p, frame->current))
+ if (!gl_video_upload_image(p, frame->current, frame->frame_id))
goto done;
pass_render_frame(p);
@@ -2949,11 +2960,15 @@ static void reinterleave_vdpau(struct gl_video *p, struct gl_hwdec_frame *frame)
}
// Returns false on failure.
-static bool gl_video_upload_image(struct gl_video *p, struct mp_image *mpi)
+static bool gl_video_upload_image(struct gl_video *p, struct mp_image *mpi,
+ uint64_t id)
{
GL *gl = p->gl;
struct video_image *vimg = &p->image;
+ if (vimg->id == id)
+ return true;
+
unref_current_image(p);
mpi = mp_image_new_ref(mpi);
@@ -2961,6 +2976,7 @@ static bool gl_video_upload_image(struct gl_video *p, struct mp_image *mpi)
goto error;
vimg->mpi = mpi;
+ vimg->id = id;
p->osd_pts = mpi->pts;
p->frames_uploaded++;
diff --git a/video/out/vo.h b/video/out/vo.h
index d2393f829b..99e6ccabae 100644
--- a/video/out/vo.h
+++ b/video/out/vo.h
@@ -223,6 +223,7 @@ struct vo_frame {
// a frame is guaranteed not to change (instant redraws will use the same
// ID). frames[n] has the ID frame_id+n, with the guarantee that frame
// drops or reconfigs will keep the guarantee.
+ // The ID is never 0 (unless num_frames==0). IDs are strictly monotonous.
uint64_t frame_id;
};