summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/client-api-changes.rst4
-rw-r--r--DOCS/client_api_examples/qml/main.cpp19
-rw-r--r--DOCS/client_api_examples/qml/main.qml39
-rw-r--r--DOCS/client_api_examples/qml/mpvrenderer.cpp125
-rw-r--r--DOCS/client_api_examples/qml/mpvrenderer.h33
-rw-r--r--DOCS/client_api_examples/qml/mpvtest.pro11
-rw-r--r--DOCS/client_api_examples/qml/mpvtest.qrc5
-rw-r--r--libmpv/client.h40
-rw-r--r--libmpv/mpv.def7
-rw-r--r--libmpv/opengl_cb.h199
-rw-r--r--old-makefile1
-rw-r--r--player/client.c57
-rw-r--r--player/client.h7
-rw-r--r--player/core.h2
-rw-r--r--player/video.c3
-rw-r--r--video/out/gl_common.c24
-rw-r--r--video/out/gl_common.h2
-rw-r--r--video/out/gl_hwdec.c15
-rw-r--r--video/out/gl_hwdec.h2
-rw-r--r--video/out/gl_hwdec_vaglx.c4
-rw-r--r--video/out/gl_hwdec_vdpau.c4
-rw-r--r--video/out/gl_video.c29
-rw-r--r--video/out/gl_video.h5
-rw-r--r--video/out/vo.c2
-rw-r--r--video/out/vo.h2
-rw-r--r--video/out/vo_opengl.c4
-rw-r--r--video/out/vo_opengl_cb.c370
-rw-r--r--wscript_build.py3
28 files changed, 993 insertions, 25 deletions
diff --git a/DOCS/client-api-changes.rst b/DOCS/client-api-changes.rst
index 918d986ee6..69458d0d49 100644
--- a/DOCS/client-api-changes.rst
+++ b/DOCS/client-api-changes.rst
@@ -25,6 +25,10 @@ API changes
::
+ 1.11 - add OpenGL rendering interop API - allows an application to combine
+ its own and mpv's OpenGL rendering
+ Warning: this API is not stable yet - anything in opengl_cb.h might
+ be changed in completely incompatible ways in minor API bumps
--- mpv 0.7.0 is released ---
1.10 - deprecate/disable everything directly related to script_dispatch
(most likely affects nobody)
diff --git a/DOCS/client_api_examples/qml/main.cpp b/DOCS/client_api_examples/qml/main.cpp
new file mode 100644
index 0000000000..cc86302be6
--- /dev/null
+++ b/DOCS/client_api_examples/qml/main.cpp
@@ -0,0 +1,19 @@
+#include <QGuiApplication>
+
+#include <QtQuick/QQuickView>
+
+#include "mpvrenderer.h"
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+
+ qmlRegisterType<MpvObject>("mpvtest", 1, 0, "MpvObject");
+
+ QQuickView view;
+ view.setResizeMode(QQuickView::SizeRootObjectToView);
+ view.setSource(QUrl("qrc:///mpvtest/main.qml"));
+ view.show();
+
+ return app.exec();
+}
diff --git a/DOCS/client_api_examples/qml/main.qml b/DOCS/client_api_examples/qml/main.qml
new file mode 100644
index 0000000000..d921e2a86c
--- /dev/null
+++ b/DOCS/client_api_examples/qml/main.qml
@@ -0,0 +1,39 @@
+import QtQuick 2.0
+import QtQuick.Controls 1.0
+
+import mpvtest 1.0
+
+Item {
+ width: 1280
+ height: 720
+
+ MpvObject {
+ id: renderer
+ anchors.fill: parent
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: renderer.loadfile("../../../test.mkv")
+ }
+ }
+
+ Rectangle {
+ id: labelFrame
+ anchors.margins: -50
+ radius: 5
+ color: "white"
+ border.color: "black"
+ opacity: 0.8
+ anchors.fill: label
+ }
+
+ Text {
+ id: label
+ anchors.bottom: renderer.bottom
+ anchors.left: renderer.left
+ anchors.right: renderer.right
+ anchors.margins: 100
+ wrapMode: Text.WordWrap
+ text: "QtQuick and mpv are both rendering stuff."
+ }
+}
diff --git a/DOCS/client_api_examples/qml/mpvrenderer.cpp b/DOCS/client_api_examples/qml/mpvrenderer.cpp
new file mode 100644
index 0000000000..af62fd2762
--- /dev/null
+++ b/DOCS/client_api_examples/qml/mpvrenderer.cpp
@@ -0,0 +1,125 @@
+#include "mpvrenderer.h"
+
+#include <QObject>
+#include <QtGlobal>
+#include <QOpenGLContext>
+
+#include <QtGui/QOpenGLFramebufferObject>
+
+#include <QtQuick/QQuickWindow>
+#include <qsgsimpletexturenode.h>
+
+class MpvRenderer : public QQuickFramebufferObject::Renderer
+{
+ static void *get_proc_address(void *ctx, const char *name) {
+ (void)ctx;
+ QOpenGLContext *glctx = QOpenGLContext::currentContext();
+ if (!glctx)
+ return NULL;
+ return (void *)glctx->getProcAddress(QByteArray(name));
+ }
+
+ mpv_opengl_cb_context *mpv_gl;
+ QQuickWindow *window;
+public:
+ MpvRenderer(mpv_opengl_cb_context *a_mpv_gl)
+ : mpv_gl(a_mpv_gl), window(NULL)
+ {
+ int r = mpv_opengl_cb_init_gl(mpv_gl, NULL, get_proc_address, NULL);
+ if (r < 0)
+ throw "could not initialize OpenGL";
+ }
+
+ virtual ~MpvRenderer()
+ {
+ mpv_opengl_cb_uninit_gl(mpv_gl);
+ }
+
+ void render()
+ {
+ assert(window); // must have been set by synchronize()
+
+ QOpenGLFramebufferObject *fbo = framebufferObject();
+ int vp[4] = {0, 0, fbo->width(), fbo->height()};
+ window->resetOpenGLState();
+ mpv_opengl_cb_render(mpv_gl, fbo->handle(), vp);
+ window->resetOpenGLState();
+ }
+
+ QOpenGLFramebufferObject *createFramebufferObject(const QSize &size)
+ {
+ QOpenGLFramebufferObjectFormat format;
+ format.setSamples(4);
+ return new QOpenGLFramebufferObject(size, format);
+ }
+
+protected:
+ virtual void synchronize(QQuickFramebufferObject *item)
+ {
+ window = item->window();
+ }
+};
+
+MpvObject::MpvObject(QQuickItem * parent)
+ : QQuickFramebufferObject(parent)
+{
+ mpv = mpv_create();
+ if (!mpv)
+ throw "could not create mpv context";
+
+ mpv_set_option_string(mpv, "terminal", "yes");
+ mpv_set_option_string(mpv, "msg-level", "all=v");
+
+ if (mpv_initialize(mpv) < 0) {
+ mpv_terminate_destroy(mpv);
+ throw "could not initialize mpv context";
+ }
+
+ // Make use of the MPV_SUB_API_OPENGL_CB API.
+ mpv::qt::set_option_variant(mpv, "vo", "opengl-cb");
+
+ // Request hw decoding, just for testing.
+ mpv::qt::set_option_variant(mpv, "hwdec", "auto");
+
+ mpv_gl = (mpv_opengl_cb_context *)mpv_get_sub_api(mpv, MPV_SUB_API_OPENGL_CB);
+ if (!mpv_gl) {
+ mpv_terminate_destroy(mpv);
+ throw "OpenGL not compiled in";
+ }
+
+ mpv_opengl_cb_set_update_callback(mpv_gl, on_update, (void *)this);
+
+ connect(this, &MpvObject::onUpdate, this, &MpvObject::doUpdate, Qt::QueuedConnection);
+}
+
+MpvObject::~MpvObject()
+{
+ mpv_terminate_destroy(mpv);
+}
+
+void MpvObject::on_update(void *ctx)
+{
+ MpvObject *self = (MpvObject *)ctx;
+ emit self->onUpdate();
+}
+
+// connected to onUpdate(); signal makes sure it runs on the GUI thread
+void MpvObject::doUpdate()
+{
+ update();
+}
+
+void MpvObject::loadfile(const QString& filename)
+{
+ QVariantList cmd;
+ cmd.append("loadfile");
+ cmd.append(filename);
+ mpv::qt::command_variant(mpv, cmd);
+}
+
+QQuickFramebufferObject::Renderer *MpvObject::createRenderer() const
+{
+ window()->setPersistentOpenGLContext(true);
+ window()->setPersistentSceneGraph(true);
+ return new MpvRenderer(mpv_gl);
+}
diff --git a/DOCS/client_api_examples/qml/mpvrenderer.h b/DOCS/client_api_examples/qml/mpvrenderer.h
new file mode 100644
index 0000000000..d0bedf720b
--- /dev/null
+++ b/DOCS/client_api_examples/qml/mpvrenderer.h
@@ -0,0 +1,33 @@
+#ifndef MPVRENDERER_H_
+#define MPVRENDERER_H_
+
+#include <assert.h>
+
+#include <QtQuick/QQuickFramebufferObject>
+
+#include "libmpv/client.h"
+#include "libmpv/opengl_cb.h"
+#include "libmpv/qthelper.hpp"
+
+class MpvObject : public QQuickFramebufferObject
+{
+ Q_OBJECT
+
+ mpv_handle *mpv;
+ mpv_opengl_cb_context *mpv_gl;
+
+public:
+ MpvObject(QQuickItem * parent = 0);
+ virtual ~MpvObject();
+ Renderer *createRenderer() const;
+public slots:
+ void loadfile(const QString& filename);
+signals:
+ void onUpdate();
+private slots:
+ void doUpdate();
+private:
+ static void on_update(void *ctx);
+};
+
+#endif
diff --git a/DOCS/client_api_examples/qml/mpvtest.pro b/DOCS/client_api_examples/qml/mpvtest.pro
new file mode 100644
index 0000000000..6681fa1884
--- /dev/null
+++ b/DOCS/client_api_examples/qml/mpvtest.pro
@@ -0,0 +1,11 @@
+QT += qml quick
+
+HEADERS += mpvrenderer.h
+SOURCES += mpvrenderer.cpp main.cpp
+
+CONFIG += link_pkgconfig debug
+PKGCONFIG = mpv
+
+RESOURCES += mpvtest.qrc
+
+OTHER_FILES += main.qml
diff --git a/DOCS/client_api_examples/qml/mpvtest.qrc b/DOCS/client_api_examples/qml/mpvtest.qrc
new file mode 100644
index 0000000000..bb672657e5
--- /dev/null
+++ b/DOCS/client_api_examples/qml/mpvtest.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/mpvtest">
+ <file>main.qml</file>
+ </qresource>
+</RCC>
diff --git a/libmpv/client.h b/libmpv/client.h
index 11b27b26df..9ed2cabd27 100644
--- a/libmpv/client.h
+++ b/libmpv/client.h
@@ -123,14 +123,15 @@ extern "C" {
* --------------------------
*
* Currently you have to get the raw window handle, and set it as "wid" option.
- * This works on X11 and win32 only. In addition, it works with a few VOs only,
- * and VOs which do not support this will just create a freestanding window.
+ * This works on X11, win32, and OSX only. In addition, it works with a few VOs
+ * only, and VOs which do not support this will just create a freestanding
+ * window.
*
* Both on X11 and win32, the player will fill the window referenced by the
* "wid" option fully and letterbox the video (i.e. add black bars if the
* aspect ratio of the window and the video mismatch).
*
- * On OSX, embedding is not yet possible, because Cocoa makes this non-trivial.
+ * Also see client API examples and the mpv manpage.
*
* Compatibility
* -------------
@@ -164,7 +165,7 @@ extern "C" {
* relational operators (<, >, <=, >=).
*/
#define MPV_MAKE_VERSION(major, minor) (((major) << 16) | (minor) | 0UL)
-#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(1, 10)
+#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(1, 11)
/**
* Return the MPV_CLIENT_API_VERSION the mpv source has been compiled with.
@@ -269,7 +270,16 @@ typedef enum mpv_error {
* When trying to load the file, the file format could not be determined,
* or the file was too broken to open it.
*/
- MPV_ERROR_UNKNOWN_FORMAT = -17
+ MPV_ERROR_UNKNOWN_FORMAT = -17,
+ /**
+ * Generic error for signaling that certain system requirements are not
+ * fulfilled.
+ */
+ MPV_ERROR_UNSUPPORTED = -18,
+ /**
+ * The API function which was called is a stub only.
+ */
+ MPV_ERROR_NOT_IMPLEMENTED = -19
} mpv_error;
/**
@@ -437,6 +447,9 @@ void mpv_resume(mpv_handle *ctx);
* with playback time. For example, playback could go faster or slower due to
* playback speed, or due to playback being paused. Use the "time-pos" property
* instead to get the playback status.
+ *
+ * Unlike other libmpv APIs, this can be called at absolutely any time (even
+ * within wakeup callbacks), as long as the context is valid.
*/
int64_t mpv_get_time_us(mpv_handle *ctx);
@@ -1426,6 +1439,23 @@ void mpv_set_wakeup_callback(mpv_handle *ctx, void (*cb)(void *d), void *d);
*/
int mpv_get_wakeup_pipe(mpv_handle *ctx);
+typedef enum mpv_sub_api {
+ /**
+ * For using mpv's OpenGL renderer on an external OpenGL context.
+ * mpv_get_sub_api(MPV_SUB_API_OPENGL_CB) returns mpv_opengl_cb_context*.
+ * This context can be used with mpv_opengl_cb_* functions.
+ * Will return NULL if unavailable (if OpenGL support was not compiled in).
+ * See opengl_cb.h for details.
+ */
+ MPV_SUB_API_OPENGL_CB = 1
+} mpv_sub_api;
+
+/**
+ * This is used for additional APIs that are not strictly part of the core API.
+ * See the individual mpv_sub_api member values.
+ */
+void *mpv_get_sub_api(mpv_handle *ctx, mpv_sub_api sub_api);
+
#ifdef __cplusplus
}
#endif
diff --git a/libmpv/mpv.def b/libmpv/mpv.def
index e8dc65db58..83ad9b315b 100644
--- a/libmpv/mpv.def
+++ b/libmpv/mpv.def
@@ -15,11 +15,16 @@ mpv_get_property
mpv_get_property_async
mpv_get_property_osd_string
mpv_get_property_string
+mpv_get_sub_api
mpv_get_time_us
mpv_get_wakeup_pipe
mpv_initialize
mpv_load_config_file
mpv_observe_property
+mpv_opengl_cb_init_gl
+mpv_opengl_cb_render
+mpv_opengl_cb_set_update_callback
+mpv_opengl_cb_uninit_gl
mpv_request_event
mpv_request_log_messages
mpv_resume
@@ -33,4 +38,4 @@ mpv_suspend
mpv_terminate_destroy
mpv_unobserve_property
mpv_wait_event
-mpv_wakeup
+mpv_wakeup \ No newline at end of file
diff --git a/libmpv/opengl_cb.h b/libmpv/opengl_cb.h
new file mode 100644
index 0000000000..3f5010b26e
--- /dev/null
+++ b/libmpv/opengl_cb.h
@@ -0,0 +1,199 @@
+/* Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Note: the client API is licensed under ISC (see above) to ease
+ * interoperability with other licenses. But keep in mind that the
+ * mpv core is still mostly GPLv2+. It's up to lawyers to decide
+ * whether applications using this API are affected by the GPL.
+ * One argument against this is that proprietary applications
+ * using mplayer in slave mode is apparently tolerated, and this
+ * API is basically equivalent to slave mode.
+ */
+
+#ifndef MPV_CLIENT_API_OPENGL_CB_H_
+#define MPV_CLIENT_API_OPENGL_CB_H_
+
+#include "client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Warning: this API is not stable yet.
+ *
+ * Overview
+ * --------
+ *
+ * This API can be used to make mpv render into a foreign OpenGL context. It
+ * can be used to handle video display. Be aware that using this API is not
+ * required: you can embed the mpv window by setting the mpv "wid" option to
+ * a native window handle (see "Embedding the video window" section in the
+ * client.h header). In general, using the "wid" option is recommended over
+ * the OpenGL API, because it's simpler and more flexible on the mpv side.
+ *
+ * The renderer needs to be explicitly initialized with mpv_opengl_cb_init_gl(),
+ * and then video can be drawn with mpv_opengl_cb_render(). The user thread can
+ * be notified by new frames with mpv_opengl_cb_set_update_callback().
+ *
+ * OpenGL interop
+ * --------------
+ *
+ * This assumes the OpenGL context lives on a certain thread controlled by the
+ * API user. The following functions require access to the OpenGL context:
+ * mpv_opengl_cb_init_gl
+ * mpv_opengl_cb_render
+ * mpv_opengl_cb_uninit_gl
+ *
+ * The OpenGL context is indirectly accessed through the OpenGL function
+ * pointers returned by the get_proc_address callback in mpv_opengl_cb_init_gl.
+ * Generally, mpv will not load the system OpenGL library when using this API.
+ *
+ * Only "desktop" OpenGL version 2.1 or later is supported. With OpenGL 2.1,
+ * the GL_ARB_texture_rg is required. The renderer was written against
+ * OpenGL 3.x core profile, with additional support for OpenGL 2.1.
+ *
+ * Note that some hardware decoding interop API (as set with the "hwdec" option)
+ * may actually access
+ *
+ * OpenGL state
+ * ------------
+ *
+ * OpenGL has a large amount of implicit state. All the mpv functions mentioned
+ * above expect that the OpenGL state is reasonably set to OpenGL standard
+ * defaults. Likewise, mpv will attempt to leave the OpenGL context with
+ * standard defaults. The following state is excluded from this:
+ *
+ * - the current viewport (can have/is set to an arbitrary value)
+ *
+ * Messing with the state could be avoided by creating shared OpenGL contexts,
+ * but this is avoided for the sake of compatibility and interoperability.
+ *
+ * On OpenGL 2.1, mpv will strictly call functions like glGenTextures() to
+ * create OpenGL objects. You will have to do the same. This ensures that
+ * objects created by mpv and the API users don't clash.
+ *
+ * Threading
+ * ---------
+ *
+ * The mpv_opengl_cb_* functions can be called from any thread, under the
+ * following conditions:
+ * - only one of the mpv_opengl_cb_* functions can be called at the same time
+ * (unless they belong to different mpv_handles)
+ * - for functions which need an OpenGL context (see above) the OpenGL context
+ * must be "current" in the current thread, and it must be the same context
+ * as used with mpv_opengl_cb_init_gl()
+ * - never can be called from within the callbacks set with
+ * mpv_set_wakeup_callback() or mpv_opengl_cb_set_update_callback()
+ */
+
+/**
+ * Opaque context, returned by mpv_get_sub_api(MPV_SUB_API_OPENGL_CB).
+ *
+ * A context is bound to the mpv_handle it was retrieved from. The context
+ * will always be the same (for the same mpv_handle), and is valid until the
+ * mpv_handle it belongs to is released.
+ */
+typedef struct mpv_opengl_cb_context mpv_opengl_cb_context;
+
+typedef void (*mpv_opengl_cb_update_fn)(void *cb_ctx);
+typedef void *(*mpv_opengl_cb_get_proc_address_fn)(void *fn_ctx, const char *name);
+
+/**
+ * Set the callback that notifies you when a new video frame is available, or
+ * if the video display configuration somehow changed and requires a redraw.
+ * Similar to mpv_set_wakeup_callback(), you must not call any mpv API from
+ * the callback.
+ *
+ * @param callback callback(callback_ctx) is called if the frame should be
+ * redrawn
+ * @param callback_ctx opaque argument to the callback
+ */
+void mpv_opengl_cb_set_update_callback(mpv_opengl_cb_context *ctx,
+ mpv_opengl_cb_update_fn callback,
+ void *callback_ctx);
+
+/**
+ * Initialize the mpv OpenGL state. This retrieves OpenGL function pointers via
+ * get_proc_address, and creates OpenGL objects needed by mpv internally. It
+ * will also call APIs needed for rendering hardware decoded video in OpenGL,
+ * according to the mpv "hwdec" option.
+ *
+ * You must free the associated state at some point by calling the
+ * mpv_opengl_cb_uninit_gl() function. Not doing so may result in memory leaks
+ * or worse.
+ *
+ * @param exts optional _additional_ extension string, can be NULL
+ * @param get_proc_address callback used to retrieve function pointers to OpenGL
+ * functions. This is used for both standard functions
+ * and extension functions. (The extension string is
+ * checked whether extensions are really available.)
+ * The callback will be called from this function only
+ * (it is not stored and never used later).
+ * @param get_proc_address_ctx arbitrary opaque user context passed to the
+ * get_proc_address callback
+ * @return error code (same as normal mpv_* API), including but not limited to:
+ * MPV_ERROR_UNSUPPORTED: the OpenGL version is not supported
+ * (or required extensions are missing)
+ * MPV_ERROR_INVALID_PARAMETER: the OpenGL state was already initialized
+ */
+int mpv_opengl_cb_init_gl(mpv_opengl_cb_context *ctx, const char *exts,
+ mpv_opengl_cb_get_proc_address_fn get_proc_address,
+ void *get_proc_address_ctx);
+
+/**
+ * Render video. Requires that the OpenGL state is initialized.
+ *
+ * The video will use the provided viewport rectangle as window size. Options
+ * like "panscan" are applied to determine which part of the video should be
+ * visible and how the video should be scaled. You can change these options
+ * at runtime by using the mpv property API.
+ *
+ * The renderer will reconfigure itself every time the output rectangle/size
+ * is changed. (If you want to do animations, it might be better to do the
+ * animation on a FBO instead.)
+ *
+ * @param fbo The framebuffer object to render on. Because the renderer might
+ * manage multiple FBOs internally for the purpose of video
+ * postprocessing, it will always bind and unbind FBOs itself. If
+ * you want mpv to render on the main framebuffer, pass 0.
+ * @param vp Viewport to render on. The renderer will essentially call:
+ * glViewport(vp[0], vp[1], vp[2], vp[3]);
+ * before rendering. The height (vp[3]) can be negative to flip the
+ * image - the renderer will flip it before setting the viewport
+ * (typically you want to flip the image if you are rendering
+ * directly to the main framebuffer).
+ * @return error code
+ */
+int mpv_opengl_cb_render(mpv_opengl_cb_context *ctx, int fbo, int vp[4]);
+
+/**
+ * Destroy the mpv OpenGL state.
+ *
+ * This will trigger undefined behavior (i.e. crash hard) if the hardware
+ * decoder is still active, because the OpenGL hardware decoding interop state
+ * can't be destroyed synchronously. If no hardware decoding is active, the
+ * state can be destroyed at any time.
+ *
+ * Calling this multiple times is ok.
+ *
+ * @return error code
+ */
+int mpv_opengl_cb_uninit_gl(mpv_opengl_cb_context *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/old-makefile b/old-makefile
index 69db63983e..a9432ed2c2 100644
--- a/old-makefile
+++ b/old-makefile
@@ -63,6 +63,7 @@ SOURCES-$(GL) += video/out/gl_common.c video/out/gl_osd.c \
video/out/vo_opengl.c video/out/gl_lcms.c \
video/out/gl_video.c video/out/dither.c \
video/out/gl_hwdec.c \
+ video/out/vo_opengl_cb.c \
video/out/vo_opengl_old.c \
video/out/pnm_loader.c
diff --git a/player/client.c b/player/client.c
index d86217106e..a46a37b10a 100644
--- a/player/client.c
+++ b/player/client.c
@@ -1511,6 +1511,8 @@ static const char *const err_table[] = {
[-MPV_ERROR_VO_INIT_FAILED] = "audio output initialization failed",
[-MPV_ERROR_NOTHING_TO_PLAY] = "the file has no audio or video data",
[-MPV_ERROR_UNKNOWN_FORMAT] = "unrecognized file format",
+ [-MPV_ERROR_UNSUPPORTED] = "not supported",
+ [-MPV_ERROR_NOT_IMPLEMENTED] = "operation not implemented",
};
const char *mpv_error_string(int error)
@@ -1567,3 +1569,58 @@ int64_t mpv_get_time_us(mpv_handle *ctx)
{
return mp_time_us();
}
+
+#include "libmpv/opengl_cb.h"
+
+#if HAVE_GL
+static mpv_opengl_cb_context *opengl_cb_get_context(mpv_handle *ctx)
+{
+ mpv_opengl_cb_context *cb = ctx->mpctx->gl_cb_ctx;
+ if (!cb) {
+ cb = mp_opengl_create(ctx->mpctx->global, ctx->mpctx->osd);
+ ctx->mpctx->gl_cb_ctx = cb;
+ }
+ return cb;
+}
+#else
+static mpv_opengl_cb_context *opengl_cb_get_context(mpv_handle *ctx)
+{
+ return NULL;
+}
+void mpv_opengl_cb_set_update_callback(mpv_opengl_cb_context *ctx,
+ mpv_opengl_cb_update_fn callback,
+ void *callback_ctx)
+{
+ return MPV_ERROR_NOT_IMPLEMENTED;
+}
+int mpv_opengl_cb_init_gl(mpv_opengl_cb_context *ctx, const char *exts,
+ mpv_opengl_cb_get_proc_address_fn get_proc_address,
+ void *get_proc_address_ctx)
+{
+ return MPV_ERROR_NOT_IMPLEMENTED;
+}
+int mpv_opengl_cb_render(mpv_opengl_cb_context *ctx, int fbo, int vp[4])
+{
+ return MPV_ERROR_NOT_IMPLEMENTED;
+}
+int mpv_opengl_cb_uninit_gl(mpv_opengl_cb_context *ctx)
+{
+ return MPV_ERROR_NOT_IMPLEMENTED;
+}
+#endif
+
+void *mpv_get_sub_api(mpv_handle *ctx, mpv_sub_api sub_api)
+{
+ if (!ctx->mpctx->initialized)
+ return NULL;
+ void *res = NULL;
+ lock_core(ctx);
+ switch (sub_api) {
+ case MPV_SUB_API_OPENGL_CB:
+ res = opengl_cb_get_context(ctx);
+ break;
+ default:;
+ }
+ unlock_core(ctx);
+ return res;
+}
diff --git a/player/client.h b/player/client.h
index a275bb9728..4e116b3bca 100644
--- a/player/client.h
+++ b/player/client.h
@@ -35,4 +35,11 @@ struct MPContext *mp_client_get_core(struct mpv_handle *ctx);
// m_option.c
void *node_get_alloc(struct mpv_node *node);
+// vo_opengl_cb.c
+struct mpv_opengl_cb_context;
+struct mpv_global;
+struct osd_state;
+struct mpv_opengl_cb_context *mp_opengl_create(struct mpv_global *g,
+ struct osd_state *osd);
+
#endif
diff --git a/player/core.h b/player/core.h
index 31a2b1eca4..344e55df19 100644
--- a/player/core.h
+++ b/player/core.h
@@ -339,6 +339,8 @@ typedef struct MPContext {
struct mp_nav_state *nav_state;
struct mp_ipc_ctx *ipc_ctx;
+
+ struct mpv_opengl_cb_context *gl_cb_ctx;
} MPContext;
// audio.c
diff --git a/player/video.c b/player/video.c
index f0829a2c8d..a14b647872 100644
--- a/player/video.c
+++ b/player/video.c
@@ -275,6 +275,9 @@ int reinit_video_chain(struct MPContext *mpctx)
goto err_out;
}
mpctx->mouse_cursor_visible = true;
+
+ vo_control(mpctx->video_out, VOCTRL_SET_LIBMPV_OPENGL_CB_CONTEXT,
+ mpctx->gl_cb_ctx);
}
update_window_title(mpctx, true);
diff --git a/video/out/gl_common.c b/video/out/gl_common.c
index 1f005934d4..dddb11a53e 100644
--- a/video/out/gl_common.c
+++ b/video/out/gl_common.c
@@ -474,15 +474,15 @@ static const struct gl_functions gl_functions[] = {
// log: used to output messages
// Note: if you create a CONTEXT_FORWARD_COMPATIBLE_BIT_ARB with OpenGL 3.0,
// you must append "GL_ARB_compatibility" to ext2.
-void mpgl_load_functions(GL *gl, void *(*getProcAddress)(const GLubyte *),
- const char *ext2, struct mp_log *log)
+void mpgl_load_functions2(GL *gl, void *(*get_fn)(void *ctx, const char *n),
+ void *fn_ctx, const char *ext2, struct mp_log *log)
{
talloc_free_children(gl);
*gl = (GL) {
.extensions = talloc_strdup(gl, ext2 ? ext2 : ""),
};
- gl->GetString = getProcAddress ? getProcAddress("glGetString") : NULL;
+ gl->GetString = get_fn(fn_ctx, "glGetString");
if (!gl->GetString) {
mp_err(log, "Can't load OpenGL functions.\n");
return;
@@ -508,8 +508,8 @@ void mpgl_load_functions(GL *gl, void *(*getProcAddress)(const GLubyte *),
bool has_legacy = false;
if (gl->version >= MPGL_VER(3, 0)) {
- gl->GetStringi = getProcAddress("glGetStringi");
- gl->GetIntegerv = getProcAddress("glGetIntegerv");
+ gl->GetStringi = get_fn(fn_ctx, "glGetStringi");
+ gl->GetIntegerv = get_fn(fn_ctx, "glGetIntegerv");
if (!(gl->GetStringi && gl->GetIntegerv))
return;
@@ -571,7 +571,7 @@ void mpgl_load_functions(GL *gl, void *(*getProcAddress)(const GLubyte *),
const struct gl_function *fn = &section->functions[i];
void *ptr = NULL;
for (int x = 0; fn->funcnames[x]; x++) {
- ptr = getProcAddress((const GLubyte *)fn->funcnames[x]);
+ ptr = get_fn(fn_ctx, fn->funcnames[x]);
if (ptr)
break;
}
@@ -620,6 +620,18 @@ void mpgl_load_functions(GL *gl, void *(*getProcAddress)(const GLubyte *),
list_features(gl->mpgl_caps, log, MSGL_V, false);
}
+static void *get_procaddr_wrapper(void *ctx, const char *name)
+{
+ void *(*getProcAddress)(const GLubyte *) = ctx;
+ return getProcAddress ? getProcAddress((const GLubyte*)name) : NULL;
+}
+
+void mpgl_load_functions(GL *gl, void *(*getProcAddress)(const GLubyte *),
+ const char *ext2, struct mp_log *log)
+{
+ mpgl_load_functions2(gl, get_procaddr_wrapper, getProcAddress, ext2, log);
+}
+
/**
* \brief return the number of bytes per pixel for the given format
* \param format OpenGL format
diff --git a/video/out/gl_common.h b/video/out/gl_common.h
index 38d952ae1b..951d2efefb 100644
--- a/video/out/gl_common.h
+++ b/video/out/gl_common.h
@@ -168,6 +168,8 @@ void mpgl_set_backend_wayland(MPGLContext *ctx);
void mpgl_load_functions(GL *gl, void *(*getProcAddress)(const GLubyte *),
const char *ext2, struct mp_log *log);
+void mpgl_load_functions2(GL *gl, void *(*get_fn)(void *ctx, const char *n),
+ void *fn_ctx, const char *ext2, struct mp_log *log);
// print a multi line string with line numbers (e.g. for shader sources)
// log, lev: module and log level, as in mp_msg()
diff --git a/video/out/gl_hwdec.c b/video/out/gl_hwdec.c
index 92f0ad095e..3bab1c1e9c 100644
--- a/video/out/gl_hwdec.c
+++ b/video/out/gl_hwdec.c
@@ -38,18 +38,19 @@ static const struct gl_hwdec_driver *const mpgl_hwdec_drivers[] = {
#if HAVE_VAAPI_GLX
&gl_hwdec_vaglx,
#endif
-#if HAVE_VDA_GL
- &gl_hwdec_vda,
-#endif
#if HAVE_VDPAU_GL_X11
&gl_hwdec_vdpau,
#endif
+#if HAVE_VDA_GL
+ &gl_hwdec_vda,
+#endif
NULL
};
static struct gl_hwdec *load_hwdec_driver(struct mp_log *log, GL *gl,</