39 gst_device_monitor_add_filter(m_deviceMonitor.get(),
"Video/Source",
nullptr);
40 gst_device_monitor_set_show_all_devices(m_deviceMonitor.get(),
true);
42 m_busObserver.installMessageFilter(
this);
43 gst_device_monitor_start(m_deviceMonitor.get());
45 GList *devices = gst_device_monitor_get_devices(m_deviceMonitor.get());
47 for (GstDevice *device : QGstUtils::GListRangeAdaptor<GstDevice *>(devices)) {
48 addDevice(QGstDeviceHandle{
50 QGstDeviceHandle::HasRef,
64 QList<QCameraDevice> devices;
66 for (
const auto &device : m_videoSources) {
67 QCameraDevicePrivate *info =
new QCameraDevicePrivate;
70 gst_device_get_display_name(device.gstDevice.get()),
72 info->description = desc.toQString();
75 QUniqueGstStructureHandle properties{
76 gst_device_get_properties(device.gstDevice.get()),
79 QGstStructureView view{ properties };
80 auto def = view[
"is-default"].toBool();
81 info->isDefault = def && *def;
85 devices.prepend(info->create());
87 devices.append(info->create());
89 auto caps = QGstCaps(gst_device_get_caps(device.gstDevice.get()), QGstCaps::HasRef);
91 QList<QCameraFormat> formats;
92 QSet<QSize> photoResolutions;
94 int size = caps.size();
95 for (
int i = 0; i < size; ++i) {
96 auto cap = caps.at(i);
97 auto pixelFormat = cap.pixelFormat();
98 auto frameRate = cap.frameRateRange();
100 if (pixelFormat == QVideoFrameFormat::PixelFormat::Format_Invalid) {
101 qCDebug(ltVideoDevices) <<
"pixel format not supported:" << cap;
105 auto addFormatForResolution = [&](QSize resolution) {
106 auto *f =
new QCameraFormatPrivate{
107 QSharedData(), pixelFormat, resolution, frameRate.min, frameRate.max,
109 formats.append(f->create());
110 photoResolutions.insert(resolution);
113 std::optional<QGRange<QSize>> resolutionRange = cap.resolutionRange();
114 if (resolutionRange) {
115 addFormatForResolution(resolutionRange->min);
116 addFormatForResolution(resolutionRange->max);
118 QSize resolution = cap.resolution();
119 if (resolution.isValid())
120 addFormatForResolution(resolution);
123 info->videoFormats = formats;
125 info->photoResolutions = photoResolutions.values();
131void QGstreamerVideoDevices::
addDevice(QGstDeviceHandle device)
133 Q_ASSERT(gst_device_has_classes(device.get(),
"Video/Source"));
135#if QT_CONFIG(linux_v4l)
136 QUniqueGstStructureHandle propertiesHandle{
137 gst_device_get_properties(device.get()),
139 if (!propertiesHandle.isValid()) {
140 qCDebug(ltVideoDevices) <<
"Skipping device without extra properties:" << device.get();
144 auto properties = QGstStructureView(propertiesHandle.get());
148 if (properties.name().contains(
"pipewire")) {
149 qCDebug(ltVideoDevices) <<
"Skipping pipewire device:" << device.get();
153 const auto *p = properties[
"device.path"].toString();
155 QUniqueFileDescriptorHandle fd{
156 qt_safe_open(p, O_RDONLY),
160 qCDebug(ltVideoDevices) <<
"Cannot open v4l2 device:" << p;
164 struct v4l2_capability cap;
165 if (::ioctl(fd.get(), VIDIOC_QUERYCAP, &cap) < 0) {
166 qCWarning(ltVideoDevices)
167 <<
"ioctl failed: VIDIOC_QUERYCAP" << qt_error_string(errno) << p;
171 if (cap.device_caps & V4L2_CAP_META_CAPTURE) {
172 qCDebug(ltVideoDevices) <<
"V4L2_CAP_META_CAPTURE device detected" << p;
176 constexpr uint32_t videoCaptureCapabilities =
177 V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
179 if (!(cap.capabilities & videoCaptureCapabilities)) {
180 qCDebug(ltVideoDevices)
181 <<
"not a V4L2_CAP_VIDEO_CAPTURE or V4L2_CAP_VIDEO_CAPTURE_MPLANE device" << p;
184 if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
185 qCDebug(ltVideoDevices) <<
"not a V4L2_CAP_STREAMING device" << p;
190 if (::ioctl(fd.get(), VIDIOC_G_INPUT, &index) < 0) {
193 qCDebug(ltVideoDevices) <<
"Device does not support VIDIOC_G_INPUT, but it could"
198 qCWarning(ltVideoDevices)
199 <<
"ioctl failed: VIDIOC_G_INPUT" << qt_error_string(errno) << p;
204 qCDebug(ltVideoDevices) <<
"Video device not a v4l2 device:" << propertiesHandle;
208 auto it = std::find_if(m_videoSources.begin(), m_videoSources.end(),
209 [&](
const QGstRecordDevice &a) {
return a.gstDevice == device; });
211 if (it != m_videoSources.end())
214 m_videoSources.push_back(QGstRecordDevice{
216 QByteArray::number(m_idGenerator),
221 onVideoInputsChanged();
226 auto it = std::find_if(m_videoSources.begin(), m_videoSources.end(),
227 [&](
const QGstRecordDevice &a) {
return a.gstDevice == device; });
229 if (it != m_videoSources.end()) {
230 m_videoSources.erase(it);
231 onVideoInputsChanged();
237 QGstDeviceHandle device;
239 switch (message.type()) {
240 case GST_MESSAGE_DEVICE_ADDED:
241 gst_message_parse_device_added(message.message(), &device);
242 addDevice(std::move(device));
244 case GST_MESSAGE_DEVICE_REMOVED:
245 gst_message_parse_device_removed(message.message(), &device);
246 removeDevice(std::move(device));