OpenShot Library | libopenshot 1.1.1
Loading...
Searching...
No Matches
CameraCaptureV4L2.h
Go to the documentation of this file.
1// Copyright (c) 2008-2026 OpenShot Studios, LLC
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
4#ifndef OPENSHOT_CAMERA_CAPTURE_V4L2_H
5#define OPENSHOT_CAMERA_CAPTURE_V4L2_H
6
7// Private, Linux-only enumeration helper. Injecting ioctl allows deterministic
8// tests without opening a camera or changing its capture configuration.
9#if defined(__linux__)
10#include "CameraCaptureReader.h"
11#include <linux/videodev2.h>
12#include <cerrno>
13#include <climits>
14#include <functional>
15#include <stdexcept>
16
17namespace openshot { namespace detail {
18using CameraIoctl = std::function<int(unsigned long, void*)>;
19
20inline bool CameraQuery(const CameraIoctl& query, unsigned long request, void* value)
21{
22 int result;
23 do { result = query(request, value); } while (result < 0 && errno == EINTR);
24 if (result >= 0) return true;
25 if (errno == EINVAL || errno == ENOTTY) return false;
26 throw std::runtime_error("Unable to enumerate V4L2 camera modes (errno " + std::to_string(errno) + ").");
27}
28
29inline std::string CameraInputFormat(unsigned int format)
30{
31 switch (format) {
32 case V4L2_PIX_FMT_MJPEG: return "mjpeg";
33 case V4L2_PIX_FMT_JPEG: return "mjpeg";
34 case V4L2_PIX_FMT_H264: return "h264";
35 case V4L2_PIX_FMT_YUYV: return "yuyv422";
36 case V4L2_PIX_FMT_UYVY: return "uyvy422";
37 case V4L2_PIX_FMT_NV12: return "nv12";
38 case V4L2_PIX_FMT_YUV420: return "yuv420p";
39 case V4L2_PIX_FMT_RGB24: return "rgb24";
40 case V4L2_PIX_FMT_BGR24: return "bgr24";
41 case V4L2_PIX_FMT_GREY: return "gray";
42 default: return ""; // Never pass an unrecognized FOURCC to FFmpeg.
43 }
44}
45
46inline std::vector<CameraCaptureMode> EnumerateCameraModes(const CameraIoctl& query)
47{
48 std::vector<CameraCaptureMode> modes;
49 auto add = [&](unsigned int width, unsigned int height, const std::string& format, v4l2_fract interval) {
50 if (!width || !height || width > INT_MAX || height > INT_MAX ||
51 !interval.numerator || !interval.denominator ||
52 interval.numerator > INT_MAX || interval.denominator > INT_MAX) return;
53 CameraCaptureMode mode;
54 mode.width = width;
55 mode.height = height;
56 mode.input_format = format;
57 mode.fps = Fraction(interval.denominator, interval.numerator);
58 mode.fps.Reduce();
59 for (const auto& existing : modes)
60 if (existing.width == mode.width && existing.height == mode.height &&
61 existing.input_format == mode.input_format && existing.fps.num == mode.fps.num &&
62 existing.fps.den == mode.fps.den) return;
63 modes.push_back(mode);
64 };
65 for (unsigned int f = 0; ; ++f) {
66 v4l2_fmtdesc format = {};
67 format.index = f;
68 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
69 if (!CameraQuery(query, VIDIOC_ENUM_FMT, &format)) break;
70 const auto input_format = CameraInputFormat(format.pixelformat);
71 if (input_format.empty()) continue;
72 for (unsigned int s = 0; ; ++s) {
73 v4l2_frmsizeenum size = {};
74 size.index = s;
75 size.pixel_format = format.pixelformat;
76 if (!CameraQuery(query, VIDIOC_ENUM_FRAMESIZES, &size)) break;
77 std::vector<std::pair<unsigned int, unsigned int>> sizes;
78 if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE)
79 sizes.emplace_back(size.discrete.width, size.discrete.height);
80 else if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE || size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
81 sizes.emplace_back(size.stepwise.min_width, size.stepwise.min_height);
82 sizes.emplace_back(size.stepwise.max_width, size.stepwise.max_height);
83 }
84 for (const auto& dimensions : sizes) {
85 for (unsigned int i = 0; ; ++i) {
86 v4l2_frmivalenum interval = {};
87 interval.index = i;
88 interval.pixel_format = format.pixelformat;
89 interval.width = dimensions.first;
90 interval.height = dimensions.second;
91 if (!CameraQuery(query, VIDIOC_ENUM_FRAMEINTERVALS, &interval)) break;
92 if (interval.type == V4L2_FRMIVAL_TYPE_DISCRETE)
93 add(interval.width, interval.height, input_format, interval.discrete);
94 else if (interval.type == V4L2_FRMIVAL_TYPE_STEPWISE || interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) {
95 add(interval.width, interval.height, input_format, interval.stepwise.min);
96 add(interval.width, interval.height, input_format, interval.stepwise.max);
97 }
98 if (interval.type != V4L2_FRMIVAL_TYPE_DISCRETE) break;
99 }
100 }
101 if (size.type != V4L2_FRMSIZE_TYPE_DISCRETE) break;
102 }
103 }
104 return modes;
105}
106}}
107#endif
108#endif
Header file for live camera capture readers.
if(avcodec_open2(video_codec_ctx, codec, &opts)< 0) throw InvalidCodec("Could not open video codec"
This namespace is the default namespace for all code in the openshot library.