diff options
-rw-r--r-- | DOCS/client-api-changes.rst | 4 | ||||
-rw-r--r-- | DOCS/client_api_examples/qml/main.cpp | 19 | ||||
-rw-r--r-- | DOCS/client_api_examples/qml/main.qml | 39 | ||||
-rw-r--r-- | DOCS/client_api_examples/qml/mpvrenderer.cpp | 125 | ||||
-rw-r--r-- | DOCS/client_api_examples/qml/mpvrenderer.h | 33 | ||||
-rw-r--r-- | DOCS/client_api_examples/qml/mpvtest.pro | 11 | ||||
-rw-r--r-- | DOCS/client_api_examples/qml/mpvtest.qrc | 5 | ||||
-rw-r--r-- | libmpv/client.h | 40 | ||||
-rw-r--r-- | libmpv/mpv.def | 7 | ||||
-rw-r--r-- | libmpv/opengl_cb.h | 199 | ||||
-rw-r--r-- | old-makefile | 1 | ||||
-rw-r--r-- | player/client.c | 57 | ||||
-rw-r--r-- | player/client.h | 7 | ||||
-rw-r--r-- | player/core.h | 2 | ||||
-rw-r--r-- | player/video.c | 3 | ||||
-rw-r--r-- | video/out/gl_common.c | 24 | ||||
-rw-r--r-- | video/out/gl_common.h | 2 | ||||
-rw-r--r-- | video/out/gl_hwdec.c | 15 | ||||
-rw-r--r-- | video/out/gl_hwdec.h | 2 | ||||
-rw-r--r-- | video/out/gl_hwdec_vaglx.c | 4 | ||||
-rw-r--r-- | video/out/gl_hwdec_vdpau.c | 4 | ||||
-rw-r--r-- | video/out/gl_video.c | 29 | ||||
-rw-r--r-- | video/out/gl_video.h | 5 | ||||
-rw-r--r-- | video/out/vo.c | 2 | ||||
-rw-r--r-- | video/out/vo.h | 2 | ||||
-rw-r--r-- | video/out/vo_opengl.c | 4 | ||||
-rw-r--r-- | video/out/vo_opengl_cb.c | 370 | ||||
-rw-r--r-- | wscript_build.py | 3 |
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 = §ion->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); } |