mirror of
https://github.com/Almamu/linux-wallpaperengine.git
synced 2025-07-13 21:02:34 +08:00
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:
parent
a24b1923f6
commit
7079d12e2a
2
.github/workflows/cmake.yml
vendored
2
.github/workflows/cmake.yml
vendored
@ -21,7 +21,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- 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
|
||||
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
|
||||
|
@ -16,12 +16,13 @@ find_package(GLEW REQUIRED)
|
||||
find_package(GLUT REQUIRED)
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(SDL REQUIRED)
|
||||
find_package(MPV REQUIRED)
|
||||
find_package(LZ4 REQUIRED)
|
||||
find_package(FFMPEG REQUIRED)
|
||||
find_package(FreeImage REQUIRED)
|
||||
|
||||
|
||||
include_directories(
|
||||
${MPV_INCLUDE_DIR}
|
||||
${X11_INCLUDE_DIR}
|
||||
${XRANDR_INCLUDE_DIR}
|
||||
${GLEW_INCLUDE_DIR}
|
||||
@ -64,6 +65,12 @@ add_executable(
|
||||
src/WallpaperEngine/Core/Core.h
|
||||
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.h
|
||||
|
||||
@ -230,6 +237,7 @@ target_link_libraries(linux-wallpaperengine
|
||||
${SDL_MIXER_LIBRARIES}
|
||||
${FFMPEG_LIBRARIES}
|
||||
${FREEIMAGE_LIBRARIES}
|
||||
${MPV_LIBRARY}
|
||||
glfw)
|
||||
|
||||
file(CREATE_LINK linux-wallpaperengine wallengine SYMBOLIC)
|
||||
|
82
CMakeModules/FindMPV.cmake
Normal file
82
CMakeModules/FindMPV.cmake
Normal 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()
|
12
main.cpp
12
main.cpp
@ -33,6 +33,7 @@
|
||||
float g_Time;
|
||||
float g_TimeLast;
|
||||
bool g_KeepRunning = true;
|
||||
bool g_AudioEnabled = true;
|
||||
int g_AudioVolume = 15;
|
||||
|
||||
void print_help (const char* route)
|
||||
@ -258,7 +259,6 @@ int main (int argc, char* argv[])
|
||||
std::map <std::string, std::string> propertyOverrides;
|
||||
|
||||
int maximumFPS = 30;
|
||||
bool shouldEnableAudio = true;
|
||||
bool shouldTakeScreenshot = false;
|
||||
bool shouldListPropertiesAndStop = false;
|
||||
FREE_IMAGE_FORMAT screenshotFormat = FIF_UNKNOWN;
|
||||
@ -321,7 +321,7 @@ int main (int argc, char* argv[])
|
||||
break;
|
||||
|
||||
case 's':
|
||||
shouldEnableAudio = false;
|
||||
g_AudioEnabled = false;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
@ -445,7 +445,7 @@ int main (int argc, char* argv[])
|
||||
std::signal(SIGINT, 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 ("Continuing without audio support");
|
||||
@ -453,7 +453,7 @@ int main (int argc, char* argv[])
|
||||
|
||||
// initialize OpenGL driver
|
||||
WallpaperEngine::Render::Drivers::COpenGLDriver videoDriver ("Wallpaper Engine");
|
||||
// initialize custom context class
|
||||
// initialize render context
|
||||
WallpaperEngine::Render::CRenderContext context (screens, videoDriver, &containers);
|
||||
// initialize mouse support
|
||||
context.setMouse (new CMouseInput (videoDriver.getWindow ()));
|
||||
@ -462,10 +462,6 @@ int main (int argc, char* argv[])
|
||||
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;
|
||||
|
||||
while (videoDriver.closeRequested () == false && g_KeepRunning == true)
|
||||
|
@ -43,14 +43,14 @@ CScene::CScene (Core::CScene* scene, CRenderContext* context) :
|
||||
scene->getOrthogonalProjection ()->getHeight ()
|
||||
);
|
||||
|
||||
// setup framebuffers here as they're required for the scene setup
|
||||
this->setupFramebuffers();
|
||||
|
||||
// set clear color
|
||||
glm::vec3 clearColor = this->getScene ()->getClearColor ();
|
||||
|
||||
glClearColor (clearColor.r, clearColor.g, clearColor.b, 1.0f);
|
||||
|
||||
// setup framebuffers
|
||||
this->setupFramebuffers ();
|
||||
|
||||
// create all objects based off their dependencies
|
||||
for (const auto& cur : scene->getObjects ())
|
||||
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
|
||||
}
|
||||
|
||||
Core::CScene* CScene::getScene ()
|
||||
Core::CScene* CScene::getScene () const
|
||||
{
|
||||
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 ()
|
||||
{
|
||||
return &this->m_mousePosition;
|
||||
|
@ -19,7 +19,10 @@ namespace WallpaperEngine::Render
|
||||
|
||||
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* getMousePositionLast ();
|
||||
|
@ -1,242 +1,133 @@
|
||||
#include "common.h"
|
||||
#include "CVideo.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <GL/glew.h>
|
||||
|
||||
extern bool g_AudioEnabled;
|
||||
|
||||
using namespace WallpaperEngine;
|
||||
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) :
|
||||
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)
|
||||
sLog.exception ("Failed to open video file ", video->getFilename ());
|
||||
// create mpv contexts
|
||||
this->m_mpv = mpv_create ();
|
||||
|
||||
if (avformat_find_stream_info (m_formatCtx, NULL) < 0)
|
||||
sLog.exception ("Failed to get stream info for video file ", video->getFilename ());
|
||||
if (this->m_mpv == nullptr)
|
||||
sLog.exception ("Could not create mpv context");
|
||||
|
||||
// Find first video stream
|
||||
for (int i = 0; i < m_formatCtx->nb_streams; i++)
|
||||
{
|
||||
if (m_formatCtx->streams [i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
|
||||
{
|
||||
m_videoStream = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mpv_set_option_string (this->m_mpv, "terminal", "yes");
|
||||
mpv_set_option_string (this->m_mpv, "msg-level", "all=v");
|
||||
mpv_set_option_string (this->m_mpv, "input-cursor", "no");
|
||||
mpv_set_option_string (this->m_mpv, "cursor-autohide", "no");
|
||||
mpv_set_option_string (this->m_mpv, "config", "no");
|
||||
mpv_set_option_string (this->m_mpv, "fbo-format", "rgba8");
|
||||
|
||||
// Find first audio stream
|
||||
for (int i = 0; i < m_formatCtx->nb_streams; i++)
|
||||
{
|
||||
if (m_formatCtx->streams [i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
|
||||
{
|
||||
m_audioStream = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mpv_initialize (this->m_mpv) < 0)
|
||||
sLog.exception ("Could not initialize mpv context");
|
||||
|
||||
// Only video stream is required
|
||||
if (m_videoStream == -1)
|
||||
sLog.exception ("Failed to find video stream for file ", video->getFilename ());
|
||||
mpv_set_option_string (this->m_mpv, "hwdec", "auto");
|
||||
mpv_set_option_string (this->m_mpv, "loop", "inf");
|
||||
|
||||
const AVCodec* codec = avcodec_find_decoder (m_formatCtx->streams [m_videoStream]->codecpar->codec_id);
|
||||
if (codec == nullptr)
|
||||
sLog.exception ("Failed to find codec for video ", video->getFilename ());
|
||||
|
||||
m_codecCtx = avcodec_alloc_context3 (codec);
|
||||
if (avcodec_parameters_to_context (m_codecCtx, m_formatCtx->streams [m_videoStream]->codecpar))
|
||||
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
|
||||
// initialize gl context for mpv
|
||||
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}
|
||||
};
|
||||
|
||||
// inverted positions so the final texture is rendered properly
|
||||
GLfloat position [] = {
|
||||
-1.0f, 1.0f, 0.0f,
|
||||
1.0, 1.0f, 0.0f,
|
||||
-1.0f, -1.0f, 0.0f,
|
||||
-1.0f, -1.0f, 0.0f,
|
||||
1.0f, 1.0f, 0.0f,
|
||||
1.0f, -1.0f, 0.0f
|
||||
if (mpv_render_context_create (&this->m_mpvGl, this->m_mpv, params) < 0)
|
||||
sLog.exception ("Failed to initialize MPV's GL context");
|
||||
|
||||
const char* command [] = {
|
||||
"loadfile", this->getVideo ()->getFilename ().c_str (), nullptr
|
||||
};
|
||||
|
||||
glGenBuffers (1, &this->m_texCoordBuffer);
|
||||
glBindBuffer (GL_ARRAY_BUFFER, this->m_texCoordBuffer);
|
||||
glBufferData (GL_ARRAY_BUFFER, sizeof (texCoords), texCoords, GL_STATIC_DRAW);
|
||||
if (mpv_command (this->m_mpv, command) < 0)
|
||||
sLog.exception ("Cannot load video to play");
|
||||
|
||||
glGenBuffers (1, &this->m_positionBuffer);
|
||||
glBindBuffer (GL_ARRAY_BUFFER, this->m_positionBuffer);
|
||||
glBufferData (GL_ARRAY_BUFFER, sizeof (position), position, GL_STATIC_DRAW);
|
||||
if (g_AudioEnabled == false)
|
||||
{
|
||||
const char* mutecommand [] = {
|
||||
"set", "mute", "yes", nullptr
|
||||
};
|
||||
|
||||
// setup gl things to render the background
|
||||
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);
|
||||
mpv_command (this->m_mpv, mutecommand);
|
||||
}
|
||||
|
||||
this->setupShaders ();
|
||||
// setup framebuffers
|
||||
this->setupFramebuffers();
|
||||
}
|
||||
|
||||
void CVideo::setSize (int width, int height)
|
||||
void CVideo::setSize (int64_t width, int64_t height)
|
||||
{
|
||||
if (m_buffer != nullptr)
|
||||
av_free (m_buffer);
|
||||
this->m_width = width > 0 ? width : this->m_width;
|
||||
this->m_height = height > 0 ? height : this->m_height;
|
||||
|
||||
if (m_swsCtx != nullptr)
|
||||
sws_freeContext (m_swsCtx);
|
||||
// do not refresh the texture if any of the sizes are invalid
|
||||
if (this->m_width <= 0 || this->m_height <= 0)
|
||||
return;
|
||||
|
||||
int numBytes = av_image_get_buffer_size (AV_PIX_FMT_RGB24, width, height, 1);
|
||||
m_buffer = (uint8_t*) av_malloc (numBytes * sizeof (uint8_t));
|
||||
|
||||
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);
|
||||
// reconfigure the texture
|
||||
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);
|
||||
}
|
||||
|
||||
void CVideo::renderFrame (glm::ivec4 viewport)
|
||||
{
|
||||
// do not render using the CWallpaper function, just use this one
|
||||
this->setSize (m_codecCtx->width, m_codecCtx->height);
|
||||
getNextFrame ();
|
||||
writeFrameToImage ();
|
||||
// read any and all the events available
|
||||
while (this->m_mpv)
|
||||
{
|
||||
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
|
||||
// write to default's framebuffer
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, this->getWallpaperFramebuffer());
|
||||
// we do not care about any of the events
|
||||
switch (event->event_id)
|
||||
{
|
||||
case MPV_EVENT_VIDEO_RECONFIG:
|
||||
{
|
||||
int64_t width, height;
|
||||
|
||||
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glDisable (GL_BLEND);
|
||||
glDisable (GL_DEPTH_TEST);
|
||||
// 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);
|
||||
if (mpv_get_property (this->m_mpv, "dwidth", MPV_FORMAT_INT64, &width) >= 0 &&
|
||||
mpv_get_property (this->m_mpv, "dheight", MPV_FORMAT_INT64, &height) >= 0)
|
||||
this->setSize (width, height);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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)
|
||||
{
|
||||
// Send video stream packet to codec
|
||||
if (avcodec_send_packet (m_codecCtx, &packet) < 0)
|
||||
return;
|
||||
mpv_opengl_fbo fbo {
|
||||
static_cast <int> (this->getWallpaperFramebuffer()),
|
||||
static_cast <int> (this->m_width),
|
||||
static_cast <int> (this->m_height),
|
||||
GL_RGBA8
|
||||
};
|
||||
|
||||
// Receive frame from codec
|
||||
if (avcodec_receive_frame (m_codecCtx, m_videoFrame) < 0)
|
||||
return;
|
||||
// no need to flip as it'll be handled by the wallpaper rendering code
|
||||
int flip_y = 0;
|
||||
|
||||
sws_scale (m_swsCtx, (uint8_t const* const*) m_videoFrame->data, m_videoFrame->linesize,
|
||||
0, m_codecCtx->height, m_videoFrameRGB->data, m_videoFrameRGB->linesize);
|
||||
mpv_render_param params [] = {
|
||||
{MPV_RENDER_PARAM_OPENGL_FBO, &fbo},
|
||||
{MPV_RENDER_PARAM_FLIP_Y, &flip_y},
|
||||
{MPV_RENDER_PARAM_INVALID, nullptr}
|
||||
};
|
||||
|
||||
}
|
||||
/*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);
|
||||
mpv_render_context_render (this->m_mpvGl, params);
|
||||
}
|
||||
|
||||
Core::CVideo* CVideo::getVideo ()
|
||||
@ -244,137 +135,14 @@ Core::CVideo* CVideo::getVideo ()
|
||||
return this->getWallpaperData ()->as<Core::CVideo> ();
|
||||
}
|
||||
|
||||
|
||||
void CVideo::setupShaders ()
|
||||
uint32_t CVideo::getWidth () const
|
||||
{
|
||||
// reserve shaders in OpenGL
|
||||
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);
|
||||
return this->m_width;
|
||||
}
|
||||
|
||||
// reserve shaders in OpenGL
|
||||
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)
|
||||
uint32_t CVideo::getHeight () const
|
||||
{
|
||||
char* logBuffer = new char [infoLogLength + 1];
|
||||
// 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;
|
||||
return this->m_height;
|
||||
}
|
||||
|
||||
const std::string CVideo::Type = "video";
|
||||
|
@ -4,14 +4,8 @@
|
||||
|
||||
#include "WallpaperEngine/Audio/CAudioStream.h"
|
||||
#include "WallpaperEngine/Render/CWallpaper.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libswscale/swscale.h>
|
||||
}
|
||||
#include <mpv/client.h>
|
||||
#include <mpv/render_gl.h>
|
||||
|
||||
namespace WallpaperEngine::Render
|
||||
{
|
||||
@ -22,10 +16,10 @@ namespace WallpaperEngine::Render
|
||||
|
||||
Core::CVideo* getVideo ();
|
||||
|
||||
int getWidth ();
|
||||
int getHeight ();
|
||||
uint32_t getWidth () const override;
|
||||
uint32_t getHeight () const override;
|
||||
|
||||
int getFPS ();
|
||||
void setSize (int64_t width, int64_t height);
|
||||
|
||||
protected:
|
||||
void renderFrame (glm::ivec4 viewport) override;
|
||||
@ -35,32 +29,10 @@ namespace WallpaperEngine::Render
|
||||
static const std::string Type;
|
||||
|
||||
private:
|
||||
void setSize (int width, int height);
|
||||
void restartStream ();
|
||||
void getNextFrame ();
|
||||
void writeFrameToImage ();
|
||||
void setupShaders ();
|
||||
mpv_handle* m_mpv;
|
||||
mpv_render_context* m_mpvGl;
|
||||
|
||||
AVFormatContext* m_formatCtx = nullptr;
|
||||
AVCodecContext* m_codecCtx = nullptr;
|
||||
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;
|
||||
int64_t m_width;
|
||||
int64_t m_height;
|
||||
};
|
||||
};
|
||||
|
@ -58,7 +58,7 @@ const CContainer* CWallpaper::getContainer () const
|
||||
return this->m_context->getContainer ();
|
||||
}
|
||||
|
||||
WallpaperEngine::Core::CWallpaper* CWallpaper::getWallpaperData ()
|
||||
WallpaperEngine::Core::CWallpaper* CWallpaper::getWallpaperData () const
|
||||
{
|
||||
return this->m_wallpaperData;
|
||||
}
|
||||
@ -205,23 +205,8 @@ void CWallpaper::render (glm::ivec4 viewport, bool vflip, bool renderFrame, bool
|
||||
if (renderFrame == true)
|
||||
this->renderFrame (viewport);
|
||||
|
||||
int projectionWidth = 1920;
|
||||
int projectionHeight = 1080;
|
||||
|
||||
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 ();
|
||||
}
|
||||
uint32_t projectionWidth = this->getWidth ();
|
||||
uint32_t projectionHeight = this->getHeight ();
|
||||
|
||||
float ustart = 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);
|
||||
|
||||
glBindVertexArray (this->m_vaoBuffer);
|
||||
|
||||
if (newFrame)
|
||||
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 ()
|
||||
{
|
||||
int projectionWidth = 1920;
|
||||
int projectionHeight = 1080;
|
||||
|
||||
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 ();
|
||||
}
|
||||
uint32_t width = this->getWidth ();
|
||||
uint32_t height = this->getHeight ();
|
||||
|
||||
// create framebuffer for the scene
|
||||
this->m_sceneFBO = this->createFBO (
|
||||
@ -347,8 +319,8 @@ void CWallpaper::setupFramebuffers ()
|
||||
ITexture::TextureFormat::ARGB8888,
|
||||
ITexture::TextureFlags::NoInterpolation,
|
||||
1.0,
|
||||
projectionWidth, projectionHeight,
|
||||
projectionWidth, projectionHeight
|
||||
width, height,
|
||||
width, height
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -46,11 +46,11 @@ namespace WallpaperEngine::Render
|
||||
/**
|
||||
* @return The scene's framebuffer
|
||||
*/
|
||||
GLuint getWallpaperFramebuffer () const;
|
||||
virtual GLuint getWallpaperFramebuffer () const;
|
||||
/**
|
||||
* @return The scene's texture
|
||||
*/
|
||||
GLuint getWallpaperTexture () const;
|
||||
virtual GLuint getWallpaperTexture () const;
|
||||
/**
|
||||
* Creates a new FBO for this wallpaper
|
||||
*
|
||||
@ -88,6 +88,16 @@ namespace WallpaperEngine::Render
|
||||
*/
|
||||
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
|
||||
*
|
||||
@ -110,7 +120,7 @@ namespace WallpaperEngine::Render
|
||||
|
||||
Core::CWallpaper* m_wallpaperData;
|
||||
|
||||
Core::CWallpaper* getWallpaperData ();
|
||||
Core::CWallpaper* getWallpaperData () const;
|
||||
|
||||
/**
|
||||
* The FBO used for scene output
|
||||
|
Loading…
Reference in New Issue
Block a user