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 plugins 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 "qdeclarativecamera_p.h"
41 #include "qdeclarativecamerarecorder_p.h"
42 
43 #include <QtCore/qurl.h>
44 
45 QT_BEGIN_NAMESPACE
46 
47 /*!
48     \qmltype CameraRecorder
49     \instantiates QDeclarativeCameraRecorder
50     \inqmlmodule QtMultimedia
51     \brief Controls video recording with the Camera.
52     \ingroup multimedia_qml
53     \ingroup camera_qml
54 
55     CameraRecorder allows recording camera streams to files, and adjusting recording
56     settings and metadata for videos.
57 
58     It should not be constructed separately, instead the
59     \c videoRecorder property of a \l Camera should be used.
60 
61     \qml
62     Camera {
63         videoRecorder.audioEncodingMode: CameraRecorder.ConstantBitrateEncoding;
64         videoRecorder.audioBitRate: 128000
65         videoRecorder.mediaContainer: "mp4"
66         // ...
67     }
68     \endqml
69 
70     There are many different settings for each part of the recording process (audio,
71     video, and output formats), as well as control over muting and where to store
72     the output file.
73 
74     \sa QAudioEncoderSettings, QVideoEncoderSettings
75 */
76 
QDeclarativeCameraRecorder(QCamera * camera,QObject * parent)77 QDeclarativeCameraRecorder::QDeclarativeCameraRecorder(QCamera *camera, QObject *parent) :
78     QObject(parent)
79 {
80     m_recorder = new QMediaRecorder(camera, this);
81     connect(m_recorder, SIGNAL(stateChanged(QMediaRecorder::State)),
82             SLOT(updateRecorderState(QMediaRecorder::State)));
83     connect(m_recorder, SIGNAL(statusChanged(QMediaRecorder::Status)),
84             SIGNAL(recorderStatusChanged()));
85     connect(m_recorder, SIGNAL(error(QMediaRecorder::Error)),
86             SLOT(updateRecorderError(QMediaRecorder::Error)));
87     connect(m_recorder, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged(bool)));
88     connect(m_recorder, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged(qint64)));
89     connect(m_recorder, SIGNAL(actualLocationChanged(QUrl)),
90             SLOT(updateActualLocation(QUrl)));
91     connect(m_recorder, SIGNAL(metaDataChanged(QString,QVariant)),
92             SIGNAL(metaDataChanged(QString,QVariant)));
93 }
94 
~QDeclarativeCameraRecorder()95 QDeclarativeCameraRecorder::~QDeclarativeCameraRecorder()
96 {
97 }
98 
99 /*!
100     \qmlproperty size QtMultimedia::CameraRecorder::resolution
101 
102     This property holds the video frame dimensions to be used for video capture.
103 */
captureResolution()104 QSize QDeclarativeCameraRecorder::captureResolution()
105 {
106     return m_videoSettings.resolution();
107 }
108 
109 /*!
110     \qmlproperty string QtMultimedia::CameraRecorder::audioCodec
111 
112     This property holds the audio codec to be used for recording video.
113     Typically this is \c aac or \c amr-wb.
114 
115     \sa {QtMultimedia::CameraImageProcessing::whiteBalanceMode}{whileBalanceMode}
116 */
audioCodec() const117 QString QDeclarativeCameraRecorder::audioCodec() const
118 {
119     return m_audioSettings.codec();
120 }
121 
122 /*!
123     \qmlproperty string QtMultimedia::CameraRecorder::videoCodec
124 
125     This property holds the video codec to be used for recording video.
126     Typically this is \c h264.
127 */
videoCodec() const128 QString QDeclarativeCameraRecorder::videoCodec() const
129 {
130     return m_videoSettings.codec();
131 }
132 
133 /*!
134     \qmlproperty string QtMultimedia::CameraRecorder::mediaContainer
135 
136     This property holds the media container to be used for recording video.
137     Typically this is \c mp4.
138 */
mediaContainer() const139 QString QDeclarativeCameraRecorder::mediaContainer() const
140 {
141     return m_mediaContainer;
142 }
143 
setCaptureResolution(const QSize & resolution)144 void QDeclarativeCameraRecorder::setCaptureResolution(const QSize &resolution)
145 {
146     m_videoSettings = m_recorder->videoSettings();
147     if (resolution != captureResolution()) {
148         m_videoSettings.setResolution(resolution);
149         m_recorder->setVideoSettings(m_videoSettings);
150         emit captureResolutionChanged(resolution);
151     }
152 }
153 
setAudioCodec(const QString & codec)154 void QDeclarativeCameraRecorder::setAudioCodec(const QString &codec)
155 {
156     m_audioSettings = m_recorder->audioSettings();
157     if (codec != audioCodec()) {
158         m_audioSettings.setCodec(codec);
159         m_recorder->setAudioSettings(m_audioSettings);
160         emit audioCodecChanged(codec);
161     }
162 }
163 
setVideoCodec(const QString & codec)164 void QDeclarativeCameraRecorder::setVideoCodec(const QString &codec)
165 {
166     m_videoSettings = m_recorder->videoSettings();
167     if (codec != videoCodec()) {
168         m_videoSettings.setCodec(codec);
169         m_recorder->setVideoSettings(m_videoSettings);
170         emit videoCodecChanged(codec);
171     }
172 }
173 
setMediaContainer(const QString & container)174 void QDeclarativeCameraRecorder::setMediaContainer(const QString &container)
175 {
176     if (container != m_mediaContainer) {
177         m_mediaContainer = container;
178         m_recorder->setContainerFormat(container);
179         emit mediaContainerChanged(container);
180     }
181 }
182 
183 /*!
184     \qmlproperty qreal QtMultimedia::CameraRecorder::frameRate
185 
186     This property holds the framerate (in frames per second) to be used for recording video.
187 */
frameRate() const188 qreal QDeclarativeCameraRecorder::frameRate() const
189 {
190     return m_videoSettings.frameRate();
191 }
192 
193 /*!
194     \qmlproperty int QtMultimedia::CameraRecorder::videoBitRate
195 
196     This property holds the bit rate (in bits per second) to be used for recording video.
197 */
videoBitRate() const198 int QDeclarativeCameraRecorder::videoBitRate() const
199 {
200     return m_videoSettings.bitRate();
201 }
202 
203 /*!
204     \qmlproperty int QtMultimedia::CameraRecorder::audioBitRate
205 
206     This property holds the audio bit rate (in bits per second) to be used for recording video.
207 */
audioBitRate() const208 int QDeclarativeCameraRecorder::audioBitRate() const
209 {
210     return m_audioSettings.bitRate();
211 }
212 
213 /*!
214     \qmlproperty int QtMultimedia::CameraRecorder::audioChannels
215 
216     This property indicates the number of audio channels to be encoded while
217     recording video (1 is mono, 2 is stereo).
218 */
audioChannels() const219 int QDeclarativeCameraRecorder::audioChannels() const
220 {
221     return m_audioSettings.channelCount();
222 }
223 
224 /*!
225     \qmlproperty int QtMultimedia::CameraRecorder::audioSampleRate
226 
227     This property holds the sample rate to be used to encode audio while recording video.
228 */
audioSampleRate() const229 int QDeclarativeCameraRecorder::audioSampleRate() const
230 {
231     return m_audioSettings.sampleRate();
232 }
233 
234 /*!
235     \qmlproperty enumeration QtMultimedia::CameraRecorder::videoEncodingMode
236 
237     This property holds the type of encoding method to be used for recording video.
238 
239     The following are the different encoding methods used:
240 
241     \table
242     \header \li Value \li Description
243     \row \li ConstantQualityEncoding
244          \li Encoding will aim to have a constant quality, adjusting bitrate to fit.
245             This is the default.  The bitrate setting will be ignored.
246     \row \li ConstantBitRateEncoding
247          \li Encoding will use a constant bit rate, adjust quality to fit.  This is
248             appropriate if you are trying to optimize for space.
249     \row \li AverageBitRateEncoding
250          \li Encoding will try to keep an average bitrate setting, but will use
251             more or less as needed.
252     \endtable
253 
254 */
videoEncodingMode() const255 QDeclarativeCameraRecorder::EncodingMode QDeclarativeCameraRecorder::videoEncodingMode() const
256 {
257     return EncodingMode(m_videoSettings.encodingMode());
258 }
259 
260 /*!
261     \qmlproperty enumeration QtMultimedia::CameraRecorder::audioEncodingMode
262 
263     The type of encoding method to use when recording audio.
264 
265     \table
266     \header \li Value \li Description
267     \row \li ConstantQualityEncoding
268          \li Encoding will aim to have a constant quality, adjusting bitrate to fit.
269             This is the default.  The bitrate setting will be ignored.
270     \row \li ConstantBitRateEncoding
271          \li Encoding will use a constant bit rate, adjust quality to fit.  This is
272             appropriate if you are trying to optimize for space.
273     \row \li AverageBitRateEncoding
274          \li Encoding will try to keep an average bitrate setting, but will use
275             more or less as needed.
276     \endtable
277 */
audioEncodingMode() const278 QDeclarativeCameraRecorder::EncodingMode QDeclarativeCameraRecorder::audioEncodingMode() const
279 {
280     return EncodingMode(m_audioSettings.encodingMode());
281 }
282 
setFrameRate(qreal frameRate)283 void QDeclarativeCameraRecorder::setFrameRate(qreal frameRate)
284 {
285     m_videoSettings = m_recorder->videoSettings();
286     if (!qFuzzyCompare(m_videoSettings.frameRate(),frameRate)) {
287         m_videoSettings.setFrameRate(frameRate);
288         m_recorder->setVideoSettings(m_videoSettings);
289         emit frameRateChanged(frameRate);
290     }
291 }
292 
setVideoBitRate(int rate)293 void QDeclarativeCameraRecorder::setVideoBitRate(int rate)
294 {
295     m_videoSettings = m_recorder->videoSettings();
296     if (m_videoSettings.bitRate() != rate) {
297         m_videoSettings.setBitRate(rate);
298         m_recorder->setVideoSettings(m_videoSettings);
299         emit videoBitRateChanged(rate);
300     }
301 }
302 
setAudioBitRate(int rate)303 void QDeclarativeCameraRecorder::setAudioBitRate(int rate)
304 {
305     m_audioSettings = m_recorder->audioSettings();
306     if (m_audioSettings.bitRate() != rate) {
307         m_audioSettings.setBitRate(rate);
308         m_recorder->setAudioSettings(m_audioSettings);
309         emit audioBitRateChanged(rate);
310     }
311 }
312 
setAudioChannels(int channels)313 void QDeclarativeCameraRecorder::setAudioChannels(int channels)
314 {
315     m_audioSettings = m_recorder->audioSettings();
316     if (m_audioSettings.channelCount() != channels) {
317         m_audioSettings.setChannelCount(channels);
318         m_recorder->setAudioSettings(m_audioSettings);
319         emit audioChannelsChanged(channels);
320     }
321 }
322 
setAudioSampleRate(int rate)323 void QDeclarativeCameraRecorder::setAudioSampleRate(int rate)
324 {
325     m_audioSettings = m_recorder->audioSettings();
326     if (m_audioSettings.sampleRate() != rate) {
327         m_audioSettings.setSampleRate(rate);
328         m_recorder->setAudioSettings(m_audioSettings);
329         emit audioSampleRateChanged(rate);
330     }
331 }
332 
setAudioEncodingMode(QDeclarativeCameraRecorder::EncodingMode encodingMode)333 void QDeclarativeCameraRecorder::setAudioEncodingMode(QDeclarativeCameraRecorder::EncodingMode encodingMode)
334 {
335     m_audioSettings = m_recorder->audioSettings();
336     if (m_audioSettings.encodingMode() != QMultimedia::EncodingMode(encodingMode)) {
337         m_audioSettings.setEncodingMode(QMultimedia::EncodingMode(encodingMode));
338         m_recorder->setAudioSettings(m_audioSettings);
339         emit audioEncodingModeChanged(encodingMode);
340     }
341 }
342 
setVideoEncodingMode(QDeclarativeCameraRecorder::EncodingMode encodingMode)343 void QDeclarativeCameraRecorder::setVideoEncodingMode(QDeclarativeCameraRecorder::EncodingMode encodingMode)
344 {
345     m_videoSettings = m_recorder->videoSettings();
346     if (m_videoSettings.encodingMode() != QMultimedia::EncodingMode(encodingMode)) {
347         m_videoSettings.setEncodingMode(QMultimedia::EncodingMode(encodingMode));
348         m_recorder->setVideoSettings(m_videoSettings);
349         emit videoEncodingModeChanged(encodingMode);
350     }
351 }
352 
353 /*!
354     \qmlproperty enumeration QtMultimedia::CameraRecorder::errorCode
355 
356     This property holds the last error code.
357 
358     \table
359     \header \li Value \li Description
360     \row \li NoError
361          \li No Errors
362 
363     \row \li ResourceError
364          \li Device is not ready or not available.
365 
366     \row \li FormatError
367          \li Current format is not supported.
368 
369     \row \li OutOfSpaceError
370          \li No space left on device.
371 
372     \endtable
373 */
errorCode() const374 QDeclarativeCameraRecorder::Error QDeclarativeCameraRecorder::errorCode() const
375 {
376     return QDeclarativeCameraRecorder::Error(m_recorder->error());
377 }
378 
379 /*!
380     \qmlproperty string QtMultimedia::CameraRecorder::errorString
381 
382     This property holds the description of the last error.
383 */
errorString() const384 QString QDeclarativeCameraRecorder::errorString() const
385 {
386     return m_recorder->errorString();
387 }
388 
389 /*!
390     \qmlproperty enumeration QtMultimedia::CameraRecorder::recorderState
391 
392     This property holds the current state of the camera recorder object.
393 
394     The state can be one of these two:
395 
396     \table
397     \header \li Value \li Description
398     \row \li StoppedState
399          \li The camera is not recording video.
400 
401     \row \li RecordingState
402          \li The camera is recording video.
403     \endtable
404 */
recorderState() const405 QDeclarativeCameraRecorder::RecorderState QDeclarativeCameraRecorder::recorderState() const
406 {
407     //paused state is not supported for camera
408     QMediaRecorder::State state = m_recorder->state();
409 
410     if (state == QMediaRecorder::PausedState)
411         state = QMediaRecorder::StoppedState;
412 
413     return RecorderState(state);
414 }
415 
416 
417 /*!
418     \qmlproperty enumeration QtMultimedia::CameraRecorder::recorderStatus
419 
420     This property holds the current status of media recording.
421 
422     \table
423     \header \li Value \li Description
424     \row \li UnavailableStatus
425          \li Recording is not supported by the camera.
426     \row \li UnloadedStatus
427          \li The recorder is available but not loaded.
428     \row \li LoadingStatus
429          \li The recorder is initializing.
430     \row \li LoadedStatus
431          \li The recorder is initialized and ready to record media.
432     \row \li StartingStatus
433          \li Recording is requested but not active yet.
434     \row \li RecordingStatus
435          \li Recording is active.
436     \row \li PausedStatus
437          \li Recording is paused.
438     \row \li FinalizingStatus
439          \li Recording is stopped with media being finalized.
440     \endtable
441 */
442 
recorderStatus() const443 QDeclarativeCameraRecorder::RecorderStatus QDeclarativeCameraRecorder::recorderStatus() const
444 {
445     return RecorderStatus(m_recorder->status());
446 }
447 
448 /*!
449     \qmlmethod QtMultimedia::CameraRecorder::record()
450 
451     Starts recording.
452 */
record()453 void QDeclarativeCameraRecorder::record()
454 {
455     setRecorderState(RecordingState);
456 }
457 
458 /*!
459     \qmlmethod QtMultimedia::CameraRecorder::stop()
460 
461     Stops recording.
462 */
stop()463 void QDeclarativeCameraRecorder::stop()
464 {
465     setRecorderState(StoppedState);
466 }
467 
setRecorderState(QDeclarativeCameraRecorder::RecorderState state)468 void QDeclarativeCameraRecorder::setRecorderState(QDeclarativeCameraRecorder::RecorderState state)
469 {
470     if (!m_recorder)
471         return;
472 
473     switch (state) {
474     case QDeclarativeCameraRecorder::RecordingState:
475         m_recorder->record();
476         break;
477     case QDeclarativeCameraRecorder::StoppedState:
478         m_recorder->stop();
479         break;
480     }
481 }
482 /*!
483     \property QDeclarativeCameraRecorder::outputLocation
484 
485     This property holds the destination location of the media content. If it is empty,
486     the recorder uses the system-specific place and file naming scheme.
487 */
488 /*!
489     \qmlproperty string QtMultimedia::CameraRecorder::outputLocation
490 
491     This property holds the destination location of the media content. If the location is empty,
492     the recorder uses the system-specific place and file naming scheme.
493 */
494 
outputLocation() const495 QString QDeclarativeCameraRecorder::outputLocation() const
496 {
497     return m_recorder->outputLocation().toString();
498 }
499 /*!
500     \property QDeclarativeCameraRecorder::actualLocation
501 
502     This property holds the absolute location to the last saved media content.
503     The location is usually available after recording starts, and reset when
504     new location is set or new recording starts.
505 */
506 /*!
507     \qmlproperty string QtMultimedia::CameraRecorder::actualLocation
508 
509     This property holds the actual location of the last saved media content. The actual location is
510     usually available after the recording starts, and reset when new location is set or the new recording starts.
511 */
512 
actualLocation() const513 QString QDeclarativeCameraRecorder::actualLocation() const
514 {
515     return m_recorder->actualLocation().toString();
516 }
517 
setOutputLocation(const QString & location)518 void QDeclarativeCameraRecorder::setOutputLocation(const QString &location)
519 {
520     if (outputLocation() != location) {
521         m_recorder->setOutputLocation(location);
522         emit outputLocationChanged(outputLocation());
523     }
524 }
525 /*!
526     \property QDeclarativeCameraRecorder::duration
527 
528     This property holds the duration (in miliseconds) of the last recording.
529 */
530 /*!
531     \qmlproperty int QtMultimedia::CameraRecorder::duration
532 
533    This property holds the duration (in miliseconds) of the last recording.
534 */
duration() const535 qint64 QDeclarativeCameraRecorder::duration() const
536 {
537     return m_recorder->duration();
538 }
539 /*!
540     \property QDeclarativeCameraRecorder::muted
541 
542     This property indicates whether the audio input is muted during
543     recording.
544 */
545 /*!
546     \qmlproperty bool QtMultimedia::CameraRecorder::muted
547 
548     This property indicates whether the audio input is muted during recording.
549 */
isMuted() const550 bool QDeclarativeCameraRecorder::isMuted() const
551 {
552     return m_recorder->isMuted();
553 }
554 
setMuted(bool muted)555 void QDeclarativeCameraRecorder::setMuted(bool muted)
556 {
557     m_recorder->setMuted(muted);
558 }
559 
560 /*!
561     \qmlmethod QtMultimedia::CameraRecorder::setMetadata(key, value)
562 
563     Sets metadata for the next video to be recorder, with
564     the given \a key being associated with \a value.
565 */
setMetadata(const QString & key,const QVariant & value)566 void QDeclarativeCameraRecorder::setMetadata(const QString &key, const QVariant &value)
567 {
568     m_recorder->setMetaData(key, value);
569 }
570 
updateRecorderState(QMediaRecorder::State state)571 void QDeclarativeCameraRecorder::updateRecorderState(QMediaRecorder::State state)
572 {
573     if (state == QMediaRecorder::PausedState)
574         state = QMediaRecorder::StoppedState;
575 
576     emit recorderStateChanged(RecorderState(state));
577 }
578 
updateRecorderError(QMediaRecorder::Error errorCode)579 void QDeclarativeCameraRecorder::updateRecorderError(QMediaRecorder::Error errorCode)
580 {
581     qWarning() << "QMediaRecorder error:" << errorString();
582     emit error(Error(errorCode), errorString());
583 }
584 
updateActualLocation(const QUrl & url)585 void QDeclarativeCameraRecorder::updateActualLocation(const QUrl &url)
586 {
587     emit actualLocationChanged(url.toString());
588 }
589 
590 QT_END_NAMESPACE
591 
592 #include "moc_qdeclarativecamerarecorder_p.cpp"
593