ffmepg 导入, 视频解码初始化逻辑, 视频解码线程逻辑
This commit is contained in:
parent
1237b164bf
commit
15018f4079
@ -15,12 +15,12 @@ file(GLOB_RECURSE tests ${PROJECT_SOURCE_DIR}/test/*.cc)
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules" ${CMAKE_MODULE_PATH})
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
include(spdlog)
|
||||
include(gtest)
|
||||
enable_testing()
|
||||
|
||||
IF(UNIX)
|
||||
include_directories(/usr/include/x86_64-linux-gnu)
|
||||
find_package(SFML 2.5 COMPONENTS system window graphics network audio REQUIRED)
|
||||
add_executable(${PROJECT_N}
|
||||
main.cc
|
||||
@ -32,7 +32,10 @@ IF(UNIX)
|
||||
sfml-graphics
|
||||
sfml-network
|
||||
sfml-audio
|
||||
|
||||
avcodec
|
||||
avformat
|
||||
vorbis
|
||||
avutil
|
||||
spdlog
|
||||
)
|
||||
|
||||
|
BIN
img/ocean.mp4
Executable file
BIN
img/ocean.mp4
Executable file
Binary file not shown.
@ -3,11 +3,13 @@
|
||||
#include <string>
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <memory>
|
||||
#include "videoService.h"
|
||||
|
||||
class MediaService
|
||||
{
|
||||
private:
|
||||
ImageService *imageService = nullptr;
|
||||
VideoService *videoService = nullptr;
|
||||
MediaType type;
|
||||
std::shared_ptr<sf::Texture> texture;
|
||||
std::shared_ptr<sf::Sprite> sprite;
|
||||
@ -16,7 +18,10 @@ private:
|
||||
int client_height = 0;
|
||||
public:
|
||||
MediaService(const std::string &filename, int width, int height);
|
||||
~MediaService() = default;
|
||||
~MediaService(){
|
||||
delete imageService;
|
||||
delete videoService;
|
||||
}
|
||||
std::shared_ptr<sf::Sprite> GetSprite()
|
||||
{
|
||||
return sprite;
|
||||
|
@ -9,7 +9,8 @@ public:
|
||||
~ThreadQueue() = default;
|
||||
|
||||
void push(const T& value) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
condition_.wait(lock, [this](){ return queue_.size() <= maxSize; });
|
||||
queue_.push(value);
|
||||
condition_.notify_one();
|
||||
}
|
||||
@ -19,6 +20,7 @@ public:
|
||||
condition_.wait(lock, [this] { return !queue_.empty(); });
|
||||
T value = queue_.front();
|
||||
queue_.pop();
|
||||
condition_.notify_one();
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -35,4 +37,5 @@ private:
|
||||
std::queue<T> queue_;
|
||||
mutable std::mutex mutex_;
|
||||
std::condition_variable condition_;
|
||||
unsigned int maxSize = 50;
|
||||
};
|
||||
|
@ -1,11 +1,48 @@
|
||||
#ifndef VIDEOSERVICE_H
|
||||
#define VIDEOSERVICE_H
|
||||
#include "thread_queue.h"
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/avutil.h>
|
||||
}
|
||||
|
||||
void AVFormatContextDeleter(AVFormatContext *context);
|
||||
|
||||
void AVCodecContextDeleter(AVCodecContext *context);
|
||||
class VideoService {
|
||||
private:
|
||||
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;
|
||||
std::string_view filename;
|
||||
std::jthread decodeThread;
|
||||
int videoStreamIndex;
|
||||
int audioStreamIndex;
|
||||
int waitDelay = 50;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
std::stop_source stopSource;
|
||||
|
||||
public:
|
||||
VideoService(std::string_view filename);
|
||||
~VideoService() {
|
||||
if (decodeThread.joinable()) {
|
||||
decodeThread.join();
|
||||
}
|
||||
}
|
||||
void InitContext();
|
||||
void Decode();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
2
main.cc
2
main.cc
@ -16,7 +16,7 @@ constexpr int CLIENT_HEIGHT = 600;
|
||||
int main(int argc, char** argv){
|
||||
spdlog::info("Current WorkDir Is: {}",argv[0]);
|
||||
#ifdef DEBUG
|
||||
argv[1] = R"(../img/ocean.jpg)";
|
||||
argv[1] = R"(../img/ocean.mp4)";
|
||||
#else
|
||||
if(argc != 2){
|
||||
spdlog::error("Usage: mp filename ");
|
||||
|
@ -18,6 +18,8 @@ MediaService::MediaService(const std::string& filename, int width, int height){
|
||||
sprite->setScale(scale, scale);
|
||||
break;
|
||||
case MediaType::VIDEO:
|
||||
videoService = new VideoService(filename);
|
||||
videoService->Decode();
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -37,6 +39,8 @@ void MediaService::Play(){
|
||||
window->draw(*sprite);
|
||||
window->display();
|
||||
break;
|
||||
case MediaType::VIDEO:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -1 +1,70 @@
|
||||
#include "videoService.h"
|
||||
|
||||
void AVFormatContextDeleter(AVFormatContext *context) {
|
||||
if (context) {
|
||||
avformat_close_input(&context);
|
||||
}
|
||||
}
|
||||
|
||||
void AVCodecContextDeleter(AVCodecContext *context) {
|
||||
if (context) {
|
||||
avcodec_free_context(&context);
|
||||
}
|
||||
}
|
||||
|
||||
VideoService::VideoService(std::string_view filename) {
|
||||
this->filename = filename;
|
||||
formatContext =
|
||||
std::unique_ptr<AVFormatContext, decltype(&AVFormatContextDeleter)>(
|
||||
nullptr, AVFormatContextDeleter);
|
||||
codecContext =
|
||||
std::unique_ptr<AVCodecContext, decltype(&AVCodecContextDeleter)>(
|
||||
nullptr, AVCodecContextDeleter);
|
||||
InitContext();
|
||||
}
|
||||
|
||||
void VideoService::InitContext() {
|
||||
AVFormatContext *formatContext = nullptr;
|
||||
AVCodecContext *codecContext = nullptr;
|
||||
auto ret = avformat_open_input(&formatContext, filename.data(), NULL, NULL);
|
||||
avformat_find_stream_info(formatContext, nullptr);
|
||||
for (int i = 0; i < formatContext->nb_streams; i++) {
|
||||
const auto stream = formatContext->streams[i];
|
||||
const auto codec = avcodec_find_decoder(stream->codecpar->codec_id);
|
||||
if (codec->type == AVMEDIA_TYPE_VIDEO) {
|
||||
videoStreamIndex = i;
|
||||
codecContext = avcodec_alloc_context3(codec);
|
||||
this->codecContext.reset(codecContext);
|
||||
avcodec_parameters_to_context(codecContext, stream->codecpar);
|
||||
avcodec_open2(codecContext, codec, nullptr);
|
||||
this->height = codecContext->height;
|
||||
this->width = codecContext->width;
|
||||
} else if (codec->type == AVMEDIA_TYPE_AUDIO) {
|
||||
audioStreamIndex = i;
|
||||
}
|
||||
}
|
||||
this->formatContext.reset(formatContext);
|
||||
}
|
||||
|
||||
void VideoService::Decode() {
|
||||
const auto &fmtCtx = formatContext.get();
|
||||
AVPacket *packet = av_packet_alloc();
|
||||
decodeThread = 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);
|
||||
} else if (packet->stream_index == this->audioStreamIndex) {
|
||||
auto temp = av_packet_alloc();
|
||||
av_packet_ref(temp, packet);
|
||||
this->packetQueue.push(temp);
|
||||
}
|
||||
} else if (ret == AVERROR_EOF) {
|
||||
return;
|
||||
}
|
||||
av_packet_unref(packet);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user