Skip to content

Commit

Permalink
MPVCore: Support software render
Browse files Browse the repository at this point in the history
  • Loading branch information
xfangfang committed Feb 27, 2023
1 parent 6d2c7e7 commit 278977e
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 22 deletions.
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ set(ANALYTICS_KEY "" CACHE STRING "Google Analytics key")
set(MAC_10_15 OFF CACHE BOOL "Set the Minimum OS X deployment version to 10.15")
set(MAC_UNIVERSAL OFF CACHE BOOL "Support x86_64;arm64 at the same time")

# mpv related
set(MPV_SW_RENDER OFF CACHE BOOL "Using CPU to draw videos")

option(USE_GLFW "using glfw for input and create window" ON)
option(USE_SDL2 "using sdl2 for input and create window" OFF)
option(USE_GL2 "using OpenGL 2.1" OFF)
Expand All @@ -35,6 +38,11 @@ endif ()
if (USE_GL2)
set(USE_GL2 ON)
add_definitions(-DUSE_GL2)
add_definitions(-DMPV_NO_FB)
endif ()

if (MPV_SW_RENDER)
add_definitions(-DMPV_SW_RENDER)
endif ()

include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/extra.cmake)
Expand Down
35 changes: 29 additions & 6 deletions wiliwili/include/view/mpv_core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include "borealis.hpp"
#include "borealis/core/singleton.hpp"
#include <mpv/client.h>
#include <mpv/render.h>
#ifndef MPV_SW_RENDER
#include <mpv/render_gl.h>
#include <glad/glad.h>
#ifdef __SDL2__
Expand All @@ -16,13 +18,13 @@
#include <GLFW/glfw3.h>
#endif
#include <nanovg_gl.h>

struct GLShader {
GLuint prog;
GLuint vao;
GLuint vbo;
GLuint ebo;
};
#endif

typedef enum MpvEventEnum {
MPV_LOADED,
Expand Down Expand Up @@ -134,21 +136,42 @@ class MPVCore : public brls::Singleton<MPVCore> {
mpv_handle *mpv = nullptr;
mpv_render_context *mpv_context = nullptr;

#ifdef MPV_SW_RENDER
const int PIXCEL_SIZE = 4;
int nvg_image = 0;
const char *sw_format = "rgba";
int sw_size[2] = {1920, 1080};
size_t pitch = PIXCEL_SIZE * sw_size[0];
void *pixels = nullptr;
mpv_render_param mpv_params[5] = {
{MPV_RENDER_PARAM_SW_SIZE, &sw_size[0]},
{MPV_RENDER_PARAM_SW_FORMAT, (void *)sw_format},
{MPV_RENDER_PARAM_SW_STRIDE, &pitch},
{MPV_RENDER_PARAM_SW_POINTER, pixels},
{ MPV_RENDER_PARAM_INVALID,
nullptr }};
#elif defined(MPV_NO_FB)
mpv_opengl_fbo mpv_fbo{0, 1920, 1080};
int flip_y{1};
mpv_render_param mpv_params[3] = {{MPV_RENDER_PARAM_OPENGL_FBO, &mpv_fbo},
{MPV_RENDER_PARAM_FLIP_Y, &flip_y},
{ MPV_RENDER_PARAM_INVALID,
nullptr }};
#else
GLuint media_framebuffer = 0;
GLuint media_texture = 0;

GLShader shader{0};
mpv_opengl_fbo mpv_fbo{0, 1920, 1080};
int flip_y{1};
mpv_render_param mpv_params[3] = {{MPV_RENDER_PARAM_OPENGL_FBO, &mpv_fbo},
{MPV_RENDER_PARAM_FLIP_Y, &flip_y},
{MPV_RENDER_PARAM_INVALID, 0}};

MPVEvent mpvCoreEvent;

{MPV_RENDER_PARAM_INVALID, nullptr}};
float vertices[20] = {1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, -1.0f,
0.0f, 1.0f, 0.0f, -1.0f, -1.0f, 0.0f, 0.0f,
0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f};
#endif

MPVEvent mpvCoreEvent;

// 当前软件是否在前台的回调
brls::Event<bool>::Subscription focusSubscription;
Expand Down
95 changes: 79 additions & 16 deletions wiliwili/source/view/mpv_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ static inline void check_error(int status) {
}
}

