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 | |
77 | QDeclarativeCameraRecorder::QDeclarativeCameraRecorder(QCamera *camera, QObject *parent) : |
78 | QObject(parent) |
79 | { |
80 | m_recorder = new QMediaRecorder(camera, this); |
81 | connect(asender: m_recorder, SIGNAL(stateChanged(QMediaRecorder::State)), |
82 | SLOT(updateRecorderState(QMediaRecorder::State))); |
83 | connect(asender: m_recorder, SIGNAL(statusChanged(QMediaRecorder::Status)), |
84 | SIGNAL(recorderStatusChanged())); |
85 | connect(asender: m_recorder, SIGNAL(error(QMediaRecorder::Error)), |
86 | SLOT(updateRecorderError(QMediaRecorder::Error))); |
87 | connect(asender: m_recorder, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged(bool))); |
88 | connect(asender: m_recorder, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged(qint64))); |
89 | connect(asender: m_recorder, SIGNAL(actualLocationChanged(QUrl)), |
90 | SLOT(updateActualLocation(QUrl))); |
91 | connect(asender: m_recorder, SIGNAL(metaDataChanged(QString,QVariant)), |
92 | SIGNAL(metaDataChanged(QString,QVariant))); |
93 | } |
94 | |
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 | */ |
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 | */ |
117 | 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 | */ |
128 | 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 | */ |
139 | QString QDeclarativeCameraRecorder::mediaContainer() const |
140 | { |
141 | return m_mediaContainer; |
142 | } |
143 | |
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 | |
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 | |
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 | |
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 | */ |
188 | 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 | */ |
198 | 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 | */ |
208 | 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 | */ |
219 | 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 | */ |
229 | 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 | */ |
255 | 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 | */ |
278 | QDeclarativeCameraRecorder::EncodingMode QDeclarativeCameraRecorder::audioEncodingMode() const |
279 | { |
280 | return EncodingMode(m_audioSettings.encodingMode()); |
281 | } |
282 | |
283 | void QDeclarativeCameraRecorder::setFrameRate(qreal frameRate) |
284 | { |
285 | m_videoSettings = m_recorder->videoSettings(); |
286 | if (!qFuzzyCompare(p1: m_videoSettings.frameRate(),p2: frameRate)) { |
287 | m_videoSettings.setFrameRate(frameRate); |
288 | m_recorder->setVideoSettings(m_videoSettings); |
289 | emit frameRateChanged(arg: frameRate); |
290 | } |
291 | } |
292 | |
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(arg: rate); |
300 | } |
301 | } |
302 | |
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(arg: rate); |
310 | } |
311 | } |
312 | |
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(arg: channels); |
320 | } |
321 | } |
322 | |
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(arg: rate); |
330 | } |
331 | } |
332 | |
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 | |
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 | */ |
374 | 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 | */ |
384 | 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 | */ |
405 | 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 | |
443 | 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 | */ |
453 | void QDeclarativeCameraRecorder::record() |
454 | { |
455 | setRecorderState(RecordingState); |
456 | } |
457 | |
458 | /*! |
459 | \qmlmethod QtMultimedia::CameraRecorder::stop() |
460 | |
461 | Stops recording. |
462 | */ |
463 | void QDeclarativeCameraRecorder::stop() |
464 | { |
465 | setRecorderState(StoppedState); |
466 | } |
467 | |
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 | |
495 | 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 | |
513 | QString QDeclarativeCameraRecorder::actualLocation() const |
514 | { |
515 | return m_recorder->actualLocation().toString(); |
516 | } |
517 | |
518 | void QDeclarativeCameraRecorder::setOutputLocation(const QString &location) |
519 | { |
520 | if (outputLocation() != location) { |
521 | m_recorder->setOutputLocation(location); |
522 | emit outputLocationChanged(location: 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 | */ |
535 | 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 | */ |
550 | bool QDeclarativeCameraRecorder::isMuted() const |
551 | { |
552 | return m_recorder->isMuted(); |
553 | } |
554 | |
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 | */ |
566 | void QDeclarativeCameraRecorder::setMetadata(const QString &key, const QVariant &value) |
567 | { |
568 | m_recorder->setMetaData(key, value); |
569 | } |
570 | |
571 | void QDeclarativeCameraRecorder::updateRecorderState(QMediaRecorder::State state) |
572 | { |
573 | if (state == QMediaRecorder::PausedState) |
574 | state = QMediaRecorder::StoppedState; |
575 | |
576 | emit recorderStateChanged(state: RecorderState(state)); |
577 | } |
578 | |
579 | void QDeclarativeCameraRecorder::updateRecorderError(QMediaRecorder::Error errorCode) |
580 | { |
581 | qWarning() << "QMediaRecorder error:" << errorString(); |
582 | emit error(errorCode: Error(errorCode), errorString: errorString()); |
583 | } |
584 | |
585 | void QDeclarativeCameraRecorder::updateActualLocation(const QUrl &url) |
586 | { |
587 | emit actualLocationChanged(location: url.toString()); |
588 | } |
589 | |
590 | QT_END_NAMESPACE |
591 | |
592 | #include "moc_qdeclarativecamerarecorder_p.cpp" |
593 | |