From e36520b31050853725fd85fe688a4cc3eb2c9890 Mon Sep 17 00:00:00 2001 From: Jie Date: Tue, 8 Oct 2024 14:34:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=92=AD=E6=94=BE=E9=80=BB=E8=BE=91=E6=9A=82?= =?UTF-8?q?=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 33 -------------------- .vscode/settings.json | 1 + .vscode/tasks.json | 28 ----------------- CMakeLists.txt | 1 + include/mediaService.h | 32 +++++++++---------- include/videoService.h | 27 +++++++++++----- main.cc | 70 +++++++++++++++++++++--------------------- src/mediaService.cc | 29 +++++++++-------- src/videoService.cc | 70 ++++++++++++++++++++++++++++++++++++++++-- test/util_test.cc | 7 ++--- 10 files changed, 153 insertions(+), 145 deletions(-) delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/tasks.json diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 9060489..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - // 使用 IntelliSense 了解相关属性。 - // 悬停以查看现有属性的描述。 - // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "(gdb) Launch", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/build/mp", - "args": ["${workspaceFolder}/img/ocean.jpg"], - "stopAtEntry": false, - "cwd": "${fileDirname}", - "environment": [], - "externalConsole": false, - "MIMode": "gdb", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - }, - { - "description": "Set Disassembly Flavor to Intel", - "text": "-gdb-set disassembly-flavor intel", - "ignoreFailures": true - } - ] - } - - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 0abcd66..fe0556e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ { + "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", "files.associations": { "*.cpp": "cpp", "cctype": "cpp", diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 05054c5..0000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "tasks": [ - { - "type": "cppbuild", - "label": "C/C++: g++ build active file", - "command": "/usr/bin/g++", - "args": [ - "-fdiagnostics-color=always", - "-g", - "${file}", - "-o", - "${fileDirname}/${fileBasenameNoExtension}" - ], - "options": { - "cwd": "${fileDirname}" - }, - "problemMatcher": [ - "$gcc" - ], - "group": { - "kind": "build", - "isDefault": true - }, - "detail": "Task generated by Debugger." - } - ], - "version": "2.0.0" -} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index cc4360a..33d16ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,7 @@ IF(UNIX) vorbis avutil spdlog + swscale ) add_executable(${PROJECT_N_T} diff --git a/include/mediaService.h b/include/mediaService.h index 474ff37..05e958d 100644 --- a/include/mediaService.h +++ b/include/mediaService.h @@ -1,13 +1,12 @@ -#include -#include -#include -#include -#include #include "videoService.h" +#include +#include +#include +#include +#include -class MediaService -{ -private: +class MediaService { + private: ImageService *imageService = nullptr; VideoService *videoService = nullptr; MediaType type; @@ -15,18 +14,15 @@ private: std::shared_ptr sprite; std::shared_ptr window; int client_width = 0; - int client_height = 0; -public: - MediaService(const std::string &filename, int width, int height); - ~MediaService(){ + int client_height = 0; + + public: + MediaService(std::shared_ptr window, + const std::string &filename, int width, int height); + ~MediaService() { delete imageService; delete videoService; } - std::shared_ptr GetSprite() - { - return sprite; - } - void SetWindow(std::shared_ptr window); + std::shared_ptr GetSprite() { return sprite; } void Play(); - }; diff --git a/include/videoService.h b/include/videoService.h index bcc8335..3f9e92c 100644 --- a/include/videoService.h +++ b/include/videoService.h @@ -10,6 +10,8 @@ extern "C" { #include #include #include +#include +#include } void AVFormatContextDeleter(AVFormatContext *context); @@ -17,32 +19,41 @@ void AVFormatContextDeleter(AVFormatContext *context); void AVCodecContextDeleter(AVCodecContext *context); class VideoService { private: - std::shared_ptr texture; std::unique_ptr> formatContext; std::unique_ptr> codecContext; - ThreadQueue packetQueue; - ThreadQueue frameQueue; - ThreadQueue audioQueue; + ThreadQueue packetQueue; + ThreadQueue frameQueue; + ThreadQueue audioQueue; std::string_view filename; - std::jthread decodeThread; + std::jthread decodePacketThread; + std::jthread decodeFrameThread; int videoStreamIndex; int audioStreamIndex; int waitDelay = 50; unsigned int width; unsigned int height; std::stop_source stopSource; + std::shared_ptr window; + std::unique_ptr sprite; + std::unique_ptr texture; + public: - VideoService(std::string_view filename); + VideoService(std::string_view filename, std::shared_ptr window); ~VideoService() { - if (decodeThread.joinable()) { - decodeThread.join(); + if (decodePacketThread.joinable()) { + decodePacketThread.join(); + } + if (decodeFrameThread.joinable()) { + decodeFrameThread.join(); } } void InitContext(); void Decode(); + void PaintFrame(); + void Play(); }; #endif diff --git a/main.cc b/main.cc index f2d6b23..450e72d 100644 --- a/main.cc +++ b/main.cc @@ -1,47 +1,47 @@ -#include -#include -#include -#include -#include -#include #include "UtilTool.h" #include "mediaService.h" +#include +#include +#include +#include +#include +#include -#define DEBUG +#define DEBUG constexpr int CLIENT_WIDTH = 800; constexpr int CLIENT_HEIGHT = 600; - -int main(int argc, char** argv){ - spdlog::info("Current WorkDir Is: {}",argv[0]); +int main(int argc, char **argv) { + spdlog::info("Current WorkDir Is: {}", argv[0]); #ifdef DEBUG - argv[1] = R"(../img/ocean.mp4)"; + argv[1] = R"(../img/ocean.mp4)"; #else - if(argc != 2){ - spdlog::error("Usage: mp filename "); - return 0; - } + if (argc != 2) { + spdlog::error("Usage: mp filename "); + return 0; + } #endif - spdlog::info("filename: {}", argv[1]); - MediaService mediaService(argv[1], CLIENT_WIDTH, CLIENT_HEIGHT); - std::shared_ptr window = std::make_shared(sf::VideoMode(CLIENT_WIDTH, CLIENT_HEIGHT), "mp"); - mediaService.SetWindow(window); - bool running = true; + spdlog::info("filename: {}", argv[1]); + std::shared_ptr window = + std::make_shared( + sf::VideoMode(CLIENT_WIDTH, CLIENT_HEIGHT), "mp"); + MediaService mediaService(window, argv[1], CLIENT_WIDTH, CLIENT_HEIGHT); + bool running = true; - while(running){ - sf::Event event; - while(window->pollEvent(event)){ - if(event.type == sf::Event::Closed){ - running = false; - } - if(event.type == sf::Event::KeyPressed){ - if(event.key.code == sf::Keyboard::Escape){ - running = false; - } - } - } - mediaService.Play(); - } - return 0; + while (running) { + sf::Event event; + while (window->pollEvent(event)) { + if (event.type == sf::Event::Closed) { + running = false; + } + if (event.type == sf::Event::KeyPressed) { + if (event.key.code == sf::Keyboard::Escape) { + running = false; + } + } + } + mediaService.Play(); + } + return 0; } diff --git a/src/mediaService.cc b/src/mediaService.cc index be6821f..5ebdb45 100644 --- a/src/mediaService.cc +++ b/src/mediaService.cc @@ -2,13 +2,14 @@ #include #include -MediaService::MediaService(const std::string& filename, int width, int height){ +MediaService::MediaService(std::shared_ptr window, + const std::string &filename, int width, int height) { type = UtilTool::CheckFileType(filename); client_width = width; client_height = height; float scale = .0f; - switch (type) - { + this->window = window; + switch (type) { case MediaType::IMAGE: imageService = new ImageService(filename); texture = imageService->GetTexture(); @@ -17,31 +18,29 @@ MediaService::MediaService(const std::string& filename, int width, int height){ scale = imageService->GetScale(client_width, client_height); sprite->setScale(scale, scale); break; - case MediaType::VIDEO: - videoService = new VideoService(filename); + case MediaType::VIDEO: + texture = std::make_shared(); + sprite = std::make_shared(); + videoService = new VideoService(filename, window); videoService->Decode(); - break; - + break; + default: break; } } -void MediaService::SetWindow(std::shared_ptr window){ - this->window = window; -} - -void MediaService::Play(){ - switch (type) - { +void MediaService::Play() { + switch (type) { case MediaType::IMAGE: window->clear(); window->draw(*sprite); window->display(); break; case MediaType::VIDEO: + videoService->Play(); break; - + default: break; } diff --git a/src/videoService.cc b/src/videoService.cc index 51c89d7..ad71632 100644 --- a/src/videoService.cc +++ b/src/videoService.cc @@ -1,4 +1,7 @@ #include "videoService.h" +#include +#include +using namespace std::literals::chrono_literals; void AVFormatContextDeleter(AVFormatContext *context) { if (context) { @@ -12,14 +15,18 @@ void AVCodecContextDeleter(AVCodecContext *context) { } } -VideoService::VideoService(std::string_view filename) { +VideoService::VideoService(std::string_view filename, + std::shared_ptr window) { this->filename = filename; + this->window = window; formatContext = std::unique_ptr( nullptr, AVFormatContextDeleter); codecContext = std::unique_ptr( nullptr, AVCodecContextDeleter); + sprite = std::make_unique(); + texture = std::make_unique(); InitContext(); } @@ -49,17 +56,20 @@ void VideoService::InitContext() { void VideoService::Decode() { const auto &fmtCtx = formatContext.get(); AVPacket *packet = av_packet_alloc(); - decodeThread = std::jthread([this, fmtCtx, packet]() { + decodePacketThread = std::jthread([this, fmtCtx, packet]() { while (!stopSource.get_token().stop_requested()) { if (auto ret = av_read_frame(fmtCtx, packet); ret == 0) { if (packet->stream_index == this->videoStreamIndex) { auto temp = av_packet_alloc(); av_packet_ref(temp, packet); this->packetQueue.push(temp); + spdlog::info("packetQueueSize: {}", packetQueue.size()); + } else if (packet->stream_index == this->audioStreamIndex) { auto temp = av_packet_alloc(); av_packet_ref(temp, packet); - this->packetQueue.push(temp); + this->audioQueue.push(temp); + spdlog::info("audioQueueSize: {}", audioQueue.size()); } } else if (ret == AVERROR_EOF) { return; @@ -67,4 +77,58 @@ void VideoService::Decode() { av_packet_unref(packet); } }); + + decodeFrameThread = std::jthread([this]() { + while (!stopSource.get_token().stop_requested()) { + auto packet = packetQueue.pop(); + auto ret = avcodec_send_packet(codecContext.get(), packet); + if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) { + av_packet_unref(packet); + continue; + } + auto frame = av_frame_alloc(); + ret = avcodec_receive_frame(codecContext.get(), frame); + if (ret < 0 && ret != AVERROR_EOF) { + av_packet_unref(packet); + continue; + } + frameQueue.push(frame); + spdlog::info("frameQueueSize: {}", frameQueue.size()); + av_packet_unref(packet); + } + }); } + +void VideoService::PaintFrame() { + auto frame = frameQueue.pop(); + SwsContext *context = sws_getContext( + frame->width, frame->height, static_cast(frame->format), + frame->width, frame->height, AV_PIX_FMT_RGBA, SWS_BILINEAR, nullptr, + nullptr, nullptr); + if (!context) { + spdlog::error("Failed to create swsContext"); + return; + } + + std::vector buffer(frame->height * frame->width * 4); + AVFrame *rgbaFrame = av_frame_alloc(); + av_image_fill_arrays(rgbaFrame->data, rgbaFrame->linesize, buffer.data(), + AV_PIX_FMT_RGBA, frame->width, frame->height, 1); + sws_scale(context, frame->data, frame->linesize, 0, frame->height, + rgbaFrame->data, rgbaFrame->linesize); + sf::Image image; + image.create(frame->width, frame->height, buffer.data()); + texture->loadFromImage(image); + av_frame_unref(frame); + sws_freeContext(context); +} + +void VideoService::Play() { + while (!stopSource.get_token().stop_requested()) { + PaintFrame(); + window->clear(); + sprite->setTexture(*(texture.get())); + window->draw(*(sprite.get())); + std::this_thread::sleep_for(41ms); + } +} \ No newline at end of file diff --git a/test/util_test.cc b/test/util_test.cc index 9a06b7a..6a0738a 100644 --- a/test/util_test.cc +++ b/test/util_test.cc @@ -1,10 +1,7 @@ -#include #include "UtilTool.h" +#include "gtest/gtest.h" #include -TEST(UtilTest, CheckIsImage) -{ +TEST(UtilTest, CheckIsImage) { EXPECT_TRUE(UtilTool::CheckFileType("file.jpg") == MediaType::IMAGE); } - -