Switched video backgrounds to mpv (should fix all the videos that weren't playing sound or had random issues)

Signed-off-by: Alexis Maiquez <almamu@almamu.com>
This commit is contained in:
Alexis Maiquez 2023-02-05 06:11:04 +01:00
parent a24b1923f6
commit 7079d12e2a
10 changed files with 412 additions and 591 deletions

View File

@ -21,7 +21,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Install dependencies - name: Install dependencies
run: sudo apt-get update && sudo apt-get -y install libxrandr-dev libfreeimage-dev libxinerama-dev libxcursor-dev libxi-dev libgl-dev libglew-dev freeglut3-dev libsdl1.2-dev libsdl-mixer1.2-dev liblz4-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libxxf86vm-dev libglm-dev libglfw3-dev run: sudo apt-get update && sudo apt-get -y install libxrandr-dev libfreeimage-dev libxinerama-dev libxcursor-dev libxi-dev libgl-dev libglew-dev freeglut3-dev libsdl1.2-dev libsdl-mixer1.2-dev liblz4-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libxxf86vm-dev libglm-dev libglfw3-dev mpv
- name: Configure CMake - name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.

View File

@ -16,12 +16,13 @@ find_package(GLEW REQUIRED)
find_package(GLUT REQUIRED) find_package(GLUT REQUIRED)
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)
find_package(SDL REQUIRED) find_package(SDL REQUIRED)
find_package(MPV REQUIRED)
find_package(LZ4 REQUIRED) find_package(LZ4 REQUIRED)
find_package(FFMPEG REQUIRED) find_package(FFMPEG REQUIRED)
find_package(FreeImage REQUIRED) find_package(FreeImage REQUIRED)
include_directories( include_directories(
${MPV_INCLUDE_DIR}
${X11_INCLUDE_DIR} ${X11_INCLUDE_DIR}
${XRANDR_INCLUDE_DIR} ${XRANDR_INCLUDE_DIR}
${GLEW_INCLUDE_DIR} ${GLEW_INCLUDE_DIR}
@ -64,6 +65,12 @@ add_executable(
src/WallpaperEngine/Core/Core.h src/WallpaperEngine/Core/Core.h
src/WallpaperEngine/Core/Core.cpp src/WallpaperEngine/Core/Core.cpp
src/WallpaperEngine/Audio/Drivers/CAudioDriver.cpp
src/WallpaperEngine/Audio/Drivers/CAudioDriver.h
src/WallpaperEngine/Audio/Drivers/CSDLAudioDriver.cpp
src/WallpaperEngine/Audio/Drivers/CSDLAudioDriver.h
src/WallpaperEngine/Audio/CAudioContext.cpp
src/WallpaperEngine/Audio/CAudioContext.h
src/WallpaperEngine/Audio/CAudioStream.cpp src/WallpaperEngine/Audio/CAudioStream.cpp
src/WallpaperEngine/Audio/CAudioStream.h src/WallpaperEngine/Audio/CAudioStream.h
@ -230,6 +237,7 @@ target_link_libraries(linux-wallpaperengine
${SDL_MIXER_LIBRARIES} ${SDL_MIXER_LIBRARIES}
${FFMPEG_LIBRARIES} ${FFMPEG_LIBRARIES}
${FREEIMAGE_LIBRARIES} ${FREEIMAGE_LIBRARIES}
${MPV_LIBRARY}
glfw) glfw)
file(CREATE_LINK linux-wallpaperengine wallengine SYMBOLIC) file(CREATE_LINK linux-wallpaperengine wallengine SYMBOLIC)

View File

@ -0,0 +1,82 @@
###############################################################################
# CMake module to search for the mpv libraries.
#
# WARNING: This module is experimental work in progress.
#
# Based one FindVLC.cmake by:
# Copyright (c) 2011 Michael Jansen <info@michael-jansen.biz>
# Modified by Tobias Hieta <tobias@hieta.se>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
###############################################################################
#
### Global Configuration Section
#
SET(_MPV_REQUIRED_VARS MPV_INCLUDE_DIR MPV_LIBRARY)
#
### MPV uses pkgconfig.
#
if(PKG_CONFIG_FOUND)
pkg_check_modules(PC_MPV QUIET mpv)
endif(PKG_CONFIG_FOUND)
#
### Look for the include files.
#
find_path(
MPV_INCLUDE_DIR
NAMES mpv/client.h
HINTS
${PC_MPV_INCLUDEDIR}
${PC_MPV_INCLUDE_DIRS} # Unused for MPV but anyway
DOC "MPV include directory"
)
#
### Look for the libraries
#
set(_MPV_LIBRARY_NAMES mpv)
if(PC_MPV_LIBRARIES)
set(_MPV_LIBRARY_NAMES ${PC_MPV_LIBRARIES})
endif(PC_MPV_LIBRARIES)
foreach(l ${_MPV_LIBRARY_NAMES})
find_library(
MPV_LIBRARY_${l}
NAMES ${l}
HINTS
${PC_MPV_LIBDIR}
${PC_MPV_LIBRARY_DIRS} # Unused for MPV but anyway
PATH_SUFFIXES lib${LIB_SUFFIX}
)
list(APPEND MPV_LIBRARY ${MPV_LIBRARY_${l}})
endforeach()
get_filename_component(_MPV_LIBRARY_DIR ${MPV_LIBRARY_mpv} PATH)
mark_as_advanced(MPV_LIBRARY)
set(MPV_LIBRARY_DIRS _MPV_LIBRARY_DIR)
list(REMOVE_DUPLICATES MPV_LIBRARY_DIRS)
mark_as_advanced(MPV_INCLUDE_DIR)
mark_as_advanced(MPV_LIBRARY_DIRS)
set(MPV_INCLUDE_DIRS ${MPV_INCLUDE_DIR})
#
### Check if everything was found and if the version is sufficient.
#
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
MPV
REQUIRED_VARS ${_MPV_REQUIRED_VARS}
VERSION_VAR MPV_VERSION_STRING
)
if(MPV_FOUND)
message(STATUS
"Found MPV: ${MPV_LIBRARY}, ${MPV_INCLUDE_DIR}")
endif()

View File

@ -33,6 +33,7 @@
float g_Time; float g_Time;
float g_TimeLast; float g_TimeLast;
bool g_KeepRunning = true; bool g_KeepRunning = true;
bool g_AudioEnabled = true;
int g_AudioVolume = 15; int g_AudioVolume = 15;
void print_help (const char* route) void print_help (const char* route)
@ -258,7 +259,6 @@ int main (int argc, char* argv[])
std::map <std::string, std::string> propertyOverrides; std::map <std::string, std::string> propertyOverrides;
int maximumFPS = 30; int maximumFPS = 30;
bool shouldEnableAudio = true;
bool shouldTakeScreenshot = false; bool shouldTakeScreenshot = false;
bool shouldListPropertiesAndStop = false; bool shouldListPropertiesAndStop = false;
FREE_IMAGE_FORMAT screenshotFormat = FIF_UNKNOWN; FREE_IMAGE_FORMAT screenshotFormat = FIF_UNKNOWN;
@ -321,7 +321,7 @@ int main (int argc, char* argv[])
break; break;
case 's': case 's':
shouldEnableAudio = false; g_AudioEnabled = false;
break; break;
case 'h': case 'h':
@ -445,7 +445,7 @@ int main (int argc, char* argv[])
std::signal(SIGINT, signalhandler); std::signal(SIGINT, signalhandler);
std::signal(SIGTERM, signalhandler); std::signal(SIGTERM, signalhandler);
if (shouldEnableAudio == true && SDL_Init (SDL_INIT_AUDIO) < 0) if (g_AudioEnabled == true && SDL_Init (SDL_INIT_AUDIO) < 0)
{ {
sLog.error ("Cannot initialize SDL audio system, SDL_GetError: ", SDL_GetError()); sLog.error ("Cannot initialize SDL audio system, SDL_GetError: ", SDL_GetError());
sLog.error ("Continuing without audio support"); sLog.error ("Continuing without audio support");
@ -453,7 +453,7 @@ int main (int argc, char* argv[])
// initialize OpenGL driver // initialize OpenGL driver
WallpaperEngine::Render::Drivers::COpenGLDriver videoDriver ("Wallpaper Engine"); WallpaperEngine::Render::Drivers::COpenGLDriver videoDriver ("Wallpaper Engine");
// initialize custom context class // initialize render context
WallpaperEngine::Render::CRenderContext context (screens, videoDriver, &containers); WallpaperEngine::Render::CRenderContext context (screens, videoDriver, &containers);
// initialize mouse support // initialize mouse support
context.setMouse (new CMouseInput (videoDriver.getWindow ())); context.setMouse (new CMouseInput (videoDriver.getWindow ()));
@ -462,10 +462,6 @@ int main (int argc, char* argv[])
WallpaperEngine::Render::CWallpaper::fromWallpaper (project->getWallpaper (), &context) WallpaperEngine::Render::CWallpaper::fromWallpaper (project->getWallpaper (), &context)
); );
// update maximum FPS if it's a video
if (context.getWallpaper ()->is <WallpaperEngine::Render::CVideo> () == true)
maximumFPS = context.getWallpaper ()->as <WallpaperEngine::Render::CVideo> ()->getFPS ();
float startTime, endTime, minimumTime = 1.0f / maximumFPS; float startTime, endTime, minimumTime = 1.0f / maximumFPS;
while (videoDriver.closeRequested () == false && g_KeepRunning == true) while (videoDriver.closeRequested () == false && g_KeepRunning == true)

View File

@ -43,14 +43,14 @@ CScene::CScene (Core::CScene* scene, CRenderContext* context) :
scene->getOrthogonalProjection ()->getHeight () scene->getOrthogonalProjection ()->getHeight ()
); );
// setup framebuffers here as they're required for the scene setup
this->setupFramebuffers();
// set clear color // set clear color
glm::vec3 clearColor = this->getScene ()->getClearColor (); glm::vec3 clearColor = this->getScene ()->getClearColor ();
glClearColor (clearColor.r, clearColor.g, clearColor.b, 1.0f); glClearColor (clearColor.r, clearColor.g, clearColor.b, 1.0f);
// setup framebuffers
this->setupFramebuffers ();
// create all objects based off their dependencies // create all objects based off their dependencies
for (const auto& cur : scene->getObjects ()) for (const auto& cur : scene->getObjects ())
this->createObject (cur.second); this->createObject (cur.second);
@ -258,11 +258,21 @@ void CScene::updateMouse (glm::ivec4 viewport)
// screen-space positions have to be transposed to what the screen will actually show // screen-space positions have to be transposed to what the screen will actually show
} }
Core::CScene* CScene::getScene () Core::CScene* CScene::getScene () const
{ {
return this->getWallpaperData ()->as<Core::CScene> (); return this->getWallpaperData ()->as<Core::CScene> ();
} }
uint32_t CScene::getWidth () const
{
return this->getScene ()->getOrthogonalProjection()->getWidth ();
}
uint32_t CScene::getHeight () const
{
return this->getScene ()->getOrthogonalProjection()->getHeight ();
}
glm::vec2* CScene::getMousePosition () glm::vec2* CScene::getMousePosition ()
{ {
return &this->m_mousePosition; return &this->m_mousePosition;

View File

@ -19,7 +19,10 @@ namespace WallpaperEngine::Render
CCamera* getCamera () const; CCamera* getCamera () const;
Core::CScene* getScene (); Core::CScene* getScene () const;
uint32_t getWidth () const override;
uint32_t getHeight () const override;
glm::vec2* getMousePosition (); glm::vec2* getMousePosition ();
glm::vec2* getMousePositionLast (); glm::vec2* getMousePositionLast ();

View File

@ -1,242 +1,133 @@
#include "common.h" #include "common.h"
#include "CVideo.h" #include "CVideo.h"
#include <pthread.h>
#include <GL/glew.h>
extern bool g_AudioEnabled;
using namespace WallpaperEngine; using namespace WallpaperEngine;
using namespace WallpaperEngine::Render; using namespace WallpaperEngine::Render;
void* get_proc_address (void* ctx, const char* name)
{
return reinterpret_cast <void*> (glfwGetProcAddress (name));
}
CVideo::CVideo (Core::CVideo* video, CRenderContext* context) : CVideo::CVideo (Core::CVideo* video, CRenderContext* context) :
CWallpaper (video, Type, context) CWallpaper (video, Type, context),
m_width (16),
m_height (16)
{ {
if (avformat_open_input (&m_formatCtx, video->getFilename ().c_str (), NULL, NULL) < 0) // create mpv contexts
sLog.exception ("Failed to open video file ", video->getFilename ()); this->m_mpv = mpv_create ();
if (avformat_find_stream_info (m_formatCtx, NULL) < 0) if (this->m_mpv == nullptr)
sLog.exception ("Failed to get stream info for video file ", video->getFilename ()); sLog.exception ("Could not create mpv context");
// Find first video stream mpv_set_option_string (this->m_mpv, "terminal", "yes");
for (int i = 0; i < m_formatCtx->nb_streams; i++) mpv_set_option_string (this->m_mpv, "msg-level", "all=v");
{ mpv_set_option_string (this->m_mpv, "input-cursor", "no");
if (m_formatCtx->streams [i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) mpv_set_option_string (this->m_mpv, "cursor-autohide", "no");
{ mpv_set_option_string (this->m_mpv, "config", "no");
m_videoStream = i; mpv_set_option_string (this->m_mpv, "fbo-format", "rgba8");
break;
}
}
// Find first audio stream if (mpv_initialize (this->m_mpv) < 0)
for (int i = 0; i < m_formatCtx->nb_streams; i++) sLog.exception ("Could not initialize mpv context");
{
if (m_formatCtx->streams [i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
{
m_audioStream = i;
break;
}
}
// Only video stream is required mpv_set_option_string (this->m_mpv, "hwdec", "auto");
if (m_videoStream == -1) mpv_set_option_string (this->m_mpv, "loop", "inf");
sLog.exception ("Failed to find video stream for file ", video->getFilename ());
const AVCodec* codec = avcodec_find_decoder (m_formatCtx->streams [m_videoStream]->codecpar->codec_id); // initialize gl context for mpv
if (codec == nullptr) mpv_opengl_init_params gl_init_params {get_proc_address, nullptr};
sLog.exception ("Failed to find codec for video ", video->getFilename ()); mpv_render_param params[] {
{MPV_RENDER_PARAM_API_TYPE, const_cast <char*> (MPV_RENDER_API_TYPE_OPENGL)},
m_codecCtx = avcodec_alloc_context3 (codec); {MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &gl_init_params},
if (avcodec_parameters_to_context (m_codecCtx, m_formatCtx->streams [m_videoStream]->codecpar)) {MPV_RENDER_PARAM_INVALID, nullptr}
sLog.exception ("Failed to copy codec parameters when playing video ", video->getFilename ());
if (avcodec_open2 (m_codecCtx, codec, NULL) < 0)
sLog.exception ("Failed to open coded for playback of video ", video->getFilename ());
// initialize audio if there's any audio stream
if (m_audioStream != -1)
{
const AVCodec* audioCodec = avcodec_find_decoder (m_formatCtx->streams [m_audioStream]->codecpar->codec_id);
if (audioCodec == nullptr)
sLog.exception ("Failed to find coded for audio in video ", video->getFilename ());
AVCodecContext* audioContext = avcodec_alloc_context3 (audioCodec);
if (avcodec_parameters_to_context (audioContext, m_formatCtx->streams [m_audioStream]->codecpar))
sLog.exception ("Failed to setup audio context for video ", video->getFilename ());
if (avcodec_open2 (audioContext, audioCodec, NULL) < 0)
sLog.exception ("Failed to open audio coded for video ", video->getFilename ());
this->m_audio = new Audio::CAudioStream (audioContext);
}
m_videoFrame = av_frame_alloc ();
m_videoFrameRGB = av_frame_alloc ();
if (m_videoFrameRGB == nullptr)
sLog.exception ("Cannot allocate video frame");
GLfloat texCoords [] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
0.0f, 0.0f,
1.0f, 1.0f,
1.0f, 0.0f
}; };
// inverted positions so the final texture is rendered properly if (mpv_render_context_create (&this->m_mpvGl, this->m_mpv, params) < 0)
GLfloat position [] = { sLog.exception ("Failed to initialize MPV's GL context");
-1.0f, 1.0f, 0.0f,
1.0, 1.0f, 0.0f, const char* command [] = {
-1.0f, -1.0f, 0.0f, "loadfile", this->getVideo ()->getFilename ().c_str (), nullptr
-1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f
}; };
glGenBuffers (1, &this->m_texCoordBuffer); if (mpv_command (this->m_mpv, command) < 0)
glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer); sLog.exception ("Cannot load video to play");
glBufferData (GL_ARRAY_BUFFER, sizeof (texCoords), texCoords, GL_STATIC_DRAW);
glGenBuffers (1, &this->m_positionBuffer); if (g_AudioEnabled == false)
glBindBuffer (GL_ARRAY_BUFFER, this->m_positionBuffer); {
glBufferData (GL_ARRAY_BUFFER, sizeof (position), position, GL_STATIC_DRAW); const char* mutecommand [] = {
"set", "mute", "yes", nullptr
};
// setup gl things to render the background mpv_command (this->m_mpv, mutecommand);
glGenTextures (1, &this->m_texture); }
// configure the texture
glBindTexture (GL_TEXTURE_2D, this->m_texture);
// set filtering parameters, otherwise the texture is not rendered
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// set texture basic data
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, m_codecCtx->width, m_codecCtx->height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
this->setupShaders (); // setup framebuffers
this->setupFramebuffers(); this->setupFramebuffers();
} }
void CVideo::setSize (int width, int height) void CVideo::setSize (int64_t width, int64_t height)
{ {
if (m_buffer != nullptr) this->m_width = width > 0 ? width : this->m_width;
av_free (m_buffer); this->m_height = height > 0 ? height : this->m_height;
if (m_swsCtx != nullptr) // do not refresh the texture if any of the sizes are invalid
sws_freeContext (m_swsCtx); if (this->m_width <= 0 || this->m_height <= 0)
return;
int numBytes = av_image_get_buffer_size (AV_PIX_FMT_RGB24, width, height, 1); // reconfigure the texture
m_buffer = (uint8_t*) av_malloc (numBytes * sizeof (uint8_t)); glBindTexture (GL_TEXTURE_2D, this->getWallpaperTexture());
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, this->m_width, this->m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
av_image_fill_arrays (m_videoFrameRGB->data, m_videoFrameRGB->linesize, m_buffer, AV_PIX_FMT_RGB24, width, height, 1);
m_swsCtx = sws_getContext (m_codecCtx->width, m_codecCtx->height,
m_codecCtx->pix_fmt,
width, height,
AV_PIX_FMT_RGB24,
SWS_BILINEAR, NULL, NULL, NULL);
} }
void CVideo::renderFrame (glm::ivec4 viewport) void CVideo::renderFrame (glm::ivec4 viewport)
{ {
// do not render using the CWallpaper function, just use this one // read any and all the events available
this->setSize (m_codecCtx->width, m_codecCtx->height); while (this->m_mpv)
getNextFrame (); {
writeFrameToImage (); mpv_event* event = mpv_wait_event (this->m_mpv, 0);
glViewport (0, 0, this->getWidth (), this->getHeight ()); if (event == nullptr || event->event_id == MPV_EVENT_NONE)
break;
// do the actual rendering // we do not care about any of the events
// write to default's framebuffer switch (event->event_id)
glBindFramebuffer (GL_FRAMEBUFFER, this->getWallpaperFramebuffer()); {
case MPV_EVENT_VIDEO_RECONFIG:
{
int64_t width, height;
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (mpv_get_property (this->m_mpv, "dwidth", MPV_FORMAT_INT64, &width) >= 0 &&
glDisable (GL_BLEND); mpv_get_property (this->m_mpv, "dheight", MPV_FORMAT_INT64, &height) >= 0)
glDisable (GL_DEPTH_TEST); this->setSize (width, height);
// do not use any shader
glUseProgram (this->m_shader);
// activate scene texture
glActiveTexture (GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, this->m_texture);
// set uniforms and attribs
glEnableVertexAttribArray (this->a_TexCoord);
glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer);
glVertexAttribPointer (this->a_TexCoord, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray (this->a_Position);
glBindBuffer (GL_ARRAY_BUFFER, this->m_positionBuffer);
glVertexAttribPointer (this->a_Position, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glUniform1i (this->g_Texture0, 0);
// write the framebuffer as is to the screen
glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer);
glDrawArrays (GL_TRIANGLES, 0, 6);
} }
void CVideo::getNextFrame ()
{
bool eof = false;
AVPacket packet;
packet.data = nullptr;
// Find video streams packet
do
{
if (packet.data != nullptr)
av_packet_unref (&packet);
int readError = av_read_frame (m_formatCtx, &packet);
if (readError == AVERROR_EOF)
{
eof = true;
break; break;
} }
else if (readError < 0)
{
char err[AV_ERROR_MAX_STRING_SIZE];
sLog.exception (av_make_error_string (err, AV_ERROR_MAX_STRING_SIZE, readError));
} }
} while (packet.stream_index != m_videoStream /*&& packet.stream_index != m_audioStream*/); // render the next
glViewport (0, 0, this->getWidth (), this->getHeight ());
if (!eof && packet.stream_index == m_videoStream) mpv_opengl_fbo fbo {
{ static_cast <int> (this->getWallpaperFramebuffer()),
// Send video stream packet to codec static_cast <int> (this->m_width),
if (avcodec_send_packet (m_codecCtx, &packet) < 0) static_cast <int> (this->m_height),
return; GL_RGBA8
};
// Receive frame from codec // no need to flip as it'll be handled by the wallpaper rendering code
if (avcodec_receive_frame (m_codecCtx, m_videoFrame) < 0) int flip_y = 0;
return;
sws_scale (m_swsCtx, (uint8_t const* const*) m_videoFrame->data, m_videoFrame->linesize, mpv_render_param params [] = {
0, m_codecCtx->height, m_videoFrameRGB->data, m_videoFrameRGB->linesize); {MPV_RENDER_PARAM_OPENGL_FBO, &fbo},
{MPV_RENDER_PARAM_FLIP_Y, &flip_y},
{MPV_RENDER_PARAM_INVALID, nullptr}
};
} mpv_render_context_render (this->m_mpvGl, params);
/*else if (packet.stream_index == m_audioStream)
{
this->m_audio->queuePacket (&packet);
}*/
av_packet_unref (&packet);
if (eof)
restartStream ();
}
void CVideo::writeFrameToImage ()
{
uint8_t* frameData = m_videoFrameRGB->data [0];
if (frameData == nullptr)
return;
// bind the texture
glBindTexture (GL_TEXTURE_2D, this->m_texture);
// give openGL the new image's data
glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, m_codecCtx->width, m_codecCtx->height, GL_RGB, GL_UNSIGNED_BYTE, frameData);
}
void CVideo::restartStream ()
{
av_seek_frame (m_formatCtx, m_videoStream, 0, AVSEEK_FLAG_FRAME);
avcodec_flush_buffers (m_codecCtx);
} }
Core::CVideo* CVideo::getVideo () Core::CVideo* CVideo::getVideo ()
@ -244,137 +135,14 @@ Core::CVideo* CVideo::getVideo ()
return this->getWallpaperData ()->as<Core::CVideo> (); return this->getWallpaperData ()->as<Core::CVideo> ();
} }
uint32_t CVideo::getWidth () const
void CVideo::setupShaders ()
{ {
// reserve shaders in OpenGL return this->m_width;
GLuint vertexShaderID = glCreateShader (GL_VERTEX_SHADER);
// give shader's source code to OpenGL to be compiled
const char* sourcePointer = "#version 120\n"
"attribute vec3 a_Position;\n"
"attribute vec2 a_TexCoord;\n"
"varying vec2 v_TexCoord;\n"
"void main () {\n"
"gl_Position = vec4 (a_Position, 1.0);\n"
"v_TexCoord = a_TexCoord;\n"
"}";
glShaderSource (vertexShaderID, 1, &sourcePointer, nullptr);
glCompileShader (vertexShaderID);
GLint result = GL_FALSE;
int infoLogLength = 0;
// ensure the vertex shader was correctly compiled
glGetShaderiv (vertexShaderID, GL_COMPILE_STATUS, &result);
glGetShaderiv (vertexShaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
if (infoLogLength > 0)
{
char* logBuffer = new char [infoLogLength + 1];
// ensure logBuffer ends with a \0
memset (logBuffer, 0, infoLogLength + 1);
// get information about the error
glGetShaderInfoLog (vertexShaderID, infoLogLength, nullptr, logBuffer);
// throw an exception about the issue
std::string message = logBuffer;
// free the buffer
delete[] logBuffer;
// throw an exception
sLog.exception (message);
} }
// reserve shaders in OpenGL uint32_t CVideo::getHeight () const
GLuint fragmentShaderID = glCreateShader (GL_FRAGMENT_SHADER);
// give shader's source code to OpenGL to be compiled
sourcePointer = "#version 120\n"
"uniform sampler2D g_Texture0;\n"
"varying vec2 v_TexCoord;\n"
"void main () {\n"
"gl_FragColor = texture2D (g_Texture0, v_TexCoord);\n"
"}";
glShaderSource (fragmentShaderID, 1, &sourcePointer, nullptr);
glCompileShader (fragmentShaderID);
result = GL_FALSE;
infoLogLength = 0;
// ensure the vertex shader was correctly compiled
glGetShaderiv (fragmentShaderID, GL_COMPILE_STATUS, &result);
glGetShaderiv (fragmentShaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
if (infoLogLength > 0)
{ {
char* logBuffer = new char [infoLogLength + 1]; return this->m_height;
// ensure logBuffer ends with a \0
memset (logBuffer, 0, infoLogLength + 1);
// get information about the error
glGetShaderInfoLog (fragmentShaderID, infoLogLength, nullptr, logBuffer);
// throw an exception about the issue
std::string message = logBuffer;
// free the buffer
delete[] logBuffer;
// throw an exception
sLog.exception (message);
}
// create the final program
this->m_shader = glCreateProgram ();
// link the shaders together
glAttachShader (this->m_shader, vertexShaderID);
glAttachShader (this->m_shader, fragmentShaderID);
glLinkProgram (this->m_shader);
// check that the shader was properly linked
result = GL_FALSE;
infoLogLength = 0;
glGetProgramiv (this->m_shader, GL_LINK_STATUS, &result);
glGetProgramiv (this->m_shader, GL_INFO_LOG_LENGTH, &infoLogLength);
if (infoLogLength > 0)
{
char* logBuffer = new char [infoLogLength + 1];
// ensure logBuffer ends with a \0
memset (logBuffer, 0, infoLogLength + 1);
// get information about the error
glGetProgramInfoLog (this->m_shader, infoLogLength, nullptr, logBuffer);
// throw an exception about the issue
std::string message = logBuffer;
// free the buffer
delete[] logBuffer;
// throw an exception
sLog.exception (message);
}
// after being liked shaders can be dettached and deleted
glDetachShader (this->m_shader, vertexShaderID);
glDetachShader (this->m_shader, fragmentShaderID);
glDeleteShader (vertexShaderID);
glDeleteShader (fragmentShaderID);
// get textures
this->g_Texture0 = glGetUniformLocation (this->m_shader, "g_Texture0");
this->a_Position = glGetAttribLocation (this->m_shader, "a_Position");
this->a_TexCoord = glGetAttribLocation (this->m_shader, "a_TexCoord");
}
int CVideo::getWidth ()
{
return this->m_codecCtx->width;
}
int CVideo::getHeight ()
{
return this->m_codecCtx->height;
}
int CVideo::getFPS ()
{
return this->m_codecCtx->framerate.num;
} }
const std::string CVideo::Type = "video"; const std::string CVideo::Type = "video";

View File

@ -4,14 +4,8 @@
#include "WallpaperEngine/Audio/CAudioStream.h" #include "WallpaperEngine/Audio/CAudioStream.h"
#include "WallpaperEngine/Render/CWallpaper.h" #include "WallpaperEngine/Render/CWallpaper.h"
#include <mpv/client.h>
extern "C" #include <mpv/render_gl.h>
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}
namespace WallpaperEngine::Render namespace WallpaperEngine::Render
{ {
@ -22,10 +16,10 @@ namespace WallpaperEngine::Render
Core::CVideo* getVideo (); Core::CVideo* getVideo ();
int getWidth (); uint32_t getWidth () const override;
int getHeight (); uint32_t getHeight () const override;
int getFPS (); void setSize (int64_t width, int64_t height);
protected: protected:
void renderFrame (glm::ivec4 viewport) override; void renderFrame (glm::ivec4 viewport) override;
@ -35,32 +29,10 @@ namespace WallpaperEngine::Render
static const std::string Type; static const std::string Type;
private: private:
void setSize (int width, int height); mpv_handle* m_mpv;
void restartStream (); mpv_render_context* m_mpvGl;
void getNextFrame ();
void writeFrameToImage ();
void setupShaders ();
AVFormatContext* m_formatCtx = nullptr; int64_t m_width;
AVCodecContext* m_codecCtx = nullptr; int64_t m_height;
AVFrame* m_videoFrameRGB = nullptr;
AVFrame* m_videoFrame = nullptr;
SwsContext* m_swsCtx = nullptr;
uint8_t* m_buffer = nullptr;
int m_videoStream = -1, m_audioStream = -1;
Audio::CAudioStream* m_audio = nullptr;
/**
* The texture used for the video output
*/
GLuint m_texture;
GLuint m_texCoordBuffer;
GLuint m_positionBuffer;
GLuint m_shader;
// shader variables
GLint g_Texture0;
GLint a_Position;
GLint a_TexCoord;
}; };
}; };

