diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index a3572bbcd418cd80f35deac01bbfe288c5f5739e..4039befa763ea9b9104bb7231baabe0a159a5215 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -3,9 +3,7 @@ { "name": "Linux", "includePath": [ - "${default}", - "/home/feng/FFmpeg/include", - "/home/femg/project/ffmpeg/ffmpeg-c-thread/include" + "${workspaceFolder}/**" ], "defines": [], "compilerPath": "/usr/bin/gcc", diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 6437b0db643484b925b375f7802e3514c394199e..0000000000000000000000000000000000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "files.associations": { - "*.md": "markdown", - "condition_variable": "cpp" - } -} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 795471d564f83a1806f7c2efa963f2be283d7c3a..0000000000000000000000000000000000000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -cmake_minimum_required(VERSION 3.24) -project(ffmpeg_c) - -set(CMAKE_CXX_STANDARD 17) -find_package(PkgConfig REQUIRED) -pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET - libavdevice - libavfilter - libavformat - libavcodec - libswresample - libswscale - libavutil -) - -include_directories(/home/feng/project/ffmpeg/ffmpeg-c-thread/include) -include_directories( /home/feng/FFmpeg/include) -add_executable(ffmpeg_c main.cpp src/demux_thread.cpp src/packet_queue.cpp src/frame_queue.cpp) - -target_link_libraries(ffmpeg_c PkgConfig::LIBAV) diff --git a/build/ffmpeg_c b/build/ffmpeg_c deleted file mode 100755 index 37015b8c421ea26accd6ade35355bf1391b939f0..0000000000000000000000000000000000000000 Binary files a/build/ffmpeg_c and /dev/null differ diff --git a/include/decode_thread.h b/include/decode_thread.h index d41e234844884778ae97c7c0f78fe8bc93e79494..927ddd3ee782051c0b69e3e3f2a9c7215d1fb2b6 100644 --- a/include/decode_thread.h +++ b/include/decode_thread.h @@ -1,10 +1,10 @@ #ifndef FFMPEG_DECODE_THREAD_H #define FFMPEG_DECODE_THREAD_H #include "frame_queue.h" +#include "libavutil/frame.h" #include "log.h" #include "packet_queue.h" #include "thread" -#include "libavutil/frame.h" extern "C" { #include "libavcodec/avcodec.h" diff --git a/include/demux_thread.h b/include/demux_thread.h index 0b10ba239714908cea45686595dd9cdf328d4844..593e58ddbfacf79f94cd8be58deec4bf0d8bb0d4 100644 --- a/include/demux_thread.h +++ b/include/demux_thread.h @@ -1,7 +1,7 @@ #ifndef FFMPEG_DEMUX_THREAD_H #define FFMPEG_DEMUX_THREAD_H #include "log.h" -#include "packet_queue.h" +#include "queue.h" #include "thread" extern "C" { #include "libavformat/avformat.h" @@ -9,7 +9,7 @@ extern "C" { class DemuxThread { public: - DemuxThread(std::string inFile, PacketQueue* packetQ); + DemuxThread(std::string inFile, Queue* packetQ); ~DemuxThread(); int Init(); // 初始化操作 int Start(); // 启动线程 @@ -22,7 +22,7 @@ public: private: std::thread* thread_ = nullptr; // 线程 - PacketQueue* packetQ_; // 存放解封装后的队列 + Queue* packetQ_; // 存放解封装后的队列 AVFormatContext* iFmtCtx_ = nullptr; // 解封装格式上下文 int videoStreamIndex_ = -1; // 视频流索引 char err_[256] = { 0 }; // 打印错误信息 diff --git a/include/frame_queue.h b/include/frame_queue.h index 1bb4b26a3315ed5e115d4e9e61b567c5a937e8df..f96ca7666b4d735190ea7e9b6387fa3d7c74c7e5 100644 --- a/include/frame_queue.h +++ b/include/frame_queue.h @@ -1,16 +1,15 @@ #ifndef FFMPEG_FRAME_QUEUE_H #define FFMPEG_FRAME_QUEUE_H -#include "log.h" #include "queue.h" extern "C" { #include "libavcodec/avcodec.h" } + class FrameQueue : public Queue { public: - FrameQueue(int max); - ~FrameQueue(); - int Init(); - void Push(AVFrame* frame); + int Init(int max) override; + void Push(AVFrame* pkt) override; + void Pop(AVFrame*& pkt) override; }; #endif \ No newline at end of file diff --git a/include/packet_queue.h b/include/packet_queue.h index cc40f2a7f9ee0e1d97c94b05b06f80bb01789e79..b3492bbc77bc18918f90af87dda4e358eca66988 100644 --- a/include/packet_queue.h +++ b/include/packet_queue.h @@ -1,17 +1,11 @@ #ifndef FFMPEG_PACKET_QUEUE_H #define FFMPEG_PACKET_QUEUE_H -#include "log.h" #include "queue.h" -extern "C" { -#include "libavcodec/avcodec.h" -} - class PacketQueue : public Queue { public: - PacketQueue(int max); - ~PacketQueue(); - // 重写Init() - int Init() override; + int Init(int max) override; void Push(AVPacket* pkt) override; + void Pop(AVPacket*& pkt) override; }; + #endif \ No newline at end of file diff --git a/include/queue.h b/include/queue.h index ab128ae451bcb940f8745219052376d127741169..65a0afd6afc3eaf1f45d782994935f1819f85562 100644 --- a/include/queue.h +++ b/include/queue.h @@ -1,18 +1,22 @@ #ifndef FFMPEG_QUEUE_H #define FFMPEG_QUEUE_H +#include "log.h" #include #include #include -#include "log.h" #include +extern "C" { +#include "libavcodec/avcodec.h" +} template class Queue { public: Queue(); - virtual int Init() = 0; // 分配空间,由实现类进行完成 - virtual void Push(T val) = 0; // 子类实现push操作, + ~Queue(); + virtual int Init(int max) = 0; // 分配空间,由实现类进行完成 + virtual void Push(T val) = 0; + virtual void Pop(T& val) = 0; int size(); - T& Pop(); bool isEmpty(); public: @@ -34,28 +38,19 @@ inline Queue::Queue() } template -inline int Queue::size() +inline Queue::~Queue() { - std::unique_lock lock(mtx_); - return size_; + max_ = 0; + front_ = 0; + rear_ = 0; + queue_.resize(0); } template -inline T& Queue::Pop() +inline int Queue::size() { std::unique_lock lock(mtx_); - if (size_ == 0) { - // 表示队列是空的,等待唤醒 - cond_.wait(lock, [this] { - return size_ != 0; - }); - } - T& t = queue_[front_]; - LOGI("front_ == %d",front_); - front_ = (front_ + 1) % max_; // 出队位置重新指定 - size_--; - cond_.notify_one(); - return t; + return size_; } template diff --git a/include/swscale_thread.h b/include/swscale_thread.h new file mode 100644 index 0000000000000000000000000000000000000000..6e6bbbec368cae752aad6ad6a3ef482ce7ba3728 --- /dev/null +++ b/include/swscale_thread.h @@ -0,0 +1,15 @@ +#ifndef FFMPEG_SWSCALE_THREAD_H + +#define FFMPEG_SWSCALE_THREAD_H + +class SwscaleThread { + SwscaleThread(); + ~SwscaleThread(); + int Init(); // 初始化操作 + int Start(); // 启动线程 + void Stop(); // 停止线程 + void Run(); // 具体线程执行的操作 + bool isStop(); // 线程是否停止 +}; + +#endif \ No newline at end of file diff --git a/main.cpp b/main.cpp index 0f3d803dcb578cd1c8c0b856ed40ffdb261d3f56..ff054c0952644f03f876a798bba83570ad7616d0 100644 --- a/main.cpp +++ b/main.cpp @@ -1,14 +1,24 @@ +#include "decode_thread.h" #include "demux_thread.h" +#include "frame_queue.h" #include "log.h" #include "packet_queue.h" +extern "C" { +#include "libavcodec/avcodec.h" +} int main() { - PacketQueue* packetQ = new PacketQueue(10); + PacketQueue* packetQ = new PacketQueue(); + packetQ->Init(10); // 为队列分配内存 std::string inFile = "/home/feng/project/ffmpeg/out.mp4"; DemuxThread* d = new DemuxThread(inFile, packetQ); d->Init(); d->Start(); - + FrameQueue* frameQ = new FrameQueue(); + frameQ->Init(10); + DecodeThread* decode = new DecodeThread(packetQ, frameQ, 0); + decode->Init(d->GetVideoParams()); + decode->Start(); getchar(); } \ No newline at end of file diff --git a/src/decode_thread.cpp b/src/decode_thread.cpp index 0f69a0162f5666293caa699e2e9f38478635302c..617f81b75ec441353641e9ebbbb90d5586a3d132 100644 --- a/src/decode_thread.cpp +++ b/src/decode_thread.cpp @@ -75,10 +75,13 @@ void DecodeThread::Stop() void DecodeThread::Run() { AVFrame* frame = av_frame_alloc(); + AVPacket* packet = av_packet_alloc(); + AVFrame* t = av_frame_alloc(); LOGI("decode thread run start"); int ret = 0, count = 0; while (!isStop()) { - AVPacket* packet = decodedPacketQueue_->Pop(); + // 队列中拿一个 + decodedPacketQueue_->Pop(packet); if (packet) { // LOGI("111"); ret = avcodec_send_packet(decodeCodecCtx_, packet); @@ -90,7 +93,6 @@ void DecodeThread::Run() } // 读取解码后的数据帧frame while (ret >= 0) { - LOGI("111"); ret = avcodec_receive_frame(decodeCodecCtx_, frame); if (AVERROR(EAGAIN) == ret || ret == AVERROR_EOF) { // 表示还有帧要进行读取 break; @@ -99,16 +101,13 @@ void DecodeThread::Run() av_strerror(ret, err_, sizeof(err_)); LOGE("avcodec_receive_frame failed %s", err_); break; - }else{ + } else { decodedFrameQueue_->Push(frame); LOGI("解码帧数 %d", ++count); -// // 测试: -// AVFrame * t = decodedFrameQueue_->Pop(); -// av_frame_unref(t); // 释放掉这个 - break; - + // 这里需要释放帧,才能继续解码 + decodedFrameQueue_->Pop(t); + av_frame_unref(t); } - } if (packet->stream_index == 5) { // 表示可以到了末尾了,可以停止线程了 @@ -117,10 +116,10 @@ void DecodeThread::Run() Stop(); break; } -// av_frame_unref(frame); - av_packet_unref(packet); // 需要彻底释放packet队列中的packet + av_packet_unref(packet); } } + av_packet_free(&packet); av_frame_free(&frame); } diff --git a/src/demux_thread.cpp b/src/demux_thread.cpp index b3dd54de15b796e56a2f944368532aaf8275771f..c4b4534122b6934c39e10461209e4bbd89298e5d 100644 --- a/src/demux_thread.cpp +++ b/src/demux_thread.cpp @@ -1,6 +1,6 @@ #include "demux_thread.h" -DemuxThread::DemuxThread(std::string inFile, PacketQueue* packetQ) +DemuxThread::DemuxThread(std::string inFile, Queue* packetQ) : inFile_(inFile) , packetQ_(packetQ) { @@ -72,6 +72,7 @@ void DemuxThread::Run() int ret = 0; AVPacket* packet = av_packet_alloc(); AVPacket* tmp = nullptr; + AVPacket* t = av_packet_alloc(); int count = 0; while (!isStop()) { ret = av_read_frame(iFmtCtx_, packet); @@ -100,9 +101,9 @@ void DemuxThread::Run() // 放入队列 packetQ_->Push(packet); LOGI("decodePacektQueue 插入:%d", ++count); -// // 测试使用 出队列 -// AVPacket * t = packetQ_->Pop(); -// av_packet_unref(t); + // 测试使用 出队列 + // packetQ_->Pop(t); + // av_packet_unref(t); } else { // 释放其他非视频流的packet av_packet_unref(packet); diff --git a/src/frame_queue.cpp b/src/frame_queue.cpp index 6cc00a981da25e0c50ceee394b735ef305a5671c..c9dba138141b24846a05fb56ece3352c60f3e3a3 100644 --- a/src/frame_queue.cpp +++ b/src/frame_queue.cpp @@ -1,41 +1,51 @@ #include "frame_queue.h" -int FrameQueue::Init() +int FrameQueue::Init(int max) { + max_ = max; queue_.resize(max_); for (int i = 0; i < max_; i++) { - AVFrame* frame = av_frame_alloc(); - if (!frame) { - LOGE("frame queue init: av_frame_alloc failed"); + AVFrame* packet = av_frame_alloc(); + if (!packet) { + // 表示分配内存失败,释放所有的资源 + for (int i = 0; i < max_; i++) { + if (queue_[i]) { + av_frame_free(&queue_[i]); + } + } return -1; } - queue_[i] = frame; + queue_[i] = packet; } return 0; } -FrameQueue::FrameQueue(int max) -{ - max_ = max; - Init(); -} - void FrameQueue::Push(AVFrame* frame) { std::unique_lock lock(mtx_); if (size_ == max_) { cond_.wait(lock, [this] { - return !size_ == max_; + return size_ != max_; }); } av_frame_move_ref(queue_[rear_], frame); - rear_ = (rear_ + 1) % max_; size_++; + rear_ = (rear_ + 1) % max_; cond_.notify_one(); } -FrameQueue::~FrameQueue() +void FrameQueue::Pop(AVFrame*& frame) { - // 调用父类的析构函数 - Queue::~Queue(); + std::unique_lock lock(mtx_); + if (size_ == 0) { + // 表示队列是空的,等待唤醒 + cond_.wait(lock, [this] { + return size_ != 0; + }); + } + // 这里会将queue中的数据的引用置为0,因此无需调用unref + av_frame_move_ref(frame, queue_[front_]); + front_ = (front_ + 1) % max_; // 出队位置重新指定 + size_--; + cond_.notify_one(); } diff --git a/src/packet_queue.cpp b/src/packet_queue.cpp index e3f9f67d0c8fcd2a911c3e75f67a73451fe33175..c79e61d62f74877283218eec2b24c6d128f40b98 100644 --- a/src/packet_queue.cpp +++ b/src/packet_queue.cpp @@ -1,34 +1,18 @@ #include "packet_queue.h" -PacketQueue::PacketQueue(int max) +int PacketQueue::Init(int max) { - LOGI("init start"); max_ = max; - // 进行Init - Init(); - LOGI("init finshed"); -} - -PacketQueue::~PacketQueue() -{ - // 调用父类的析构函数 - Queue::~Queue(); -} - -int PacketQueue::Init() -{ queue_.resize(max_); for (int i = 0; i < max_; i++) { AVPacket* packet = av_packet_alloc(); if (!packet) { - // 释放已经分配的内存 + // 表示分配内存失败,释放所有的资源 for (int i = 0; i < max_; i++) { if (queue_[i]) { av_packet_free(&queue_[i]); - queue_[i] = nullptr; } } - LOGE("packet queue init: av_packet_alloc failed"); return -1; } queue_[i] = packet; @@ -38,17 +22,30 @@ int PacketQueue::Init() void PacketQueue::Push(AVPacket* pkt) { - // 上锁 std::unique_lock lock(mtx_); - // 如果满了就等待 if (size_ == max_) { cond_.wait(lock, [this] { return !(size_ == max_); }); } - // 插入, 这里不进行流的类型判断 av_packet_move_ref(queue_[rear_], pkt); - rear_ = (rear_ + 1) % max_; size_++; + rear_ = (rear_ + 1) % max_; + cond_.notify_one(); +} + +void PacketQueue::Pop(AVPacket*& pkt) +{ + std::unique_lock lock(mtx_); + if (size_ == 0) { + // 表示队列是空的,等待唤醒 + cond_.wait(lock, [this] { + return size_ != 0; + }); + } + // 这里会将queue中的数据的引用置为0,因此无需调用unref + av_packet_move_ref(pkt, queue_[front_]); + front_ = (front_ + 1) % max_; // 出队位置重新指定 + size_--; cond_.notify_one(); } diff --git a/src/swscale_thread.cpp b/src/swscale_thread.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7ec0d81b515b8859c46933c11c10b41cdc865a70 --- /dev/null +++ b/src/swscale_thread.cpp @@ -0,0 +1 @@ +#include "swscale_thread.h" \ No newline at end of file