From 5d5ce361fede30e966cf1e726b09fa7e545f9cba Mon Sep 17 00:00:00 2001 From: IceCryptonym <59789660+IceCryptonym@users.noreply.github.com> Date: Tue, 28 Apr 2020 02:50:17 +1000 Subject: [PATCH] Initial video support without audio (#14) * Adds FFmpeg to CMake * Refactors to allow support for other wallpaper types * Updates README.md for compilation requirements * Initial video support without audio * Properly support different wallpapers * Fixes videos not rendering * Nitpicks * Moves code related to rendering from Core::CVideo to Render::CVideo --- CMakeLists.txt | 13 +- CMakeModules/FindFFmpeg.cmake | 110 +++++++++++++++ README.md | 1 + main.cpp | 28 +++- src/WallpaperEngine/Core/CProject.cpp | 26 +++- src/WallpaperEngine/Core/CProject.h | 11 +- src/WallpaperEngine/Core/CScene.cpp | 14 +- src/WallpaperEngine/Core/CScene.h | 13 +- src/WallpaperEngine/Core/CVideo.cpp | 17 +++ src/WallpaperEngine/Core/CVideo.h | 36 +++++ src/WallpaperEngine/Core/CWallpaper.cpp | 18 +++ src/WallpaperEngine/Core/CWallpaper.h | 33 +++++ src/WallpaperEngine/Irrlicht/CContext.cpp | 11 +- src/WallpaperEngine/Irrlicht/CContext.h | 8 +- src/WallpaperEngine/Render/CScene.cpp | 47 ++---- src/WallpaperEngine/Render/CScene.h | 29 ++-- src/WallpaperEngine/Render/CVideo.cpp | 165 ++++++++++++++++++++++ src/WallpaperEngine/Render/CVideo.h | 52 +++++++ src/WallpaperEngine/Render/CWallpaper.cpp | 40 ++++++ src/WallpaperEngine/Render/CWallpaper.h | 45 ++++++ 20 files changed, 617 insertions(+), 100 deletions(-) create mode 100644 CMakeModules/FindFFmpeg.cmake create mode 100644 src/WallpaperEngine/Core/CVideo.cpp create mode 100644 src/WallpaperEngine/Core/CVideo.h create mode 100644 src/WallpaperEngine/Core/CWallpaper.cpp create mode 100644 src/WallpaperEngine/Core/CWallpaper.h create mode 100644 src/WallpaperEngine/Render/CVideo.cpp create mode 100644 src/WallpaperEngine/Render/CVideo.h create mode 100644 src/WallpaperEngine/Render/CWallpaper.cpp create mode 100644 src/WallpaperEngine/Render/CWallpaper.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 40c5622..ea45fbe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,8 +15,9 @@ find_package(Irrlicht REQUIRED) find_package(SDL REQUIRED) find_package(SDL_mixer REQUIRED) find_package(LZ4 REQUIRED) +find_package(FFmpeg REQUIRED) -include_directories(${X11_INCLUDE_DIR} ${XRANDR_INCLUDE_DIR} ${IRRLICHT_INCLUDE_DIR} ${LZ4_INCLUDE_DIR} ${SDL_INCLUDE_DIRS} ${SDL_MIXER_INCLUDE_DIRS} src include) +include_directories(${X11_INCLUDE_DIR} ${XRANDR_INCLUDE_DIR} ${IRRLICHT_INCLUDE_DIR} ${LZ4_INCLUDE_DIR} ${SDL_INCLUDE_DIRS} ${SDL_MIXER_INCLUDE_DIRS} ${FFMPEG_INCLUDE_DIR} src include) add_executable( wallengine @@ -46,8 +47,12 @@ add_executable( src/WallpaperEngine/Render/Shaders/Compiler.h src/WallpaperEngine/Render/Shaders/Compiler.cpp + src/WallpaperEngine/Render/CWallpaper.h + src/WallpaperEngine/Render/CWallpaper.cpp src/WallpaperEngine/Render/CScene.h src/WallpaperEngine/Render/CScene.cpp + src/WallpaperEngine/Render/CVideo.h + src/WallpaperEngine/Render/CVideo.cpp src/WallpaperEngine/Render/CCamera.h src/WallpaperEngine/Render/CCamera.cpp src/WallpaperEngine/Render/CObject.h @@ -83,8 +88,12 @@ add_executable( src/WallpaperEngine/Core/CProject.cpp src/WallpaperEngine/Core/CProject.h + src/WallpaperEngine/Core/CWallpaper.cpp + src/WallpaperEngine/Core/CWallpaper.h src/WallpaperEngine/Core/CScene.cpp src/WallpaperEngine/Core/CScene.h + src/WallpaperEngine/Core/CVideo.cpp + src/WallpaperEngine/Core/CVideo.h src/WallpaperEngine/Core/CObject.cpp src/WallpaperEngine/Core/CObject.h @@ -150,4 +159,4 @@ add_executable( src/WallpaperEngine/Core/Objects/Images/Materials/CPass.h ) -target_link_libraries(wallengine ${X11_LIBRARIES} ${XRANDR_LIBRARIES} ${X11_Xxf86vm_LIB} ${OPENGL_LIBRARIES} ${GLUT_LIBRARIES} ${ZLIB_LIBRARIES} ${IRRLICHT_LIBRARY} ${LZ4_LIBRARY} ${SDL_LIBRARY} ${SDL_MIXER_LIBRARIES}) \ No newline at end of file +target_link_libraries(wallengine ${X11_LIBRARIES} ${XRANDR_LIBRARIES} ${X11_Xxf86vm_LIB} ${OPENGL_LIBRARIES} ${GLUT_LIBRARIES} ${ZLIB_LIBRARIES} ${IRRLICHT_LIBRARY} ${LZ4_LIBRARY} ${SDL_LIBRARY} ${SDL_MIXER_LIBRARIES} ${FFMPEG_LIBRARIES}) \ No newline at end of file diff --git a/CMakeModules/FindFFmpeg.cmake b/CMakeModules/FindFFmpeg.cmake new file mode 100644 index 0000000..bfd7b21 --- /dev/null +++ b/CMakeModules/FindFFmpeg.cmake @@ -0,0 +1,110 @@ +# - Try to find ffmpeg libraries (libavcodec, libavformat, libavutil and libswscale) +# Once done this will define +# +# FFMPEG_FOUND - system has ffmpeg or libav +# FFMPEG_INCLUDE_DIR - the ffmpeg include directory +# FFMPEG_LIBRARIES - Link these to use ffmpeg +# FFMPEG_LIBAVCODEC +# FFMPEG_LIBAVFORMAT +# FFMPEG_LIBAVUTIL +# FFMPEG_LIBSWSCALE +# +# Copyright (c) 2008 Andreas Schneider +# Modified for other libraries by Lasse Kärkkäinen +# Modified for Hedgewars by Stepik777 +# Modified for FFmpeg-example Tuukka Pasanen 2018 +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# + +include(FindPackageHandleStandardArgs) + + find_package_handle_standard_args(FFMPEG + FOUND_VAR FFMPEG_FOUND + REQUIRED_VARS + FFMPEG_LIBRARY + FFMPEG_INCLUDE_DIR + VERSION_VAR FFMPEG_VERSION + ) + +if(FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR) + # in cache already + set(FFMPEG_FOUND TRUE) +else() + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + find_package(PkgConfig) + if(PKG_CONFIG_FOUND) + pkg_check_modules(_FFMPEG_AVCODEC libavcodec) + pkg_check_modules(_FFMPEG_AVFORMAT libavformat) + pkg_check_modules(_FFMPEG_AVUTIL libavutil) + pkg_check_modules(_FFMPEG_SWSCALE libswscale) + endif() + + find_path(FFMPEG_AVCODEC_INCLUDE_DIR + NAMES libavcodec/avcodec.h + PATHS ${_FFMPEG_AVCODEC_INCLUDE_DIRS} + /usr/include + /usr/local/include + /opt/local/include + /sw/include + PATH_SUFFIXES ffmpeg libav) + + find_library(FFMPEG_LIBAVCODEC + NAMES avcodec + PATHS ${_FFMPEG_AVCODEC_LIBRARY_DIRS} + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib) + + find_library(FFMPEG_LIBAVFORMAT + NAMES avformat + PATHS ${_FFMPEG_AVFORMAT_LIBRARY_DIRS} + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib) + + find_library(FFMPEG_LIBAVUTIL + NAMES avutil + PATHS ${_FFMPEG_AVUTIL_LIBRARY_DIRS} + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib) + + find_library(FFMPEG_LIBSWSCALE + NAMES swscale + PATHS ${_FFMPEG_SWSCALE_LIBRARY_DIRS} + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib) + + if(FFMPEG_LIBAVCODEC AND FFMPEG_LIBAVFORMAT) + set(FFMPEG_FOUND TRUE) + endif() + + if(FFMPEG_FOUND) + set(FFMPEG_INCLUDE_DIR ${FFMPEG_AVCODEC_INCLUDE_DIR}) + set(FFMPEG_LIBRARIES + ${FFMPEG_LIBAVCODEC} + ${FFMPEG_LIBAVFORMAT} + ${FFMPEG_LIBAVUTIL} + ${FFMPEG_LIBSWSCALE}) + endif() + + if(FFMPEG_FOUND) + if(NOT FFMPEG_FIND_QUIETLY) + message(STATUS + "Found FFMPEG or Libav: ${FFMPEG_LIBRARIES}, ${FFMPEG_INCLUDE_DIR}") + endif() + else() + if(FFMPEG_FIND_REQUIRED) + message(FATAL_ERROR + "Could not find libavcodec or libavformat or libavutil or libswscale") + endif() + endif() +endif() diff --git a/README.md b/README.md index 8e43d86..fb42c0c 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Wallpaper Engine is a software designed by [Kristjan Skutta](https://store.steam - ZLIB - SDL - SDL_mixer +- FFmpeg - X11 - Xrandr diff --git a/main.cpp b/main.cpp index 4eed0c5..4248094 100644 --- a/main.cpp +++ b/main.cpp @@ -6,7 +6,9 @@ #include "WallpaperEngine/Core/CProject.h" #include "WallpaperEngine/Irrlicht/CContext.h" +#include "WallpaperEngine/Render/CWallpaper.h" #include "WallpaperEngine/Render/CScene.h" +#include "WallpaperEngine/Render/CVideo.h" enum BACKGROUND_RUN_MODE { @@ -161,14 +163,32 @@ int main (int argc, char* argv[]) } WallpaperEngine::Core::CProject* project = WallpaperEngine::Core::CProject::fromFile (project_path); - WallpaperEngine::Render::CScene* scene = new WallpaperEngine::Render::CScene (project, IrrlichtContext); + WallpaperEngine::Render::CWallpaper* wallpaper; + if (project->getType () == "scene") + { + WallpaperEngine::Core::CScene* scene = project->getWallpaper ()->as (); + wallpaper = new WallpaperEngine::Render::CScene (scene, IrrlichtContext); + IrrlichtContext->getDevice ()->getSceneManager ()->setAmbientLight ( + scene->getAmbientColor ().toSColor () + ); + } + else if (project->getType () == "video") + { + wallpaper = new WallpaperEngine::Render::CVideo ( + project->getWallpaper ()->as (), + IrrlichtContext + ); + } + else + { + throw std::runtime_error ("Unsupported wallpaper type"); + } + irr::u32 minimumTime = 1000 / maximumFPS; irr::u32 startTime = 0; irr::u32 endTime = 0; - IrrlichtContext->getDevice ()->getSceneManager ()->setAmbientLight (scene->getScene ()->getAmbientColor ().toSColor ()); - while (IrrlichtContext && IrrlichtContext->getDevice () && IrrlichtContext->getDevice ()->run ()) { if (IrrlichtContext->getDevice ()->getVideoDriver () == nullptr) @@ -176,7 +196,7 @@ int main (int argc, char* argv[]) startTime = IrrlichtContext->getDevice ()->getTimer ()->getTime (); - IrrlichtContext->renderFrame (scene); + IrrlichtContext->renderFrame (wallpaper); endTime = IrrlichtContext->getDevice ()->getTimer ()->getTime (); diff --git a/src/WallpaperEngine/Core/CProject.cpp b/src/WallpaperEngine/Core/CProject.cpp index 0fb84f7..4ab0831 100644 --- a/src/WallpaperEngine/Core/CProject.cpp +++ b/src/WallpaperEngine/Core/CProject.cpp @@ -1,15 +1,17 @@ #include #include "CProject.h" +#include "CScene.h" +#include "CVideo.h" using namespace WallpaperEngine::Core; -CProject::CProject (std::string title, std::string type, CScene *scene) : +CProject::CProject (std::string title, std::string type, CWallpaper* wallpaper) : m_title (std::move (title)), m_type (std::move (type)), - m_scene (scene) + m_wallpaper (wallpaper) { - this->m_scene->setProject (this); + this->m_wallpaper->setProject (this); } CProject* CProject::fromFile (const irr::io::path& filename) @@ -20,11 +22,23 @@ CProject* CProject::fromFile (const irr::io::path& filename) auto type = jsonFindRequired (content, "type", "Project type missing"); auto file = jsonFindRequired (content, "file", "Project's main file missing"); auto general = content.find ("general"); + CWallpaper* wallpaper; + + if (strcmp ((*type).get ().c_str (), "scene") == 0) + { + wallpaper = CScene::fromFile ((*file).get ().c_str ()); + } + else if (strcmp ((*type).get ().c_str (), "video") == 0) + { + wallpaper = new CVideo ((*file).get ().c_str ()); + } + else + throw std::runtime_error ("Unsupported wallpaper type"); CProject* project = new CProject ( *title, *type, - CScene::fromFile ((*file).get ().c_str ()) + wallpaper ); if (general != content.end ()) @@ -48,9 +62,9 @@ CProject* CProject::fromFile (const irr::io::path& filename) return project; } -const CScene* CProject::getScene () const +CWallpaper* CProject::getWallpaper () const { - return this->m_scene; + return this->m_wallpaper; } const std::string& CProject::getTitle () const diff --git a/src/WallpaperEngine/Core/CProject.h b/src/WallpaperEngine/Core/CProject.h index aee6396..c48db55 100644 --- a/src/WallpaperEngine/Core/CProject.h +++ b/src/WallpaperEngine/Core/CProject.h @@ -2,7 +2,7 @@ #include -#include "CScene.h" +#include "CWallpaper.h" #include "WallpaperEngine/Core/Core.h" #include "WallpaperEngine/Core/Projects/CProperty.h" @@ -10,21 +10,21 @@ namespace WallpaperEngine::Core { using json = nlohmann::json; - class CScene; + class CWallpaper; class CProject { public: static CProject* fromFile (const irr::io::path& filename); - const CScene* getScene () const; + CWallpaper* getWallpaper () const; const std::string& getTitle () const; const std::string& getType () const; const std::vector& getProperties () const; protected: - CProject (std::string title, std::string type, CScene* scene); + CProject (std::string title, std::string type, CWallpaper* wallpaper); void insertProperty (Projects::CProperty* property); private: @@ -32,7 +32,6 @@ namespace WallpaperEngine::Core std::string m_title; std::string m_type; - CScene* m_scene; + CWallpaper* m_wallpaper; }; }; - diff --git a/src/WallpaperEngine/Core/CScene.cpp b/src/WallpaperEngine/Core/CScene.cpp index b1339ff..a0d93b0 100644 --- a/src/WallpaperEngine/Core/CScene.cpp +++ b/src/WallpaperEngine/Core/CScene.cpp @@ -24,6 +24,7 @@ CScene::CScene ( irr::video::SColorf clearColor, Scenes::CProjection* orthogonalProjection, irr::video::SColorf skylightColor) : + CWallpaper (Type), m_camera (camera), m_ambientColor (ambientColor), m_bloom (bloom), @@ -105,7 +106,6 @@ CScene* CScene::fromFile (const irr::io::path& filename) return scene; } - const std::vector& CScene::getObjects () const { return this->m_objects; @@ -116,16 +116,6 @@ void CScene::insertObject (CObject* object) this->m_objects.push_back (object); } -CProject* CScene::getProject () -{ - return this->m_project; -} - -void CScene::setProject (CProject* project) -{ - this->m_project = project; -} - const Scenes::CCamera* CScene::getCamera () const { return this->m_camera; @@ -215,3 +205,5 @@ const irr::video::SColorf& CScene::getSkylightColor () const { return this->m_skylightColor; } + +const std::string CScene::Type = "scene"; diff --git a/src/WallpaperEngine/Core/CScene.h b/src/WallpaperEngine/Core/CScene.h index c9a828c..16f901f 100644 --- a/src/WallpaperEngine/Core/CScene.h +++ b/src/WallpaperEngine/Core/CScene.h @@ -2,8 +2,8 @@ #include -#include "CProject.h" #include "CObject.h" +#include "CWallpaper.h" #include "Core.h" @@ -14,15 +14,13 @@ namespace WallpaperEngine::Core { using json = nlohmann::json; - class CProject; class CObject; - class CScene + class CScene : public CWallpaper { public: static CScene* fromFile (const irr::io::path& filename); - CProject* getProject (); const std::vector& getObjects () const; const irr::video::SColorf& getAmbientColor() const; @@ -45,9 +43,7 @@ namespace WallpaperEngine::Core const Scenes::CCamera* getCamera () const; protected: - friend class CProject; - - void setProject (CProject* project); + friend class CWallpaper; CScene ( Scenes::CCamera* camera, @@ -70,9 +66,10 @@ namespace WallpaperEngine::Core irr::video::SColorf skylightColor ); + static const std::string Type; + void insertObject (CObject* object); private: - CProject* m_project; Scenes::CCamera* m_camera; // data from general section on the json diff --git a/src/WallpaperEngine/Core/CVideo.cpp b/src/WallpaperEngine/Core/CVideo.cpp new file mode 100644 index 0000000..e7f25d8 --- /dev/null +++ b/src/WallpaperEngine/Core/CVideo.cpp @@ -0,0 +1,17 @@ +#include "CVideo.h" + +using namespace WallpaperEngine::Core; + +CVideo::CVideo ( + const irr::io::path& filename) : + CWallpaper (Type), + m_filename (filename) +{ +} + +const irr::io::path CVideo::getFilename () +{ + return this->m_filename; +} + +const std::string CVideo::Type = "video"; diff --git a/src/WallpaperEngine/Core/CVideo.h b/src/WallpaperEngine/Core/CVideo.h new file mode 100644 index 0000000..2fca344 --- /dev/null +++ b/src/WallpaperEngine/Core/CVideo.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include "Core.h" +#include "CWallpaper.h" + +extern "C" +{ + #include + #include + #include + #include +} + +namespace WallpaperEngine::Core +{ + class CVideo : public CWallpaper + { + public: + CVideo ( + const irr::io::path& filename + ); + + const irr::io::path getFilename (); + + protected: + friend class CWallpaper; + + const irr::io::path m_filename; + + static const std::string Type; + + private: + }; +}; diff --git a/src/WallpaperEngine/Core/CWallpaper.cpp b/src/WallpaperEngine/Core/CWallpaper.cpp new file mode 100644 index 0000000..df455d9 --- /dev/null +++ b/src/WallpaperEngine/Core/CWallpaper.cpp @@ -0,0 +1,18 @@ +#include "CWallpaper.h" + +using namespace WallpaperEngine::Core; + +CWallpaper::CWallpaper (std::string type) : + m_type (type) +{ +} + +CProject* CWallpaper::getProject () +{ + return this->m_project; +} + +void CWallpaper::setProject (CProject* project) +{ + this->m_project = project; +} diff --git a/src/WallpaperEngine/Core/CWallpaper.h b/src/WallpaperEngine/Core/CWallpaper.h new file mode 100644 index 0000000..e08f3b5 --- /dev/null +++ b/src/WallpaperEngine/Core/CWallpaper.h @@ -0,0 +1,33 @@ +#pragma once + +#include + +#include "CProject.h" + +namespace WallpaperEngine::Core +{ + class CProject; + + class CWallpaper + { + public: + template const T* as () const { assert (is ()); return (const T*) this; } + template T* as () { assert (is ()); return (T*) this; } + + template bool is () { return this->m_type == T::Type; } + + CWallpaper (std::string type); + + CProject* getProject (); + + protected: + friend class CProject; + + void setProject (CProject* project); + + private: + CProject* m_project; + + std::string m_type; + }; +} diff --git a/src/WallpaperEngine/Irrlicht/CContext.cpp b/src/WallpaperEngine/Irrlicht/CContext.cpp index 1b2d6fd..83465b3 100644 --- a/src/WallpaperEngine/Irrlicht/CContext.cpp +++ b/src/WallpaperEngine/Irrlicht/CContext.cpp @@ -162,7 +162,7 @@ void CContext::initializeViewports (irr::SIrrlichtCreationParameters &irrlichtCr irrlichtCreationParameters.WindowId = reinterpret_cast (DefaultRootWindow (display)); } -void CContext::renderFrame (Render::CScene* scene) +void CContext::renderFrame (Render::CWallpaper* wallpaper) { this->m_time = this->getDevice ()->getTimer ()->getTime () / 1000.0f; this->m_pointerPosition.X = this->m_eventReceiver->getPosition ().X / (irr::f32) this->getDevice ()->getVideoDriver ()->getScreenSize ().Width; @@ -170,7 +170,7 @@ void CContext::renderFrame (Render::CScene* scene) if (this->m_viewports.empty () == true) { - this->drawScene (scene, true); + this->drawWallpaper (wallpaper, true); } else { @@ -181,14 +181,15 @@ void CContext::renderFrame (Render::CScene* scene) { // change viewport to render to the correct portion of the display this->getDevice ()->getVideoDriver ()->setViewPort (*cur); - this->drawScene (scene, false); + this->drawWallpaper (wallpaper, false); } } } -void CContext::drawScene (Render::CScene* scene, bool backBuffer) +void CContext::drawWallpaper (Render::CWallpaper* wallpaper, bool backBuffer) { - this->getDevice ()->getVideoDriver ()->beginScene (backBuffer, true, scene->getScene ()->getClearColor ().toSColor()); + // TODO: Get scene clear color + this->getDevice ()->getVideoDriver ()->beginScene (backBuffer, true); this->getDevice ()->getSceneManager ()->drawAll (); this->getDevice ()->getVideoDriver ()->endScene (); } diff --git a/src/WallpaperEngine/Irrlicht/CContext.h b/src/WallpaperEngine/Irrlicht/CContext.h index c456b92..d254f55 100644 --- a/src/WallpaperEngine/Irrlicht/CContext.h +++ b/src/WallpaperEngine/Irrlicht/CContext.h @@ -5,7 +5,7 @@ #include -#include "WallpaperEngine/Render/CScene.h" +#include "WallpaperEngine/Render/CWallpaper.h" #include "WallpaperEngine/Render/Shaders/Variables/CShaderVariable.h" @@ -13,7 +13,7 @@ namespace WallpaperEngine::Render { - class CScene; + class CWallpaper; }; namespace WallpaperEngine::Irrlicht @@ -29,7 +29,7 @@ namespace WallpaperEngine::Irrlicht void insertShaderVariable (Render::Shaders::Variables::CShaderVariable* variable); const std::vector& getShaderVariables () const; - void renderFrame (Render::CScene* scene); + void renderFrame (Render::CWallpaper* wallpaper); irr::IrrlichtDevice* getDevice (); irr::io::path resolveMaterials (const std::string& materialName); @@ -38,7 +38,7 @@ namespace WallpaperEngine::Irrlicht irr::io::path resolveIncludeShader (const std::string& includeShader); private: void initializeViewports (irr::SIrrlichtCreationParameters& irrlichtCreationParameters); - void drawScene (Render::CScene* scene, bool backBuffer); + void drawWallpaper (Render::CWallpaper* wallpaper, bool backBuffer); irr::io::path resolveFile (const irr::io::path& file); diff --git a/src/WallpaperEngine/Render/CScene.cpp b/src/WallpaperEngine/Render/CScene.cpp index 2f72881..d8f3c08 100644 --- a/src/WallpaperEngine/Render/CScene.cpp +++ b/src/WallpaperEngine/Render/CScene.cpp @@ -1,5 +1,3 @@ -#include "WallpaperEngine/Irrlicht/CContext.h" - #include "WallpaperEngine/Core/Objects/CImage.h" #include "WallpaperEngine/Core/Objects/CSound.h" @@ -11,23 +9,17 @@ using namespace WallpaperEngine; using namespace WallpaperEngine::Render; -CScene::CScene (const Core::CProject* project, Irrlicht::CContext* context) : - irr::scene::ISceneNode ( - context->getDevice ()->getSceneManager ()->getRootSceneNode (), - context->getDevice ()->getSceneManager () - ), - m_project (project), - m_scene (project->getScene ()), - m_context (context) +CScene::CScene (Core::CScene* scene, Irrlicht::CContext* context) : + CWallpaper (scene, Type, context) { - this->m_camera = new CCamera (this, this->m_project->getScene ()->getCamera ()); + this->m_camera = new CCamera (this, scene->getCamera ()); this->m_camera->setOrthogonalProjection ( - this->m_scene->getOrthogonalProjection ()->getWidth (), - this->m_scene->getOrthogonalProjection ()->getHeight () + scene->getOrthogonalProjection ()->getWidth (), + scene->getOrthogonalProjection ()->getHeight () ); - auto cur = this->m_scene->getObjects ().begin (); - auto end = this->m_scene->getObjects ().end (); + auto cur = scene->getObjects ().begin (); + auto end = scene->getObjects ().end (); int highestId = 0; @@ -48,21 +40,6 @@ CScene::CScene (const Core::CProject* project, Irrlicht::CContext* context) : this->m_nextId = ++highestId; this->setAutomaticCulling (irr::scene::EAC_OFF); - this->m_boundingBox = irr::core::aabbox3d(0, 0, 0, 0, 0, 0); -} - -CScene::~CScene () -{ -} - -Irrlicht::CContext* CScene::getContext () -{ - return this->m_context; -} - -const Core::CScene* CScene::getScene () const -{ - return this->m_scene; } CCamera* CScene::getCamera () const @@ -79,13 +56,9 @@ void CScene::render () { } -const irr::core::aabbox3d& CScene::getBoundingBox () const +Core::CScene* CScene::getScene () { - return this->m_boundingBox; + return this->getWallpaperData ()->as (); } -void CScene::OnRegisterSceneNode () -{ - SceneManager->registerNodeForRendering (this); - ISceneNode::OnRegisterSceneNode (); -} \ No newline at end of file +const std::string CScene::Type = "scene"; diff --git a/src/WallpaperEngine/Render/CScene.h b/src/WallpaperEngine/Render/CScene.h index 5307a8d..96f1c86 100644 --- a/src/WallpaperEngine/Render/CScene.h +++ b/src/WallpaperEngine/Render/CScene.h @@ -2,40 +2,35 @@ #include "CCamera.h" -#include "WallpaperEngine/Core/CProject.h" #include "WallpaperEngine/Core/CScene.h" -#include "WallpaperEngine/Irrlicht/CContext.h" +#include "WallpaperEngine/Render/CWallpaper.h" -namespace WallpaperEngine::Irrlicht -{ - class CContext; -}; +#include "WallpaperEngine/Irrlicht/CContext.h" namespace WallpaperEngine::Render { class CCamera; - class CScene : public irr::scene::ISceneNode + class CScene : public CWallpaper { public: - CScene (const Core::CProject* project, Irrlicht::CContext* context); - ~CScene () override; + CScene (Core::CScene* scene, WallpaperEngine::Irrlicht::CContext* context); - Irrlicht::CContext* getContext (); - const Core::CScene* getScene () const; CCamera* getCamera () const; int nextId (); void render () override; - const irr::core::aabbox3d& getBoundingBox() const override; - void OnRegisterSceneNode () override; + + Core::CScene* getScene (); + + protected: + friend class CWallpaper; + + static const std::string Type; + private: - const Core::CProject* m_project; - const Core::CScene* m_scene; CCamera* m_camera; - Irrlicht::CContext* m_context; irr::u32 m_nextId; - irr::core::aabbox3d m_boundingBox; }; } diff --git a/src/WallpaperEngine/Render/CVideo.cpp b/src/WallpaperEngine/Render/CVideo.cpp new file mode 100644 index 0000000..f9d0823 --- /dev/null +++ b/src/WallpaperEngine/Render/CVideo.cpp @@ -0,0 +1,165 @@ +#include "CVideo.h" + +using namespace WallpaperEngine; + +using namespace WallpaperEngine::Render; + +CVideo::CVideo (Core::CVideo* video, WallpaperEngine::Irrlicht::CContext* context) : + CWallpaper (video, Type, context) +{ + if (avformat_open_input (&m_formatCtx, video->getFilename ().c_str (), NULL, NULL) < 0) + throw std::runtime_error ("Failed to open video file"); + + if (avformat_find_stream_info (m_formatCtx, NULL) < 0) + throw std::runtime_error ("Failed to get stream info"); + + // 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; + } + } + + // 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; + } + } + + // Only video stream is required + if (m_videoStream == -1) + throw std::runtime_error ("Failed to find video stream"); + + AVCodec* codec = avcodec_find_decoder (m_formatCtx->streams[m_videoStream]->codecpar->codec_id); + if (codec == nullptr) + throw std::runtime_error ("Failed to find codec"); + + m_codecCtx = avcodec_alloc_context3 (codec); + if (avcodec_parameters_to_context (m_codecCtx, m_formatCtx->streams[m_videoStream]->codecpar)) + throw std::runtime_error ("Failed to copy codec parameters"); + + if (avcodec_open2 (m_codecCtx, codec, NULL) < 0) + throw std::runtime_error ("Failed to open codec"); + + m_videoFrame = av_frame_alloc (); + m_videoFrameRGB = av_frame_alloc (); + if (m_videoFrameRGB == nullptr) + throw std::runtime_error ("Failed to allocate video frame"); +} + +void CVideo::setSize (int width, int height) +{ + if (m_buffer != nullptr) + av_free (m_buffer); + + if (m_swsCtx != nullptr) + sws_freeContext (m_swsCtx); + + 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); +} + +void CVideo::render () +{ + irr::video::IVideoDriver* driver = m_context->getDevice ()->getVideoDriver (); + int width = driver->getScreenSize ().Width; + int height = driver->getScreenSize ().Height; + + m_frameImage = m_context->getDevice ()->getVideoDriver ()->createImage (irr::video::ECOLOR_FORMAT::ECF_R8G8B8, + irr::core::dimension2du(width, height)); + + setSize (width, height); + getNextFrame (); + writeFrameToImage (); + + driver->removeTexture (m_frameTexture); + m_frameTexture = driver->addTexture ("frameTexture", m_frameImage); + m_frameImage->drop (); + + driver->draw2DImage (m_frameTexture, irr::core::vector2di(0)); +} + +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]; + throw std::runtime_error (av_make_error_string (err, AV_ERROR_MAX_STRING_SIZE, readError)); + } + + } while (packet.stream_index != m_videoStream); + + // Send video stream packet to codec + if (avcodec_send_packet (m_codecCtx, &packet) < 0) + return; + + // Receive frame from codec + if (avcodec_receive_frame (m_codecCtx, m_videoFrame) < 0) + return; + + sws_scale (m_swsCtx, (uint8_t const* const*)m_videoFrame->data, m_videoFrame->linesize, + 0, m_codecCtx->height, m_videoFrameRGB->data, m_videoFrameRGB->linesize); + + av_packet_unref (&packet); + + if (eof) + restartStream (); +} + +void CVideo::writeFrameToImage () +{ + uint8_t* frameData = m_videoFrameRGB->data[0]; + if (frameData == nullptr) + return; + + irr::u32 imgWidth = m_frameImage->getDimension().Width; + irr::u32 imgHeight = m_frameImage->getDimension().Height; + + unsigned char* data = (unsigned char*)m_frameImage->lock (); + memcpy (data, frameData, imgWidth * imgHeight * 3); + m_frameImage->unlock (); +} + +void CVideo::restartStream () +{ + av_seek_frame (m_formatCtx, m_videoStream, 0, AVSEEK_FLAG_FRAME); + avcodec_flush_buffers (m_codecCtx); +} + +Core::CVideo* CVideo::getVideo () +{ + return this->getWallpaperData ()->as (); +} + +const std::string CVideo::Type = "video"; diff --git a/src/WallpaperEngine/Render/CVideo.h b/src/WallpaperEngine/Render/CVideo.h new file mode 100644 index 0000000..77382fc --- /dev/null +++ b/src/WallpaperEngine/Render/CVideo.h @@ -0,0 +1,52 @@ +#pragma once + +#include + +#include "WallpaperEngine/Core/CVideo.h" + +#include "WallpaperEngine/Render/CWallpaper.h" + +#include "WallpaperEngine/Irrlicht/CContext.h" + +extern "C" +{ + #include + #include + #include + #include +} + +namespace WallpaperEngine::Render +{ + class CVideo : public CWallpaper + { + public: + CVideo (Core::CVideo* video, WallpaperEngine::Irrlicht::CContext* context); + + void render () override; + + Core::CVideo* getVideo (); + + protected: + friend class CWallpaper; + + static const std::string Type; + + private: + void setSize (int width, int height); + void restartStream (); + void getNextFrame (); + void writeFrameToImage (); + + AVFormatContext* m_formatCtx = nullptr; + AVCodecContext* m_codecCtx = nullptr; + AVFrame* m_videoFrame = nullptr; + AVFrame* m_videoFrameRGB = nullptr; + SwsContext* m_swsCtx = nullptr; + uint8_t* m_buffer = nullptr; + int m_videoStream = -1, m_audioStream = -1; + + irr::video::IImage* m_frameImage; + irr::video::ITexture* m_frameTexture; + }; +}; diff --git a/src/WallpaperEngine/Render/CWallpaper.cpp b/src/WallpaperEngine/Render/CWallpaper.cpp new file mode 100644 index 0000000..788e4cd --- /dev/null +++ b/src/WallpaperEngine/Render/CWallpaper.cpp @@ -0,0 +1,40 @@ +#include "CWallpaper.h" + +using namespace WallpaperEngine::Render; + +CWallpaper::CWallpaper (Core::CWallpaper* wallpaperData, std::string type, WallpaperEngine::Irrlicht::CContext* context) : + irr::scene::ISceneNode ( + context->getDevice ()->getSceneManager ()->getRootSceneNode (), + context->getDevice ()->getSceneManager () + ), + m_context (context), + m_wallpaperData (wallpaperData), + m_type (type) +{ +} + +CWallpaper::~CWallpaper () +{ +} + +void CWallpaper::OnRegisterSceneNode () +{ + SceneManager->registerNodeForRendering (this); + + ISceneNode::OnRegisterSceneNode (); +} + +WallpaperEngine::Irrlicht::CContext* CWallpaper::getContext () const +{ + return this->m_context; +} + +const irr::core::aabbox3d& CWallpaper::getBoundingBox () const +{ + return this->m_boundingBox; +} + +WallpaperEngine::Core::CWallpaper* CWallpaper::getWallpaperData () +{ + return this->m_wallpaperData; +} diff --git a/src/WallpaperEngine/Render/CWallpaper.h b/src/WallpaperEngine/Render/CWallpaper.h new file mode 100644 index 0000000..8f260a7 --- /dev/null +++ b/src/WallpaperEngine/Render/CWallpaper.h @@ -0,0 +1,45 @@ +#pragma once + +#include + +#include "WallpaperEngine/Core/CWallpaper.h" +#include "WallpaperEngine/Core/CScene.h" +#include "WallpaperEngine/Core/CVideo.h" + +#include "WallpaperEngine/Irrlicht/CContext.h" + +namespace WallpaperEngine::Irrlicht +{ + class CContext; +}; + +namespace WallpaperEngine::Render +{ + class CWallpaper : public irr::scene::ISceneNode + { + public: + template const T* as () const { assert (is ()); return (const T*) this; } + template T* as () { assert (is ()); return (T*) this; } + + template bool is () { return this->m_type == T::Type; } + + CWallpaper (Core::CWallpaper* wallpaperData, std::string type, WallpaperEngine::Irrlicht::CContext* context); + ~CWallpaper () override; + + void OnRegisterSceneNode () override; + + WallpaperEngine::Irrlicht::CContext* getContext () const; + const irr::core::aabbox3d& getBoundingBox () const override; + + protected: + WallpaperEngine::Irrlicht::CContext* m_context; + Core::CWallpaper* m_wallpaperData; + + Core::CWallpaper* getWallpaperData (); + + private: + irr::core::aabbox3d m_boundingBox = irr::core::aabbox3d (0, 0, 0, 0, 0, 0); + + std::string m_type; + }; +}