Loading...
Searching...
No Matches
VideoCaptureStrategy.hpp
Go to the documentation of this file.
1#pragma once
2
25#include <atomic>
26#include <cstddef>
27#include <cstdint>
28
29class QRhi;
30class QRhiTexture;
31class QRhiResourceUpdateBatch;
32class QRhiCommandBuffer;
33
34namespace score::gfx
35{
36struct RenderState;
37}
38
39namespace score::gfx::interop
40{
41
43{
44 QRhi* rhi{};
45 const score::gfx::RenderState* state{};
46
49 std::uint32_t frameByteSize{};
50
51 int width{};
52 int height{};
53
62 QRhiTexture* outputTexture{};
63
71 std::vector<QRhiTexture*> planes{};
72};
73
84{
85 virtual ~VideoCaptureStrategy() = default;
86
89 virtual const char* name() const noexcept = 0;
90
91 virtual bool init(const VideoCaptureStrategyConfig& cfg) = 0;
92 virtual void release() = 0;
93
97 virtual std::size_t slotCount() const noexcept = 0;
98
104 virtual void* slotBuffer(std::size_t i) const noexcept = 0;
105
109 virtual bool ingestFrame(std::size_t i) = 0;
110
113 virtual QRhiTexture* outputTexture() const noexcept = 0;
114
122 virtual QRhiTexture* currentTexture() const noexcept { return outputTexture(); }
123
131 virtual std::size_t outputPlaneCount() const noexcept { return 1; }
132
135 virtual QRhiTexture* outputPlane(std::size_t i) const noexcept
136 {
137 return i == 0 ? outputTexture() : nullptr;
138 }
139
141 virtual QRhiTexture* currentPlane(std::size_t i) const noexcept
142 {
143 return i == 0 ? currentTexture() : outputPlane(i);
144 }
145
149 virtual void acquireForRender() = 0;
150 virtual void releaseAfterRender() = 0;
151
159 virtual void acquireForRender(QRhiResourceUpdateBatch&) { acquireForRender(); }
160
165 virtual void acquireForRender(QRhiResourceUpdateBatch& res, QRhiCommandBuffer*)
166 {
167 acquireForRender(res);
168 }
169
182 virtual bool
183 acquireSlotForRender(std::size_t, QRhiResourceUpdateBatch&, QRhiCommandBuffer*)
184 {
185 return false;
186 }
187
191 virtual bool supportsSlotSelection() const noexcept { return false; }
192};
193
210{
211 std::atomic<std::uint64_t> latestFrameId{0};
212 std::atomic<std::size_t> latestSlot{0};
213
214 // Live input-format channel. The capture thread publishes a newly detected
215 // wire geometry and bumps formatGeneration; the render thread polls it beside
216 // latestFrameId and reallocates its size-dependent GPU resources. Read via a
217 // seqlock: capture writes the fields then bumps the generation (even = stable,
218 // odd = mid-write); the render side reads the generation, the fields, then
219 // re-reads the generation and retries on mismatch.
220 std::atomic<std::uint64_t> formatGeneration{0};
221 std::atomic<std::int32_t> detectedWidth{0};
222 std::atomic<std::int32_t> detectedHeight{0};
223 std::atomic<std::int32_t> detectedPixelFormat{-1}; // AVPixelFormat; -1 = unset
224 std::atomic<double> detectedRate{0.0};
225
226 // Capture-thread side: publish a detected format change. No-op if the
227 // geometry is unchanged, so a per-frame poll can call it unconditionally.
228 bool publishFormat(int w, int h, int pixfmt, double rate) noexcept
229 {
230 if(w == detectedWidth.load(std::memory_order_relaxed)
231 && h == detectedHeight.load(std::memory_order_relaxed)
232 && pixfmt == detectedPixelFormat.load(std::memory_order_relaxed))
233 return false;
234 const auto g = formatGeneration.load(std::memory_order_relaxed);
235 formatGeneration.store(g + 1, std::memory_order_release); // odd: mid-write
236 detectedWidth.store(w, std::memory_order_relaxed);
237 detectedHeight.store(h, std::memory_order_relaxed);
238 detectedPixelFormat.store(pixfmt, std::memory_order_relaxed);
239 detectedRate.store(rate, std::memory_order_relaxed);
240 formatGeneration.store(g + 2, std::memory_order_release); // even: stable
241 return true;
242 }
243
245 {
246 std::uint64_t generation{0};
247 int width{0}, height{0}, pixfmt{-1};
248 double rate{0.0};
249 };
250
251 // Render-thread side: consistent snapshot of the latest published format.
252 DetectedFormat loadFormat() const noexcept
253 {
255 for(;;)
256 {
257 const auto g0 = formatGeneration.load(std::memory_order_acquire);
258 if(g0 & 1u)
259 continue; // writer mid-update
260 f.width = detectedWidth.load(std::memory_order_relaxed);
261 f.height = detectedHeight.load(std::memory_order_relaxed);
262 f.pixfmt = detectedPixelFormat.load(std::memory_order_relaxed);
263 f.rate = detectedRate.load(std::memory_order_relaxed);
264 std::atomic_thread_fence(std::memory_order_acquire);
265 if(formatGeneration.load(std::memory_order_relaxed) == g0)
266 {
267 f.generation = g0;
268 return f;
269 }
270 }
271 }
272};
273
274} // namespace score::gfx::interop
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:11
STL namespace.
Global state associated to a rendering context.
Definition RenderState.hpp:37
Definition VideoCaptureStrategy.hpp:245
Lock-free SPSC handoff between the capture thread and the renderer. Capture thread bumps latestFrameI...
Definition VideoCaptureStrategy.hpp:210
Definition VideoCaptureStrategy.hpp:43
std::vector< QRhiTexture * > planes
Definition VideoCaptureStrategy.hpp:71
QRhiTexture * outputTexture
Definition VideoCaptureStrategy.hpp:62
std::uint32_t frameByteSize
Definition VideoCaptureStrategy.hpp:49
Per-graphics-API strategy for getting a captured video frame into a GPU QRhiTexture without CPU stagi...
Definition VideoCaptureStrategy.hpp:84
virtual void * slotBuffer(std::size_t i) const noexcept=0
virtual std::size_t outputPlaneCount() const noexcept
Definition VideoCaptureStrategy.hpp:131
virtual QRhiTexture * outputTexture() const noexcept=0
virtual bool acquireSlotForRender(std::size_t, QRhiResourceUpdateBatch &, QRhiCommandBuffer *)
Definition VideoCaptureStrategy.hpp:183
virtual bool ingestFrame(std::size_t i)=0
virtual void acquireForRender(QRhiResourceUpdateBatch &)
Definition VideoCaptureStrategy.hpp:159
virtual bool supportsSlotSelection() const noexcept
Definition VideoCaptureStrategy.hpp:191
virtual void acquireForRender(QRhiResourceUpdateBatch &res, QRhiCommandBuffer *)
Definition VideoCaptureStrategy.hpp:165
virtual const char * name() const noexcept=0
virtual QRhiTexture * currentPlane(std::size_t i) const noexcept
Freshest completed plane i, the per-plane twin of currentTexture().
Definition VideoCaptureStrategy.hpp:141
virtual std::size_t slotCount() const noexcept=0
virtual QRhiTexture * outputPlane(std::size_t i) const noexcept
Definition VideoCaptureStrategy.hpp:135
virtual QRhiTexture * currentTexture() const noexcept
Definition VideoCaptureStrategy.hpp:122