From 62a29abd372a39a413e43a8f75146af823fe7bb3 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sun, 4 Aug 2019 14:58:03 +0200 Subject: Add video seek, play next video on end file --- src/VideoPlayer.cpp | 157 ++++++++++++++++++++++++++-------------------------- 1 file changed, 77 insertions(+), 80 deletions(-) (limited to 'src/VideoPlayer.cpp') diff --git a/src/VideoPlayer.cpp b/src/VideoPlayer.cpp index 304ef2d..ecbca34 100644 --- a/src/VideoPlayer.cpp +++ b/src/VideoPlayer.cpp @@ -1,66 +1,31 @@ #include "../include/VideoPlayer.hpp" +#include #include #include +#include #include -#include - -#if defined(SFML_SYSTEM_WINDOWS) - #ifdef _MSC_VER - #include - #endif - #include - #include -#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) - #if defined(SFML_OPENGL_ES) - #include - #include - #else - #include - #endif - #include - #define glGetProcAddress glXGetProcAddress -#elif defined(SFML_SYSTEM_MACOS) - #include -#elif defined (SFML_SYSTEM_IOS) - #include - #include -#elif defined (SFML_SYSTEM_ANDROID) - #include - #include - // We're not using OpenGL ES 2+ yet, but we can use the sRGB extension - #include -#endif - -using namespace std; - namespace QuickMedia { void* getProcAddressMpv(void *funcContext, const char *name) { - return (void*)glGetProcAddress((const GLubyte*)name); + VideoPlayer *video_player = (VideoPlayer*)funcContext; + return (void*)video_player->context.getFunction(name); } void onMpvRedraw(void *rawVideo) { - VideoPlayer *video = (VideoPlayer*)rawVideo; - ++video->redrawCounter; + VideoPlayer *video_player = (VideoPlayer*)rawVideo; + ++video_player->redrawCounter; } VideoPlayer::VideoPlayer(unsigned int width, unsigned int height, const char *file, bool loop) : redrawCounter(0), context(sf::ContextSettings(), width, height), + onPlaybackEndedCallback(nullptr), mpv(nullptr), mpvGl(nullptr), - textureBuffer((sf::Uint8*)malloc(width * height * 4)), // 4 = red, green, blue and alpha - alive(true), - video_size(width, height), - desired_size(width, height) + textureBuffer(nullptr), + alive(true) { - if(!textureBuffer) - throw VideoInitializationException("Failed to allocate memory for video"); - context.setActive(true); - - if(!texture.create(width, height)) - throw VideoInitializationException("Failed to create texture for video"); texture.setSmooth(true); // mpv_create requires LC_NUMERIC to be set to "C" for some reason, see mpv_create documentation @@ -68,27 +33,29 @@ namespace QuickMedia { mpv = mpv_create(); if(!mpv) throw VideoInitializationException("Failed to create mpv handle"); - - if(mpv_initialize(mpv) < 0) - throw VideoInitializationException("Failed to initialize mpv"); mpv_set_option_string(mpv, "input-default-bindings", "yes"); - // Enable keyboard input on the X11 window mpv_set_option_string(mpv, "input-vo-keyboard", "yes"); mpv_set_option_string(mpv, "vo", "opengl-cb"); mpv_set_option_string(mpv, "hwdec", "auto"); + if(loop) mpv_set_option_string(mpv, "loop", "inf"); + + if(mpv_initialize(mpv) < 0) + throw VideoInitializationException("Failed to initialize mpv"); + mpvGl = (mpv_opengl_cb_context*)mpv_get_sub_api(mpv, MPV_SUB_API_OPENGL_CB); if(!mpvGl) throw VideoInitializationException("Failed to initialize mpv opengl render context"); mpv_opengl_cb_set_update_callback(mpvGl, onMpvRedraw, this); - if(mpv_opengl_cb_init_gl(mpvGl, nullptr, getProcAddressMpv, nullptr) < 0) + if(mpv_opengl_cb_init_gl(mpvGl, nullptr, getProcAddressMpv, this) < 0) throw VideoInitializationException("Failed to initialize mpv gl callback func"); - renderThread = thread([this]() { + context.setActive(false); + renderThread = std::thread([this]() { context.setActive(true); while(alive) { while(true) { @@ -103,26 +70,32 @@ namespace QuickMedia { mpv_get_property(mpv, "dheight", MPV_FORMAT_INT64, &h) >= 0 && w > 0 && h > 0 && (w != video_size.x || h != video_size.y)) { - { - lock_guard lock(renderMutex); - video_size.x = w; - video_size.y = h; - context.setActive(true); - if(texture.create(w, h)) { - void *newTextureBuf = realloc(textureBuffer, w * h * 4); - if(newTextureBuf) - textureBuffer = (sf::Uint8*)newTextureBuf; - } + std::lock_guard lock(renderMutex); + video_size.x = w; + video_size.y = h; + context.setActive(true); + // TODO: Verify if it's valid to re-create the texture like this, + // instead of using deconstructor + if(texture.create(w, h)) { + void *newTextureBuf = realloc(textureBuffer, w * h * 4); + if(newTextureBuf) + textureBuffer = (sf::Uint8*)newTextureBuf; } - resize(desired_size); + glViewport(0, 0, w, h); } + resize(desired_size); + } else if(mpvEvent->event_id == MPV_EVENT_END_FILE) { + if(onPlaybackEndedCallback) + onPlaybackEndedCallback(); + } else { + //printf("Mpv event: %s\n", mpv_event_name(mpvEvent->event_id)); } } - if(redrawCounter > 0) { + if(redrawCounter > 0 && textureBuffer) { --redrawCounter; context.setActive(true); - lock_guard lock(renderMutex); + std::lock_guard lock(renderMutex); auto textureSize = texture.getSize(); //mpv_render_context_render(mpvGl, params); mpv_opengl_cb_draw(mpvGl, 0, textureSize.x, textureSize.y); @@ -135,16 +108,16 @@ namespace QuickMedia { } }); - const char *cmd[] = { "loadfile", file, nullptr }; - mpv_command(mpv, cmd); - context.setActive(false); + seekbar.setFillColor(sf::Color::White); + seekbar_background.setFillColor(sf::Color(0, 0, 0, 150)); + load_file(file); } VideoPlayer::~VideoPlayer() { alive = false; renderThread.join(); - lock_guard lock(renderMutex); + std::lock_guard lock(renderMutex); context.setActive(true); if(mpvGl) mpv_opengl_cb_set_update_callback(mpvGl, nullptr, nullptr); @@ -159,7 +132,9 @@ namespace QuickMedia { } bool VideoPlayer::resize(const sf::Vector2i &size) { - lock_guard lock(renderMutex); + desired_size = size; + if(!textureBuffer) + return true; float video_ratio = (double)video_size.x / (double)video_size.y; float scale_x = 1.0f; float scale_y = 1.0f; @@ -175,21 +150,43 @@ namespace QuickMedia { sprite.setPosition(size.x * 0.5f - video_size.x * scale_x * 0.5f, 0.0f); } sprite.setScale(scale_x, scale_y); - desired_size = size; - #if 0 - void *newTextureBuf = realloc(textureBuffer, size.x * size.y * 4); - if(!newTextureBuf) - return false; - textureBuffer = (sf::Uint8*)newTextureBuf; - if(!texture.create(size.x, size.y)) - return false; - return true; - #endif return true; } void VideoPlayer::draw(sf::RenderWindow &window) { - lock_guard lock(renderMutex); - window.draw(sprite); + { + std::lock_guard lock(renderMutex); + window.draw(sprite); + } + double pos = 0.0; + mpv_get_property(mpv, "percent-pos", MPV_FORMAT_DOUBLE, &pos); + pos *= 0.01; + + auto textureSize = sprite.getTextureRect(); + auto scale = sprite.getScale(); + auto video_size = sf::Vector2f(textureSize.width * scale.x, textureSize.height * scale.y); + + const float seekbar_height = video_size.y * 0.025f; + seekbar.setPosition(sprite.getPosition() + sf::Vector2f(0.0f, video_size.y - seekbar_height)); + seekbar.setSize(sf::Vector2f(video_size.x * pos, seekbar_height)); + window.draw(seekbar); + seekbar_background.setPosition(seekbar.getPosition() + sf::Vector2f(video_size.x * pos, 0.0f)); + seekbar_background.setSize(sf::Vector2f(video_size.x - video_size.x * pos, seekbar_height)); + window.draw(seekbar_background); + + if(sf::Mouse::isButtonPressed(sf::Mouse::Left)) { + auto mouse_pos = sf::Mouse::getPosition(window); + auto seekbar_pos = seekbar.getPosition(); + float diff_x = mouse_pos.x - seekbar_pos.x; + if(diff_x >= 0.0f && diff_x <= video_size.x && mouse_pos.y >= seekbar_pos.y && mouse_pos.y <= seekbar_pos.y + seekbar_height) { + double new_pos = ((double)diff_x / video_size.x) * 100.0; + mpv_set_property(mpv, "percent-pos", MPV_FORMAT_DOUBLE, &new_pos); + } + } + } + + void VideoPlayer::load_file(const std::string &path) { + const char *cmd[] = { "loadfile", path.c_str(), nullptr }; + mpv_command(mpv, cmd); } } -- cgit v1.2.3