1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
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 <QtMultimedia/private/qtmultimediaglobal_p.h> |
41 | #include "camerabinimageprocessing.h" |
42 | #include "camerabinsession.h" |
43 | |
44 | #if QT_CONFIG(linux_v4l) |
45 | #include "camerabinv4limageprocessing.h" |
46 | #endif |
47 | |
48 | #if GST_CHECK_VERSION(1,0,0) |
49 | # include <gst/video/colorbalance.h> |
50 | #else |
51 | # include <gst/interfaces/colorbalance.h> |
52 | #endif |
53 | |
54 | QT_BEGIN_NAMESPACE |
55 | |
56 | CameraBinImageProcessing::CameraBinImageProcessing(CameraBinSession *session) |
57 | : QCameraImageProcessingControl(session) |
58 | , m_session(session) |
59 | , m_whiteBalanceMode(QCameraImageProcessing::WhiteBalanceAuto) |
60 | #if QT_CONFIG(linux_v4l) |
61 | , m_v4lImageControl(nullptr) |
62 | #endif |
63 | { |
64 | #if QT_CONFIG(gstreamer_photography) |
65 | if (m_session->photography()) { |
66 | m_mappedWbValues[GST_PHOTOGRAPHY_WB_MODE_AUTO] = QCameraImageProcessing::WhiteBalanceAuto; |
67 | m_mappedWbValues[GST_PHOTOGRAPHY_WB_MODE_DAYLIGHT] = QCameraImageProcessing::WhiteBalanceSunlight; |
68 | m_mappedWbValues[GST_PHOTOGRAPHY_WB_MODE_CLOUDY] = QCameraImageProcessing::WhiteBalanceCloudy; |
69 | m_mappedWbValues[GST_PHOTOGRAPHY_WB_MODE_SUNSET] = QCameraImageProcessing::WhiteBalanceSunset; |
70 | m_mappedWbValues[GST_PHOTOGRAPHY_WB_MODE_TUNGSTEN] = QCameraImageProcessing::WhiteBalanceTungsten; |
71 | m_mappedWbValues[GST_PHOTOGRAPHY_WB_MODE_FLUORESCENT] = QCameraImageProcessing::WhiteBalanceFluorescent; |
72 | unlockWhiteBalance(); |
73 | } |
74 | |
75 | #if GST_CHECK_VERSION(1, 0, 0) |
76 | m_filterMap.insert(akey: QCameraImageProcessing::ColorFilterNone, avalue: GST_PHOTOGRAPHY_COLOR_TONE_MODE_NORMAL); |
77 | if (m_session->photography()) { |
78 | m_filterMap.insert(akey: QCameraImageProcessing::ColorFilterSepia, avalue: GST_PHOTOGRAPHY_COLOR_TONE_MODE_SEPIA); |
79 | m_filterMap.insert(akey: QCameraImageProcessing::ColorFilterGrayscale, avalue: GST_PHOTOGRAPHY_COLOR_TONE_MODE_GRAYSCALE); |
80 | m_filterMap.insert(akey: QCameraImageProcessing::ColorFilterNegative, avalue: GST_PHOTOGRAPHY_COLOR_TONE_MODE_NEGATIVE); |
81 | m_filterMap.insert(akey: QCameraImageProcessing::ColorFilterSolarize, avalue: GST_PHOTOGRAPHY_COLOR_TONE_MODE_SOLARIZE); |
82 | #if GST_CHECK_VERSION(1, 2, 0) |
83 | m_filterMap.insert(akey: QCameraImageProcessing::ColorFilterPosterize, avalue: GST_PHOTOGRAPHY_COLOR_TONE_MODE_POSTERIZE); |
84 | m_filterMap.insert(akey: QCameraImageProcessing::ColorFilterWhiteboard, avalue: GST_PHOTOGRAPHY_COLOR_TONE_MODE_WHITEBOARD); |
85 | m_filterMap.insert(akey: QCameraImageProcessing::ColorFilterBlackboard, avalue: GST_PHOTOGRAPHY_COLOR_TONE_MODE_BLACKBOARD); |
86 | m_filterMap.insert(akey: QCameraImageProcessing::ColorFilterAqua, avalue: GST_PHOTOGRAPHY_COLOR_TONE_MODE_AQUA); |
87 | #endif |
88 | } |
89 | #else |
90 | m_filterMap.insert(QCameraImageProcessing::ColorFilterNone, GST_PHOTOGRAPHY_COLOUR_TONE_MODE_NORMAL); |
91 | if (m_session->photography()) { |
92 | m_filterMap.insert(QCameraImageProcessing::ColorFilterSepia, GST_PHOTOGRAPHY_COLOUR_TONE_MODE_SEPIA); |
93 | m_filterMap.insert(QCameraImageProcessing::ColorFilterGrayscale, GST_PHOTOGRAPHY_COLOUR_TONE_MODE_GRAYSCALE); |
94 | m_filterMap.insert(QCameraImageProcessing::ColorFilterNegative, GST_PHOTOGRAPHY_COLOUR_TONE_MODE_NEGATIVE); |
95 | m_filterMap.insert(QCameraImageProcessing::ColorFilterSolarize, GST_PHOTOGRAPHY_COLOUR_TONE_MODE_SOLARIZE); |
96 | } |
97 | #endif |
98 | #endif |
99 | |
100 | #if QT_CONFIG(linux_v4l) |
101 | m_v4lImageControl = new CameraBinV4LImageProcessing(m_session); |
102 | connect(sender: m_session, signal: &CameraBinSession::statusChanged, |
103 | receiver: m_v4lImageControl, slot: &CameraBinV4LImageProcessing::updateParametersInfo); |
104 | #endif |
105 | |
106 | updateColorBalanceValues(); |
107 | } |
108 | |
109 | CameraBinImageProcessing::~CameraBinImageProcessing() |
110 | { |
111 | } |
112 | |
113 | void CameraBinImageProcessing::updateColorBalanceValues() |
114 | { |
115 | if (!GST_IS_COLOR_BALANCE(m_session->cameraBin())) { |
116 | // Camerabin doesn't implement gstcolorbalance interface |
117 | return; |
118 | } |
119 | |
120 | GstColorBalance *balance = GST_COLOR_BALANCE(m_session->cameraBin()); |
121 | const GList *controls = gst_color_balance_list_channels(balance); |
122 | |
123 | const GList *item; |
124 | GstColorBalanceChannel *channel; |
125 | gint cur_value; |
126 | qreal scaledValue = 0; |
127 | |
128 | for (item = controls; item; item = g_list_next (item)) { |
129 | channel = (GstColorBalanceChannel *)item->data; |
130 | cur_value = gst_color_balance_get_value (balance, channel); |
131 | |
132 | //map the [min_value..max_value] range to [-1.0 .. 1.0] |
133 | if (channel->min_value != channel->max_value) { |
134 | scaledValue = qreal(cur_value - channel->min_value) / |
135 | (channel->max_value - channel->min_value) * 2 - 1; |
136 | } |
137 | |
138 | if (!g_ascii_strcasecmp (s1: channel->label, s2: "brightness" )) { |
139 | m_values[QCameraImageProcessingControl::BrightnessAdjustment] = scaledValue; |
140 | } else if (!g_ascii_strcasecmp (s1: channel->label, s2: "contrast" )) { |
141 | m_values[QCameraImageProcessingControl::ContrastAdjustment] = scaledValue; |
142 | } else if (!g_ascii_strcasecmp (s1: channel->label, s2: "saturation" )) { |
143 | m_values[QCameraImageProcessingControl::SaturationAdjustment] = scaledValue; |
144 | } |
145 | } |
146 | } |
147 | |
148 | bool CameraBinImageProcessing::setColorBalanceValue(const QString& channel, qreal value) |
149 | { |
150 | |
151 | if (!GST_IS_COLOR_BALANCE(m_session->cameraBin())) { |
152 | // Camerabin doesn't implement gstcolorbalance interface |
153 | return false; |
154 | } |
155 | |
156 | GstColorBalance *balance = GST_COLOR_BALANCE(m_session->cameraBin()); |
157 | const GList *controls = gst_color_balance_list_channels(balance); |
158 | |
159 | const GList *item; |
160 | GstColorBalanceChannel *colorBalanceChannel; |
161 | |
162 | for (item = controls; item; item = g_list_next (item)) { |
163 | colorBalanceChannel = (GstColorBalanceChannel *)item->data; |
164 | |
165 | if (!g_ascii_strcasecmp (s1: colorBalanceChannel->label, s2: channel.toLatin1())) { |
166 | //map the [-1.0 .. 1.0] range to [min_value..max_value] |
167 | gint scaledValue = colorBalanceChannel->min_value + qRound( |
168 | d: (value+1.0)/2.0 * (colorBalanceChannel->max_value - colorBalanceChannel->min_value)); |
169 | |
170 | gst_color_balance_set_value (balance, channel: colorBalanceChannel, value: scaledValue); |
171 | return true; |
172 | } |
173 | } |
174 | |
175 | return false; |
176 | } |
177 | |
178 | QCameraImageProcessing::WhiteBalanceMode CameraBinImageProcessing::whiteBalanceMode() const |
179 | { |
180 | return m_whiteBalanceMode; |
181 | } |
182 | |
183 | bool CameraBinImageProcessing::setWhiteBalanceMode(QCameraImageProcessing::WhiteBalanceMode mode) |
184 | { |
185 | #if QT_CONFIG(gstreamer_photography) |
186 | if (isWhiteBalanceModeSupported(mode)) { |
187 | m_whiteBalanceMode = mode; |
188 | #if GST_CHECK_VERSION(1, 2, 0) |
189 | GstPhotographyWhiteBalanceMode currentMode; |
190 | if (gst_photography_get_white_balance_mode(photo: m_session->photography(), wb_mode: ¤tMode) |
191 | && currentMode != GST_PHOTOGRAPHY_WB_MODE_MANUAL) |
192 | #endif |
193 | { |
194 | unlockWhiteBalance(); |
195 | return true; |
196 | } |
197 | } |
198 | #else |
199 | Q_UNUSED(mode); |
200 | #endif |
201 | return false; |
202 | } |
203 | |
204 | bool CameraBinImageProcessing::isWhiteBalanceModeSupported(QCameraImageProcessing::WhiteBalanceMode mode) const |
205 | { |
206 | #if QT_CONFIG(gstreamer_photography) |
207 | return m_mappedWbValues.values().contains(t: mode); |
208 | #else |
209 | Q_UNUSED(mode); |
210 | return false; |
211 | #endif |
212 | } |
213 | |
214 | bool CameraBinImageProcessing::isParameterSupported(QCameraImageProcessingControl::ProcessingParameter parameter) const |
215 | { |
216 | #if QT_CONFIG(gstreamer_photography) |
217 | if (parameter == QCameraImageProcessingControl::WhiteBalancePreset |
218 | || parameter == QCameraImageProcessingControl::ColorFilter) { |
219 | if (m_session->photography()) |
220 | return true; |
221 | } |
222 | #endif |
223 | |
224 | if (parameter == QCameraImageProcessingControl::Contrast |
225 | || parameter == QCameraImageProcessingControl::Brightness |
226 | || parameter == QCameraImageProcessingControl::Saturation) { |
227 | if (GST_IS_COLOR_BALANCE(m_session->cameraBin())) |
228 | return true; |
229 | } |
230 | |
231 | #if QT_CONFIG(linux_v4l) |
232 | if (m_v4lImageControl->isParameterSupported(parameter)) |
233 | return true; |
234 | #endif |
235 | |
236 | return false; |
237 | } |
238 | |
239 | bool CameraBinImageProcessing::isParameterValueSupported(QCameraImageProcessingControl::ProcessingParameter parameter, const QVariant &value) const |
240 | { |
241 | switch (parameter) { |
242 | case ContrastAdjustment: |
243 | case BrightnessAdjustment: |
244 | case SaturationAdjustment: { |
245 | const bool isGstColorBalanceValueSupported = GST_IS_COLOR_BALANCE(m_session->cameraBin()) |
246 | && qAbs(t: value.toReal()) <= 1.0; |
247 | #if QT_CONFIG(linux_v4l) |
248 | if (!isGstColorBalanceValueSupported) |
249 | return m_v4lImageControl->isParameterValueSupported(parameter, value); |
250 | #endif |
251 | return isGstColorBalanceValueSupported; |
252 | } |
253 | case SharpeningAdjustment: { |
254 | #if QT_CONFIG(linux_v4l) |
255 | return m_v4lImageControl->isParameterValueSupported(parameter, value); |
256 | #else |
257 | return false; |
258 | #endif |
259 | } |
260 | case WhiteBalancePreset: { |
261 | const QCameraImageProcessing::WhiteBalanceMode mode = |
262 | value.value<QCameraImageProcessing::WhiteBalanceMode>(); |
263 | const bool isPhotographyWhiteBalanceSupported = isWhiteBalanceModeSupported(mode); |
264 | #if QT_CONFIG(linux_v4l) |
265 | if (!isPhotographyWhiteBalanceSupported) |
266 | return m_v4lImageControl->isParameterValueSupported(parameter, value); |
267 | #endif |
268 | return isPhotographyWhiteBalanceSupported; |
269 | } |
270 | case ColorTemperature: { |
271 | #if QT_CONFIG(linux_v4l) |
272 | return m_v4lImageControl->isParameterValueSupported(parameter, value); |
273 | #else |
274 | return false; |
275 | #endif |
276 | } |
277 | case ColorFilter: { |
278 | const QCameraImageProcessing::ColorFilter filter = value.value<QCameraImageProcessing::ColorFilter>(); |
279 | #if QT_CONFIG(gstreamer_photography) |
280 | return m_filterMap.contains(akey: filter); |
281 | #else |
282 | return filter == QCameraImageProcessing::ColorFilterNone; |
283 | #endif |
284 | } |
285 | default: |
286 | break; |
287 | } |
288 | |
289 | return false; |
290 | } |
291 | |
292 | QVariant CameraBinImageProcessing::parameter( |
293 | QCameraImageProcessingControl::ProcessingParameter parameter) const |
294 | { |
295 | switch (parameter) { |
296 | case QCameraImageProcessingControl::WhiteBalancePreset: { |
297 | const QCameraImageProcessing::WhiteBalanceMode mode = whiteBalanceMode(); |
298 | #if QT_CONFIG(linux_v4l) |
299 | if (mode == QCameraImageProcessing::WhiteBalanceAuto |
300 | || mode == QCameraImageProcessing::WhiteBalanceManual) { |
301 | return m_v4lImageControl->parameter(parameter); |
302 | } |
303 | #endif |
304 | return QVariant::fromValue<QCameraImageProcessing::WhiteBalanceMode>(value: mode); |
305 | } |
306 | case QCameraImageProcessingControl::ColorTemperature: { |
307 | #if QT_CONFIG(linux_v4l) |
308 | return m_v4lImageControl->parameter(parameter); |
309 | #else |
310 | return QVariant(); |
311 | #endif |
312 | } |
313 | case QCameraImageProcessingControl::ColorFilter: |
314 | #if QT_CONFIG(gstreamer_photography) |
315 | if (GstPhotography *photography = m_session->photography()) { |
316 | #if GST_CHECK_VERSION(1, 0, 0) |
317 | GstPhotographyColorToneMode mode = GST_PHOTOGRAPHY_COLOR_TONE_MODE_NORMAL; |
318 | gst_photography_get_color_tone_mode(photo: photography, tone_mode: &mode); |
319 | #else |
320 | GstColourToneMode mode = GST_PHOTOGRAPHY_COLOUR_TONE_MODE_NORMAL; |
321 | gst_photography_get_colour_tone_mode(photography, &mode); |
322 | #endif |
323 | return QVariant::fromValue(value: m_filterMap.key(avalue: mode, defaultKey: QCameraImageProcessing::ColorFilterNone)); |
324 | } |
325 | #endif |
326 | return QVariant::fromValue(value: QCameraImageProcessing::ColorFilterNone); |
327 | default: { |
328 | const bool isGstParameterSupported = m_values.contains(akey: parameter); |
329 | #if QT_CONFIG(linux_v4l) |
330 | if (!isGstParameterSupported) { |
331 | if (parameter == QCameraImageProcessingControl::BrightnessAdjustment |
332 | || parameter == QCameraImageProcessingControl::ContrastAdjustment |
333 | || parameter == QCameraImageProcessingControl::SaturationAdjustment |
334 | || parameter == QCameraImageProcessingControl::SharpeningAdjustment) { |
335 | return m_v4lImageControl->parameter(parameter); |
336 | } |
337 | } |
338 | #endif |
339 | return isGstParameterSupported |
340 | ? QVariant(m_values.value(akey: parameter)) |
341 | : QVariant(); |
342 | } |
343 | } |
344 | } |
345 | |
346 | void CameraBinImageProcessing::setParameter(QCameraImageProcessingControl::ProcessingParameter parameter, |
347 | const QVariant &value) |
348 | { |
349 | switch (parameter) { |
350 | case ContrastAdjustment: { |
351 | if (!setColorBalanceValue(channel: "contrast" , value: value.toReal())) { |
352 | #if QT_CONFIG(linux_v4l) |
353 | m_v4lImageControl->setParameter(parameter, value); |
354 | #endif |
355 | } |
356 | } |
357 | break; |
358 | case BrightnessAdjustment: { |
359 | if (!setColorBalanceValue(channel: "brightness" , value: value.toReal())) { |
360 | #if QT_CONFIG(linux_v4l) |
361 | m_v4lImageControl->setParameter(parameter, value); |
362 | #endif |
363 | } |
364 | } |
365 | break; |
366 | case SaturationAdjustment: { |
367 | if (!setColorBalanceValue(channel: "saturation" , value: value.toReal())) { |
368 | #if QT_CONFIG(linux_v4l) |
369 | m_v4lImageControl->setParameter(parameter, value); |
370 | #endif |
371 | } |
372 | } |
373 | break; |
374 | case SharpeningAdjustment: { |
375 | #if QT_CONFIG(linux_v4l) |
376 | m_v4lImageControl->setParameter(parameter, value); |
377 | #endif |
378 | } |
379 | break; |
380 | case WhiteBalancePreset: { |
381 | if (!setWhiteBalanceMode(value.value<QCameraImageProcessing::WhiteBalanceMode>())) { |
382 | #if QT_CONFIG(linux_v4l) |
383 | const QCameraImageProcessing::WhiteBalanceMode mode = |
384 | value.value<QCameraImageProcessing::WhiteBalanceMode>(); |
385 | if (mode == QCameraImageProcessing::WhiteBalanceAuto |
386 | || mode == QCameraImageProcessing::WhiteBalanceManual) { |
387 | m_v4lImageControl->setParameter(parameter, value); |
388 | return; |
389 | } |
390 | #endif |
391 | } |
392 | } |
393 | break; |
394 | case QCameraImageProcessingControl::ColorTemperature: { |
395 | #if QT_CONFIG(linux_v4l) |
396 | m_v4lImageControl->setParameter(parameter, value); |
397 | #endif |
398 | break; |
399 | } |
400 | case QCameraImageProcessingControl::ColorFilter: |
401 | #if QT_CONFIG(gstreamer_photography) |
402 | if (GstPhotography *photography = m_session->photography()) { |
403 | #if GST_CHECK_VERSION(1, 0, 0) |
404 | gst_photography_set_color_tone_mode(photo: photography, tone_mode: m_filterMap.value( |
405 | akey: value.value<QCameraImageProcessing::ColorFilter>(), |
406 | adefaultValue: GST_PHOTOGRAPHY_COLOR_TONE_MODE_NORMAL)); |
407 | #else |
408 | gst_photography_set_colour_tone_mode(photography, m_filterMap.value( |
409 | value.value<QCameraImageProcessing::ColorFilter>(), |
410 | GST_PHOTOGRAPHY_COLOUR_TONE_MODE_NORMAL)); |
411 | #endif |
412 | } |
413 | #endif |
414 | break; |
415 | default: |
416 | break; |
417 | } |
418 | |
419 | updateColorBalanceValues(); |
420 | } |
421 | |
422 | #if QT_CONFIG(gstreamer_photography) |
423 | void CameraBinImageProcessing::lockWhiteBalance() |
424 | { |
425 | #if GST_CHECK_VERSION(1, 2, 0) |
426 | if (GstPhotography *photography = m_session->photography()) { |
427 | gst_photography_set_white_balance_mode(photo: photography, wb_mode: GST_PHOTOGRAPHY_WB_MODE_MANUAL); |
428 | } |
429 | #endif |
430 | } |
431 | |
432 | void CameraBinImageProcessing::unlockWhiteBalance() |
433 | { |
434 | if (GstPhotography *photography = m_session->photography()) { |
435 | gst_photography_set_white_balance_mode( |
436 | photo: photography, wb_mode: m_mappedWbValues.key(avalue: m_whiteBalanceMode)); |
437 | } |
438 | } |
439 | #endif |
440 | |
441 | QT_END_NAMESPACE |
442 | |