Loading...
Searching...
No Matches
FrameQueue.hpp
1#pragma once
2#include <Media/Libav.hpp>
3
4#if SCORE_HAS_LIBAV
5#include <Video/VideoInterface.hpp>
6
7#include <ossia/detail/lockfree_queue.hpp>
8
9#include <score_plugin_media_export.h>
10
11#if defined(SCORE_LIBAV_FRAME_DEBUGGING)
12#include <mutex>
13#define BOOST_STACKTRACE_USE_BACKTRACE 1
14#include <boost/stacktrace.hpp>
15#endif
16
17#include <atomic>
18#include <vector>
19
20extern "C" {
21#include <libavutil/frame.h>
22}
23namespace Video
24{
25
26#if defined(SCORE_LIBAV_FRAME_DEBUGGING)
27inline struct frame_counters
28{
29 std::mutex mtx;
30 struct fc
31 {
32 AVFrame* frame{};
33 boost::stacktrace::stacktrace st;
34 };
35 std::vector<fc> allocated;
36 void allocate(AVFrame*);
37 void deallocate(AVFrame*);
38} frame_counts;
39#define SCORE_LIBAV_FRAME_ALLOC_CHECK(f) frame_counts.allocate(f)
40#define SCORE_LIBAV_FRAME_DEALLOC_CHECK(f) frame_counts.deallocate(f)
41#else
42#define SCORE_LIBAV_FRAME_ALLOC_CHECK(f) \
43 do \
44 { \
45 } while(0)
46#define SCORE_LIBAV_FRAME_DEALLOC_CHECK(f) \
47 do \
48 { \
49 } while(0)
50#endif
51
52struct SCORE_PLUGIN_MEDIA_EXPORT FrameQueue
53{
54public:
55 FrameQueue();
57
58 FrameQueue(const FrameQueue&) = delete;
59 FrameQueue(FrameQueue&&) = delete;
60 FrameQueue& operator=(const FrameQueue&) = delete;
61 FrameQueue& operator=(FrameQueue&&) = delete;
62
63 AVFramePointer newFrame() noexcept;
64
65 void enqueue_decoding_error(AVFrame* f);
66 void enqueue(AVFrame* f);
67 AVFrame* dequeue() noexcept;
68 AVFrame* dequeue_one() noexcept;
69 AVFrame* discard_and_dequeue() noexcept;
70 AVFrame* discard_and_dequeue_one() noexcept;
71
79 void set_discard_before(int64_t pts) noexcept;
80 void release(AVFrame* frame) noexcept;
81
84 int start_generation() noexcept { return ++m_generation; }
85 void drain();
86
87 std::size_t size() const noexcept { return available.size_approx(); }
88
92 void watch(AVFrame* f) noexcept { m_watched = f; }
93 AVFrame* watched() const noexcept { return m_watched; }
94
95private:
96 AVFramePointer newFrameImpl() noexcept;
97
98 ossia::mpmc_queue<AVFrame*> available;
99 ossia::mpmc_queue<AVFrame*> released;
100
102 struct Discard
103 {
104 int64_t pts{};
105 int generation{};
106 uint32_t sequence{};
107 };
108 bool pendingDiscard(Discard& d) const noexcept;
109 static bool before(const AVFrame& f, const Discard& d) noexcept;
110 template <typename Dequeue>
111 AVFrame* dequeueDiscarding(const Dequeue& dequeue) noexcept;
112
113 std::vector<AVFrame*> m_decodeThreadFrameBuffer;
114 AVFrame* m_watched{};
115 // A sequence lock around the marker: odd while the decoding thread writes
116 // it; a marker is pending while its sequence is not the one the consumer
117 // last finished.
118 std::atomic<uint32_t> m_discardSequence{};
119 std::atomic<int64_t> m_discardPts{};
120 std::atomic_int m_discardGeneration{};
121 std::atomic<uint32_t> m_discardDone{};
122 std::atomic_int m_generation{};
123};
124
126inline int frameGeneration(const AVFrame& f) noexcept
127{
128 return int(reinterpret_cast<intptr_t>(f.opaque));
129}
130
131SCORE_PLUGIN_MEDIA_EXPORT
132uint8_t* initFrameBuffer(AVFrame& frame, std::size_t bytes);
133
134}
135#endif
Definition FrameQueue.hpp:53
int start_generation() noexcept
Definition FrameQueue.hpp:84
void watch(AVFrame *f) noexcept
Definition FrameQueue.hpp:92