43 gst_device_monitor_add_filter(m_deviceMonitor.get(),
"Video/Source",
nullptr);
44 gst_device_monitor_set_show_all_devices(m_deviceMonitor.get(),
true);
46 m_busObserver.installMessageFilter(
this);
47 gst_device_monitor_start(m_deviceMonitor.get());
49 GList *devices = gst_device_monitor_get_devices(m_deviceMonitor.get());
51 for (GstDevice *device : QGstUtils::GListRangeAdaptor<GstDevice *>(devices)) {
52 addDevice(QGstDeviceHandle{
54 QGstDeviceHandle::HasRef,
68 QList<QCameraDevice> devices;
70 for (
const auto &device : m_videoSources) {
71 QCameraDevicePrivate *info =
new QCameraDevicePrivate;
74 gst_device_get_display_name(device.gstDevice.get()),
76 info->description = desc.toQString();
79 QUniqueGstStructureHandle properties{
80 gst_device_get_properties(device.gstDevice.get()),
83 QGstStructureView view{ properties };
84 auto def = view[
"is-default"].toBool();
85 info->isDefault = def && *def;
89 devices.prepend(info->create());
91 devices.append(info->create());
93 auto caps = QGstCaps(gst_device_get_caps(device.gstDevice.get()), QGstCaps::HasRef);
95 QList<QCameraFormat> formats;
96 QSet<QSize> photoResolutions;
98 int size = caps.size();
99 for (
int i = 0; i < size; ++i) {
100 auto cap = caps.at(i);
101 QList<QVideoFrameFormat::PixelFormat> pixelFormats = cap.pixelFormats();
103 auto frameRate = cap.frameRateRange();
105 if (pixelFormats.isEmpty()) {
106 qCDebug(ltVideoDevices) <<
"pixel format(s) not supported:" << cap;
110 auto addFormatForResolution = [&](QSize resolution) {
111 for (QVideoFrameFormat::PixelFormat pixelFormat : std::as_const(pixelFormats)){
112 auto *f =
new QCameraFormatPrivate{
113 QSharedData(), pixelFormat, resolution, frameRate.min, frameRate.max,
115 formats.append(f->create());
117 photoResolutions.insert(resolution);
120 std::optional<QGRange<QSize>> resolutionRange = cap.resolutionRange();
121 if (resolutionRange) {
122 addFormatForResolution(resolutionRange->min);
123 addFormatForResolution(resolutionRange->max);
125 QSize resolution = cap.resolution();
126 if (resolution.isValid())
127 addFormatForResolution(resolution);
130 info->videoFormats = formats;
132 info->photoResolutions = photoResolutions.values();
138void QGstreamerVideoDevices::
addDevice(QGstDeviceHandle device)
140 Q_ASSERT(gst_device_has_classes(device.get(),
"Video/Source"));
142#if QT_CONFIG(linux_v4l)
143 QUniqueGstStructureHandle propertiesHandle{
144 gst_device_get_properties(device.get()),
146 if (!propertiesHandle.isValid()) {
147 qCDebug(ltVideoDevices) <<
"Skipping device without extra properties:" << device.get();
151 auto properties = QGstStructureView(propertiesHandle.get());
155 if (properties.name().contains(
"pipewire")) {
156 qCDebug(ltVideoDevices) <<
"Skipping pipewire device:" << device.get();
161 static const bool skipImxCapture = qEnvironmentVariableIsSet(
"QT_GSTREAMER_SKIP_IMXCAPTURE");
162 if (skipImxCapture) {
163 const char *name = properties[
"device.product.name"].toString();
164 if (name && std::strstr(name,
"imx-capture")) {
165 qWarning() << Q_FUNC_INFO <<
"Skipping video device with product name" << name;
170 const auto *p = properties[
"device.path"].toString();
172 QUniqueFileDescriptorHandle fd{
173 qt_safe_open(p, O_RDONLY),
177 qCDebug(ltVideoDevices) <<
"Cannot open v4l2 device:" << p;
181 struct v4l2_capability cap;
182 if (QtMultimediaPrivate::qt_safe_ioctl(fd.get(), VIDIOC_QUERYCAP, &cap) < 0) {
183 qCWarning(ltVideoDevices)
184 <<
"ioctl failed: VIDIOC_QUERYCAP" << qt_error_string(errno) << p;
188 if (cap.device_caps & V4L2_CAP_META_CAPTURE) {
189 qCDebug(ltVideoDevices) <<
"V4L2_CAP_META_CAPTURE device detected" << p;
193 constexpr uint32_t videoCaptureCapabilities =
194 V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
196 if (!(cap.capabilities & videoCaptureCapabilities)) {
197 qCDebug(ltVideoDevices)
198 <<
"not a V4L2_CAP_VIDEO_CAPTURE or V4L2_CAP_VIDEO_CAPTURE_MPLANE device" << p;
201 if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
202 qCDebug(ltVideoDevices) <<
"not a V4L2_CAP_STREAMING device" << p;
207 if (QtMultimediaPrivate::qt_safe_ioctl(fd.get(), VIDIOC_G_INPUT, &index) < 0) {
210 qCDebug(ltVideoDevices) <<
"Device does not support VIDIOC_G_INPUT, but it could"
215 qCWarning(ltVideoDevices)
216 <<
"ioctl failed: VIDIOC_G_INPUT" << qt_error_string(errno) << p;
221 qCDebug(ltVideoDevices) <<
"Video device not a v4l2 device:" << propertiesHandle;
225 auto it = ranges::find_if(m_videoSources, [&](
const QGstRecordDevice &a) {
226 return a.gstDevice == device;
229 if (it != m_videoSources.end())
232 m_videoSources.push_back(QGstRecordDevice{
234 QByteArray::number(m_idGenerator),
239 onVideoInputsChanged();
256 QGstDeviceHandle device;
258 switch (message.type()) {
259 case GST_MESSAGE_DEVICE_ADDED:
260 gst_message_parse_device_added(message.message(), &device);
261 addDevice(std::move(device));
263 case GST_MESSAGE_DEVICE_REMOVED:
264 gst_message_parse_device_removed(message.message(), &device);
265 removeDevice(std::move(device));