summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/client-api-changes.rst4
-rw-r--r--libmpv/mpv.def1
-rw-r--r--libmpv/render.h151
-rw-r--r--video/out/vo_libmpv.c92
4 files changed, 219 insertions, 29 deletions
diff --git a/DOCS/client-api-changes.rst b/DOCS/client-api-changes.rst
index 32244a6e37..cb80d0a698 100644
--- a/DOCS/client-api-changes.rst
+++ b/DOCS/client-api-changes.rst
@@ -34,6 +34,10 @@ API changes
--- mpv 0.29.0 ---
1.101 - add MPV_RENDER_PARAM_ADVANCED_CONTROL and related API
+ - add MPV_RENDER_PARAM_NEXT_FRAME_INFO and related symbols
+ - add MPV_RENDER_PARAM_BLOCK_FOR_TARGET_TIME
+ - add MPV_RENDER_PARAM_SKIP_RENDERING
+ - add mpv_render_context_get_info()
1.100 - bump API number to avoid confusion with mpv release versions
- actually apply the GL_MP_MPGetNativeDisplay change for the new render
API. This also means compatibility for anything but x11 and wayland
diff --git a/libmpv/mpv.def b/libmpv/mpv.def
index efbf713622..b74378c4ae 100644
--- a/libmpv/mpv.def
+++ b/libmpv/mpv.def
@@ -34,6 +34,7 @@ mpv_opengl_cb_set_update_callback
mpv_opengl_cb_uninit_gl
mpv_render_context_create
mpv_render_context_free
+mpv_render_context_get_info
mpv_render_context_render
mpv_render_context_report_swap
mpv_render_context_set_parameter
diff --git a/libmpv/render.h b/libmpv/render.h
index af434b04e2..acd50cd03e 100644
--- a/libmpv/render.h
+++ b/libmpv/render.h
@@ -230,14 +230,55 @@ typedef enum mpv_render_param_type {
* Type: int*: 0 for disable (default), 1 for enable
*/
MPV_RENDER_PARAM_ADVANCED_CONTROL = 10,
+ /**
+ * Return information about the next frame to render. Valid for
+ * mpv_render_context_get_info().
+ *
+ * Type: mpv_render_frame_info*
+ *
+ * It strictly returns information about the _next_ frame. The implication
+ * is that e.g. mpv_render_context_update()'s return value will have
+ * MPV_RENDER_UPDATE_FRAME set, and the user is supposed to call
+ * mpv_render_context_render(). If there is no next frame, then the
+ * return value will have is_valid set to 0.
+ */
+ MPV_RENDER_PARAM_NEXT_FRAME_INFO = 11,
+ /**
+ * Enable or disable video timing. Valid for mpv_render_context_render().
+ *
+ * Type: int*: 0 for disable, 1 for enable (default)
+ *
+ * When video is timed to audio, the player attempts to render video a bit
+ * ahead, and then do a blocking wait until the target display time is
+ * reached. This blocks mpv_render_context_render() for up to the amount
+ * specified with the "video-timing-offset" global option. You can set
+ * this parameter to 0 to disable this kind of waiting. If you do, it's
+ * recommended to use the target time value in mpv_render_frame_info to
+ * wait yourself, or to set the "video-timing-offset" to 0 instead.
+ *
+ * Disabling this without doing anything in addition will result in A/V sync
+ * being slightly off.
+ */
+ MPV_RENDER_PARAM_BLOCK_FOR_TARGET_TIME = 12,
+ /**
+ * Use to skip rendering in mpv_render_context_render().
+ *
+ * Type: int*: 0 for rendering (default), 1 for skipping
+ *
+ * If this is set, you don't need to pass a target surface to the render
+ * function (and if you do, it's completely ignored). This can still call
+ * into the lower level APIs (i.e. if you use OpenGL, the OpenGL context
+ * must be set).
+ *
+ * Be aware that the render API will consider this frame as having been
+ * rendered. All other normal rules also apply, for example about whether
+ * you have to call mpv_render_context_report_swap(). It also does timing
+ * in the same way.
+ */
+ MPV_RENDER_PARAM_SKIP_RENDERING = 13,
} mpv_render_param_type;
/**
- * Predefined values for MPV_RENDER_PARAM_API_TYPE.
- */
-#define MPV_RENDER_API_TYPE_OPENGL "opengl"
-
-/**
* Used to pass arbitrary parameters to some mpv_render_* functions. The
* meaning of the data parameter is determined by the type, and each
* MPV_RENDER_PARAM_* documents what type the value must point to.
@@ -267,6 +308,84 @@ typedef struct mpv_render_param {
void *data;
} mpv_render_param;
+
+/**
+ * Predefined values for MPV_RENDER_PARAM_API_TYPE.
+ */
+#define MPV_RENDER_API_TYPE_OPENGL "opengl"
+
+/**
+ * Flags used in mpv_render_frame_info.flags. Each value represents a bit in it.
+ */
+typedef enum mpv_render_frame_info_flag {
+ /**
+ * Set if there is actually a next frame. If unset, there is no next frame
+ * yet, and other flags and fields that require a frame to be queued will
+ * be unset.
+ *
+ * This is set for _any_ kind of frame, even for redraw requests.
+ *
+ * Note that when this is unset, it simply means no new frame was
+ * decoded/queued yet, not necessarily that the end of the video was
+ * reached. A new frame can be queued after some time.
+ *
+ * If the return value of mpv_render_context_render() had the
+ * MPV_RENDER_UPDATE_FRAME flag set, this flag will usually be set as well,
+ * unless the frame is rendered, or discarded by other asynchronous events.
+ */
+ MPV_RENDER_FRAME_INFO_PRESENT = 1 << 0,
+ /**
+ * If set, the frame is not an actual new video frame, but a redraw request.
+ * For example if the video is paused, and an option that affects video
+ * rendering was changed (or any other reason), an update request can be
+ * issued and this flag will be set.
+ *
+ * Typically, redraw frames will not be subject to video timing.
+ *
+ * Implies MPV_RENDER_FRAME_INFO_PRESENT.
+ */
+ MPV_RENDER_FRAME_INFO_REDRAW = 1 << 1,
+ /**
+ * If set, this is supposed to reproduce the previous frame perfectly. This
+ * is usually used for certain "video-sync" options ("display-..." modes).
+ * Typically the renderer will blit the video from a FBO. Unset otherwise.
+ *
+ * Implies MPV_RENDER_FRAME_INFO_PRESENT.
+ */
+ MPV_RENDER_FRAME_INFO_REPEAT = 1 << 2,
+ /**
+ * If set, the player timing code expects that the user thread blocks on
+ * vsync (by either delaying the render call, or by making a call to
+ * mpv_render_context_report_swap() at vsync time).
+ *
+ * Implies MPV_RENDER_FRAME_INFO_PRESENT.
+ */
+ MPV_RENDER_FRAME_INFO_BLOCK_VSYNC = 1 << 3,
+} mpv_render_frame_info_flag;
+
+/**
+ * Information about the next video frame that will be rendered. Can be
+ * retrieved with MPV_RENDER_PARAM_NEXT_FRAME_INFO.
+ */
+typedef struct mpv_render_frame_info {
+ /**
+ * A bitset of mpv_render_frame_info_flag values (i.e. multiple flags are
+ * combined with bitwise or).
+ */
+ uint64_t flags;
+ /**
+ * Absolute time at which the frame is supposed to be displayed. This is in
+ * the same unit and base as the time returned by mpv_get_time_us(). For
+ * frames that are redrawn, or if vsync locked video timing is used (see
+ * "video-sync" option), then this can be 0. The "video-timing-offset"
+ * option determines how much "headroom" the render thread gets (but a high
+ * enough frame rate can reduce it anyway). mpv_render_context_render() will
+ * normally block until the time is elapsed, unless you pass it
+ * MPV_RENDER_PARAM_BLOCK_FOR_TARGET_TIME = 0.
+ */
+ int64_t target_time;
+} mpv_render_frame_info;
+
/**
* Initialize the renderer state. Depending on the backend used, this will
* access the underlying GPU API and initialize its own objects.
@@ -310,6 +429,28 @@ int mpv_render_context_create(mpv_render_context **res, mpv_handle *mpv,
int mpv_render_context_set_parameter(mpv_render_context *ctx,
mpv_render_param param);
+/**
+ * Retrieve information from the render context. This is NOT a counterpart to
+ * mpv_render_context_set_parameter(), because you generally can't read
+ * parameters set with it, and this function is not meant for this purpose.
+ * Instead, this is for communicating information from the renderer back to the
+ * user. See mpv_render_param_type; entries which support this function
+ * explicitly mention it, and for other entries you can assume it will fail.
+ *
+ * You pass param with param.type set and param.data pointing to a variable
+ * of the required data type. The function will then overwrite that variable
+ * with the returned value (at least on success).
+ *
+ * @param ctx a valid render context
+ * @param param the parameter type and data that should be retrieved
+ * @return error code. If a parameter could actually be retrieved, this returns
+ * success, otherwise an error code depending on the parameter type
+ * and situation. MPV_ERROR_NOT_IMPLEMENTED is used for unknown
+ * param.type, or if retrieving it is not supported.
+ */
+int mpv_render_context_get_info(mpv_render_context *ctx,
+ mpv_render_param param);
+
typedef void (*mpv_render_update_fn)(void *cb_ctx);
/**
diff --git a/video/out/vo_libmpv.c b/video/out/vo_libmpv.c
index ef5dc9809e..59d3b6883c 100644
--- a/video/out/vo_libmpv.c
+++ b/video/out/vo_libmpv.c
@@ -323,38 +323,45 @@ bool mp_render_context_acquire(mpv_render_context *ctx)
int mpv_render_context_render(mpv_render_context *ctx, mpv_render_param *params)
{
- int vp_w, vp_h;
- int err = ctx->renderer->fns->get_target_size(ctx->renderer, params,
- &vp_w, &vp_h);
- if (err < 0)
- return err;
-
pthread_mutex_lock(&ctx->lock);
- struct vo *vo = ctx->vo;
+ int do_render =
+ !GET_MPV_RENDER_PARAM(params, MPV_RENDER_PARAM_SKIP_RENDERING, int, 0);
- if (vo && (ctx->vp_w != vp_w || ctx->vp_h != vp_h || ctx->need_resize)) {
- ctx->vp_w = vp_w;
- ctx->vp_h = vp_h;
+ if (do_render) {
+ int vp_w, vp_h;
+ int err = ctx->renderer->fns->get_target_size(ctx->renderer, params,
+ &vp_w, &vp_h);
+ if (err < 0) {
+ pthread_mutex_unlock(&ctx->lock);
+ return err;
+ }
+
+ if (ctx->vo && (ctx->vp_w != vp_w || ctx->vp_h != vp_h ||
+ ctx->need_resize))
+ {
+ ctx->vp_w = vp_w;
+ ctx->vp_h = vp_h;
- m_config_cache_update(ctx->vo_opts_cache);
+ m_config_cache_update(ctx->vo_opts_cache);
- struct mp_rect src, dst;
- struct mp_osd_res osd;
- mp_get_src_dst_rects(ctx->log, ctx->vo_opts, vo->driver->caps,
- &ctx->img_params, vp_w, abs(vp_h),
- 1.0, &src, &dst, &osd);
+ struct mp_rect src, dst;
+ struct mp_osd_res osd;
+ mp_get_src_dst_rects(ctx->log, ctx->vo_opts, ctx->vo->driver->caps,
+ &ctx->img_params, vp_w, abs(vp_h),
+ 1.0, &src, &dst, &osd);
- ctx->renderer->fns->resize(ctx->renderer, &src, &dst, &osd);
+ ctx->renderer->fns->resize(ctx->renderer, &src, &dst, &osd);
+ }
+ ctx->need_resize = false;
}
- ctx->need_resize = false;
if (ctx->need_reconfig)
ctx->renderer->fns->reconfig(ctx->renderer, &ctx->img_params);
ctx->need_reconfig = false;
if (ctx->need_update_external)
- ctx->renderer->fns->update_external(ctx->renderer, vo);
+ ctx->renderer->fns->update_external(ctx->renderer, ctx->vo);
ctx->need_update_external = false;
if (ctx->need_reset) {
@@ -387,15 +394,22 @@ int mpv_render_context_render(mpv_render_context *ctx, mpv_render_param *params)
MP_STATS(ctx, "glcb-render");
- err = ctx->renderer->fns->render(ctx->renderer, params, frame);
+ int err = 0;
+
+ if (do_render)
+ err = ctx->renderer->fns->render(ctx->renderer, params, frame);
if (frame != &dummy)
talloc_free(frame);
- pthread_mutex_lock(&ctx->lock);
- while (wait_present_count > ctx->present_count)
- pthread_cond_wait(&ctx->video_wait, &ctx->lock);
- pthread_mutex_unlock(&ctx->lock);
+ if (GET_MPV_RENDER_PARAM(params, MPV_RENDER_PARAM_BLOCK_FOR_TARGET_TIME,
+ int, 1))
+ {
+ pthread_mutex_lock(&ctx->lock);
+ while (wait_present_count > ctx->present_count)
+ pthread_cond_wait(&ctx->video_wait, &ctx->lock);
+ pthread_mutex_unlock(&ctx->lock);
+ }
return err;
}
@@ -430,6 +444,36 @@ int mpv_render_context_set_parameter(mpv_render_context *ctx,
return ctx->renderer->fns->set_parameter(ctx->renderer, param);
}
+int mpv_render_context_get_info(mpv_render_context *ctx,
+ mpv_render_param param)
+{
+ int res = MPV_ERROR_NOT_IMPLEMENTED;
+ pthread_mutex_lock(&ctx->lock);
+
+ switch (param.type) {
+ case MPV_RENDER_PARAM_NEXT_FRAME_INFO: {
+ mpv_render_frame_info *info = param.data;
+ *info = (mpv_render_frame_info){0};
+ struct vo_frame *frame = ctx->next_frame;
+ if (frame) {
+ info->flags =
+ MPV_RENDER_FRAME_INFO_PRESENT |
+ (frame->redraw ? MPV_RENDER_FRAME_INFO_REDRAW : 0) |
+ (frame->repeat ? MPV_RENDER_FRAME_INFO_REPEAT : 0) |
+ (frame->display_synced && !frame->redraw ?
+ MPV_RENDER_FRAME_INFO_BLOCK_VSYNC : 0);
+ info->target_time = frame->pts;
+ }
+ res = 0;
+ break;
+ }
+ default:;
+ }
+
+ pthread_mutex_unlock(&ctx->lock);
+ return res;
+}
+
static void draw_frame(struct vo *vo, struct vo_frame *frame)
{
struct vo_priv *p = vo->priv;