summaryrefslogtreecommitdiffstats
path: root/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/android/src/mediacapture/qandroidcapturesession.cpp')
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcapturesession.cpp594
1 files changed, 0 insertions, 594 deletions
diff --git a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
deleted file mode 100644
index 768bb4442..000000000
--- a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
+++ /dev/null
@@ -1,594 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qandroidcapturesession.h"
-
-#include "androidcamera.h"
-#include "qandroidcamerasession.h"
-#include "androidmultimediautils.h"
-#include "qandroidmultimediautils.h"
-#include "qandroidvideooutput.h"
-#include "qandroidglobal.h"
-
-#include <algorithm>
-
-QT_BEGIN_NAMESPACE
-
-QAndroidCaptureSession::QAndroidCaptureSession(QAndroidCameraSession *cameraSession)
- : QObject()
- , m_mediaRecorder(0)
- , m_cameraSession(cameraSession)
- , m_audioSource(AndroidMediaRecorder::DefaultAudioSource)
- , m_duration(0)
- , m_state(QMediaRecorder::StoppedState)
- , m_status(QMediaRecorder::UnloadedStatus)
- , m_containerFormatDirty(true)
- , m_videoSettingsDirty(true)
- , m_audioSettingsDirty(true)
- , m_outputFormat(AndroidMediaRecorder::DefaultOutputFormat)
- , m_audioEncoder(AndroidMediaRecorder::DefaultAudioEncoder)
- , m_videoEncoder(AndroidMediaRecorder::DefaultVideoEncoder)
-{
- m_mediaStorageLocation.addStorageLocation(
- QMediaStorageLocation::Movies,
- AndroidMultimediaUtils::getDefaultMediaDirectory(AndroidMultimediaUtils::DCIM));
-
- m_mediaStorageLocation.addStorageLocation(
- QMediaStorageLocation::Sounds,
- AndroidMultimediaUtils::getDefaultMediaDirectory(AndroidMultimediaUtils::Sounds));
-
- if (cameraSession) {
- connect(cameraSession, SIGNAL(opened()), this, SLOT(onCameraOpened()));
- connect(cameraSession, &QAndroidCameraSession::statusChanged, this,
- [this](QCamera::Status status) {
- if (status == QCamera::UnavailableStatus) {
- setState(QMediaRecorder::StoppedState);
- setStatus(QMediaRecorder::UnavailableStatus);
- return;
- }
-
- // Stop recording when stopping the camera.
- if (status == QCamera::StoppingStatus) {
- setState(QMediaRecorder::StoppedState);
- setStatus(QMediaRecorder::UnloadedStatus);
- return;
- }
-
- if (status == QCamera::LoadingStatus)
- setStatus(QMediaRecorder::LoadingStatus);
- });
- connect(cameraSession, &QAndroidCameraSession::captureModeChanged, this,
- [this](QCamera::CaptureModes mode) {
- if (!mode.testFlag(QCamera::CaptureVideo)) {
- setState(QMediaRecorder::StoppedState);
- setStatus(QMediaRecorder::UnloadedStatus);
- }
- });
- connect(cameraSession, &QAndroidCameraSession::readyForCaptureChanged, this,
- [this](bool ready) {
- if (ready)
- setStatus(QMediaRecorder::LoadedStatus);
- });
- } else {
- // Audio-only recording.
- setStatus(QMediaRecorder::LoadedStatus);
- }
-
- m_notifyTimer.setInterval(1000);
- connect(&m_notifyTimer, SIGNAL(timeout()), this, SLOT(updateDuration()));
-}
-
-QAndroidCaptureSession::~QAndroidCaptureSession()
-{
- stop();
- delete m_mediaRecorder;
-}
-
-void QAndroidCaptureSession::setAudioInput(const QString &input)
-{
- if (m_audioInput == input)
- return;
-
- m_audioInput = input;
-
- if (m_audioInput == QLatin1String("default"))
- m_audioSource = AndroidMediaRecorder::DefaultAudioSource;
- else if (m_audioInput == QLatin1String("mic"))
- m_audioSource = AndroidMediaRecorder::Mic;
- else if (m_audioInput == QLatin1String("voice_uplink"))
- m_audioSource = AndroidMediaRecorder::VoiceUplink;
- else if (m_audioInput == QLatin1String("voice_downlink"))
- m_audioSource = AndroidMediaRecorder::VoiceDownlink;
- else if (m_audioInput == QLatin1String("voice_call"))
- m_audioSource = AndroidMediaRecorder::VoiceCall;
- else if (m_audioInput == QLatin1String("voice_recognition"))
- m_audioSource = AndroidMediaRecorder::VoiceRecognition;
- else
- m_audioSource = AndroidMediaRecorder::DefaultAudioSource;
-
- emit audioInputChanged(m_audioInput);
-}
-
-QUrl QAndroidCaptureSession::outputLocation() const
-{
- return m_actualOutputLocation;
-}
-
-bool QAndroidCaptureSession::setOutputLocation(const QUrl &location)
-{
- if (m_requestedOutputLocation == location)
- return false;
-
- m_actualOutputLocation = QUrl();
- m_requestedOutputLocation = location;
-
- if (m_requestedOutputLocation.isEmpty())
- return true;
-
- if (m_requestedOutputLocation.isValid()
- && (m_requestedOutputLocation.isLocalFile() || m_requestedOutputLocation.isRelative())) {
- return true;
- }
-
- m_requestedOutputLocation = QUrl();
- return false;
-}
-
-QMediaRecorder::State QAndroidCaptureSession::state() const
-{
- return m_state;
-}
-
-void QAndroidCaptureSession::setState(QMediaRecorder::State state)
-{
- if (m_state == state)
- return;
-
- switch (state) {
- case QMediaRecorder::StoppedState:
- stop();
- break;
- case QMediaRecorder::RecordingState:
- start();
- break;
- case QMediaRecorder::PausedState:
- // Not supported by Android API
- qWarning("QMediaRecorder::PausedState is not supported on Android");
- break;
- }
-}
-
-void QAndroidCaptureSession::start()
-{
- if (m_state == QMediaRecorder::RecordingState || m_status != QMediaRecorder::LoadedStatus)
- return;
-
- setStatus(QMediaRecorder::StartingStatus);
-
- if (m_mediaRecorder) {
- m_mediaRecorder->release();
- delete m_mediaRecorder;
- }
-
- const bool granted = m_cameraSession
- ? m_cameraSession->requestRecordingPermission()
- : qt_androidRequestRecordingPermission();
- if (!granted) {
- setStatus(QMediaRecorder::UnavailableStatus);
- Q_EMIT error(QMediaRecorder::ResourceError, QLatin1String("Permission denied."));
- return;
- }
-
- m_mediaRecorder = new AndroidMediaRecorder;
- connect(m_mediaRecorder, SIGNAL(error(int,int)), this, SLOT(onError(int,int)));
- connect(m_mediaRecorder, SIGNAL(info(int,int)), this, SLOT(onInfo(int,int)));
-
- // Set audio/video sources
- if (m_cameraSession) {
- updateViewfinder();
- m_cameraSession->camera()->unlock();
- m_mediaRecorder->setCamera(m_cameraSession->camera());
- m_mediaRecorder->setAudioSource(AndroidMediaRecorder::Camcorder);
- m_mediaRecorder->setVideoSource(AndroidMediaRecorder::Camera);
- } else {
- m_mediaRecorder->setAudioSource(m_audioSource);
- }
-
- // Set output format
- m_mediaRecorder->setOutputFormat(m_outputFormat);
-
- // Set audio encoder settings
- m_mediaRecorder->setAudioChannels(m_audioSettings.channelCount());
- m_mediaRecorder->setAudioEncodingBitRate(m_audioSettings.bitRate());
- m_mediaRecorder->setAudioSamplingRate(m_audioSettings.sampleRate());
- m_mediaRecorder->setAudioEncoder(m_audioEncoder);
-
- // Set video encoder settings
- if (m_cameraSession) {
- m_mediaRecorder->setVideoSize(m_videoSettings.resolution());
- m_mediaRecorder->setVideoFrameRate(qRound(m_videoSettings.frameRate()));
- m_mediaRecorder->setVideoEncodingBitRate(m_videoSettings.bitRate());
- m_mediaRecorder->setVideoEncoder(m_videoEncoder);
-
- m_mediaRecorder->setOrientationHint(m_cameraSession->currentCameraRotation());
- }
-
- // Set output file
- QString filePath = m_mediaStorageLocation.generateFileName(
- m_requestedOutputLocation.isLocalFile() ? m_requestedOutputLocation.toLocalFile()
- : m_requestedOutputLocation.toString(),
- m_cameraSession ? QMediaStorageLocation::Movies
- : QMediaStorageLocation::Sounds,
- m_cameraSession ? QLatin1String("VID_")
- : QLatin1String("REC_"),
- m_containerFormat);
-
- m_usedOutputLocation = QUrl::fromLocalFile(filePath);
- m_mediaRecorder->setOutputFile(filePath);
-
- // Even though the Android doc explicitly says that calling MediaRecorder.setPreviewDisplay()
- // is not necessary when the Camera already has a Surface, it doesn't actually work on some
- // devices. For example on the Samsung Galaxy Tab 2, the camera server dies after prepare()
- // and start() if MediaRecorder.setPreviewDispaly() is not called.
- if (m_cameraSession) {
- // When using a SurfaceTexture, we need to pass a new one to the MediaRecorder, not the same
- // one that is set on the Camera or it will crash, hence the reset().
- m_cameraSession->videoOutput()->reset();
- if (m_cameraSession->videoOutput()->surfaceTexture())
- m_mediaRecorder->setSurfaceTexture(m_cameraSession->videoOutput()->surfaceTexture());
- else if (m_cameraSession->videoOutput()->surfaceHolder())
- m_mediaRecorder->setSurfaceHolder(m_cameraSession->videoOutput()->surfaceHolder());
- }
-
- if (!m_mediaRecorder->prepare()) {
- emit error(QMediaRecorder::FormatError, QLatin1String("Unable to prepare the media recorder."));
- if (m_cameraSession)
- restartViewfinder();
- return;
- }
-
- if (!m_mediaRecorder->start()) {
- emit error(QMediaRecorder::FormatError, QLatin1String("Unable to start the media recorder."));
- if (m_cameraSession)
- restartViewfinder();
- return;
- }
-
- m_elapsedTime.start();
- m_notifyTimer.start();
- updateDuration();
-
- if (m_cameraSession) {
- m_cameraSession->setReadyForCapture(false);
-
- // Preview frame callback is cleared when setting up the camera with the media recorder.
- // We need to reset it.
- m_cameraSession->camera()->setupPreviewFrameCallback();
- }
-
- m_state = QMediaRecorder::RecordingState;
- emit stateChanged(m_state);
- setStatus(QMediaRecorder::RecordingStatus);
-}
-
-void QAndroidCaptureSession::stop(bool error)
-{
- if (m_state == QMediaRecorder::StoppedState || m_mediaRecorder == 0)
- return;
-
- setStatus(QMediaRecorder::FinalizingStatus);
-
- m_mediaRecorder->stop();
- m_notifyTimer.stop();
- updateDuration();
- m_elapsedTime.invalidate();
- m_mediaRecorder->release();
- delete m_mediaRecorder;
- m_mediaRecorder = 0;
-
- if (m_cameraSession && m_cameraSession->status() == QCamera::ActiveStatus) {
- // Viewport needs to be restarted after recording
- restartViewfinder();
- }
-
- if (!error) {
- // if the media is saved into the standard media location, register it
- // with the Android media scanner so it appears immediately in apps
- // such as the gallery.
- QString mediaPath = m_usedOutputLocation.toLocalFile();
- QString standardLoc = m_cameraSession ? AndroidMultimediaUtils::getDefaultMediaDirectory(AndroidMultimediaUtils::DCIM)
- : AndroidMultimediaUtils::getDefaultMediaDirectory(AndroidMultimediaUtils::Sounds);
- if (mediaPath.startsWith(standardLoc))
- AndroidMultimediaUtils::registerMediaFile(mediaPath);
-
- m_actualOutputLocation = m_usedOutputLocation;
- emit actualLocationChanged(m_actualOutputLocation);
- }
-
- m_state = QMediaRecorder::StoppedState;
- emit stateChanged(m_state);
- if (!m_cameraSession)
- setStatus(QMediaRecorder::LoadedStatus);
-}
-
-void QAndroidCaptureSession::setStatus(QMediaRecorder::Status status)
-{
- if (m_status == status)
- return;
-
- m_status = status;
- emit statusChanged(m_status);
-}
-
-QMediaRecorder::Status QAndroidCaptureSession::status() const
-{
- return m_status;
-}
-
-qint64 QAndroidCaptureSession::duration() const
-{
- return m_duration;
-}
-
-void QAndroidCaptureSession::setContainerFormat(const QString &format)
-{
- if (m_containerFormat == format)
- return;
-
- m_containerFormat = format;
- m_containerFormatDirty = true;
-}
-
-void QAndroidCaptureSession::setAudioSettings(const QAudioEncoderSettings &settings)
-{
- if (m_audioSettings == settings)
- return;
-
- m_audioSettings = settings;
- m_audioSettingsDirty = true;
-}
-
-void QAndroidCaptureSession::setVideoSettings(const QVideoEncoderSettings &settings)
-{
- if (!m_cameraSession || m_videoSettings == settings)
- return;
-
- m_videoSettings = settings;
- m_videoSettingsDirty = true;
-}
-
-void QAndroidCaptureSession::applySettings()
-{
- // container settings
- if (m_containerFormatDirty) {
- if (m_containerFormat.isEmpty()) {
- m_containerFormat = m_defaultSettings.outputFileExtension;
- m_outputFormat = m_defaultSettings.outputFormat;
- } else if (m_containerFormat == QLatin1String("3gp")) {
- m_outputFormat = AndroidMediaRecorder::THREE_GPP;
- } else if (!m_cameraSession && m_containerFormat == QLatin1String("amr")) {
- m_outputFormat = AndroidMediaRecorder::AMR_NB_Format;
- } else if (!m_cameraSession && m_containerFormat == QLatin1String("awb")) {
- m_outputFormat = AndroidMediaRecorder::AMR_WB_Format;
- } else {
- m_containerFormat = QStringLiteral("mp4");
- m_outputFormat = AndroidMediaRecorder::MPEG_4;
- }
-
- m_containerFormatDirty = false;
- }
-
- // audio settings
- if (m_audioSettingsDirty) {
- if (m_audioSettings.channelCount() <= 0)
- m_audioSettings.setChannelCount(m_defaultSettings.audioChannels);
- if (m_audioSettings.bitRate() <= 0)
- m_audioSettings.setBitRate(m_defaultSettings.audioBitRate);
- if (m_audioSettings.sampleRate() <= 0)
- m_audioSettings.setSampleRate(m_defaultSettings.audioSampleRate);
-
- if (m_audioSettings.codec().isEmpty())
- m_audioEncoder = m_defaultSettings.audioEncoder;
- else if (m_audioSettings.codec() == QLatin1String("aac"))
- m_audioEncoder = AndroidMediaRecorder::AAC;
- else if (m_audioSettings.codec() == QLatin1String("amr-nb"))
- m_audioEncoder = AndroidMediaRecorder::AMR_NB_Encoder;
- else if (m_audioSettings.codec() == QLatin1String("amr-wb"))
- m_audioEncoder = AndroidMediaRecorder::AMR_WB_Encoder;
- else
- m_audioEncoder = m_defaultSettings.audioEncoder;
-
- m_audioSettingsDirty = false;
- }
-
- // video settings
- if (m_cameraSession && m_cameraSession->camera() && m_videoSettingsDirty) {
- if (m_videoSettings.resolution().isEmpty()) {
- m_videoSettings.setResolution(m_defaultSettings.videoResolution);
- } else if (!m_supportedResolutions.contains(m_videoSettings.resolution())) {
- // if the requested resolution is not supported, find the closest one
- QSize reqSize = m_videoSettings.resolution();
- int reqPixelCount = reqSize.width() * reqSize.height();
- QList<int> supportedPixelCounts;
- for (int i = 0; i < m_supportedResolutions.size(); ++i) {
- const QSize &s = m_supportedResolutions.at(i);
- supportedPixelCounts.append(s.width() * s.height());
- }
- int closestIndex = qt_findClosestValue(supportedPixelCounts, reqPixelCount);
- m_videoSettings.setResolution(m_supportedResolutions.at(closestIndex));
- }
-
- if (m_videoSettings.frameRate() <= 0)
- m_videoSettings.setFrameRate(m_defaultSettings.videoFrameRate);
- if (m_videoSettings.bitRate() <= 0)
- m_videoSettings.setBitRate(m_defaultSettings.videoBitRate);
-
- if (m_videoSettings.codec().isEmpty())
- m_videoEncoder = m_defaultSettings.videoEncoder;
- else if (m_videoSettings.codec() == QLatin1String("h263"))
- m_videoEncoder = AndroidMediaRecorder::H263;
- else if (m_videoSettings.codec() == QLatin1String("h264"))
- m_videoEncoder = AndroidMediaRecorder::H264;
- else if (m_videoSettings.codec() == QLatin1String("mpeg4_sp"))
- m_videoEncoder = AndroidMediaRecorder::MPEG_4_SP;
- else
- m_videoEncoder = m_defaultSettings.videoEncoder;
-
- m_videoSettingsDirty = false;
- }
-}
-
-void QAndroidCaptureSession::updateViewfinder()
-{
- m_cameraSession->camera()->stopPreviewSynchronous();
- m_cameraSession->applyViewfinderSettings(m_videoSettings.resolution(), false);
-}
-
-void QAndroidCaptureSession::restartViewfinder()
-{
- if (!m_cameraSession)
- return;
-
- m_cameraSession->camera()->reconnect();
-
- // This is not necessary on most devices, but it crashes on some if we don't stop the
- // preview and reset the preview display on the camera when recording is over.
- m_cameraSession->camera()->stopPreviewSynchronous();
- m_cameraSession->videoOutput()->reset();
- if (m_cameraSession->videoOutput()->surfaceTexture())
- m_cameraSession->camera()->setPreviewTexture(m_cameraSession->videoOutput()->surfaceTexture());
- else if (m_cameraSession->videoOutput()->surfaceHolder())
- m_cameraSession->camera()->setPreviewDisplay(m_cameraSession->videoOutput()->surfaceHolder());
-
- m_cameraSession->camera()->startPreview();
- m_cameraSession->setReadyForCapture(true);
-}
-
-void QAndroidCaptureSession::updateDuration()
-{
- if (m_elapsedTime.isValid())
- m_duration = m_elapsedTime.elapsed();
-
- emit durationChanged(m_duration);
-}
-
-void QAndroidCaptureSession::onCameraOpened()
-{
- m_supportedResolutions.clear();
- m_supportedFramerates.clear();
-
- // get supported resolutions from predefined profiles
- for (int i = 0; i < 8; ++i) {
- CaptureProfile profile = getProfile(i);
- if (!profile.isNull) {
- if (i == AndroidCamcorderProfile::QUALITY_HIGH)
- m_defaultSettings = profile;
-
- if (!m_supportedResolutions.contains(profile.videoResolution))
- m_supportedResolutions.append(profile.videoResolution);
- if (!m_supportedFramerates.contains(profile.videoFrameRate))
- m_supportedFramerates.append(profile.videoFrameRate);
- }
- }
-
- std::sort(m_supportedResolutions.begin(), m_supportedResolutions.end(), qt_sizeLessThan);
- std::sort(m_supportedFramerates.begin(), m_supportedFramerates.end());
-
- applySettings();
-}
-
-QAndroidCaptureSession::CaptureProfile QAndroidCaptureSession::getProfile(int id)
-{
- CaptureProfile profile;
- const bool hasProfile = AndroidCamcorderProfile::hasProfile(m_cameraSession->camera()->cameraId(),
- AndroidCamcorderProfile::Quality(id));
-
- if (hasProfile) {
- AndroidCamcorderProfile camProfile = AndroidCamcorderProfile::get(m_cameraSession->camera()->cameraId(),
- AndroidCamcorderProfile::Quality(id));
-
- profile.outputFormat = AndroidMediaRecorder::OutputFormat(camProfile.getValue(AndroidCamcorderProfile::fileFormat));
- profile.audioEncoder = AndroidMediaRecorder::AudioEncoder(camProfile.getValue(AndroidCamcorderProfile::audioCodec));
- profile.audioBitRate = camProfile.getValue(AndroidCamcorderProfile::audioBitRate);
- profile.audioChannels = camProfile.getValue(AndroidCamcorderProfile::audioChannels);
- profile.audioSampleRate = camProfile.getValue(AndroidCamcorderProfile::audioSampleRate);
- profile.videoEncoder = AndroidMediaRecorder::VideoEncoder(camProfile.getValue(AndroidCamcorderProfile::videoCodec));
- profile.videoBitRate = camProfile.getValue(AndroidCamcorderProfile::videoBitRate);
- profile.videoFrameRate = camProfile.getValue(AndroidCamcorderProfile::videoFrameRate);
- profile.videoResolution = QSize(camProfile.getValue(AndroidCamcorderProfile::videoFrameWidth),
- camProfile.getValue(AndroidCamcorderProfile::videoFrameHeight));
-
- if (profile.outputFormat == AndroidMediaRecorder::MPEG_4)
- profile.outputFileExtension = QStringLiteral("mp4");
- else if (profile.outputFormat == AndroidMediaRecorder::THREE_GPP)
- profile.outputFileExtension = QStringLiteral("3gp");
- else if (profile.outputFormat == AndroidMediaRecorder::AMR_NB_Format)
- profile.outputFileExtension = QStringLiteral("amr");
- else if (profile.outputFormat == AndroidMediaRecorder::AMR_WB_Format)
- profile.outputFileExtension = QStringLiteral("awb");
-
- profile.isNull = false;
- }
-
- return profile;
-}
-
-void QAndroidCaptureSession::onError(int what, int extra)
-{
- Q_UNUSED(what);
- Q_UNUSED(extra);
- stop(true);
- emit error(QMediaRecorder::ResourceError, QLatin1String("Unknown error."));
-}
-
-void QAndroidCaptureSession::onInfo(int what, int extra)
-{
- Q_UNUSED(extra);
- if (what == 800) {
- // MEDIA_RECORDER_INFO_MAX_DURATION_REACHED
- setState(QMediaRecorder::StoppedState);
- emit error(QMediaRecorder::OutOfSpaceError, QLatin1String("Maximum duration reached."));
- } else if (what == 801) {
- // MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED
- setState(QMediaRecorder::StoppedState);
- emit error(QMediaRecorder::OutOfSpaceError, QLatin1String("Maximum file size reached."));
- }
-}
-
-QT_END_NAMESPACE