diff options
Diffstat (limited to 'src/plugins/avfoundation/camera/avfmediarecordercontrol.mm')
-rw-r--r-- | src/plugins/avfoundation/camera/avfmediarecordercontrol.mm | 342 |
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" |