#ifndef MPV_SW_RENDER
static void *get_proc_address(void *unused, const char *name) {
#ifdef __SDL2__
SDL_GL_GetCurrentContext();
Expand All @@ -50,6 +51,7 @@ static void *get_proc_address(void *unused, const char *name) {
return (void *)glfwGetProcAddress(name);
#endif
}
#endif

void MPVCore::on_update(void *self) {
brls::sync(
Expand Down Expand Up @@ -80,7 +82,7 @@ void MPVCore::init() {
mpv_set_option_string(mpv, "video-timing-offset", "0"); // 60fps
mpv_set_option_string(mpv, "keep-open", "yes");
mpv_set_option_string(mpv, "hr-seek", "yes");
#ifdef USE_GL2
#ifdef MPV_NO_FB
mpv_set_option_string(mpv, "reset-on-next-file", "speed,pause");
#else
mpv_set_option_string(mpv, "fbo-format", "rgba8");
Expand Down Expand Up @@ -151,12 +153,18 @@ void MPVCore::init() {
// check_error(mpv_observe_property(mpv, 9, "demuxer-cache-state", MPV_FORMAT_NODE));

// init renderer params
#ifdef MPV_SW_RENDER
mpv_render_param params[]{
{MPV_RENDER_PARAM_API_TYPE, const_cast<char *>(MPV_RENDER_API_TYPE_SW)},
{MPV_RENDER_PARAM_INVALID, nullptr}};
#else
mpv_opengl_init_params gl_init_params{get_proc_address, nullptr};
mpv_render_param params[]{
{MPV_RENDER_PARAM_API_TYPE,
const_cast<char *>(MPV_RENDER_API_TYPE_OPENGL)},
{MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &gl_init_params},
{MPV_RENDER_PARAM_INVALID, nullptr}};
#endif

if (mpv_render_context_create(&mpv_context, mpv, params) < 0) {
mpv_terminate_destroy(mpv);
Expand Down Expand Up @@ -198,7 +206,16 @@ void MPVCore::init() {
});
}

MPVCore::~MPVCore() { this->clean(); }
MPVCore::~MPVCore() {
this->clean();
#ifdef MPV_SW_RENDER
if (pixels) {
free(pixels);
pixels = nullptr;
mpv_params[3].data = nullptr;
}
#endif
}

void MPVCore::clean() {
check_error(mpv_command_string(this->mpv, "quit"));
Expand Down Expand Up @@ -232,6 +249,8 @@ void MPVCore::restart() {
}

void MPVCore::deleteFrameBuffer() {
#if defined(MPV_NO_FB) || defined(MPV_SW_RENDER)
#else
if (this->media_framebuffer != 0) {
glDeleteFramebuffers(1, &this->media_framebuffer);
this->media_framebuffer = 0;
Expand All @@ -240,20 +259,22 @@ void MPVCore::deleteFrameBuffer() {
glDeleteTextures(1, &this->media_texture);
this->media_texture = 0;
}
#endif
}

void MPVCore::deleteShader() {
#if defined(MPV_NO_FB) || defined(MPV_SW_RENDER)
#else
if (shader.vao != 0) glDeleteVertexArrays(1, &shader.vao);
if (shader.vbo != 0) glDeleteBuffers(1, &shader.vbo);
if (shader.ebo != 0) glDeleteBuffers(1, &shader.ebo);
if (shader.prog != 0) glDeleteProgram(shader.prog);
#endif
}

void MPVCore::initializeGL() {
#ifdef USE_GL2
// Using default framebuffer
return;
#endif
#if defined(MPV_NO_FB) || defined(MPV_SW_RENDER)
#else
if (media_framebuffer != 0) return;
brls::Logger::debug("initializeGL");

Expand Down Expand Up @@ -355,6 +376,7 @@ void MPVCore::initializeGL() {
glBindVertexArray(0);

brls::Logger::debug("initializeGL done");
#endif
}

void MPVCore::command_str(const char *args) {
Expand All @@ -370,8 +392,31 @@ void MPVCore::command_async(const char **args) {
}

void MPVCore::setFrameSize(brls::Rect rect) {
#ifdef USE_GL2
// hardcode workaround for OpenGL2
#ifdef MPV_SW_RENDER
int drawWidth = rect.getWidth() * brls::Application::windowScale;
int drawHeight = rect.getHeight() * brls::Application::windowScale;
if (drawWidth == 0 || drawHeight == 0) return;
int frameSize = drawWidth * drawHeight;

if (pixels != nullptr && frameSize > sw_size[0] * sw_size[1]) {
brls::Logger::debug("Enlarge video surface buffer");
free(pixels);
pixels = nullptr;
nvgDeleteImage(brls::Application::getNVGContext(), nvg_image);
}

if (pixels == nullptr) {
pixels = malloc(frameSize * PIXCEL_SIZE);
mpv_params[3].data = pixels;
sw_size[0] = drawWidth;
sw_size[1] = drawHeight;
pitch = PIXCEL_SIZE * sw_size[0];
nvg_image =
nvgCreateImageRGBA(brls::Application::getNVGContext(), drawWidth,
drawHeight, 0, (const unsigned char *)pixels);
}
#elif defined(MPV_NO_FB)
// Using default framebuffer
this->mpv_fbo.w = brls::Application::windowWidth;
this->mpv_fbo.h = brls::Application::windowHeight;
mpv_set_option_string(
Expand All @@ -392,18 +437,12 @@ void MPVCore::setFrameSize(brls::Rect rect) {
fmt::format("{}", (brls::Application::contentHeight - rect.getMaxY()) /
brls::Application::contentHeight)
.c_str());
return;
#endif

#else
if (this->media_texture == 0) return;
int drawWidth = rect.getWidth() * brls::Application::windowScale;
int drawHeight = rect.getHeight() * brls::Application::windowScale;

if (drawWidth == 0 || drawHeight == 0) return;
// 在没有用到更小的视频时减少对texture的申请
#ifdef __SWITCH__
if (rect.getWidth() < 400 || rect.getHeight() < 400) return;
#endif
brls::Logger::debug("MPVCore::setFrameSize: {}/{}", drawWidth, drawHeight);
glBindTexture(GL_TEXTURE_2D, this->media_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, drawWidth, drawHeight, 0, GL_RGBA,
Expand All @@ -427,14 +466,38 @@ void MPVCore::setFrameSize(brls::Rect rect) {

glBindBuffer(GL_ARRAY_BUFFER, this->shader.vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
#endif
}

bool MPVCore::isValid() { return mpv_context != nullptr; }

void MPVCore::openglDraw(brls::Rect rect, float alpha) {
if (mpv_context == nullptr) return;

#ifdef USE_GL2
#ifdef MPV_SW_RENDER
if (!pixels) return;
mpv_render_context_render(this->mpv_context, mpv_params);
mpv_render_context_report_swap(this->mpv_context);

auto *vg = brls::Application::getNVGContext();
nvgUpdateImage(vg, nvg_image, (const unsigned char *)pixels);

// draw black background
nvgBeginPath(vg);
nvgFillColor(vg, NVGcolor{0, 0, 0, alpha});
nvgRect(vg, rect.getMinX(), rect.getMinY(), rect.getWidth(),
rect.getHeight());
nvgFill(vg);

// draw video
nvgBeginPath(vg);
nvgRect(vg, rect.getMinX(), rect.getMinY(), rect.getWidth(),
rect.getHeight());
nvgFillPaint(vg, nvgImagePattern(vg, 0, 0, rect.getWidth(),
rect.getHeight(), 0, nvg_image, alpha));
nvgFill(vg);

#elif defined(MPV_NO_FB)
// 只在非透明时绘制视频,可以避免退出页面时视频画面残留
if (alpha >= 1) {
// 绘制视频
Expand Down

0 comments on commit 278977e

Please sign in to comment.