View File

@ -58,7 +58,7 @@ const CContainer* CWallpaper::getContainer () const
return this->m_context->getContainer (); return this->m_context->getContainer ();
} }
WallpaperEngine::Core::CWallpaper* CWallpaper::getWallpaperData () WallpaperEngine::Core::CWallpaper* CWallpaper::getWallpaperData () const
{ {
return this->m_wallpaperData; return this->m_wallpaperData;
} }
@ -205,23 +205,8 @@ void CWallpaper::render (glm::ivec4 viewport, bool vflip, bool renderFrame, bool
if (renderFrame == true) if (renderFrame == true)
this->renderFrame (viewport); this->renderFrame (viewport);
int projectionWidth = 1920; uint32_t projectionWidth = this->getWidth ();
int projectionHeight = 1080; uint32_t projectionHeight = this->getHeight ();
if (this->getWallpaperData ()->is <WallpaperEngine::Core::CScene> ())
{
auto projection = this->getWallpaperData ()->as <WallpaperEngine::Core::CScene> ()->getOrthogonalProjection ();
projectionWidth = projection->getWidth ();
projectionHeight = projection->getHeight ();
}
else if (this->is <WallpaperEngine::Render::CVideo> ())
{
auto video = this->as <WallpaperEngine::Render::CVideo> ();
projectionWidth = video->getWidth ();
projectionHeight = video->getHeight ();
}
float ustart = 0.0f; float ustart = 0.0f;
float uend = 0.0f; float uend = 0.0f;
@ -295,6 +280,8 @@ void CWallpaper::render (glm::ivec4 viewport, bool vflip, bool renderFrame, bool
glBindFramebuffer (GL_FRAMEBUFFER, this->m_destFramebuffer); glBindFramebuffer (GL_FRAMEBUFFER, this->m_destFramebuffer);
glBindVertexArray (this->m_vaoBuffer);
if (newFrame) if (newFrame)
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -323,23 +310,8 @@ void CWallpaper::render (glm::ivec4 viewport, bool vflip, bool renderFrame, bool
void CWallpaper::setupFramebuffers () void CWallpaper::setupFramebuffers ()
{ {
int projectionWidth = 1920; uint32_t width = this->getWidth ();
int projectionHeight = 1080; uint32_t height = this->getHeight ();
if (this->getWallpaperData ()->is <WallpaperEngine::Core::CScene> ())
{
auto projection = this->getWallpaperData ()->as <WallpaperEngine::Core::CScene> ()->getOrthogonalProjection ();
projectionWidth = projection->getWidth ();
projectionHeight = projection->getHeight ();
}
else if (this->is <WallpaperEngine::Render::CVideo> ())
{
auto video = this->as <WallpaperEngine::Render::CVideo> ();
projectionWidth = video->getWidth ();
projectionHeight = video->getHeight ();
}
// create framebuffer for the scene // create framebuffer for the scene
this->m_sceneFBO = this->createFBO ( this->m_sceneFBO = this->createFBO (
@ -347,8 +319,8 @@ void CWallpaper::setupFramebuffers ()
ITexture::TextureFormat::ARGB8888, ITexture::TextureFormat::ARGB8888,
ITexture::TextureFlags::NoInterpolation, ITexture::TextureFlags::NoInterpolation,
1.0, 1.0,
projectionWidth, projectionHeight, width, height,
projectionWidth, projectionHeight width, height
); );
} }

View File

@ -46,11 +46,11 @@ namespace WallpaperEngine::Render
/** /**
* @return The scene's framebuffer * @return The scene's framebuffer
*/ */
GLuint getWallpaperFramebuffer () const; virtual GLuint getWallpaperFramebuffer () const;
/** /**
* @return The scene's texture * @return The scene's texture
*/ */
GLuint getWallpaperTexture () const; virtual GLuint getWallpaperTexture () const;
/** /**
* Creates a new FBO for this wallpaper * Creates a new FBO for this wallpaper
* *
@ -88,6 +88,16 @@ namespace WallpaperEngine::Render
*/ */
void setDestinationFramebuffer (GLuint framebuffer); void setDestinationFramebuffer (GLuint framebuffer);
/**
* @return The width of this wallpaper
*/
virtual uint32_t getWidth () const = 0;
/**
* @return The height of this wallpaper
*/
virtual uint32_t getHeight () const = 0;
/** /**
* Creates a new instance of CWallpaper based on the information provided by the read backgrounds * Creates a new instance of CWallpaper based on the information provided by the read backgrounds
* *
@ -110,7 +120,7 @@ namespace WallpaperEngine::Render
Core::CWallpaper* m_wallpaperData; Core::CWallpaper* m_wallpaperData;
Core::CWallpaper* getWallpaperData (); Core::CWallpaper* getWallpaperData () const;
/** /**
* The FBO used for scene output * The FBO used for scene output