xref: /OK3568_Linux_fs/app/qcamera/qtcamera.cpp (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /****************************************************************************
2 **
3 ** Copyright (C) 2017 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the examples of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
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 ** BSD License Usage
18 ** Alternatively, you may use this file under the terms of the BSD license
19 ** as follows:
20 **
21 ** "Redistribution and use in source and binary forms, with or without
22 ** modification, are permitted provided that the following conditions are
23 ** met:
24 **   * Redistributions of source code must retain the above copyright
25 **     notice, this list of conditions and the following disclaimer.
26 **   * Redistributions in binary form must reproduce the above copyright
27 **     notice, this list of conditions and the following disclaimer in
28 **     the documentation and/or other materials provided with the
29 **     distribution.
30 **   * Neither the name of The Qt Company Ltd nor the names of its
31 **     contributors may be used to endorse or promote products derived
32 **     from this software without specific prior written permission.
33 **
34 **
35 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46 **
47 ** $QT_END_LICENSE$
48 **
49 ****************************************************************************/
50 
51 #include "qtcamera.h"
52 #include <QApplication>
53 #include <QMediaService>
54 #include <QMediaRecorder>
55 #include <QCameraViewfinder>
56 #include <QCameraInfo>
57 #include <QMediaMetaData>
58 
59 #include <QMessageBox>
60 #include <QPalette>
61 #include <QTabWidget>
62 #include <QtWidgets>
63 #include <QHBoxLayout>
64 #include <QVBoxLayout>
65 
66 #define FONT_SIZE 12
67 #define QCAMERA_CAPTURE_MODE "Image Mode"
68 #define QCAMERA_VIDEO_MODE "Video Mode"
69 #define DIR_USERDATA "/userdata"
70 #define DIR_HOME QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
Q_DECLARE_METATYPE(QCameraInfo)71 Q_DECLARE_METATYPE(QCameraInfo)
72 
73 qtCamera::qtCamera()
74 {
75     initlayout();
76     QFileInfo fi(DIR_USERDATA);
77     if(fi.isDir()){
78         locationDir = DIR_USERDATA;
79     }else {
80         QFileInfo fi(DIR_HOME);
81         if(fi.isDir()){
82             locationDir = DIR_HOME;
83         }
84     }
85     imageCnt = videoCnt = 0;
86     setCamera(QCameraInfo::defaultCamera());
87 }
88 
initlayout()89 void qtCamera::initlayout()
90 {
91     QBoxLayout *vLayout = new QVBoxLayout();
92     const QRect availableGeometry = QApplication::desktop()->availableGeometry(this);
93     QFont font;
94     font.setPixelSize(FONT_SIZE);
95     resize(availableGeometry.width(), availableGeometry.height());
96 
97     const QList<QCameraInfo> availableCameras = QCameraInfo::availableCameras();
98     for (const QCameraInfo &cameraInfo : availableCameras) {
99         qDebug() << cameraInfo.description();
100         QPushButton *camera = getButton();
101         camera->setText(cameraInfo.description());
102         camera->setFont(font);
103         camera->setCheckable(true);
104         if (cameraInfo == QCameraInfo::defaultCamera()){
105             camera->setDefault(true);
106         }else {
107             camera->setDefault(false);
108         }
109         connect(camera, SIGNAL(clicked(bool)), this, SLOT(on_cameraSwitch()));
110         vLayout->addWidget(camera);
111     }
112 
113     modeButton = getButton();
114     modeButton->setText(cameraMode);
115     modeButton->setFont(font);
116     connect(modeButton, SIGNAL(clicked(bool)), this, SLOT(updateCaptureMode()));
117 
118     captureButton = getButton();
119     captureButton->setText(tr("Capture"));
120     captureButton->setFont(font);
121     connect(captureButton, SIGNAL(clicked(bool)), this, SLOT(on_captureClicked()));
122 
123     exitButton = getButton();
124     exitButton->setText(tr("Exit"));
125     exitButton->setFont(font);
126     connect(exitButton, SIGNAL(clicked(bool)), this, SLOT(on_exitClicked()));
127 
128     vLayout->addWidget(modeButton);
129     vLayout->addWidget(captureButton);
130     vLayout->addWidget(exitButton);
131     vLayout->setAlignment(Qt::AlignTop);
132 
133     viewfinder.setWindowFlag(Qt::FramelessWindowHint);
134     //viewfinder.setFixedSize(availableGeometry.width() - 150, availableGeometry.height());
135 
136     QBoxLayout *hlayout = new QHBoxLayout;
137     hlayout->setMargin(0);
138     hlayout->addWidget(&viewfinder);
139     hlayout->addLayout(vLayout);
140 
141     QWidget *widget = new QWidget;
142     widget->setLayout(hlayout);
143     setCentralWidget(widget);
144     setWindowState(Qt::WindowMaximized);
145     setWindowFlags(Qt::FramelessWindowHint);
146 }
147 
setCamera(const QCameraInfo & cameraInfo)148 void qtCamera::setCamera(const QCameraInfo &cameraInfo)
149 {
150     m_camera.reset(new QCamera(cameraInfo));
151 
152     connect(m_camera.data(), &QCamera::stateChanged, this, &qtCamera::updateCameraState);
153     connect(m_camera.data(), QOverload<QCamera::Error>::of(&QCamera::error), this, &qtCamera::displayCameraError);
154 
155     m_mediaRecorder.reset(new QMediaRecorder(m_camera.data()));
156     connect(m_mediaRecorder.data(), &QMediaRecorder::stateChanged, this, &qtCamera::updateRecorderState);
157 
158     m_imageCapture.reset(new QCameraImageCapture(m_camera.data()));
159 
160     connect(m_mediaRecorder.data(), &QMediaRecorder::durationChanged, this, &qtCamera::updateRecordTime);
161     connect(m_mediaRecorder.data(), QOverload<QMediaRecorder::Error>::of(&QMediaRecorder::error),
162             this, &qtCamera::displayRecorderError);
163 
164     m_mediaRecorder->setMetaData(QMediaMetaData::Title, QVariant(QLatin1String("Test Title")));
165 
166     configureCaptureSettings();
167 
168     m_camera->setViewfinder(&viewfinder);
169 
170     updateCameraState(m_camera->state());
171     updateRecorderState(m_mediaRecorder->state());
172 
173     connect(m_imageCapture.data(), &QCameraImageCapture::imageSaved, this, &qtCamera::imageSaved);
174     connect(m_imageCapture.data(), QOverload<int, QCameraImageCapture::Error, const QString &>::of(&QCameraImageCapture::error),
175             this, &qtCamera::displayCaptureError);
176 
177     updateCaptureMode();
178 }
179 
configureCaptureSettings()180 void qtCamera::configureCaptureSettings()
181 {
182     QSize size(640, 480);
183 
184     m_imageSettings.setCodec("jpeg");
185     m_imageSettings.setQuality(QMultimedia::VeryHighQuality);
186     m_imageSettings.setResolution(size);
187     m_imageCapture->setEncodingSettings(m_imageSettings);
188 
189     m_audioSettings.setCodec("audio/x-adpcm");
190     m_audioSettings.setChannelCount(2);
191     m_audioSettings.setQuality(QMultimedia::NormalQuality);
192     m_mediaRecorder->setAudioSettings(m_audioSettings);
193 
194     m_videoSettings.setCodec("video/x-h264");
195     m_videoSettings.setResolution(size);
196     m_videoSettings.setQuality(QMultimedia::NormalQuality);
197     m_mediaRecorder->setVideoSettings(m_videoSettings);
198 
199     m_mediaRecorder->setContainerFormat("video/quicktime");
200 
201     if (0) {
202         QList<QSize> supportedResolutions;
203         supportedResolutions = m_imageCapture->supportedResolutions();
204         for (const QSize &resolution : supportedResolutions) {
205              qDebug() << "image resolution: " << resolution.width() << "x" << resolution.height();
206         }
207 
208         supportedResolutions = m_mediaRecorder->supportedResolutions();
209         for (const QSize &resolution : supportedResolutions) {
210             qDebug() << "video resolution: " << resolution.width() << "x" << resolution.height();
211         }
212 
213         const QStringList supportedAudioCodecs = m_mediaRecorder->supportedAudioCodecs();
214         for (const QString &codecName : supportedAudioCodecs) {
215             QString description = m_mediaRecorder->audioCodecDescription(codecName);
216             qDebug() << "audio codec:" << codecName + ": " + description;
217         }
218 
219         const QStringList supportedVideoCodecs = m_mediaRecorder->supportedVideoCodecs();
220         for (const QString &codecName : supportedVideoCodecs) {
221             QString description = m_mediaRecorder->videoCodecDescription(codecName);
222             qDebug() << "video codec:" << codecName + ": " + description;
223         }
224 
225         const QStringList formats = m_mediaRecorder->supportedContainers();
226         for (const QString &format : formats) {
227             QString description = m_mediaRecorder->containerDescription(format);
228             qDebug() << "container: " << format << ": " << description;
229         }
230     }
231 }
232 
getButton()233 QPushButton* qtCamera::getButton()
234 {
235     QPushButton *button = new QPushButton;
236     button->setFixedSize(144, 70);
237     return button;
238 }
239 
updateRecordTime()240 void qtCamera::updateRecordTime()
241 {
242     quint32 dura_smal;
243     quint64 duration;
244 
245     dura_smal = m_mediaRecorder->duration() % 1000;
246     duration = m_mediaRecorder->duration() / 1000;
247     if (dura_smal >= 500)
248         duration += 1;
249 
250     QString str = QString("Recorded %1 sec").arg(duration);
251     statusBar()->showMessage(str);
252 }
253 
record()254 void qtCamera::record()
255 {
256     QFileInfo fi;
257     QString lo;
258 
259     lo = locationDir + "/" + "VIDEO" + QString::number(videoCnt) + ".mov";
260     fi = QFileInfo(lo);
261 
262     while(fi.isFile()){
263         videoCnt++;
264         lo = locationDir + "/" + "VIDEO" + QString::number(videoCnt) + ".mov";
265         fi = QFileInfo(lo);
266     }
267 
268     m_mediaRecorder->setOutputLocation(QUrl::fromLocalFile(lo));
269     m_mediaRecorder->record();
270     updateRecordTime();
271 }
272 
stop()273 void qtCamera::stop()
274 {
275     m_mediaRecorder->stop();
276 }
277 
takeImage()278 void qtCamera::takeImage()
279 {
280     m_isCapturingImage = true;
281     QFileInfo fi;
282     QString lo;
283 
284     lo = locationDir + "/" + "PIC" + QString::number(imageCnt) + ".jpg";
285     fi = QFileInfo(lo);
286 
287     while(fi.isFile()){
288         imageCnt++;
289         lo = locationDir + "/" + "PIC" + QString::number(imageCnt) + ".jpg";
290         fi = QFileInfo(lo);
291     }
292 
293     m_imageCapture->capture(lo);
294 }
295 
displayCaptureError(int id,const QCameraImageCapture::Error error,const QString & errorString)296 void qtCamera::displayCaptureError(int id, const QCameraImageCapture::Error error, const QString &errorString)
297 {
298     Q_UNUSED(id);
299     Q_UNUSED(error);
300     QMessageBox::warning(this, tr("Image Capture Error"), errorString);
301     m_isCapturingImage = false;
302 }
303 
updateCaptureMode()304 void qtCamera::updateCaptureMode()
305 {
306     QCamera::CaptureModes captureMode;
307     QString capture;
308     if (cameraMode.compare(QCAMERA_CAPTURE_MODE)){
309         captureMode = QCamera::CaptureStillImage ;
310     }else {
311         captureMode = QCamera::CaptureVideo;
312     }
313 
314     if (m_camera->isCaptureModeSupported(captureMode)){
315         m_camera->unload();
316         m_camera->setCaptureMode(captureMode);
317         m_camera->start();
318         if(captureMode == QCamera::CaptureStillImage){
319             cameraMode = QString(QCAMERA_CAPTURE_MODE);
320             capture = "Capture";
321         }else {
322             cameraMode = QString(QCAMERA_VIDEO_MODE);
323             capture = "Record";
324         }
325         modeButton->setText(cameraMode);
326         captureButton->setText(capture);
327     }
328 }
329 
updateCameraState(QCamera::State state)330 void qtCamera::updateCameraState(QCamera::State state)
331 {
332     switch (state) {
333     case QCamera::ActiveState:
334         break;
335     case QCamera::UnloadedState:
336     case QCamera::LoadedState:
337         break;
338     }
339 }
340 
updateRecorderState(QMediaRecorder::State state)341 void qtCamera::updateRecorderState(QMediaRecorder::State state)
342 {
343     switch (state) {
344     case QMediaRecorder::StoppedState:
345         captureButton->setText(tr("Record"));
346         break;
347     case QMediaRecorder::PausedState:
348         break;
349     case QMediaRecorder::RecordingState:
350         captureButton->setText(tr("Recording"));
351         break;
352     }
353 }
354 
displayRecorderError()355 void qtCamera::displayRecorderError()
356 {
357     QMessageBox::warning(this, tr("Capture Error"), m_mediaRecorder->errorString());
358 }
359 
displayCameraError()360 void qtCamera::displayCameraError()
361 {
362     QMessageBox::warning(this, tr("Camera Error"), m_camera->errorString());
363 }
364 
imageSaved(int id,const QString & fileName)365 void qtCamera::imageSaved(int id, const QString &fileName)
366 {
367     Q_UNUSED(id);
368     statusBar()->showMessage(tr("Captured \"%1\"").arg(QDir::toNativeSeparators(fileName)));
369     statusBar()->show();
370     m_isCapturingImage = false;
371     if (m_applicationExiting)
372         close();
373 }
374 
closeEvent(QCloseEvent * event)375 void qtCamera::closeEvent(QCloseEvent *event)
376 {
377     if (m_isCapturingImage) {
378         setEnabled(false);
379         m_applicationExiting = true;
380         event->ignore();
381     } else {
382         event->accept();
383     }
384 }
385 
on_cameraSwitch()386 void qtCamera::on_cameraSwitch()
387 {
388     QList<QPushButton *> buttons = centralWidget()->findChildren<QPushButton *>();
389     for(auto *bt: buttons){
390         if(bt->isChecked()){
391             for(auto *button: buttons){
392                 if(button->isDefault())
393                     button->setDefault(false);
394             }
395             bt->setDefault(true);
396             bt->setChecked(false);
397             qDebug() << "switch to " + bt->text();
398             const QList<QCameraInfo> availableCameras = QCameraInfo::availableCameras();
399             for (const QCameraInfo &cameraInfo : availableCameras) {
400                 if(! bt->text().compare(cameraInfo.description())){
401                     qDebug() << cameraInfo.description();
402                     setCamera(cameraInfo);
403                 }
404             }
405             break;
406         }
407     }
408 }
409 
on_captureClicked()410 void qtCamera::on_captureClicked()
411 {
412     if (m_camera->captureMode() == QCamera::CaptureStillImage) {
413         if(m_imageCapture->isReadyForCapture())
414             takeImage();
415     } else if(m_camera->captureMode() == QCamera::CaptureVideo){
416         if (m_mediaRecorder->state() == QMediaRecorder::RecordingState)
417             stop();
418         else
419             record();
420     }
421 }
422 
on_exitClicked()423 void qtCamera::on_exitClicked()
424 {
425         qApp->exit(0);
426 }
427