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
This commit is contained in:
IceCryptonym 2020-04-28 02:50:17 +10:00 committed by GitHub
parent 98e245b4cb
commit 5d5ce361fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 617 additions and 100 deletions

View File

@ -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})
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})

View File

@ -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 <mail@cynapses.org>
# Modified for other libraries by Lasse Kärkkäinen <tronic>
# 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()

View File

@ -15,6 +15,7 @@ Wallpaper Engine is a software designed by [Kristjan Skutta](https://store.steam
- ZLIB
- SDL
- SDL_mixer
- FFmpeg
- X11
- Xrandr

View File

@ -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 <WallpaperEngine::Core::CScene> ();
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 <WallpaperEngine::Core::CVideo> (),
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 ();

View File

@ -1,15 +1,17 @@
#include <WallpaperEngine/FileSystem/FileSystem.h>
#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 <std::string> ().c_str (), "scene") == 0)
{
wallpaper = CScene::fromFile ((*file).get <std::string> ().c_str ());
}
else if (strcmp ((*type).get <std::string> ().c_str (), "video") == 0)
{
wallpaper = new CVideo ((*file).get <std::string> ().c_str ());
}
else
throw std::runtime_error ("Unsupported wallpaper type");
CProject* project = new CProject (
*title,
*type,
CScene::fromFile ((*file).get <std::string> ().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

View File

@ -2,7 +2,7 @@
#include <irrlicht/irrlicht.h>
#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<Projects::CProperty*>& 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;
};
};

View File

@ -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<CObject*>& 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";

View File

@ -2,8 +2,8 @@
#include <irrlicht/irrlicht.h>
#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<CObject*>& 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

View File

@ -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";

View File

@ -0,0 +1,36 @@
#pragma once
#include <irrlicht/irrlicht.h>
#include "Core.h"
#include "CWallpaper.h"
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}
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:
};
};

View File

@ -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;
}

View File

@ -0,0 +1,33 @@
#pragma once
#include <assert.h>
#include "CProject.h"
namespace WallpaperEngine::Core
{
class CProject;
class CWallpaper
{
public:
template<class T> const T* as () const { assert (is <T> ()); return (const T*) this; }
template<class T> T* as () { assert (is <T> ()); return (T*) this; }
template<class T> 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;
};
}

View File

@ -162,7 +162,7 @@ void CContext::initializeViewports (irr::SIrrlichtCreationParameters &irrlichtCr
irrlichtCreationParameters.WindowId = reinterpret_cast<void*> (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 ();
}

View File

@ -5,7 +5,7 @@
#include <irrlicht/irrlicht.h>
#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<Render::Shaders::Variables::CShaderVariable*>& 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);

View File

@ -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<irr::f32>(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<irr::f32>& CScene::getBoundingBox () const
Core::CScene* CScene::getScene ()
{
return this->m_boundingBox;
return this->getWallpaperData ()->as<Core::CScene> ();
}
void CScene::OnRegisterSceneNode ()
{
SceneManager->registerNodeForRendering (this);
ISceneNode::OnRegisterSceneNode ();
}
const std::string CScene::Type = "scene";

View File

@ -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<irr::f32>& 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<irr::f32> m_boundingBox;
};
}

View File

@ -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<Core::CVideo> ();
}
const std::string CVideo::Type = "video";

View File

@ -0,0 +1,52 @@
#pragma once
#include <irrlicht/irrlicht.h>
#include "WallpaperEngine/Core/CVideo.h"
#include "WallpaperEngine/Render/CWallpaper.h"
#include "WallpaperEngine/Irrlicht/CContext.h"
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}
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;
};
};

View File

@ -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<irr::f32>& CWallpaper::getBoundingBox () const
{
return this->m_boundingBox;
}
WallpaperEngine::Core::CWallpaper* CWallpaper::getWallpaperData ()
{
return this->m_wallpaperData;
}

View File

@ -0,0 +1,45 @@
#pragma once
#include <irrlicht/irrlicht.h>
#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<class T> const T* as () const { assert (is<T> ()); return (const T*) this; }
template<class T> T* as () { assert (is<T> ()); return (T*) this; }
template<class T> 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<irr::f32>& getBoundingBox () const override;
protected:
WallpaperEngine::Irrlicht::CContext* m_context;
Core::CWallpaper* m_wallpaperData;
Core::CWallpaper* getWallpaperData ();
private:
irr::core::aabbox3d<irr::f32> m_boundingBox = irr::core::aabbox3d<irr::f32> (0, 0, 0, 0, 0, 0);
std::string m_type;
};
}