diff options
author | dec05eba <dec05eba@protonmail.com> | 2018-04-22 05:58:44 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2018-04-22 05:59:18 +0200 |
commit | 1e0e68f9cda51c881b32a54d9eece71c1428f7ac (patch) | |
tree | b8faa1d971c245e3fcf046aa1d2daa1fa601e0f9 /src/Video.cpp | |
parent | 424b02609fa34175a4e2aadb95e68b3c9c8dc93c (diff) |
Add video and gif support
Gif streams from url.
Todo: Add play controls to video
Diffstat (limited to 'src/Video.cpp')
-rw-r--r-- | src/Video.cpp | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/src/Video.cpp b/src/Video.cpp new file mode 100644 index 0000000..4ef16d6 --- /dev/null +++ b/src/Video.cpp @@ -0,0 +1,150 @@ +#include "../include/Video.hpp" +#include <mpv/client.h> +#include <mpv/render_gl.h> +#include <clocale> + +#include <SFML/Config.hpp> + +#if defined(SFML_SYSTEM_WINDOWS) + #ifdef _MSC_VER + #include <windows.h> + #endif + #include <GL/gl.h> + #include <GL/glx.h> +#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) + #if defined(SFML_OPENGL_ES) + #include <GLES/gl.h> + #include <GLES/glext.h> + #else + #include <GL/gl.h> + #endif + #include <GL/glx.h> + #define glGetProcAddress glXGetProcAddress +#elif defined(SFML_SYSTEM_MACOS) + #include <OpenGL/gl.h> +#elif defined (SFML_SYSTEM_IOS) + #include <OpenGLES/ES1/gl.h> + #include <OpenGLES/ES1/glext.h> +#elif defined (SFML_SYSTEM_ANDROID) + #include <GLES/gl.h> + #include <GLES/glext.h> + // We're not using OpenGL ES 2+ yet, but we can use the sRGB extension + #include <GLES2/gl2ext.h> +#endif + +using namespace std; + +namespace dchat +{ + void* getProcAddressMpv(void *funcContext, const char *name) + { + return (void*)glGetProcAddress((const GLubyte*)name); + } + + void onMpvRedraw(void *rawVideo) + { + Video *video = (Video*)rawVideo; + ++video->redrawCounter; + } + + Video::Video(unsigned int width, unsigned int height, const char *file, bool loop) : + redrawCounter(0), + context(sf::ContextSettings(), width, height), + mpv(nullptr), + mpvGl(nullptr), + textureBuffer(new sf::Uint8[width * height * 4]) // 4 = red, green, blue and alpha + { + 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 + std::setlocale(LC_NUMERIC, "C"); + mpv = mpv_create(); + if(!mpv) + throw VideoInitializationException("Failed to create mpv handle"); + + if(mpv_initialize(mpv) < 0) + throw VideoInitializationException("Failed to initialize mpv"); + + mpv_opengl_init_params openglInitParams { .get_proc_address = getProcAddressMpv }; + mpv_render_param params[] = + { + { MPV_RENDER_PARAM_API_TYPE, (void*)MPV_RENDER_API_TYPE_OPENGL }, + { MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &openglInitParams }, + { (mpv_render_param_type)0, nullptr } + }; + + if(mpv_render_context_create(&mpvGl, mpv, params) < 0) + throw VideoInitializationException("Failed to initialize mpv opengl render context"); + + if(loop) + mpv_set_option_string(mpv, "loop", "inf"); + mpv_set_option_string(mpv, "hwdec", "auto"); + mpv_render_context_set_update_callback(mpvGl, onMpvRedraw, this); + + renderThread = thread([this, width, height]() + { + context.setActive(true); + while(true) + { + while(true) + { + mpv_event *mpvEvent = mpv_wait_event(mpv, 0.0); + if(mpvEvent->event_id == MPV_EVENT_NONE) + break; + else if(mpvEvent->event_id == MPV_EVENT_SHUTDOWN) + break; + } + + if(redrawCounter > 0) + { + --redrawCounter; + mpv_opengl_fbo openglFbo { .fbo = 0, .w = (int)width, .h = (int)height }; + mpv_render_param params[] = + { + { MPV_RENDER_PARAM_OPENGL_FBO, &openglFbo }, + { (mpv_render_param_type)0, nullptr } + }; + + context.setActive(true); + renderMutex.lock(); + mpv_render_context_render(mpvGl, params); + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, textureBuffer); + texture.update(textureBuffer); + sprite.setTexture(texture, true); + renderMutex.unlock(); + } + this_thread::sleep_for(chrono::milliseconds(10)); + } + }); + renderThread.detach(); + + const char *cmd[] = { "loadfile", file, nullptr }; + mpv_command(mpv, cmd); + context.setActive(false); + } + + Video::~Video() + { + lock_guard<mutex> lock(renderMutex); + delete[] textureBuffer; + mpv_render_context_free(mpvGl); + mpv_destroy(mpv); + if(renderThread.joinable()) + renderThread.join(); + } + + void Video::setPosition(float x, float y) + { + sprite.setPosition(x, y); + } + + void Video::draw(sf::RenderWindow &window) + { + lock_guard<mutex> lock(renderMutex); + window.draw(sprite); + } +} |