diff --git a/src/WallpaperEngine/Core/CVideo.cpp b/src/WallpaperEngine/Core/CVideo.cpp index bda74da..e7f25d8 100644 --- a/src/WallpaperEngine/Core/CVideo.cpp +++ b/src/WallpaperEngine/Core/CVideo.cpp @@ -4,114 +4,14 @@ using namespace WallpaperEngine::Core; CVideo::CVideo ( const irr::io::path& filename) : - CWallpaper (Type) + CWallpaper (Type), + m_filename (filename) { - if (avformat_open_input (&m_formatCtx, filename.c_str(), NULL, NULL) < 0) - throw std::runtime_error ("Failed to open 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) +const irr::io::path CVideo::getFilename () { - if (buffer != nullptr) - av_free (buffer); - - if (m_swsCtx != nullptr) - sws_freeContext (m_swsCtx); - - int numBytes = av_image_get_buffer_size (AV_PIX_FMT_RGB24, width, height, 1); - buffer = (uint8_t*)av_malloc (numBytes * sizeof (uint8_t)); - - av_image_fill_arrays (m_videoFrameRGB->data, m_videoFrameRGB->linesize, 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::restartStream () -{ - av_seek_frame (m_formatCtx, m_videoStream, 0, AVSEEK_FLAG_FRAME); - avcodec_flush_buffers (m_codecCtx); -} - -AVFormatContext* CVideo::getFormatContext () -{ - return this->m_formatCtx; -} - -AVCodecContext* CVideo::getCodecContext () -{ - return this->m_codecCtx; -} - -AVFrame* CVideo::getVideoFrame () -{ - return this->m_videoFrame; -} - -AVFrame* CVideo::getVideoFrameRGB () -{ - return this->m_videoFrameRGB; -} - -SwsContext* CVideo::getSwsContext () -{ - return this->m_swsCtx; -} - -int CVideo::getVideoStreamIndex () -{ - return this->m_videoStream; -} - -int CVideo::getAudioStreamIndex () -{ - return this->m_audioStream; + return this->m_filename; } const std::string CVideo::Type = "video"; diff --git a/src/WallpaperEngine/Core/CVideo.h b/src/WallpaperEngine/Core/CVideo.h index 22ca896..2fca344 100644 --- a/src/WallpaperEngine/Core/CVideo.h +++ b/src/WallpaperEngine/Core/CVideo.h @@ -22,30 +22,15 @@ namespace WallpaperEngine::Core const irr::io::path& filename ); - void setSize (int width, int height); - void restartStream (); - - AVFormatContext* getFormatContext (); - AVCodecContext* getCodecContext (); - AVFrame* getVideoFrame (); - AVFrame* getVideoFrameRGB (); - SwsContext* getSwsContext (); - int getVideoStreamIndex (); - int getAudioStreamIndex (); + const irr::io::path getFilename (); protected: friend class CWallpaper; + const irr::io::path m_filename; + static const std::string Type; private: - AVFormatContext* m_formatCtx = nullptr; - AVCodecContext* m_codecCtx = nullptr; - AVFrame* m_videoFrame = nullptr; - AVFrame* m_videoFrameRGB = nullptr; - SwsContext* m_swsCtx = nullptr; - uint8_t* buffer = nullptr; - - int m_videoStream = -1, m_audioStream = -1; }; }; diff --git a/src/WallpaperEngine/Render/CVideo.cpp b/src/WallpaperEngine/Render/CVideo.cpp index 72228af..f9d0823 100644 --- a/src/WallpaperEngine/Render/CVideo.cpp +++ b/src/WallpaperEngine/Render/CVideo.cpp @@ -7,6 +7,71 @@ 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 () @@ -18,7 +83,7 @@ void CVideo::render () m_frameImage = m_context->getDevice ()->getVideoDriver ()->createImage (irr::video::ECOLOR_FORMAT::ECF_R8G8B8, irr::core::dimension2du(width, height)); - getVideo ()->setSize (width, height); + setSize (width, height); getNextFrame (); writeFrameToImage (); @@ -31,7 +96,6 @@ void CVideo::render () void CVideo::getNextFrame () { - Core::CVideo* videoData = getVideo (); bool eof = false; AVPacket packet; packet.data = nullptr; @@ -42,7 +106,7 @@ void CVideo::getNextFrame () if (packet.data != nullptr) av_packet_unref (&packet); - int readError = av_read_frame (videoData->getFormatContext (), &packet); + int readError = av_read_frame (m_formatCtx, &packet); if (readError == AVERROR_EOF) { eof = true; @@ -54,28 +118,28 @@ void CVideo::getNextFrame () throw std::runtime_error (av_make_error_string (err, AV_ERROR_MAX_STRING_SIZE, readError)); } - } while (packet.stream_index != videoData->getVideoStreamIndex ()); + } while (packet.stream_index != m_videoStream); // Send video stream packet to codec - if (avcodec_send_packet (videoData->getCodecContext (), &packet) < 0) + if (avcodec_send_packet (m_codecCtx, &packet) < 0) return; // Receive frame from codec - if (avcodec_receive_frame (videoData->getCodecContext (), videoData->getVideoFrame ()) < 0) + if (avcodec_receive_frame (m_codecCtx, m_videoFrame) < 0) return; - sws_scale (videoData->getSwsContext (), (uint8_t const* const*)videoData->getVideoFrame ()->data, videoData->getVideoFrame ()->linesize, - 0, videoData->getCodecContext ()->height, videoData->getVideoFrameRGB ()->data, videoData->getVideoFrameRGB ()->linesize); + 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) - videoData->restartStream (); + restartStream (); } void CVideo::writeFrameToImage () { - uint8_t* frameData = getVideo ()->getVideoFrameRGB ()->data[0]; + uint8_t* frameData = m_videoFrameRGB->data[0]; if (frameData == nullptr) return; @@ -87,6 +151,12 @@ void CVideo::writeFrameToImage () 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 (); diff --git a/src/WallpaperEngine/Render/CVideo.h b/src/WallpaperEngine/Render/CVideo.h index 6a9bc2e..77382fc 100644 --- a/src/WallpaperEngine/Render/CVideo.h +++ b/src/WallpaperEngine/Render/CVideo.h @@ -33,9 +33,19 @@ namespace WallpaperEngine::Render 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; };