合并
This commit is contained in:
commit
0f94cbaa9f
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,2 +1,5 @@
|
||||
/build/
|
||||
.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": {
|
||||
"*.cpp": "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
|
||||
avutil
|
||||
spdlog
|
||||
swscale
|
||||
)
|
||||
|
||||
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 <SFML/Graphics.hpp>
|
||||
#include <UtilTool.h>
|
||||
#include <imageService.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class MediaService
|
||||
{
|
||||
private:
|
||||
class MediaService {
|
||||
private:
|
||||
ImageService *imageService = nullptr;
|
||||
VideoService *videoService = nullptr;
|
||||
MediaType type;
|
||||
@ -16,17 +15,14 @@ private:
|
||||
std::shared_ptr<sf::RenderWindow> window;
|
||||
int client_width = 0;
|
||||
int client_height = 0;
|
||||
public:
|
||||
MediaService(const std::string &filename, int width, int height);
|
||||
~MediaService(){
|
||||
|
||||
public:
|
||||
MediaService(std::shared_ptr<sf::RenderWindow> window,
|
||||
const std::string &filename, int width, int height);
|
||||
~MediaService() {
|
||||
delete imageService;
|
||||
delete videoService;
|
||||
}
|
||||
std::shared_ptr<sf::Sprite> GetSprite()
|
||||
{
|
||||
return sprite;
|
||||
}
|
||||
void SetWindow(std::shared_ptr<sf::RenderWindow> window);
|
||||
std::shared_ptr<sf::Sprite> GetSprite() { return sprite; }
|
||||
void Play();
|
||||
|
||||
};
|
||||
|
@ -10,6 +10,8 @@ extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/avutil.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libswscale/swscale.h>
|
||||
}
|
||||
|
||||
void AVFormatContextDeleter(AVFormatContext *context);
|
||||
@ -17,32 +19,41 @@ void AVFormatContextDeleter(AVFormatContext *context);
|
||||
void AVCodecContextDeleter(AVCodecContext *context);
|
||||
class VideoService {
|
||||
private:
|
||||
std::shared_ptr<sf::Texture> texture;
|
||||
std::unique_ptr<AVFormatContext, std::function<void(AVFormatContext *)>>
|
||||
formatContext;
|
||||
std::unique_ptr<AVCodecContext, std::function<void(AVCodecContext *)>>
|
||||
codecContext;
|
||||
ThreadQueue<AVPacket*> packetQueue;
|
||||
ThreadQueue<AVFrame*> frameQueue;
|
||||
ThreadQueue<AVPacket*> audioQueue;
|
||||
ThreadQueue<AVPacket *> packetQueue;
|
||||
ThreadQueue<AVFrame *> frameQueue;
|
||||
ThreadQueue<AVPacket *> 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<sf::RenderWindow> window;
|
||||
std::unique_ptr<sf::Sprite> sprite;
|
||||
std::unique_ptr<sf::Texture> texture;
|
||||
|
||||
|
||||
public:
|
||||
VideoService(std::string_view filename);
|
||||
VideoService(std::string_view filename, std::shared_ptr<sf::RenderWindow> 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
|
||||
|
8
main.cc
8
main.cc
@ -1,8 +1,10 @@
|
||||
#include <SFML/Graphics/RenderWindow.hpp>
|
||||
#include <cstdio>
|
||||
#include <SFML/System.hpp>
|
||||
#include "UtilTool.h"
|
||||
#include "mediaService.h"
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <SFML/Graphics/RenderWindow.hpp>
|
||||
#include <SFML/System.hpp>
|
||||
#include <SFML/Window.hpp>
|
||||
#include <cstdio>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include "UtilTool.h"
|
||||
#include "mediaService.h"
|
||||
|
@ -2,13 +2,14 @@
|
||||
#include <memory>
|
||||
#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);
|
||||
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();
|
||||
@ -18,7 +19,9 @@ MediaService::MediaService(const std::string& filename, int width, int height){
|
||||
sprite->setScale(scale, scale);
|
||||
break;
|
||||
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();
|
||||
break;
|
||||
|
||||
@ -27,19 +30,15 @@ MediaService::MediaService(const std::string& filename, int width, int height){
|
||||
}
|
||||
}
|
||||
|
||||
void MediaService::SetWindow(std::shared_ptr<sf::RenderWindow> 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:
|
||||
|
@ -1,4 +1,7 @@
|
||||
#include "videoService.h"
|
||||
#include <chrono>
|
||||
#include <spdlog/spdlog.h>
|
||||
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<sf::RenderWindow> window) {
|
||||
this->filename = filename;
|
||||
this->window = window;
|
||||
formatContext =
|
||||
std::unique_ptr<AVFormatContext, decltype(&AVFormatContextDeleter)>(
|
||||
nullptr, AVFormatContextDeleter);
|
||||
codecContext =
|
||||
std::unique_ptr<AVCodecContext, decltype(&AVCodecContextDeleter)>(
|
||||
nullptr, AVCodecContextDeleter);
|
||||
sprite = std::make_unique<sf::Sprite>();
|
||||
texture = std::make_unique<sf::Texture>();
|
||||
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<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 "gtest/gtest.h"
|
||||
#include <iostream>
|
||||
|
||||
TEST(UtilTest, CheckIsImage)
|
||||
{
|
||||
TEST(UtilTest, CheckIsImage) {
|
||||
EXPECT_TRUE(UtilTool::CheckFileType("file.jpg") == MediaType::IMAGE);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user