From 795fe94d5630bb5b165f342142f66db736d6e509 Mon Sep 17 00:00:00 2001 From: xufuji456 Date: Fri, 23 Sep 2022 18:33:25 +0800 Subject: [PATCH] Feature: add PacketQueue and FrameQueue --- app/src/main/cpp/CMakeLists.txt | 5 + app/src/main/cpp/ffplayer/ffplay_define.h | 12 ++ .../main/cpp/ffplayer/queue/FrameQueue.cpp | 93 ++++++++++++ app/src/main/cpp/ffplayer/queue/FrameQueue.h | 66 ++++++++ .../main/cpp/ffplayer/queue/PacketQueue.cpp | 142 ++++++++++++++++++ app/src/main/cpp/ffplayer/queue/PacketQueue.h | 62 ++++++++ 6 files changed, 380 insertions(+) create mode 100644 app/src/main/cpp/ffplayer/ffplay_define.h create mode 100644 app/src/main/cpp/ffplayer/queue/FrameQueue.cpp create mode 100644 app/src/main/cpp/ffplayer/queue/FrameQueue.h create mode 100644 app/src/main/cpp/ffplayer/queue/PacketQueue.cpp create mode 100644 app/src/main/cpp/ffplayer/queue/PacketQueue.h diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 0a326bd..df9afa8 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -32,6 +32,10 @@ set(SRC_METADATA metadata/metadata_util.c metadata/ffmpeg_media_retriever.c) +set(SRC_FFPLAYER + ffplayer/queue/FrameQueue.cpp + ffplayer/queue/PacketQueue.cpp) + add_library( # Sets the name of the library. media-handle @@ -42,6 +46,7 @@ add_library( # Sets the name of the library. ${SRC_FFMPEG} ${SRC_VISUALIZER} ${SRC_METADATA} + ${SRC_FFPLAYER} video_player.cpp video_filter.c ffprobe_cmd.cpp diff --git a/app/src/main/cpp/ffplayer/ffplay_define.h b/app/src/main/cpp/ffplayer/ffplay_define.h new file mode 100644 index 0000000..f66cfe8 --- /dev/null +++ b/app/src/main/cpp/ffplayer/ffplay_define.h @@ -0,0 +1,12 @@ +// +// Created by xu fulong on 2022/9/22. +// + +#ifndef FFMPEGANDROID_FFPLAY_DEFINE_H +#define FFMPEGANDROID_FFPLAY_DEFINE_H + +#define PACKET_QUEUE_SIZE 16 + +#define FRAME_QUEUE_SIZE 16 + +#endif //FFMPEGANDROID_FFPLAY_DEFINE_H diff --git a/app/src/main/cpp/ffplayer/queue/FrameQueue.cpp b/app/src/main/cpp/ffplayer/queue/FrameQueue.cpp new file mode 100644 index 0000000..75b1ee1 --- /dev/null +++ b/app/src/main/cpp/ffplayer/queue/FrameQueue.cpp @@ -0,0 +1,93 @@ + +#include "FrameQueue.h" + +FrameQueue::FrameQueue(int max_size, int keep_last):m_size(0), + m_show_idx(0), + m_read_idx(0), + m_write_idx(0), + m_keep_last(keep_last), + m_abort_request(0) { + m_max_size = FFMIN(max_size, FRAME_QUEUE_SIZE); + memset(m_queue, 0, sizeof(Frame) * FRAME_QUEUE_SIZE); + + for (int i = 0; i < this->m_max_size; ++i) { + m_queue[i].frame = av_frame_alloc(); + } +} + +void FrameQueue::start() { + std::lock_guard lock(m_mutex); + m_abort_request = 0; +} + +void FrameQueue::abort() { + std::lock_guard lock(m_mutex); + m_abort_request = 1; +} + +Frame *FrameQueue::currentFrame() { + return &m_queue[(m_read_idx + m_show_idx) % m_max_size]; +} + +Frame *FrameQueue::nextFrame() { + return &m_queue[(m_read_idx + m_show_idx + 1) % m_max_size]; +} + +Frame *FrameQueue::lastFrame() { + return &m_queue[m_read_idx]; +} + +Frame *FrameQueue::peekWritable() { + if (m_abort_request) { + return nullptr; + } + + return &m_queue[m_write_idx]; +} + +void FrameQueue::pushFrame() { + std::unique_lock lock(m_mutex); + if (++m_write_idx == m_max_size) { + m_write_idx = 0; + } + m_size++; +} + +void FrameQueue::popFrame() { + std::unique_lock lock(m_mutex); + if (m_keep_last && !m_show_idx) { + m_show_idx = 1; + return; + } + unrefFrame(&m_queue[m_read_idx]); + if (++m_read_idx == m_max_size) { + m_read_idx = 0; + } + m_size--; +} + +void FrameQueue::flush() { + while (getFrameSize() > 0) { + popFrame(); + } +} + +int FrameQueue::getFrameSize() { + return m_size - m_show_idx; +} + +int FrameQueue::getShowIndex() const { + return m_show_idx; +} + +void FrameQueue::unrefFrame(Frame *vp) { + av_frame_unref(vp->frame); +} + +FrameQueue::~FrameQueue() { + for (int i = 0; i < m_max_size; ++i) { + Frame *vp = &m_queue[i]; + unrefFrame(vp); + av_frame_free(&vp->frame); + } +} \ No newline at end of file diff --git a/app/src/main/cpp/ffplayer/queue/FrameQueue.h b/app/src/main/cpp/ffplayer/queue/FrameQueue.h new file mode 100644 index 0000000..f93a972 --- /dev/null +++ b/app/src/main/cpp/ffplayer/queue/FrameQueue.h @@ -0,0 +1,66 @@ + +#ifndef FFMPEGANDROID_FRAMEQUEUE_H +#define FFMPEGANDROID_FRAMEQUEUE_H + +#include +#include "ffplayer/ffplay_define.h" + +extern "C" { +#include "libavcodec/avcodec.h" +} + +typedef struct Frame { + double pts; + int width; + int height; + int format; + AVFrame *frame; + double duration; +} Frame; + +class FrameQueue { + +private: + std::mutex m_mutex; + int m_abort_request; + int m_read_idx; + int m_write_idx; + int m_size; + int m_max_size; + int m_keep_last; + int m_show_idx; + Frame m_queue[FRAME_QUEUE_SIZE]; + + void unrefFrame(Frame *vp); + +public: + FrameQueue(int max_size, int keep_last); + + virtual ~FrameQueue(); + + void start(); + + void abort(); + + Frame *currentFrame(); + + Frame *nextFrame(); + + Frame *lastFrame(); + + Frame *peekWritable(); + + void pushFrame(); + + void popFrame(); + + void flush(); + + int getFrameSize(); + + int getShowIndex() const; + +}; + + +#endif //FFMPEGANDROID_FRAMEQUEUE_H diff --git a/app/src/main/cpp/ffplayer/queue/PacketQueue.cpp b/app/src/main/cpp/ffplayer/queue/PacketQueue.cpp new file mode 100644 index 0000000..b1d9db1 --- /dev/null +++ b/app/src/main/cpp/ffplayer/queue/PacketQueue.cpp @@ -0,0 +1,142 @@ + +#include "PacketQueue.h" + +PacketQueue::PacketQueue():m_size(0), + m_duration(0), + m_nb_packets(0), + m_abort_request(0), + last_pkt_list(nullptr), + first_pkt_list(nullptr) { +} + +int PacketQueue::put(AVPacket *pkt) { + PacketList *pkt1; + + if (m_abort_request) { + return -1; + } + + pkt1 = (PacketList *) av_malloc(sizeof(PacketList)); + if (!pkt1) { + return -1; + } + pkt1->pkt = *pkt; + pkt1->next = nullptr; + + if (!last_pkt_list) { + first_pkt_list = pkt1; + } else { + last_pkt_list->next = pkt1; + } + + m_nb_packets++; + last_pkt_list = pkt1; + m_size += pkt1->pkt.size + sizeof(*pkt1); + m_duration += pkt1->pkt.duration; + return 0; +} + +int PacketQueue::pushPacket(AVPacket *pkt) { + std::unique_lock lock(m_mutex); + int ret = put(pkt); + if (ret < 0) { + av_packet_unref(pkt); + } + m_cond.notify_all(); + + return ret; +} + +int PacketQueue::pushEmptyPacket(int stream_idx) { + AVPacket pkt1; + AVPacket*pkt = &pkt1; + av_init_packet(pkt); + + pkt->size = 0; + pkt->data = nullptr; + pkt->stream_index = stream_idx; + + return pushPacket(pkt); +} + +int PacketQueue::popPacket(AVPacket *pkt) { + std::unique_lock lock(m_mutex); + int ret; + PacketList *pkt1; + + for (;;) { + if (m_abort_request) { + ret = -1; + break; + } + + pkt1 = first_pkt_list; + if (pkt1) { + first_pkt_list = pkt1->next; + if (!first_pkt_list) { + last_pkt_list = nullptr; + } + m_nb_packets--; + m_size -= pkt1->pkt.size + sizeof(*pkt1); + m_duration -= pkt1->pkt.duration; + *pkt = pkt1->pkt; + av_free(pkt1); + ret = 1; + break; + } else { + m_cond.wait(lock); + } + } + return ret; +} + +void PacketQueue::flush() { + std::unique_lock lock(m_mutex); + PacketList *pkt, *pkt1; + + for (pkt = first_pkt_list; pkt; pkt = pkt1) { + pkt1 = pkt->next; + av_packet_unref(&pkt->pkt); + av_freep(&pkt); + } + + m_size = 0; + m_duration = 0; + m_nb_packets = 0; + last_pkt_list = nullptr; + first_pkt_list = nullptr; + m_cond.notify_all(); +} + +void PacketQueue::start() { + std::lock_guard lock(m_mutex); + m_abort_request = 0; +} + +void PacketQueue::abort() { + std::lock_guard lock(m_mutex); + m_abort_request = 1; +} + +int PacketQueue::getSize() { + std::lock_guard lock(m_mutex); + return m_size; +} + +int PacketQueue::getPacketSize() { + std::lock_guard lock(m_mutex); + return m_nb_packets; +} + +int64_t PacketQueue::getDuration() { + return m_duration; +} + +int PacketQueue::isAbortRequest() { + return m_abort_request; +} + +PacketQueue::~PacketQueue() { + abort(); + flush(); +} \ No newline at end of file diff --git a/app/src/main/cpp/ffplayer/queue/PacketQueue.h b/app/src/main/cpp/ffplayer/queue/PacketQueue.h new file mode 100644 index 0000000..23973cf --- /dev/null +++ b/app/src/main/cpp/ffplayer/queue/PacketQueue.h @@ -0,0 +1,62 @@ + +#ifndef FFMPEGANDROID_PACKETQUEUE_H +#define FFMPEGANDROID_PACKETQUEUE_H + + +#include +#include + +extern "C" { +#include +} + +typedef struct PacketList { + AVPacket pkt; + struct PacketList *next; +} PacketList; + +class PacketQueue { + +private: + std::mutex m_mutex; + std::condition_variable m_cond; + + int m_size; + int m_nb_packets; + int64_t m_duration; + int m_abort_request; + PacketList *first_pkt_list; + PacketList *last_pkt_list; + + int put(AVPacket *pkt); + +public: + + PacketQueue(); + + int pushPacket(AVPacket *pkt); + + int pushEmptyPacket(int stream_idx); + + int popPacket(AVPacket *pkt); + + void flush(); + + void start(); + + void abort(); + + int getSize(); + + int getPacketSize(); + + int64_t getDuration(); + + int isAbortRequest(); + + virtual ~PacketQueue(); + +}; + + +#endif //FFMPEGANDROID_PACKETQUEUE_H