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 "camerabincontrol.h"
42#include "camerabincontainer.h"
43#include "camerabinaudioencoder.h"
44#include "camerabinvideoencoder.h"
45#include "camerabinimageencoder.h"
46#include "camerabinresourcepolicy.h"
47
48#include <QtCore/qdebug.h>
49#include <QtCore/qfile.h>
50#include <QtCore/qmetaobject.h>
51
52QT_BEGIN_NAMESPACE
53
54//#define CAMEABIN_DEBUG 1
55#define ENUM_NAME(c,e,v) (c::staticMetaObject.enumerator(c::staticMetaObject.indexOfEnumerator(e)).valueToKey((v)))
56
57CameraBinControl::CameraBinControl(CameraBinSession *session)
58 :QCameraControl(session),
59 m_session(session),
60 m_state(QCamera::UnloadedState),
61 m_reloadPending(false)
62{
63 connect(sender: m_session, SIGNAL(statusChanged(QCamera::Status)),
64 receiver: this, SIGNAL(statusChanged(QCamera::Status)));
65
66 connect(asender: m_session, SIGNAL(viewfinderChanged()),
67 SLOT(reloadLater()));
68 connect(asender: m_session, SIGNAL(readyChanged(bool)),
69 SLOT(reloadLater()));
70 connect(asender: m_session, SIGNAL(error(int,QString)),
71 SLOT(handleCameraError(int,QString)));
72
73 m_resourcePolicy = new CamerabinResourcePolicy(this);
74 connect(asender: m_resourcePolicy, SIGNAL(resourcesGranted()),
75 SLOT(handleResourcesGranted()));
76 connect(asender: m_resourcePolicy, SIGNAL(resourcesDenied()),
77 SLOT(handleResourcesLost()));
78 connect(asender: m_resourcePolicy, SIGNAL(resourcesLost()),
79 SLOT(handleResourcesLost()));
80
81 connect(asender: m_session, SIGNAL(busyChanged(bool)),
82 SLOT(handleBusyChanged(bool)));
83}
84
85CameraBinControl::~CameraBinControl()
86{
87}
88
89QCamera::CaptureModes CameraBinControl::captureMode() const
90{
91 return m_session->captureMode();
92}
93
94void CameraBinControl::setCaptureMode(QCamera::CaptureModes mode)
95{
96 if (m_session->captureMode() != mode) {
97 m_session->setCaptureMode(mode);
98
99 if (m_state == QCamera::ActiveState) {
100 m_resourcePolicy->setResourceSet(
101 captureMode() == QCamera::CaptureStillImage ?
102 CamerabinResourcePolicy::ImageCaptureResources :
103 CamerabinResourcePolicy::VideoCaptureResources);
104 }
105 emit captureModeChanged(mode);
106 }
107}
108
109bool CameraBinControl::isCaptureModeSupported(QCamera::CaptureModes mode) const
110{
111 return mode == QCamera::CaptureStillImage || mode == QCamera::CaptureVideo;
112}
113
114void CameraBinControl::setState(QCamera::State state)
115{
116#ifdef CAMEABIN_DEBUG
117 qDebug() << Q_FUNC_INFO << ENUM_NAME(QCamera, "State", state);
118#endif
119 if (m_state != state) {
120 m_state = state;
121
122 //special case for stopping the camera while it's busy,
123 //it should be delayed until the camera is idle
124 if ((state == QCamera::LoadedState || state == QCamera::UnloadedState) &&
125 m_session->status() == QCamera::ActiveStatus &&
126 m_session->isBusy()) {
127#ifdef CAMEABIN_DEBUG
128 qDebug() << Q_FUNC_INFO << "Camera is busy, QCamera::stop() is delayed";
129#endif
130 emit stateChanged(m_state);
131 return;
132 }
133
134 CamerabinResourcePolicy::ResourceSet resourceSet = CamerabinResourcePolicy::NoResources;
135 switch (state) {
136 case QCamera::UnloadedState:
137 resourceSet = CamerabinResourcePolicy::NoResources;
138 break;
139 case QCamera::LoadedState:
140 resourceSet = CamerabinResourcePolicy::LoadedResources;
141 break;
142 case QCamera::ActiveState:
143 resourceSet = captureMode() == QCamera::CaptureStillImage ?
144 CamerabinResourcePolicy::ImageCaptureResources :
145 CamerabinResourcePolicy::VideoCaptureResources;
146 break;
147 }
148
149 m_resourcePolicy->setResourceSet(resourceSet);
150
151 if (m_resourcePolicy->isResourcesGranted()) {
152 //postpone changing to Active if the session is nor ready yet
153 if (state == QCamera::ActiveState) {
154 if (m_session->isReady()) {
155 m_session->setState(state);
156 } else {
157#ifdef CAMEABIN_DEBUG
158 qDebug() << "Camera session is not ready yet, postpone activating";
159#endif
160 }
161 } else
162 m_session->setState(state);
163 }
164
165 emit stateChanged(m_state);
166 }
167}
168
169QCamera::State CameraBinControl::state() const
170{
171 return m_state;
172}
173
174QCamera::Status CameraBinControl::status() const
175{
176 return m_session->status();
177}
178
179void CameraBinControl::reloadLater()
180{
181#ifdef CAMEABIN_DEBUG
182 qDebug() << "CameraBinControl: reload pipeline requested" << ENUM_NAME(QCamera, "State", m_state);
183#endif
184 if (!m_reloadPending && m_state == QCamera::ActiveState) {
185 m_reloadPending = true;
186
187 if (!m_session->isBusy()) {
188 m_session->setState(QCamera::LoadedState);
189 QMetaObject::invokeMethod(obj: this, member: "delayedReload", type: Qt::QueuedConnection);
190 }
191 }
192}
193
194void CameraBinControl::handleResourcesLost()
195{
196#ifdef CAMEABIN_DEBUG
197 qDebug() << Q_FUNC_INFO << ENUM_NAME(QCamera, "State", m_state);
198#endif
199 m_session->setState(QCamera::UnloadedState);
200}
201
202void CameraBinControl::handleResourcesGranted()
203{
204#ifdef CAMEABIN_DEBUG
205 qDebug() << Q_FUNC_INFO << ENUM_NAME(QCamera, "State", m_state);
206#endif
207
208 //camera will be started soon by delayedReload()
209 if (m_reloadPending && m_state == QCamera::ActiveState)
210 return;
211
212 if (m_state == QCamera::ActiveState && m_session->isReady())
213 m_session->setState(QCamera::ActiveState);
214 else if (m_state == QCamera::LoadedState)
215 m_session->setState(QCamera::LoadedState);
216}
217
218void CameraBinControl::handleBusyChanged(bool busy)
219{
220 if (!busy && m_session->status() == QCamera::ActiveStatus) {
221 if (m_state == QCamera::LoadedState) {
222 //handle delayed stop() because of busy camera
223 m_resourcePolicy->setResourceSet(CamerabinResourcePolicy::LoadedResources);
224 m_session->setState(QCamera::LoadedState);
225 } else if (m_state == QCamera::ActiveState && m_reloadPending) {
226 //handle delayed reload because of busy camera
227 m_session->setState(QCamera::LoadedState);
228 QMetaObject::invokeMethod(obj: this, member: "delayedReload", type: Qt::QueuedConnection);
229 }
230 }
231}
232
233void CameraBinControl::handleCameraError(int errorCode, const QString &errorString)
234{
235 emit error(error: errorCode, errorString);
236 setState(QCamera::UnloadedState);
237}
238
239void CameraBinControl::delayedReload()
240{
241#ifdef CAMEABIN_DEBUG
242 qDebug() << "CameraBinControl: reload pipeline";
243#endif
244 if (m_reloadPending) {
245 m_reloadPending = false;
246 if (m_state == QCamera::ActiveState &&
247 m_session->isReady() &&
248 m_resourcePolicy->isResourcesGranted()) {
249 m_session->setState(QCamera::ActiveState);
250 }
251 }
252}
253
254bool CameraBinControl::canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const
255{
256 Q_UNUSED(status);
257
258 switch (changeType) {
259 case QCameraControl::Viewfinder:
260 return true;
261 case QCameraControl::CaptureMode:
262 case QCameraControl::ImageEncodingSettings:
263 case QCameraControl::VideoEncodingSettings:
264 case QCameraControl::ViewfinderSettings:
265 default:
266 return status != QCamera::ActiveStatus;
267 }
268}
269
270#define VIEWFINDER_COLORSPACE_CONVERSION 0x00000004
271
272bool CameraBinControl::viewfinderColorSpaceConversion() const
273{
274 gint flags = 0;
275 g_object_get(G_OBJECT(m_session->cameraBin()), first_property_name: "flags", &flags, NULL);
276
277 return flags & VIEWFINDER_COLORSPACE_CONVERSION;
278}
279
280void CameraBinControl::setViewfinderColorSpaceConversion(bool enabled)
281{
282 gint flags = 0;
283 g_object_get(G_OBJECT(m_session->cameraBin()), first_property_name: "flags", &flags, NULL);
284
285 if (enabled)
286 flags |= VIEWFINDER_COLORSPACE_CONVERSION;
287 else
288 flags &= ~VIEWFINDER_COLORSPACE_CONVERSION;
289
290 g_object_set(G_OBJECT(m_session->cameraBin()), first_property_name: "flags", flags, NULL);
291}
292
293QT_END_NAMESPACE
294

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