1/****************************************************************************
2**
3** Copyright (C) 2016 Denis Shienkov <denis.shienkov@gmail.com>
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "camerabinv4limageprocessing.h"
41#include "camerabinsession.h"
42
43#include <QDebug>
44
45#include <private/qcore_unix_p.h>
46#include <linux/videodev2.h>
47
48QT_BEGIN_NAMESPACE
49
50CameraBinV4LImageProcessing::CameraBinV4LImageProcessing(CameraBinSession *session)
51 : QCameraImageProcessingControl(session)
52 , m_session(session)
53{
54}
55
56CameraBinV4LImageProcessing::~CameraBinV4LImageProcessing()
57{
58}
59
60bool CameraBinV4LImageProcessing::isParameterSupported(
61 ProcessingParameter parameter) const
62{
63 return m_parametersInfo.contains(akey: parameter);
64}
65
66bool CameraBinV4LImageProcessing::isParameterValueSupported(
67 ProcessingParameter parameter, const QVariant &value) const
68{
69 QMap<ProcessingParameter, SourceParameterValueInfo>::const_iterator sourceValueInfo =
70 m_parametersInfo.constFind(akey: parameter);
71 if (sourceValueInfo == m_parametersInfo.constEnd())
72 return false;
73
74 switch (parameter) {
75
76 case QCameraImageProcessingControl::WhiteBalancePreset: {
77 const QCameraImageProcessing::WhiteBalanceMode checkedValue =
78 value.value<QCameraImageProcessing::WhiteBalanceMode>();
79 const QCameraImageProcessing::WhiteBalanceMode firstAllowedValue =
80 (*sourceValueInfo).minimumValue ? QCameraImageProcessing::WhiteBalanceAuto
81 : QCameraImageProcessing::WhiteBalanceManual;
82 const QCameraImageProcessing::WhiteBalanceMode secondAllowedValue =
83 (*sourceValueInfo).maximumValue ? QCameraImageProcessing::WhiteBalanceAuto
84 : QCameraImageProcessing::WhiteBalanceManual;
85 if (checkedValue != firstAllowedValue
86 && checkedValue != secondAllowedValue) {
87 return false;
88 }
89 }
90 break;
91
92 case QCameraImageProcessingControl::ColorTemperature: {
93 const qint32 checkedValue = value.toInt();
94 if (checkedValue < (*sourceValueInfo).minimumValue
95 || checkedValue > (*sourceValueInfo).maximumValue) {
96 return false;
97 }
98 }
99 break;
100
101 case QCameraImageProcessingControl::ContrastAdjustment: // falling back
102 case QCameraImageProcessingControl::SaturationAdjustment: // falling back
103 case QCameraImageProcessingControl::BrightnessAdjustment: // falling back
104 case QCameraImageProcessingControl::SharpeningAdjustment: {
105 const qint32 sourceValue = sourceImageProcessingParameterValue(
106 scaledValue: value.toReal(), valueRange: (*sourceValueInfo));
107 if (sourceValue < (*sourceValueInfo).minimumValue
108 || sourceValue > (*sourceValueInfo).maximumValue) {
109 return false;
110 }
111 }
112 break;
113
114 default:
115 return false;
116 }
117
118 return true;
119}
120
121QVariant CameraBinV4LImageProcessing::parameter(
122 ProcessingParameter parameter) const
123{
124 QMap<ProcessingParameter, SourceParameterValueInfo>::const_iterator sourceValueInfo =
125 m_parametersInfo.constFind(akey: parameter);
126 if (sourceValueInfo == m_parametersInfo.constEnd()) {
127 if (!m_parametersInfo.empty())
128 qWarning() << "Unable to get the unsupported parameter:" << parameter;
129 return QVariant();
130 }
131
132 const QString deviceName = m_session->device();
133 const int fd = qt_safe_open(pathname: deviceName.toLocal8Bit().constData(), O_RDONLY);
134 if (fd == -1) {
135 qWarning() << "Unable to open the camera" << deviceName
136 << "for read to get the parameter value:" << qt_error_string(errno);
137 return QVariant();
138 }
139
140 struct v4l2_control control;
141 ::memset(s: &control, c: 0, n: sizeof(control));
142 control.id = (*sourceValueInfo).cid;
143
144 const bool ret = (::ioctl(fd: fd, VIDIOC_G_CTRL, &control) == 0);
145
146 qt_safe_close(fd);
147
148 if (!ret) {
149 qWarning() << "Unable to get the parameter value:" << parameter << ":" << qt_error_string(errno);
150 return QVariant();
151 }
152
153 switch (parameter) {
154
155 case QCameraImageProcessingControl::WhiteBalancePreset:
156 return QVariant::fromValue<QCameraImageProcessing::WhiteBalanceMode>(
157 value: control.value ? QCameraImageProcessing::WhiteBalanceAuto
158 : QCameraImageProcessing::WhiteBalanceManual);
159
160 case QCameraImageProcessingControl::ColorTemperature:
161 return QVariant::fromValue<qint32>(value: control.value);
162
163 case QCameraImageProcessingControl::ContrastAdjustment: // falling back
164 case QCameraImageProcessingControl::SaturationAdjustment: // falling back
165 case QCameraImageProcessingControl::BrightnessAdjustment: // falling back
166 case QCameraImageProcessingControl::SharpeningAdjustment: {
167 return scaledImageProcessingParameterValue(
168 sourceValue: control.value, sourceValueInfo: (*sourceValueInfo));
169 }
170
171 default:
172 return QVariant();
173 }
174}
175
176void CameraBinV4LImageProcessing::setParameter(
177 ProcessingParameter parameter, const QVariant &value)
178{
179 QMap<ProcessingParameter, SourceParameterValueInfo>::const_iterator sourceValueInfo =
180 m_parametersInfo.constFind(akey: parameter);
181 if (sourceValueInfo == m_parametersInfo.constEnd()) {
182 if (!m_parametersInfo.empty())
183 qWarning() << "Unable to set the unsupported parameter:" << parameter;
184 return;
185 }
186
187 const QString deviceName = m_session->device();
188 const int fd = qt_safe_open(pathname: deviceName.toLocal8Bit().constData(), O_WRONLY);
189 if (fd == -1) {
190 qWarning() << "Unable to open the camera" << deviceName
191 << "for write to set the parameter value:" << qt_error_string(errno);
192 return;
193 }
194
195 struct v4l2_control control;
196 ::memset(s: &control, c: 0, n: sizeof(control));
197 control.id = (*sourceValueInfo).cid;
198
199 switch (parameter) {
200
201 case QCameraImageProcessingControl::WhiteBalancePreset: {
202 const QCameraImageProcessing::WhiteBalanceMode m =
203 value.value<QCameraImageProcessing::WhiteBalanceMode>();
204 if (m != QCameraImageProcessing::WhiteBalanceAuto
205 && m != QCameraImageProcessing::WhiteBalanceManual) {
206 qt_safe_close(fd);
207 return;
208 }
209
210 control.value = (m == QCameraImageProcessing::WhiteBalanceAuto) ? true : false;
211 }
212 break;
213
214 case QCameraImageProcessingControl::ColorTemperature:
215 control.value = value.toInt();
216 break;
217
218 case QCameraImageProcessingControl::ContrastAdjustment: // falling back
219 case QCameraImageProcessingControl::SaturationAdjustment: // falling back
220 case QCameraImageProcessingControl::BrightnessAdjustment: // falling back
221 case QCameraImageProcessingControl::SharpeningAdjustment:
222 control.value = sourceImageProcessingParameterValue(
223 scaledValue: value.toReal(), valueRange: (*sourceValueInfo));
224 break;
225
226 default:
227 qt_safe_close(fd);
228 return;
229 }
230
231 if (::ioctl(fd: fd, VIDIOC_S_CTRL, &control) != 0)
232 qWarning() << "Unable to set the parameter value:" << parameter << ":" << qt_error_string(errno);
233
234 qt_safe_close(fd);
235}
236
237void CameraBinV4LImageProcessing::updateParametersInfo(
238 QCamera::Status cameraStatus)
239{
240 if (cameraStatus == QCamera::UnloadedStatus)
241 m_parametersInfo.clear();
242 else if (cameraStatus == QCamera::LoadedStatus) {
243 const QString deviceName = m_session->device();
244 const int fd = qt_safe_open(pathname: deviceName.toLocal8Bit().constData(), O_RDONLY);
245 if (fd == -1) {
246 qWarning() << "Unable to open the camera" << deviceName
247 << "for read to query the parameter info:" << qt_error_string(errno);
248 return;
249 }
250
251 static const struct SupportedParameterEntry {
252 quint32 cid;
253 QCameraImageProcessingControl::ProcessingParameter parameter;
254 } supportedParametersEntries[] = {
255 { V4L2_CID_AUTO_WHITE_BALANCE, .parameter: QCameraImageProcessingControl::WhiteBalancePreset },
256 { V4L2_CID_WHITE_BALANCE_TEMPERATURE, .parameter: QCameraImageProcessingControl::ColorTemperature },
257 { V4L2_CID_CONTRAST, .parameter: QCameraImageProcessingControl::ContrastAdjustment },
258 { V4L2_CID_SATURATION, .parameter: QCameraImageProcessingControl::SaturationAdjustment },
259 { V4L2_CID_BRIGHTNESS, .parameter: QCameraImageProcessingControl::BrightnessAdjustment },
260 { V4L2_CID_SHARPNESS, .parameter: QCameraImageProcessingControl::SharpeningAdjustment }
261 };
262
263 for (int i = 0; i < int(sizeof(supportedParametersEntries) / sizeof(SupportedParameterEntry)); ++i) {
264 struct v4l2_queryctrl queryControl;
265 ::memset(s: &queryControl, c: 0, n: sizeof(queryControl));
266 queryControl.id = supportedParametersEntries[i].cid;
267
268 if (::ioctl(fd: fd, VIDIOC_QUERYCTRL, &queryControl) != 0) {
269 qWarning() << "Unable to query the parameter info:" << supportedParametersEntries[i].parameter
270 << ":" << qt_error_string(errno);
271 continue;
272 }
273
274 SourceParameterValueInfo sourceValueInfo;
275 sourceValueInfo.cid = queryControl.id;
276 sourceValueInfo.defaultValue = queryControl.default_value;
277 sourceValueInfo.maximumValue = queryControl.maximum;
278 sourceValueInfo.minimumValue = queryControl.minimum;
279
280 m_parametersInfo.insert(akey: supportedParametersEntries[i].parameter, avalue: sourceValueInfo);
281 }
282
283 qt_safe_close(fd);
284 }
285}
286
287qreal CameraBinV4LImageProcessing::scaledImageProcessingParameterValue(
288 qint32 sourceValue, const SourceParameterValueInfo &sourceValueInfo)
289{
290 if (sourceValue == sourceValueInfo.defaultValue) {
291 return 0.0f;
292 } else if (sourceValue < sourceValueInfo.defaultValue) {
293 return ((sourceValue - sourceValueInfo.minimumValue)
294 / qreal(sourceValueInfo.defaultValue - sourceValueInfo.minimumValue))
295 + (-1.0f);
296 } else {
297 return ((sourceValue - sourceValueInfo.defaultValue)
298 / qreal(sourceValueInfo.maximumValue - sourceValueInfo.defaultValue));
299 }
300}
301
302qint32 CameraBinV4LImageProcessing::sourceImageProcessingParameterValue(
303 qreal scaledValue, const SourceParameterValueInfo &valueRange)
304{
305 if (qFuzzyIsNull(d: scaledValue)) {
306 return valueRange.defaultValue;
307 } else if (scaledValue < 0.0f) {
308 return ((scaledValue - (-1.0f)) * (valueRange.defaultValue - valueRange.minimumValue))
309 + valueRange.minimumValue;
310 } else {
311 return (scaledValue * (valueRange.maximumValue - valueRange.defaultValue))
312 + valueRange.defaultValue;
313 }
314}
315
316QT_END_NAMESPACE
317

source code of qtmultimedia/src/plugins/gstreamer/camerabin/camerabinv4limageprocessing.cpp