summaryrefslogtreecommitdiffstats
path: root/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/avfoundation/camera/avfmediarecordercontrol.mm')
-rw-r--r--src/plugins/avfoundation/camera/avfmediarecordercontrol.mm342
1 files changed, 342 insertions, 0 deletions
diff --git a/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm b/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm
new file mode 100644
index 000000000..5278ee519
--- /dev/null
+++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm
@@ -0,0 +1,342 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "avfcameradebug.h"
+#include "avfmediarecordercontrol.h"
+#include "avfcamerasession.h"
+#include "avfcameraservice.h"
+#include "avfcameracontrol.h"
+
+#include <QtCore/qurl.h>
+#include <QtCore/qfileinfo.h>
+#include <QtMultimedia/qcameracontrol.h>
+
+
+QT_USE_NAMESPACE
+
+@interface AVFMediaRecorderDelegate : NSObject <AVCaptureFileOutputRecordingDelegate>
+{
+@private
+ AVFMediaRecorderControl *m_recorder;
+}
+
+- (AVFMediaRecorderDelegate *) initWithRecorder:(AVFMediaRecorderControl*)recorder;
+
+- (void) captureOutput:(AVCaptureFileOutput *)captureOutput
+ didStartRecordingToOutputFileAtURL:(NSURL *)fileURL
+ fromConnections:(NSArray *)connections;
+
+- (void) captureOutput:(AVCaptureFileOutput *)captureOutput
+ didFinishRecordingToOutputFileAtURL:(NSURL *)fileURL
+ fromConnections:(NSArray *)connections
+ error:(NSError *)error;
+@end
+
+@implementation AVFMediaRecorderDelegate
+
+- (AVFMediaRecorderDelegate *) initWithRecorder:(AVFMediaRecorderControl*)recorder
+{
+ if (!(self = [super init]))
+ return nil;
+
+ self->m_recorder = recorder;
+ return self;
+}
+
+- (void) captureOutput:(AVCaptureFileOutput *)captureOutput
+ didStartRecordingToOutputFileAtURL:(NSURL *)fileURL
+ fromConnections:(NSArray *)connections
+{
+ Q_UNUSED(captureOutput);
+ Q_UNUSED(fileURL);
+ Q_UNUSED(connections)
+
+ QMetaObject::invokeMethod(m_recorder, "handleRecordingStarted", Qt::QueuedConnection);
+}
+
+- (void) captureOutput:(AVCaptureFileOutput *)captureOutput
+ didFinishRecordingToOutputFileAtURL:(NSURL *)fileURL
+ fromConnections:(NSArray *)connections
+ error:(NSError *)error
+{
+ Q_UNUSED(captureOutput);
+ Q_UNUSED(fileURL);
+ Q_UNUSED(connections)
+
+ if (error) {
+ QStringList messageParts;
+ messageParts << QString::fromUtf8([[error localizedDescription] UTF8String]);
+ messageParts << QString::fromUtf8([[error localizedFailureReason] UTF8String]);
+ messageParts << QString::fromUtf8([[error localizedRecoverySuggestion] UTF8String]);
+
+ QString errorMessage = messageParts.join(" ");
+
+ QMetaObject::invokeMethod(m_recorder, "handleRecordingFailed", Qt::QueuedConnection,
+ Q_ARG(QString, errorMessage));
+ } else {
+ QMetaObject::invokeMethod(m_recorder, "handleRecordingFinished", Qt::QueuedConnection);
+ }
+}
+
+@end
+
+
+AVFMediaRecorderControl::AVFMediaRecorderControl(AVFCameraService *service, QObject *parent)
+ : QMediaRecorderControl(parent)
+ , m_cameraControl(service->cameraControl())
+ , m_session(service->session())
+ , m_connected(false)
+ , m_state(QMediaRecorder::StoppedState)
+ , m_lastStatus(QMediaRecorder::UnloadedStatus)
+ , m_recordingStarted(false)
+ , m_recordingFinished(false)
+ , m_muted(false)
+ , m_volume(1.0)
+{
+ m_movieOutput = [[AVCaptureMovieFileOutput alloc] init];
+ m_recorderDelagate = [[AVFMediaRecorderDelegate alloc] initWithRecorder:this];
+
+ connect(m_cameraControl, SIGNAL(stateChanged(QCamera::State)), SLOT(updateStatus()));
+ connect(m_cameraControl, SIGNAL(statusChanged(QCamera::Status)), SLOT(updateStatus()));
+ connect(m_cameraControl, SIGNAL(captureModeChanged(QCamera::CaptureModes)), SLOT(reconnectMovieOutput()));
+
+ reconnectMovieOutput();
+}
+
+AVFMediaRecorderControl::~AVFMediaRecorderControl()
+{
+ if (m_movieOutput)
+ [m_session->captureSession() removeOutput:m_movieOutput];
+
+ [m_recorderDelagate release];
+}
+
+QUrl AVFMediaRecorderControl::outputLocation() const
+{
+ return m_outputLocation;
+}
+
+bool AVFMediaRecorderControl::setOutputLocation(const QUrl &location)
+{
+ m_outputLocation = location;
+ return location.scheme() == QLatin1String("file") || location.scheme().isEmpty();
+}
+
+QMediaRecorder::State AVFMediaRecorderControl::state() const
+{
+ return m_state;
+}
+
+QMediaRecorder::Status AVFMediaRecorderControl::status() const
+{
+ QMediaRecorder::Status status = m_lastStatus;
+ //bool videoEnabled = m_cameraControl->captureMode().testFlag(QCamera::CaptureVideo);
+
+ if (m_cameraControl->status() == QCamera::ActiveStatus && m_connected) {
+ if (m_state == QMediaRecorder::StoppedState) {
+ if (m_recordingStarted && !m_recordingFinished)
+ status = QMediaRecorder::FinalizingStatus;
+ else
+ status = QMediaRecorder::LoadedStatus;
+ } else {
+ status = m_recordingStarted ? QMediaRecorder::RecordingStatus :
+ QMediaRecorder::StartingStatus;
+ }
+ } else {
+ //camera not started yet
+ status = m_cameraControl->state() == QCamera::ActiveState && m_connected ?
+ QMediaRecorder::LoadingStatus:
+ QMediaRecorder::UnloadedStatus;
+ }
+
+ return status;
+}
+
+void AVFMediaRecorderControl::updateStatus()
+{
+ QMediaRecorder::Status newStatus = status();
+
+ if (m_lastStatus != newStatus) {
+ qDebugCamera() << "Camera recorder status changed: " << m_lastStatus << " -> " << newStatus;
+ m_lastStatus = newStatus;
+ Q_EMIT statusChanged(m_lastStatus);
+ }
+}
+
+
+qint64 AVFMediaRecorderControl::duration() const
+{
+ if (!m_movieOutput)
+ return 0;
+
+ return qint64(CMTimeGetSeconds(m_movieOutput.recordedDuration) * 1000);
+}
+
+bool AVFMediaRecorderControl::isMuted() const
+{
+ return m_muted;
+}
+
+qreal AVFMediaRecorderControl::volume() const
+{
+ return m_volume;
+}
+
+void AVFMediaRecorderControl::applySettings()
+{
+}
+
+void AVFMediaRecorderControl::setState(QMediaRecorder::State state)
+{
+ if (m_state == state)
+ return;
+
+ qDebugCamera() << Q_FUNC_INFO << m_state << " -> " << state;
+
+ switch (state) {
+ case QMediaRecorder::RecordingState:
+ {
+ if (m_connected) {
+ m_state = QMediaRecorder::RecordingState;
+ m_recordingStarted = false;
+ m_recordingFinished = false;
+
+ QString outputLocationPath = m_outputLocation.scheme() == QLatin1String("file") ?
+ m_outputLocation.path() : m_outputLocation.toString();
+
+ QUrl actualLocation = QUrl::fromLocalFile(
+ m_storageLocation.generateFileName(outputLocationPath,
+ QCamera::CaptureVideo,
+ QLatin1String("clip_"),
+ QLatin1String("mp4")));
+
+ qDebugCamera() << "Video capture location:" << actualLocation.toString();
+
+ NSString *urlString = [NSString stringWithUTF8String:actualLocation.toString().toUtf8().constData()];
+ NSURL *fileURL = [NSURL URLWithString:urlString];
+
+ [m_movieOutput startRecordingToOutputFileURL:fileURL recordingDelegate:m_recorderDelagate];
+
+ Q_EMIT actualLocationChanged(actualLocation);
+ } else {
+ Q_EMIT error(QMediaRecorder::FormatError, tr("Recorder not configured"));
+ }
+
+ } break;
+ case QMediaRecorder::PausedState:
+ {
+ Q_EMIT error(QMediaRecorder::FormatError, tr("Recording pause not supported"));
+ return;
+ } break;
+ case QMediaRecorder::StoppedState:
+ {
+ m_state = QMediaRecorder::StoppedState;
+ [m_movieOutput stopRecording];
+ }
+ }
+
+ updateStatus();
+ Q_EMIT stateChanged(m_state);
+}
+
+void AVFMediaRecorderControl::setMuted(bool muted)
+{
+ if (m_muted != muted) {
+ m_muted = muted;
+ Q_EMIT mutedChanged(muted);
+ }
+}
+
+void AVFMediaRecorderControl::setVolume(qreal volume)
+{
+ if (m_volume != volume) {
+ m_volume = volume;
+ Q_EMIT volumeChanged(volume);
+ }
+}
+
+void AVFMediaRecorderControl::handleRecordingStarted()
+{
+ m_recordingStarted = true;
+ updateStatus();
+}
+
+void AVFMediaRecorderControl::handleRecordingFinished()
+{
+ m_recordingFinished = true;
+ updateStatus();
+}
+
+void AVFMediaRecorderControl::handleRecordingFailed(const QString &message)
+{
+ m_recordingFinished = true;
+ if (m_state != QMediaRecorder::StoppedState) {
+ m_state = QMediaRecorder::StoppedState;
+ Q_EMIT stateChanged(m_state);
+ }
+ updateStatus();
+
+ Q_EMIT error(QMediaRecorder::ResourceError, message);
+}
+
+void AVFMediaRecorderControl::reconnectMovieOutput()
+{
+ //adding movie output causes high CPU usage even when while recording is not active,
+ //connect it only while video capture mode is enabled
+ AVCaptureSession *captureSession = m_session->captureSession();
+
+ if (!m_connected && m_cameraControl->captureMode().testFlag(QCamera::CaptureVideo)) {
+ if ([captureSession canAddOutput:m_movieOutput]) {
+ [captureSession addOutput:m_movieOutput];
+ m_connected = true;
+ } else {
+ Q_EMIT error(QMediaRecorder::ResourceError, tr("Could not connect the video recorder"));
+ qWarning() << "Could not connect the video recorder";
+ }
+ } else if (m_connected && !m_cameraControl->captureMode().testFlag(QCamera::CaptureVideo)) {
+ [captureSession removeOutput:m_movieOutput];
+ m_connected = false;
+ }
+
+ updateStatus();
+}
+
+#include "moc_avfmediarecordercontrol.cpp"