aboutsummaryrefslogtreecommitdiff
path: root/src/Video.cpp
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2018-04-22 05:58:44 +0200
committerdec05eba <dec05eba@protonmail.com>2018-04-22 05:59:18 +0200
commit1e0e68f9cda51c881b32a54d9eece71c1428f7ac (patch)
treeb8faa1d971c245e3fcf046aa1d2daa1fa601e0f9 /src/Video.cpp
parent424b02609fa34175a4e2aadb95e68b3c9c8dc93c (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.cpp150
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);
+ }
+}