11#include <promeki/config.h>
12#if PROMEKI_ENABLE_V4L2
31typedef struct _snd_pcm snd_pcm_t;
33PROMEKI_NAMESPACE_BEGIN
131class V4l2MediaIO :
public DedicatedThreadMediaIO {
132 PROMEKI_OBJECT(V4l2MediaIO, DedicatedThreadMediaIO)
135 static inline const MediaIOStats::ID StatsCaptured{
"V4l2Captured"};
137 static inline const MediaIOStats::ID StatsAlsaOverruns{
"V4l2AlsaOverruns"};
140 V4l2MediaIO(ObjectBase *parent =
nullptr);
143 ~V4l2MediaIO()
override;
156 int instanceID()
const {
return _instanceId; }
159 static PixelFormat::ID v4l2ToPixelFormat(uint32_t v4l2fmt);
162 static uint32_t pixelFormatToV4l2(PixelFormat::ID pd);
165 Error executeCmd(MediaIOCommandOpen &cmd)
override;
166 Error executeCmd(MediaIOCommandClose &cmd)
override;
167 Error executeCmd(MediaIOCommandRead &cmd)
override;
168 Error executeCmd(MediaIOCommandStats &cmd)
override;
174 void cancelBlockingWork()
override;
191 Error openVideo(
const MediaIO::Config &cfg);
192 Error startStreaming();
193 void stopStreaming();
197 Error openAudio(
const MediaIO::Config &cfg);
202 void videoCaptureLoop();
203 void audioCaptureLoop();
207 void *start =
nullptr;
211 List<MmapBuffer> _buffers;
212 bool _streaming =
false;
213 ImageDesc _imageDesc;
216 snd_pcm_t *_pcm =
nullptr;
217 AudioDesc _audioDesc;
218 bool _audioEnabled =
false;
221 Atomic<bool> _stopFlag{
false};
222 Atomic<int> _deviceError{0};
231 Atomic<bool> _readCancelled{
false};
232 BasicThread _videoThread;
233 BasicThread _audioThread;
237 static constexpr int VideoQueueDepth = 2;
238 Queue<VideoPayload::Ptr> _videoQueue;
247 AudioBuffer _audioRing;
250 Atomic<int64_t> _framesCaptured{0};
251 Atomic<int64_t> _alsaOverruns{0};
254 PeriodicCallback _debugReport;
255 int64_t _ringAccum = 0;
256 int64_t _ringAccumFrames = 0;
257 double _ringAvgBaseline = 0.0;
258 TimeStamp _ringBaselineTime;
259 bool _ringBaselineSet =
false;
262 TimeStamp _lastCaptureTime;
263 TimeStamp _firstCaptureTime;
264 int64_t _firstCaptureFrame = -1;
265 double _frameDeltaSum = 0.0;
266 double _frameDeltaSqSum = 0.0;
267 int64_t _frameDeltaCount = 0;
268 double _prevPeriodFps = 0.0;
271 bool _ringOverflowWarned =
false;
290 Atomic<uint32_t> _lastVbufSequence{0};
291 Atomic<int64_t> _kernelDroppedPeriod{0};
292 Atomic<int64_t> _loopIterationsPeriod{0};
293 Atomic<int64_t> _loopTimeSumUsPeriod{0};
294 Atomic<int64_t> _loopTimeMaxUsPeriod{0};
295 Atomic<int64_t> _dqbufLagSumUsPeriod{0};
296 Atomic<int64_t> _dqbufLagMaxUsPeriod{0};
297 Atomic<int64_t> _dqbufLagCountPeriod{0};
304 Atomic<int64_t> _timestampSubstitutedPeriod{0};
306 bool _seqInitialized =
false;
307 int64_t _prevIterUs = 0;
310 FrameRate _frameRate;
311 FrameCount _frameCount{0};
318class V4l2Factory :
public MediaIOFactory {
320 V4l2Factory() =
default;
322 String name()
const override {
return String(
"V4L2"); }
323 String displayName()
const override {
return String(
"V4L2 Capture"); }
324 String description()
const override {
325 return String(
"V4L2 video capture with optional ALSA audio (Linux)");
328 bool canBeSource()
const override {
return true; }
330 bool canHandlePath(
const String &path)
const override;
331 StringList enumerate()
const override;
332 Config::SpecMap configSpecs()
const override;
333 List<MediaDesc> queryDevice(
const Config &config)
const override;
334 void printDeviceInfo(
const Config &config)
const override;
336 MediaIO *create(
const Config &config, ObjectBase *parent =
nullptr)
const override;