合并
This commit is contained in:
commit
0f94cbaa9f
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,2 +1,5 @@
|
|||||||
/build/
|
/build/
|
||||||
.cache/
|
.cache/
|
||||||
|
/enc_temp_folder
|
||||||
|
/out/build/x64-Debug
|
||||||
|
/.vs
|
||||||
|
33
.vscode/launch.json
vendored
33
.vscode/launch.json
vendored
@ -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
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
]
|
|
||||||
}
|
|
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"*.cpp": "cpp",
|
"*.cpp": "cpp",
|
||||||
"cctype": "cpp",
|
"cctype": "cpp",
|
||||||
|
28
.vscode/tasks.json
vendored
28
.vscode/tasks.json
vendored
@ -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"
|
|
||||||
}
|
|
@ -37,6 +37,7 @@ IF(UNIX)
|
|||||||
vorbis
|
vorbis
|
||||||
avutil
|
avutil
|
||||||
spdlog
|
spdlog
|
||||||
|
swscale
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(${PROJECT_N_T}
|
add_executable(${PROJECT_N_T}
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
#include <imageService.h>
|
|
||||||
#include <UtilTool.h>
|
|
||||||
#include <string>
|
|
||||||
#include <SFML/Graphics.hpp>
|
|
||||||
#include <memory>
|
|
||||||
#include "videoService.h"
|
#include "videoService.h"
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
#include <UtilTool.h>
|
||||||
|
#include <imageService.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
class MediaService
|
class MediaService {
|
||||||
{
|
private:
|
||||||
private:
|
|
||||||
ImageService *imageService = nullptr;
|
ImageService *imageService = nullptr;
|
||||||
VideoService *videoService = nullptr;
|
VideoService *videoService = nullptr;
|
||||||
MediaType type;
|
MediaType type;
|
||||||
@ -15,18 +14,15 @@ private:
|
|||||||
std::shared_ptr<sf::Sprite> sprite;
|
std::shared_ptr<sf::Sprite> sprite;
|
||||||
std::shared_ptr<sf::RenderWindow> window;
|
std::shared_ptr<sf::RenderWindow> window;
|
||||||
int client_width = 0;
|
int client_width = 0;
|
||||||
int client_height = 0;
|
int client_height = 0;
|
||||||
public:
|
|
||||||
MediaService(const std::string &filename, int width, int height);
|
public:
|
||||||
~MediaService(){
|
MediaService(std::shared_ptr<sf::RenderWindow> window,
|
||||||
|
const std::string &filename, int width, int height);
|
||||||
|
~MediaService() {
|
||||||
delete imageService;
|
delete imageService;
|
||||||
delete videoService;
|
delete videoService;
|
||||||
}
|
}
|
||||||
std::shared_ptr<sf::Sprite> GetSprite()
|
std::shared_ptr<sf::Sprite> GetSprite() { return sprite; }
|
||||||
{
|
|
||||||
return sprite;
|
|
||||||
}
|
|
||||||
void SetWindow(std::shared_ptr<sf::RenderWindow> window);
|
|
||||||
void Play();
|
void Play();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -10,6 +10,8 @@ extern "C" {
|
|||||||
#include <libavcodec/avcodec.h>
|
#include <libavcodec/avcodec.h>
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
#include <libavutil/avutil.h>
|
#include <libavutil/avutil.h>
|
||||||
|
#include <libavutil/imgutils.h>
|
||||||
|
#include <libswscale/swscale.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
void AVFormatContextDeleter(AVFormatContext *context);
|
void AVFormatContextDeleter(AVFormatContext *context);
|
||||||
@ -17,32 +19,41 @@ void AVFormatContextDeleter(AVFormatContext *context);
|
|||||||
void AVCodecContextDeleter(AVCodecContext *context);
|
void AVCodecContextDeleter(AVCodecContext *context);
|
||||||
class VideoService {
|
class VideoService {
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<sf::Texture> texture;
|
|
||||||
std::unique_ptr<AVFormatContext, std::function<void(AVFormatContext *)>>
|
std::unique_ptr<AVFormatContext, std::function<void(AVFormatContext *)>>
|
||||||
formatContext;
|
formatContext;
|
||||||
std::unique_ptr<AVCodecContext, std::function<void(AVCodecContext *)>>
|
std::unique_ptr<AVCodecContext, std::function<void(AVCodecContext *)>>
|
||||||
codecContext;
|
codecContext;
|
||||||
ThreadQueue<AVPacket*> packetQueue;
|
ThreadQueue<AVPacket *> packetQueue;
|
||||||
ThreadQueue<AVFrame*> frameQueue;
|
ThreadQueue<AVFrame *> frameQueue;
|
||||||
ThreadQueue<AVPacket*> audioQueue;
|
ThreadQueue<AVPacket *> audioQueue;
|
||||||
std::string_view filename;
|
std::string_view filename;
|
||||||
std::jthread decodeThread;
|
std::jthread decodePacketThread;
|
||||||
|
std::jthread decodeFrameThread;
|
||||||
int videoStreamIndex;
|
int videoStreamIndex;
|
||||||
int audioStreamIndex;
|
int audioStreamIndex;
|
||||||
int waitDelay = 50;
|
int waitDelay = 50;
|
||||||
unsigned int width;
|
unsigned int width;
|
||||||
unsigned int height;
|
unsigned int height;
|
||||||
std::stop_source stopSource;
|
std::stop_source stopSource;
|
||||||
|
std::shared_ptr<sf::RenderWindow> window;
|
||||||
|
std::unique_ptr<sf::Sprite> sprite;
|
||||||
|
std::unique_ptr<sf::Texture> texture;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VideoService(std::string_view filename);
|
VideoService(std::string_view filename, std::shared_ptr<sf::RenderWindow> window);
|
||||||
~VideoService() {
|
~VideoService() {
|
||||||
if (decodeThread.joinable()) {
|
if (decodePacketThread.joinable()) {
|
||||||
decodeThread.join();
|
decodePacketThread.join();
|
||||||
|
}
|
||||||
|
if (decodeFrameThread.joinable()) {
|
||||||
|
decodeFrameThread.join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void InitContext();
|
void InitContext();
|
||||||
void Decode();
|
void Decode();
|
||||||
|
void PaintFrame();
|
||||||
|
void Play();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
8
main.cc
8
main.cc
@ -1,8 +1,10 @@
|
|||||||
#include <SFML/Graphics/RenderWindow.hpp>
|
#include "UtilTool.h"
|
||||||
#include <cstdio>
|
#include "mediaService.h"
|
||||||
#include <SFML/System.hpp>
|
|
||||||
#include <SFML/Graphics.hpp>
|
#include <SFML/Graphics.hpp>
|
||||||
|
#include <SFML/Graphics/RenderWindow.hpp>
|
||||||
|
#include <SFML/System.hpp>
|
||||||
#include <SFML/Window.hpp>
|
#include <SFML/Window.hpp>
|
||||||
|
#include <cstdio>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
#include "UtilTool.h"
|
#include "UtilTool.h"
|
||||||
#include "mediaService.h"
|
#include "mediaService.h"
|
||||||
|
@ -2,13 +2,14 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <videoService.h>
|
#include <videoService.h>
|
||||||
|
|
||||||
MediaService::MediaService(const std::string& filename, int width, int height){
|
MediaService::MediaService(std::shared_ptr<sf::RenderWindow> window,
|
||||||
|
const std::string &filename, int width, int height) {
|
||||||
type = UtilTool::CheckFileType(filename);
|
type = UtilTool::CheckFileType(filename);
|
||||||
client_width = width;
|
client_width = width;
|
||||||
client_height = height;
|
client_height = height;
|
||||||
float scale = .0f;
|
float scale = .0f;
|
||||||
switch (type)
|
this->window = window;
|
||||||
{
|
switch (type) {
|
||||||
case MediaType::IMAGE:
|
case MediaType::IMAGE:
|
||||||
imageService = new ImageService(filename);
|
imageService = new ImageService(filename);
|
||||||
texture = imageService->GetTexture();
|
texture = imageService->GetTexture();
|
||||||
@ -17,31 +18,29 @@ MediaService::MediaService(const std::string& filename, int width, int height){
|
|||||||
scale = imageService->GetScale(client_width, client_height);
|
scale = imageService->GetScale(client_width, client_height);
|
||||||
sprite->setScale(scale, scale);
|
sprite->setScale(scale, scale);
|
||||||
break;
|
break;
|
||||||
case MediaType::VIDEO:
|
case MediaType::VIDEO:
|
||||||
videoService = new VideoService(filename);
|
texture = std::make_shared<sf::Texture>();
|
||||||
|
sprite = std::make_shared<sf::Sprite>();
|
||||||
|
videoService = new VideoService(filename, window);
|
||||||
videoService->Decode();
|
videoService->Decode();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaService::SetWindow(std::shared_ptr<sf::RenderWindow> window){
|
void MediaService::Play() {
|
||||||
this->window = window;
|
switch (type) {
|
||||||
}
|
|
||||||
|
|
||||||
void MediaService::Play(){
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case MediaType::IMAGE:
|
case MediaType::IMAGE:
|
||||||
window->clear();
|
window->clear();
|
||||||
window->draw(*sprite);
|
window->draw(*sprite);
|
||||||
window->display();
|
window->display();
|
||||||
break;
|
break;
|
||||||
case MediaType::VIDEO:
|
case MediaType::VIDEO:
|
||||||
|
videoService->Play();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
#include "videoService.h"
|
#include "videoService.h"
|
||||||
|
#include <chrono>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
using namespace std::literals::chrono_literals;
|
||||||
|
|
||||||
void AVFormatContextDeleter(AVFormatContext *context) {
|
void AVFormatContextDeleter(AVFormatContext *context) {
|
||||||
if (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<sf::RenderWindow> window) {
|
||||||
this->filename = filename;
|
this->filename = filename;
|
||||||
|
this->window = window;
|
||||||
formatContext =
|
formatContext =
|
||||||
std::unique_ptr<AVFormatContext, decltype(&AVFormatContextDeleter)>(
|
std::unique_ptr<AVFormatContext, decltype(&AVFormatContextDeleter)>(
|
||||||
nullptr, AVFormatContextDeleter);
|
nullptr, AVFormatContextDeleter);
|
||||||
codecContext =
|
codecContext =
|
||||||
std::unique_ptr<AVCodecContext, decltype(&AVCodecContextDeleter)>(
|
std::unique_ptr<AVCodecContext, decltype(&AVCodecContextDeleter)>(
|
||||||
nullptr, AVCodecContextDeleter);
|
nullptr, AVCodecContextDeleter);
|
||||||
|
sprite = std::make_unique<sf::Sprite>();
|
||||||
|
texture = std::make_unique<sf::Texture>();
|
||||||
InitContext();
|
InitContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,17 +56,20 @@ void VideoService::InitContext() {
|
|||||||
void VideoService::Decode() {
|
void VideoService::Decode() {
|
||||||
const auto &fmtCtx = formatContext.get();
|
const auto &fmtCtx = formatContext.get();
|
||||||
AVPacket *packet = av_packet_alloc();
|
AVPacket *packet = av_packet_alloc();
|
||||||
decodeThread = std::jthread([this, fmtCtx, packet]() {
|
decodePacketThread = std::jthread([this, fmtCtx, packet]() {
|
||||||
while (!stopSource.get_token().stop_requested()) {
|
while (!stopSource.get_token().stop_requested()) {
|
||||||
if (auto ret = av_read_frame(fmtCtx, packet); ret == 0) {
|
if (auto ret = av_read_frame(fmtCtx, packet); ret == 0) {
|
||||||
if (packet->stream_index == this->videoStreamIndex) {
|
if (packet->stream_index == this->videoStreamIndex) {
|
||||||
auto temp = av_packet_alloc();
|
auto temp = av_packet_alloc();
|
||||||
av_packet_ref(temp, packet);
|
av_packet_ref(temp, packet);
|
||||||
this->packetQueue.push(temp);
|
this->packetQueue.push(temp);
|
||||||
|
spdlog::info("packetQueueSize: {}", packetQueue.size());
|
||||||
|
|
||||||
} else if (packet->stream_index == this->audioStreamIndex) {
|
} else if (packet->stream_index == this->audioStreamIndex) {
|
||||||
auto temp = av_packet_alloc();
|
auto temp = av_packet_alloc();
|
||||||
av_packet_ref(temp, packet);
|
av_packet_ref(temp, packet);
|
||||||
this->packetQueue.push(temp);
|
this->audioQueue.push(temp);
|
||||||
|
spdlog::info("audioQueueSize: {}", audioQueue.size());
|
||||||
}
|
}
|
||||||
} else if (ret == AVERROR_EOF) {
|
} else if (ret == AVERROR_EOF) {
|
||||||
return;
|
return;
|
||||||
@ -67,4 +77,58 @@ void VideoService::Decode() {
|
|||||||
av_packet_unref(packet);
|
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<AVPixelFormat>(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<uint8_t> 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);
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,7 @@
|
|||||||
#include <gtest/gtest.h>
|
|
||||||
#include "UtilTool.h"
|
#include "UtilTool.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
TEST(UtilTest, CheckIsImage)
|
TEST(UtilTest, CheckIsImage) {
|
||||||
{
|
|
||||||
EXPECT_TRUE(UtilTool::CheckFileType("file.jpg") == MediaType::IMAGE);
|
EXPECT_TRUE(UtilTool::CheckFileType("file.jpg") == MediaType::IMAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user