diff options
Diffstat (limited to 'src/plugins/symbian/ecam/s60videocapturesession.cpp')
-rw-r--r-- | src/plugins/symbian/ecam/s60videocapturesession.cpp | 2995 |
1 files changed, 2995 insertions, 0 deletions
diff --git a/src/plugins/symbian/ecam/s60videocapturesession.cpp b/src/plugins/symbian/ecam/s60videocapturesession.cpp new file mode 100644 index 000000000..7158f8696 --- /dev/null +++ b/src/plugins/symbian/ecam/s60videocapturesession.cpp @@ -0,0 +1,2995 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qstring.h> +#include <QtCore/qdir.h> +#include <QtCore/qtimer.h> + +#include "s60videocapturesession.h" +#include "s60cameraconstants.h" + +#include <utf.h> +#include <bautils.h> + +#ifdef S60_DEVVIDEO_RECORDING_SUPPORTED +#include <mmf/devvideo/devvideorecord.h> +#endif + +S60VideoCaptureSession::S60VideoCaptureSession(QObject *parent) : + QObject(parent), + m_cameraEngine(0), + m_videoRecorder(0), + m_position(0), + m_error(KErrNone), + m_cameraStarted(false), + m_captureState(ENotInitialized), // Default state + m_sink(QUrl()), + m_requestedSink(QUrl()), + m_captureSettingsSet(false), + m_container(QString()), + m_requestedContainer(QString()), + m_muted(false), + m_maxClipSize(-1), + m_videoControllerMap(QHash<int, QHash<int,VideoFormatData> >()), + m_videoParametersForEncoder(QList<MaxResolutionRatesAndTypes>()), + m_openWhenReady(false), + m_prepareAfterOpenComplete(false), + m_startAfterPrepareComplete(false), + m_uncommittedSettings(false), + m_commitSettingsWhenReady(false) +{ +#ifdef S60_DEVVIDEO_RECORDING_SUPPORTED + // Populate info of supported codecs, and their resolution, etc. + TRAPD(err, doPopulateVideoCodecsDataL()); + setError(err, tr("Failed to gather video codec information.")); +#endif // S60_DEVVIDEO_RECORDING_SUPPORTED + + initializeVideoCaptureSettings(); + + m_durationTimer = new QTimer; + m_durationTimer->setInterval(KDurationChangedInterval); + connect(m_durationTimer, SIGNAL(timeout()), this, SLOT(durationTimerTriggered())); +} + +S60VideoCaptureSession::~S60VideoCaptureSession() +{ + if (m_captureState >= ERecording) + m_videoRecorder->Stop(); + + if (m_captureState >= EInitialized) + m_videoRecorder->Close(); + + if (m_videoRecorder) { + delete m_videoRecorder; + m_videoRecorder = 0; + } + + if (m_durationTimer) { + delete m_durationTimer; + m_durationTimer = 0; + } + + // Clear all data structures + foreach (MaxResolutionRatesAndTypes structure, m_videoParametersForEncoder) { + structure.frameRatePictureSizePair.clear(); + structure.mimeTypes.clear(); + } + m_videoParametersForEncoder.clear(); + + m_videoCodecList.clear(); + m_audioCodecList.clear(); + + QList<TInt> controllers = m_videoControllerMap.keys(); + for (int i = 0; i < controllers.size(); ++i) { + foreach(VideoFormatData data, m_videoControllerMap[controllers[i]]){ + data.supportedMimeTypes.clear(); + } + m_videoControllerMap[controllers[i]].clear(); + } + m_videoControllerMap.clear(); +} + +/* + * This function can be used both internally and from Control classes using this session. + * The error notification will go to client application through QMediaRecorder error signal. + */ +void S60VideoCaptureSession::setError(const TInt error, const QString &description) +{ + if (error == KErrNone) + return; + + m_error = error; + QMediaRecorder::Error recError = fromSymbianErrorToQtMultimediaError(m_error); + + // Stop/Close/Reset only of other than "not supported" error + if (m_error != KErrNotSupported) { + if (m_captureState >= ERecording) + m_videoRecorder->Stop(); + + if (m_captureState >= EInitialized) + m_videoRecorder->Close(); + + // Reset state + if (m_captureState != ENotInitialized) { + if (m_durationTimer->isActive()) + m_durationTimer->stop(); + m_captureState = ENotInitialized; + emit stateChanged(m_captureState); + } + } + + emit this->error(recError, description); + + // Reset only of other than "not supported" error + if (m_error != KErrNotSupported) + resetSession(true); + else + m_error = KErrNone; // Reset error +} + +QMediaRecorder::Error S60VideoCaptureSession::fromSymbianErrorToQtMultimediaError(int aError) +{ + switch(aError) { + case KErrNone: + return QMediaRecorder::NoError; // No errors have occurred + case KErrArgument: + case KErrNotSupported: + return QMediaRecorder::FormatError; // The feature/format is not supported + case KErrNoMemory: + case KErrNotFound: + case KErrBadHandle: + return QMediaRecorder::ResourceError; // Not able to use camera/recorder resources + + default: + return QMediaRecorder::ResourceError; // Other error has occurred + } +} + +/* + * This function applies all recording settings to make latency during the + * start of the recording as short as possible. After this it is not possible to + * set settings (inc. output location) before stopping the recording. + */ +void S60VideoCaptureSession::applyAllSettings() +{ + switch (m_captureState) { + case ENotInitialized: + case EInitializing: + m_commitSettingsWhenReady = true; + return; + case EInitialized: + setOutputLocation(QUrl()); + m_prepareAfterOpenComplete = true; + return; + case EOpening: + m_prepareAfterOpenComplete = true; + return; + case EOpenComplete: + // Do nothing, ready to commit + break; + case EPreparing: + m_commitSettingsWhenReady = true; + return; + case EPrepared: + // Revert state internally, since logically applying settings means going + // from OpenComplete ==> Preparing ==> Prepared. + m_captureState = EOpenComplete; + break; + case ERecording: + case EPaused: + setError(KErrNotReady, tr("Cannot apply settings while recording.")); + return; + + default: + setError(KErrGeneral, tr("Unexpected camera error.")); + return; + } + + // Commit settings - State is now OpenComplete (possibly reverted from Prepared) + commitVideoEncoderSettings(); + + // If capture state has been changed to: + // * Opening: A different media container has been requested + // * Other: Failure during the setting committing + // ==> Return + if (m_captureState != EOpenComplete) + return; + + // Start preparing + m_captureState = EPreparing; + emit stateChanged(m_captureState); + + if (m_cameraEngine->IsCameraReady()) + m_videoRecorder->Prepare(); +} + +void S60VideoCaptureSession::setCameraHandle(CCameraEngine* cameraHandle) +{ + m_cameraEngine = cameraHandle; + + // Initialize settings for the new camera + initializeVideoCaptureSettings(); + + resetSession(); +} + +void S60VideoCaptureSession::notifySettingsSet() +{ + m_captureSettingsSet = true; +} + +void S60VideoCaptureSession::doInitializeVideoRecorderL() +{ + if (m_captureState > ENotInitialized) + resetSession(); + + m_captureState = EInitializing; + emit stateChanged(m_captureState); + + // Open Dummy file to be able to query supported settings + int cameraHandle = m_cameraEngine->Camera() ? m_cameraEngine->Camera()->Handle() : 0; + + TUid controllerUid; + TUid formatUid; + selectController(m_requestedContainer, controllerUid, formatUid); + + if (m_videoRecorder) { + // File open completes in MvruoOpenComplete + TRAPD(err, m_videoRecorder->OpenFileL(KDummyVideoFile, cameraHandle, controllerUid, formatUid)); + setError(err, tr("Failed to initialize video recorder.")); + m_container = m_requestedContainer; + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } +} + +void S60VideoCaptureSession::resetSession(bool errorHandling) +{ + if (m_videoRecorder) { + delete m_videoRecorder; + m_videoRecorder = 0; + } + + if (m_captureState != ENotInitialized) { + if (m_durationTimer->isActive()) + m_durationTimer->stop(); + m_captureState = ENotInitialized; + emit stateChanged(m_captureState); + } + + // Reset error to be able to recover + m_error = KErrNone; + + // Reset flags + m_openWhenReady = false; + m_prepareAfterOpenComplete = false; + m_startAfterPrepareComplete = false; + m_uncommittedSettings = false; + m_commitSettingsWhenReady = false; + + TRAPD(err, m_videoRecorder = CVideoRecorderUtility::NewL(*this)); + if (err) { + qWarning("Failed to create video recorder."); + if (errorHandling) + emit error(QMediaRecorder::ResourceError, tr("Failed to recover from video error.")); + else + setError(err, tr("Failure in creation of video recorder device.")); + return; + } + + updateVideoCaptureContainers(); +} + +QList<QSize> S60VideoCaptureSession::supportedVideoResolutions(bool *continuous) +{ + QList<QSize> resolutions; + + // Secondary Camera + if (m_cameraEngine->CurrentCameraIndex() != 0) { + TCameraInfo *info = m_cameraEngine->CameraInfo(); + if (info) { + TInt videoResolutionCount = info->iNumVideoFrameSizesSupported; + CCamera *camera = m_cameraEngine->Camera(); + if (camera) { + for (TInt i = 0; i < videoResolutionCount; ++i) { + TSize checkedResolution; + camera->EnumerateVideoFrameSizes(checkedResolution, i, CCamera::EFormatYUV420Planar); + QSize qtResolution(checkedResolution.iWidth, checkedResolution.iHeight); + if (!resolutions.contains(qtResolution)) + resolutions.append(qtResolution); + } + } else { + setError(KErrGeneral, tr("Could not query supported video resolutions.")); + } + } else { + setError(KErrGeneral, tr("Could not query supported video resolutions.")); + } + + // Primary Camera + } else { + + if (m_videoParametersForEncoder.count() > 0) { + + // Also arbitrary resolutions are supported + if (continuous) + *continuous = true; + + // Append all supported resolutions to the list + foreach (MaxResolutionRatesAndTypes parameters, m_videoParametersForEncoder) + for (int i = 0; i < parameters.frameRatePictureSizePair.count(); ++i) + if (!resolutions.contains(parameters.frameRatePictureSizePair[i].frameSize)) + resolutions.append(parameters.frameRatePictureSizePair[i].frameSize); + } + } + +#ifdef Q_CC_NOKIAX86 // Emulator + resolutions << QSize(160, 120); + resolutions << QSize(352, 288); + resolutions << QSize(640,480); +#endif // Q_CC_NOKIAX86 + + return resolutions; +} + +QList<QSize> S60VideoCaptureSession::supportedVideoResolutions(const QVideoEncoderSettings &settings, bool *continuous) +{ + QList<QSize> supportedFrameSizes; + + // Secondary Camera + if (m_cameraEngine->CurrentCameraIndex() != 0) { + TCameraInfo *info = m_cameraEngine->CameraInfo(); + if (info) { + TInt videoResolutionCount = info->iNumVideoFrameSizesSupported; + CCamera *camera = m_cameraEngine->Camera(); + if (camera) { + for (TInt i = 0; i < videoResolutionCount; ++i) { + TSize checkedResolution; + camera->EnumerateVideoFrameSizes(checkedResolution, i, CCamera::EFormatYUV420Planar); + QSize qtResolution(checkedResolution.iWidth, checkedResolution.iHeight); + if (!supportedFrameSizes.contains(qtResolution)) + supportedFrameSizes.append(qtResolution); + } + } else { + setError(KErrGeneral, tr("Could not query supported video resolutions.")); + } + } else { + setError(KErrGeneral, tr("Could not query supported video resolutions.")); + } + + // Primary Camera + } else { + + if (settings.codec().isEmpty()) + return supportedFrameSizes; + + if (!m_videoCodecList.contains(settings.codec(), Qt::CaseInsensitive)) + return supportedFrameSizes; + + // Also arbitrary resolutions are supported + if (continuous) + *continuous = true; + + // Find maximum resolution (using defined framerate if set) + for (int i = 0; i < m_videoParametersForEncoder.count(); ++i) { + // Check if encoder supports the requested codec + if (!m_videoParametersForEncoder[i].mimeTypes.contains(settings.codec(), Qt::CaseInsensitive)) + continue; + + foreach (SupportedFrameRatePictureSize pair, m_videoParametersForEncoder[i].frameRatePictureSizePair) { + if (!supportedFrameSizes.contains(pair.frameSize)) { + QSize maxForMime = maximumResolutionForMimeType(settings.codec()); + if (settings.frameRate() != 0) { + if (settings.frameRate() <= pair.frameRate) { + if ((pair.frameSize.width() * pair.frameSize.height()) <= (maxForMime.width() * maxForMime.height())) + supportedFrameSizes.append(pair.frameSize); + } + } else { + if ((pair.frameSize.width() * pair.frameSize.height()) <= (maxForMime.width() * maxForMime.height())) + supportedFrameSizes.append(pair.frameSize); + } + } + } + } + } + +#ifdef Q_CC_NOKIAX86 // Emulator + supportedFrameSizes << QSize(160, 120); + supportedFrameSizes << QSize(352, 288); + supportedFrameSizes << QSize(640,480); +#endif + + return supportedFrameSizes; +} + +QList<qreal> S60VideoCaptureSession::supportedVideoFrameRates(bool *continuous) +{ + QList<qreal> supportedRatesList; + + if (m_videoParametersForEncoder.count() > 0) { + // Insert min and max to the list + supportedRatesList.append(1.0); // Use 1fps as sensible minimum + qreal foundMaxFrameRate(0.0); + + // Also arbitrary framerates are supported + if (continuous) + *continuous = true; + + // Find max framerate + foreach (MaxResolutionRatesAndTypes parameters, m_videoParametersForEncoder) { + for (int i = 0; i < parameters.frameRatePictureSizePair.count(); ++i) { + qreal maxFrameRate = parameters.frameRatePictureSizePair[i].frameRate; + if (maxFrameRate > foundMaxFrameRate) + foundMaxFrameRate = maxFrameRate; + } + } + + supportedRatesList.append(foundMaxFrameRate); + } + + // Add also other standard framerates to the list + if (!supportedRatesList.isEmpty()) { + if (supportedRatesList.last() > 30.0) { + if (!supportedRatesList.contains(30.0)) + supportedRatesList.insert(1, 30.0); + } + if (supportedRatesList.last() > 25.0) { + if (!supportedRatesList.contains(25.0)) + supportedRatesList.insert(1, 25.0); + } + if (supportedRatesList.last() > 15.0) { + if (!supportedRatesList.contains(15.0)) + supportedRatesList.insert(1, 15.0); + } + if (supportedRatesList.last() > 10.0) { + if (!supportedRatesList.contains(10)) + supportedRatesList.insert(1, 10.0); + } + } + +#ifdef Q_CC_NOKIAX86 // Emulator + supportedRatesList << 30.0 << 25.0 << 15.0 << 10.0 << 5.0; +#endif + + return supportedRatesList; +} + +QList<qreal> S60VideoCaptureSession::supportedVideoFrameRates(const QVideoEncoderSettings &settings, bool *continuous) +{ + QList<qreal> supportedFrameRates; + + if (settings.codec().isEmpty()) + return supportedFrameRates; + if (!m_videoCodecList.contains(settings.codec(), Qt::CaseInsensitive)) + return supportedFrameRates; + + // Also arbitrary framerates are supported + if (continuous) + *continuous = true; + + // Find maximum framerate (using defined resolution if set) + for (int i = 0; i < m_videoParametersForEncoder.count(); ++i) { + // Check if encoder supports the requested codec + if (!m_videoParametersForEncoder[i].mimeTypes.contains(settings.codec(), Qt::CaseInsensitive)) + continue; + + foreach (SupportedFrameRatePictureSize pair, m_videoParametersForEncoder[i].frameRatePictureSizePair) { + if (!supportedFrameRates.contains(pair.frameRate)) { + qreal maxRateForMime = maximumFrameRateForMimeType(settings.codec()); + if (settings.resolution().width() != 0 && settings.resolution().height() != 0) { + if((settings.resolution().width() * settings.resolution().height()) <= (pair.frameSize.width() * pair.frameSize.height())) { + if (pair.frameRate <= maxRateForMime) + supportedFrameRates.append(pair.frameRate); + } + } else { + if (pair.frameRate <= maxRateForMime) + supportedFrameRates.append(pair.frameRate); + } + } + } + } + + // Add also other standard framerates to the list + if (!supportedFrameRates.isEmpty()) { + if (supportedFrameRates.last() > 30.0) { + if (!supportedFrameRates.contains(30.0)) + supportedFrameRates.insert(1, 30.0); + } + if (supportedFrameRates.last() > 25.0) { + if (!supportedFrameRates.contains(25.0)) + supportedFrameRates.insert(1, 25.0); + } + if (supportedFrameRates.last() > 15.0) { + if (!supportedFrameRates.contains(15.0)) + supportedFrameRates.insert(1, 15.0); + } + if (supportedFrameRates.last() > 10.0) { + if (!supportedFrameRates.contains(10)) + supportedFrameRates.insert(1, 10.0); + } + } + +#ifdef Q_CC_NOKIAX86 // Emulator + supportedFrameRates << 30.0 << 25.0 << 15.0 << 10.0 << 5.0; +#endif + + return supportedFrameRates; +} + +bool S60VideoCaptureSession::setOutputLocation(const QUrl &sink) +{ + m_requestedSink = sink; + + if (m_error) + return false; + + switch (m_captureState) { + case ENotInitialized: + case EInitializing: + case EOpening: + case EPreparing: + m_openWhenReady = true; + return true; + + case EInitialized: + case EOpenComplete: + case EPrepared: + // Continue + break; + + case ERecording: + case EPaused: + setError(KErrNotReady, tr("Cannot set file name while recording.")); + return false; + + default: + setError(KErrGeneral, tr("Unexpected camera error.")); + return false; + } + + // Empty URL - Use default file name and path (C:\Data\Videos\video.mp4) + if (sink.isEmpty()) { + + // Make sure default directory exists + QDir videoDir(QDir::rootPath()); + if (!videoDir.exists(KDefaultVideoPath)) + videoDir.mkpath(KDefaultVideoPath); + QString defaultFile = KDefaultVideoPath; + defaultFile.append("\\"); + defaultFile.append(KDefaultVideoFileName); + m_sink.setUrl(defaultFile); + + } else { // Non-empty URL + + QString fullUrl = sink.scheme(); + + // Relative URL + if (sink.isRelative()) { + + // Extract file name and path from the URL + fullUrl = KDefaultVideoPath; + fullUrl.append("\\"); + fullUrl.append(QDir::toNativeSeparators(sink.path())); + + // Absolute URL + } else { + + // Extract file name and path from the URL + if (fullUrl == "file") { + fullUrl = QDir::toNativeSeparators(sink.path().right(sink.path().length() - 1)); + } else { + fullUrl.append(":"); + fullUrl.append(QDir::toNativeSeparators(sink.path())); + } + } + + QString fileName = fullUrl.right(fullUrl.length() - fullUrl.lastIndexOf("\\") - 1); + QString directory = fullUrl.left(fullUrl.lastIndexOf("\\")); + if (directory.lastIndexOf("\\") == (directory.length() - 1)) + directory = directory.left(directory.length() - 1); + + // URL is Absolute path, not including file name + if (!fileName.contains(".")) { + if (fileName != "") { + directory.append("\\"); + directory.append(fileName); + } + fileName = KDefaultVideoFileName; + } + + // Make sure absolute directory exists + QDir videoDir(QDir::rootPath()); + if (!videoDir.exists(directory)) + videoDir.mkpath(directory); + + QString resolvedURL = directory; + resolvedURL.append("\\"); + resolvedURL.append(fileName); + m_sink = QUrl(resolvedURL); + } + + // State is either Initialized, OpenComplete or Prepared, Close previously opened file + if (m_videoRecorder) + m_videoRecorder->Close(); + else + setError(KErrNotReady, tr("Unexpected camera error.")); + + // Open file + + QString fileName = QDir::toNativeSeparators(m_sink.toString()); + TPtrC16 fileSink(reinterpret_cast<const TUint16*>(fileName.utf16())); + + int cameraHandle = m_cameraEngine->Camera() ? m_cameraEngine->Camera()->Handle() : 0; + + TUid controllerUid; + TUid formatUid; + selectController(m_requestedContainer, controllerUid, formatUid); + + if (m_videoRecorder) { + // File open completes in MvruoOpenComplete + TRAPD(err, m_videoRecorder->OpenFileL(fileSink, cameraHandle, controllerUid, formatUid)); + setError(err, tr("Failed to initialize video recorder.")); + m_container = m_requestedContainer; + m_captureState = EOpening; + emit stateChanged(m_captureState); + } + else + setError(KErrNotReady, tr("Unexpected camera error.")); + + m_uncommittedSettings = true; + return true; +} + +QUrl S60VideoCaptureSession::outputLocation() const +{ + return m_sink; +} + +qint64 S60VideoCaptureSession::position() +{ + // Update position only if recording is ongoing + if ((m_captureState == ERecording) && m_videoRecorder) { + // Signal will be automatically emitted of position changes + TRAPD(err, m_position = m_videoRecorder->DurationL().Int64() / 1000); + setError(err, tr("Cannot retrieve video position.")); + } + + return m_position; +} + +S60VideoCaptureSession::TVideoCaptureState S60VideoCaptureSession::state() const +{ + return m_captureState; +} + +bool S60VideoCaptureSession::isMuted() const +{ + return m_muted; +} + +void S60VideoCaptureSession::setMuted(const bool muted) +{ + // CVideoRecorderUtility can mute/unmute only if not recording + if (m_captureState > EPrepared) { + if (muted) + setError(KErrNotSupported, tr("Muting audio is not supported during recording.")); + else + setError(KErrNotSupported, tr("Unmuting audio is not supported during recording.")); + return; + } + + // Check if request is already active + if (muted == isMuted()) + return; + + m_muted = muted; + + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::commitVideoEncoderSettings() +{ + if (m_captureState == EOpenComplete) { + + if (m_container != m_requestedContainer) { + setOutputLocation(m_requestedSink); + return; + } + + TRAPD(err, doSetCodecsL()); + if (err) { + setError(err, tr("Failed to set audio or video codec.")); + m_audioSettings.setCodec(KMimeTypeDefaultAudioCodec); + m_videoSettings.setCodec(KMimeTypeDefaultVideoCodec); + } + + doSetVideoResolution(m_videoSettings.resolution()); + doSetFrameRate(m_videoSettings.frameRate()); + doSetBitrate(m_videoSettings.bitRate()); + + // Audio/Video EncodingMode are not supported in Symbian + +#ifndef S60_31_PLATFORM + if (m_audioSettings.sampleRate() != -1 && m_audioSettings.sampleRate() != 0) { + TRAP(err, m_videoRecorder->SetAudioSampleRateL((TInt)m_audioSettings.sampleRate())); + if (err != KErrNotSupported) { + setError(err, tr("Setting audio sample rate failed.")); + } else { + setError(err, tr("Setting audio sample rate is not supported.")); + m_audioSettings.setSampleRate(KDefaultSampleRate); // Reset + } + } +#endif // S60_31_PLATFORM + + TRAP(err, m_videoRecorder->SetAudioBitRateL((TInt)m_audioSettings.bitRate())); + if (err != KErrNotSupported) { + if (err == KErrArgument) { + setError(KErrNotSupported, tr("Requested audio bitrate is not supported or previously set codec is not supported with requested bitrate.")); + int fallback = 16000; + TRAP(err, m_videoRecorder->SetAudioBitRateL(TInt(fallback))); + if (err == KErrNone) + m_audioSettings.setBitRate(fallback); + } else { + setError(err, tr("Setting audio bitrate failed.")); + } + } + +#ifndef S60_31_PLATFORM + if (m_audioSettings.channelCount() != -1) { + TRAP(err, m_videoRecorder->SetAudioChannelsL(TUint(m_audioSettings.channelCount()))); + if (err != KErrNotSupported) { + setError(err, tr("Setting audio channel count failed.")); + } else { + setError(err, tr("Setting audio channel count is not supported.")); + m_audioSettings.setChannelCount(KDefaultChannelCount); // Reset + } + } +#endif // S60_31_PLATFORM + + TBool isAudioMuted = EFalse; + TRAP(err, isAudioMuted = !m_videoRecorder->AudioEnabledL()); + if (err != KErrNotSupported && err != KErrNone) + setError(err, tr("Failure when checking if audio is enabled.")); + + if (m_muted != (bool)isAudioMuted) { + TRAP(err, m_videoRecorder->SetAudioEnabledL(TBool(!m_muted))); + if (err) { + if (err != KErrNotSupported) { + setError(err, tr("Failed to mute/unmute audio.")); + } else { + setError(err, tr("Muting/unmuting audio is not supported.")); + } + } + else + emit mutedChanged(m_muted); + } + + m_uncommittedSettings = false; // Reset + } +} + +void S60VideoCaptureSession::queryAudioEncoderSettings() +{ + if (!m_videoRecorder) + return; + + switch (m_captureState) { + case ENotInitialized: + case EInitializing: + case EOpening: + case EPreparing: + return; + + // Possible to query settings from CVideoRecorderUtility + case EInitialized: + case EOpenComplete: + case EPrepared: + case ERecording: + case EPaused: + break; + + default: + return; + } + + TInt err = KErrNone; + + // Codec + TFourCC audioCodec; + TRAP(err, audioCodec = m_videoRecorder->AudioTypeL()); + if (err) { + if (err != KErrNotSupported) + setError(err, tr("Querying audio codec failed.")); + } + QString codec = ""; + foreach (TFourCC aCodec, m_audioCodecList) { + if (audioCodec == aCodec) + codec = m_audioCodecList.key(aCodec); + } + m_audioSettings.setCodec(codec); + +#ifndef S60_31_PLATFORM + // Samplerate + TInt sampleRate = -1; + TRAP(err, sampleRate = m_videoRecorder->AudioSampleRateL()); + if (err) { + if (err != KErrNotSupported) + setError(err, tr("Querying audio sample rate failed.")); + } + m_audioSettings.setSampleRate(int(sampleRate)); +#endif // S60_31_PLATFORM + + // BitRate + TInt bitRate = -1; + TRAP(err, bitRate = m_videoRecorder->AudioBitRateL()); + if (err) { + if (err != KErrNotSupported) + setError(err, tr("Querying audio bitrate failed.")); + } + m_audioSettings.setBitRate(int(bitRate)); + +#ifndef S60_31_PLATFORM + // ChannelCount + TUint channelCount = 0; + TRAP(err, channelCount = m_videoRecorder->AudioChannelsL()); + if (err) { + if (err != KErrNotSupported) + setError(err, tr("Querying audio channel count failed.")); + } + if (channelCount != 0) + m_audioSettings.setChannelCount(int(channelCount)); + else + m_audioSettings.setChannelCount(-1); +#endif // S60_31_PLATFORM + + // EncodingMode + m_audioSettings.setEncodingMode(QtMultimediaKit::ConstantQualityEncoding); + + // IsMuted + TBool isEnabled = ETrue; + TRAP(err, isEnabled = m_videoRecorder->AudioEnabledL()); + if (err) { + if (err != KErrNotSupported) + setError(err, tr("Querying whether audio is muted failed.")); + } + m_muted = bool(!isEnabled); +} + +void S60VideoCaptureSession::queryVideoEncoderSettings() +{ + if (!m_videoRecorder) + return; + + switch (m_captureState) { + case ENotInitialized: + case EInitializing: + case EOpening: + case EPreparing: + return; + + // Possible to query settings from CVideoRecorderUtility + case EInitialized: + case EOpenComplete: + case EPrepared: + case ERecording: + case EPaused: + break; + + default: + return; + } + + TInt err = KErrNone; + + // Codec + const TDesC8 &videoMimeType = m_videoRecorder->VideoFormatMimeType(); + QString videoMimeTypeString = ""; + if (videoMimeType.Length() > 0) { + // First convert the 8-bit descriptor to Unicode + HBufC16* videoCodec; + videoCodec = CnvUtfConverter::ConvertToUnicodeFromUtf8L(videoMimeType); + CleanupStack::PushL(videoCodec); + + // Then deep copy QString from that + videoMimeTypeString = QString::fromUtf16(videoCodec->Ptr(), videoCodec->Length()); + m_videoSettings.setCodec(videoMimeTypeString); + + CleanupStack::PopAndDestroy(videoCodec); + } + + // Resolution + TSize symbianResolution; + TRAP(err, m_videoRecorder->GetVideoFrameSizeL(symbianResolution)); + if (err) { + if (err != KErrNotSupported) + setError(err, tr("Querying video resolution failed.")); + } + QSize resolution = QSize(symbianResolution.iWidth, symbianResolution.iHeight); + m_videoSettings.setResolution(resolution); + + // FrameRate + TReal32 frameRate = 0; + TRAP(err, frameRate = m_videoRecorder->VideoFrameRateL()); + if (err) { + if (err != KErrNotSupported) + setError(err, tr("Querying video framerate failed.")); + } + m_videoSettings.setFrameRate(qreal(frameRate)); + + // BitRate + TInt bitRate = -1; + TRAP(err, bitRate = m_videoRecorder->VideoBitRateL()); + if (err) { + if (err != KErrNotSupported) + setError(err, tr("Querying video bitrate failed.")); + } + m_videoSettings.setBitRate(int(bitRate)); + + // EncodingMode + m_audioSettings.setEncodingMode(QtMultimediaKit::ConstantQualityEncoding); +} + +void S60VideoCaptureSession::videoEncoderSettings(QVideoEncoderSettings &videoSettings) +{ + switch (m_captureState) { + // CVideoRecorderUtility, return requested settings + case ENotInitialized: + case EInitializing: + case EInitialized: + case EOpening: + case EOpenComplete: + case EPreparing: + break; + + // Possible to query settings from CVideoRecorderUtility + case EPrepared: + case ERecording: + case EPaused: + queryVideoEncoderSettings(); + break; + + default: + videoSettings = QVideoEncoderSettings(); + setError(KErrGeneral, tr("Unexpected video error.")); + return; + } + + videoSettings = m_videoSettings; +} + +void S60VideoCaptureSession::audioEncoderSettings(QAudioEncoderSettings &audioSettings) +{ + switch (m_captureState) { + // CVideoRecorderUtility, return requested settings + case ENotInitialized: + case EInitializing: + case EInitialized: + case EOpening: + case EOpenComplete: + case EPreparing: + break; + + // Possible to query settings from CVideoRecorderUtility + case EPrepared: + case ERecording: + case EPaused: + queryAudioEncoderSettings(); + break; + + default: + audioSettings = QAudioEncoderSettings(); + setError(KErrGeneral, tr("Unexpected video error.")); + return; + } + + audioSettings = m_audioSettings; +} + +void S60VideoCaptureSession::validateRequestedCodecs() +{ + if (!m_audioCodecList.contains(m_audioSettings.codec())) { + m_audioSettings.setCodec(KMimeTypeDefaultAudioCodec); + setError(KErrNotSupported, tr("Currently selected audio codec is not supported by the platform.")); + } + if (!m_videoCodecList.contains(m_videoSettings.codec())) { + m_videoSettings.setCodec(KMimeTypeDefaultVideoCodec); + setError(KErrNotSupported, tr("Currently selected video codec is not supported by the platform.")); + } +} + +void S60VideoCaptureSession::setVideoCaptureQuality(const QtMultimediaKit::EncodingQuality quality, + const VideoQualityDefinition mode) +{ + // Sensible presets + switch (mode) { + case ENoVideoQuality: + // Do nothing + break; + case EOnlyVideoQuality: + if (quality == QtMultimediaKit::VeryLowQuality) { + m_videoSettings.setResolution(QSize(128,96)); + m_videoSettings.setFrameRate(10); + m_videoSettings.setBitRate(64000); + } else if (quality == QtMultimediaKit::LowQuality) { + m_videoSettings.setResolution(QSize(176,144)); + m_videoSettings.setFrameRate(15); + m_videoSettings.setBitRate(64000); + } else if (quality == QtMultimediaKit::NormalQuality) { + m_videoSettings.setResolution(QSize(176,144)); + m_videoSettings.setFrameRate(15); + m_videoSettings.setBitRate(128000); + } else if (quality == QtMultimediaKit::HighQuality) { + m_videoSettings.setResolution(QSize(352,288)); + m_videoSettings.setFrameRate(15); + m_videoSettings.setBitRate(384000); + } else if (quality == QtMultimediaKit::VeryHighQuality) { + if (m_cameraEngine && m_cameraEngine->CurrentCameraIndex() == 0) + m_videoSettings.setResolution(QSize(640,480)); // Primary camera + else + m_videoSettings.setResolution(QSize(352,288)); // Other cameras + m_videoSettings.setFrameRate(15); + m_videoSettings.setBitRate(2000000); + } else { + m_videoSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported video quality.")); + return; + } + break; + case EVideoQualityAndResolution: + if (quality == QtMultimediaKit::VeryLowQuality) { + m_videoSettings.setFrameRate(10); + m_videoSettings.setBitRate(64000); + } else if (quality == QtMultimediaKit::LowQuality) { + m_videoSettings.setFrameRate(15); + m_videoSettings.setBitRate(64000); + } else if (quality == QtMultimediaKit::NormalQuality) { + m_videoSettings.setFrameRate(15); + m_videoSettings.setBitRate(128000); + } else if (quality == QtMultimediaKit::HighQuality) { + m_videoSettings.setFrameRate(15); + m_videoSettings.setBitRate(384000); + } else if (quality == QtMultimediaKit::VeryHighQuality) { + m_videoSettings.setFrameRate(15); + m_videoSettings.setBitRate(2000000); + } else { + m_videoSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported video quality.")); + return; + } + break; + case EVideoQualityAndFrameRate: + if (quality == QtMultimediaKit::VeryLowQuality) { + m_videoSettings.setResolution(QSize(128,96)); + m_videoSettings.setBitRate(64000); + } else if (quality == QtMultimediaKit::LowQuality) { + m_videoSettings.setResolution(QSize(176,144)); + m_videoSettings.setBitRate(64000); + } else if (quality == QtMultimediaKit::NormalQuality) { + m_videoSettings.setResolution(QSize(176,144)); + m_videoSettings.setBitRate(128000); + } else if (quality == QtMultimediaKit::HighQuality) { + m_videoSettings.setResolution(QSize(352,288)); + m_videoSettings.setBitRate(384000); + } else if (quality == QtMultimediaKit::VeryHighQuality) { + if (m_cameraEngine && m_cameraEngine->CurrentCameraIndex() == 0) + m_videoSettings.setResolution(QSize(640,480)); // Primary camera + else + m_videoSettings.setResolution(QSize(352,288)); // Other cameras + m_videoSettings.setBitRate(2000000); + } else { + m_videoSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported video quality.")); + return; + } + break; + case EVideoQualityAndBitRate: + if (quality == QtMultimediaKit::VeryLowQuality) { + m_videoSettings.setResolution(QSize(128,96)); + m_videoSettings.setFrameRate(10); + } else if (quality == QtMultimediaKit::LowQuality) { + m_videoSettings.setResolution(QSize(176,144)); + m_videoSettings.setFrameRate(15); + } else if (quality == QtMultimediaKit::NormalQuality) { + m_videoSettings.setResolution(QSize(176,144)); + m_videoSettings.setFrameRate(15); + } else if (quality == QtMultimediaKit::HighQuality) { + m_videoSettings.setResolution(QSize(352,288)); + m_videoSettings.setFrameRate(15); + } else if (quality == QtMultimediaKit::VeryHighQuality) { + if (m_cameraEngine && m_cameraEngine->CurrentCameraIndex() == 0) + m_videoSettings.setResolution(QSize(640,480)); // Primary camera + else + m_videoSettings.setResolution(QSize(352,288)); // Other cameras + m_videoSettings.setFrameRate(15); + } else { + m_videoSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported video quality.")); + return; + } + break; + case EVideoQualityAndResolutionAndBitRate: + if (quality == QtMultimediaKit::VeryLowQuality) { + m_videoSettings.setFrameRate(10); + } else if (quality == QtMultimediaKit::LowQuality) { + m_videoSettings.setFrameRate(15); + } else if (quality == QtMultimediaKit::NormalQuality) { + m_videoSettings.setFrameRate(15); + } else if (quality == QtMultimediaKit::HighQuality) { + m_videoSettings.setFrameRate(15); + } else if (quality == QtMultimediaKit::VeryHighQuality) { + m_videoSettings.setFrameRate(15); + } else { + m_videoSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported video quality.")); + return; + } + break; + case EVideoQualityAndResolutionAndFrameRate: + if (quality == QtMultimediaKit::VeryLowQuality) { + m_videoSettings.setBitRate(64000); + } else if (quality == QtMultimediaKit::LowQuality) { + m_videoSettings.setBitRate(64000); + } else if (quality == QtMultimediaKit::NormalQuality) { + m_videoSettings.setBitRate(128000); + } else if (quality == QtMultimediaKit::HighQuality) { + m_videoSettings.setBitRate(384000); + } else if (quality == QtMultimediaKit::VeryHighQuality) { + m_videoSettings.setBitRate(2000000); + } else { + m_videoSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported video quality.")); + return; + } + break; + case EVideoQualityAndFrameRateAndBitRate: + if (quality == QtMultimediaKit::VeryLowQuality) { + m_videoSettings.setResolution(QSize(128,96)); + } else if (quality == QtMultimediaKit::LowQuality) { + m_videoSettings.setResolution(QSize(176,144)); + } else if (quality == QtMultimediaKit::NormalQuality) { + m_videoSettings.setResolution(QSize(176,144)); + } else if (quality == QtMultimediaKit::HighQuality) { + m_videoSettings.setResolution(QSize(352,288)); + } else if (quality == QtMultimediaKit::VeryHighQuality) { + if (m_cameraEngine && m_cameraEngine->CurrentCameraIndex() == 0) + m_videoSettings.setResolution(QSize(640,480)); // Primary camera + else + m_videoSettings.setResolution(QSize(352,288)); // Other cameras + } else { + m_videoSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported video quality.")); + return; + } + break; + } + + m_videoSettings.setQuality(quality); + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::setAudioCaptureQuality(const QtMultimediaKit::EncodingQuality quality, + const AudioQualityDefinition mode) +{ + // Based on audio quality definition mode, select proper SampleRate and BitRate + switch (mode) { + case EOnlyAudioQuality: + switch (quality) { + case QtMultimediaKit::VeryLowQuality: + m_audioSettings.setBitRate(16000); + m_audioSettings.setSampleRate(-1); + break; + case QtMultimediaKit::LowQuality: + m_audioSettings.setBitRate(16000); + m_audioSettings.setSampleRate(-1); + break; + case QtMultimediaKit::NormalQuality: + m_audioSettings.setBitRate(32000); + m_audioSettings.setSampleRate(-1); + break; + case QtMultimediaKit::HighQuality: + m_audioSettings.setBitRate(64000); + m_audioSettings.setSampleRate(-1); + break; + case QtMultimediaKit::VeryHighQuality: + m_audioSettings.setBitRate(64000); + m_audioSettings.setSampleRate(-1); + break; + default: + m_audioSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported audio quality.")); + return; + } + break; + case EAudioQualityAndBitRate: + switch (quality) { + case QtMultimediaKit::VeryLowQuality: + m_audioSettings.setSampleRate(-1); + break; + case QtMultimediaKit::LowQuality: + m_audioSettings.setSampleRate(-1); + break; + case QtMultimediaKit::NormalQuality: + m_audioSettings.setSampleRate(-1); + break; + case QtMultimediaKit::HighQuality: + m_audioSettings.setSampleRate(-1); + break; + case QtMultimediaKit::VeryHighQuality: + m_audioSettings.setSampleRate(-1); + break; + default: + m_audioSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported audio quality.")); + return; + } + break; + case EAudioQualityAndSampleRate: + switch (quality) { + case QtMultimediaKit::VeryLowQuality: + m_audioSettings.setBitRate(16000); + break; + case QtMultimediaKit::LowQuality: + m_audioSettings.setBitRate(16000); + break; + case QtMultimediaKit::NormalQuality: + m_audioSettings.setBitRate(32000); + break; + case QtMultimediaKit::HighQuality: + m_audioSettings.setBitRate(64000); + break; + case QtMultimediaKit::VeryHighQuality: + m_audioSettings.setBitRate(64000); + break; + default: + m_audioSettings.setQuality(QtMultimediaKit::NormalQuality); + setError(KErrNotSupported, tr("Unsupported audio quality.")); + return; + } + break; + case ENoAudioQuality: + // No actions required, just set quality parameter + break; + + default: + setError(KErrGeneral, tr("Unexpected camera error.")); + return; + } + + m_audioSettings.setQuality(quality); + m_uncommittedSettings = true; +} + +int S60VideoCaptureSession::initializeVideoRecording() +{ + if (m_error) + return m_error; + + TRAPD(symbianError, doInitializeVideoRecorderL()); + setError(symbianError, tr("Failed to initialize video recorder.")); + + return symbianError; +} + +void S60VideoCaptureSession::releaseVideoRecording() +{ + if (m_captureState >= ERecording) { + m_videoRecorder->Stop(); + if (m_durationTimer->isActive()) + m_durationTimer->stop(); + } + + if (m_captureState >= EInitialized) + m_videoRecorder->Close(); + + // Reset state + m_captureState = ENotInitialized; + + // Reset error to be able to recover from error + m_error = KErrNone; + + // Reset flags + m_openWhenReady = false; + m_prepareAfterOpenComplete = false; + m_startAfterPrepareComplete = false; + m_uncommittedSettings = false; + m_commitSettingsWhenReady = false; +} + +void S60VideoCaptureSession::startRecording() +{ + if (m_error) { + setError(m_error, tr("Unexpected recording error.")); + return; + } + + switch (m_captureState) { + case ENotInitialized: + case EInitializing: + case EInitialized: + if (m_captureState == EInitialized) + setOutputLocation(m_requestedSink); + m_startAfterPrepareComplete = true; + return; + + case EOpening: + case EPreparing: + // Execute FileOpenL() and Prepare() asap and then start recording + m_startAfterPrepareComplete = true; + return; + case EOpenComplete: + case EPrepared: + if (m_captureState == EPrepared && !m_uncommittedSettings) + break; + + // Revert state internally, since logically applying settings means going + // from OpenComplete ==> Preparing ==> Prepared. + m_captureState = EOpenComplete; + m_startAfterPrepareComplete = true; + + // Commit settings and prepare with them + applyAllSettings(); + return; + case ERecording: + // Discard + return; + case EPaused: + // Continue + break; + + default: + setError(KErrGeneral, tr("Unexpected camera error.")); + return; + } + + // State should now be either Prepared with no Uncommitted Settings or Paused + + if (!m_cameraStarted) { + m_startAfterPrepareComplete = true; + return; + } + + if (m_cameraEngine && !m_cameraEngine->IsCameraReady()) { + setError(KErrNotReady, tr("Camera not ready to start video recording.")); + return; + } + + if (m_videoRecorder) { + m_videoRecorder->Record(); + m_captureState = ERecording; + emit stateChanged(m_captureState); + m_durationTimer->start(); + + // Reset all flags + m_openWhenReady = false; + m_prepareAfterOpenComplete = false; + m_startAfterPrepareComplete = false; + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } +} + +void S60VideoCaptureSession::pauseRecording() +{ + if (m_captureState == ERecording) { + if (m_videoRecorder) { + TRAPD(err, m_videoRecorder->PauseL()); + setError(err, tr("Pausing video recording failed.")); + m_captureState = EPaused; + emit stateChanged(m_captureState); + if (m_durationTimer->isActive()) + m_durationTimer->stop(); + + // Notify last duration + TRAP(err, m_position = m_videoRecorder->DurationL().Int64() / 1000); + setError(err, tr("Cannot retrieve video position.")); + emit positionChanged(m_position); + } + else + setError(KErrNotReady, tr("Unexpected camera error.")); + } +} + +void S60VideoCaptureSession::stopRecording(const bool reInitialize) +{ + if (m_captureState != ERecording && m_captureState != EPaused) + return; // Ignore + + if (m_videoRecorder) { + m_videoRecorder->Stop(); + m_videoRecorder->Close(); + + // Notify muting is disabled if needed + if (m_muted) + emit mutedChanged(false); + + m_captureState = ENotInitialized; + emit stateChanged(m_captureState); + + if (m_durationTimer->isActive()) + m_durationTimer->stop(); + + // VideoRecording will be re-initialized unless explicitly requested not to do so + if (reInitialize) { + if (m_cameraEngine->IsCameraReady()) + initializeVideoRecording(); + } + } + else + setError(KErrNotReady, tr("Unexpected camera error.")); +} + +void S60VideoCaptureSession::updateVideoCaptureContainers() +{ + TRAPD(err, doUpdateVideoCaptureContainersL()); + setError(err, tr("Failed to gather video container information.")); +} + +void S60VideoCaptureSession::doUpdateVideoCaptureContainersL() +{ + // Clear container data structure + QList<TInt> mapControllers = m_videoControllerMap.keys(); + for (int i = 0; i < mapControllers.size(); ++i) { + foreach(VideoFormatData data, m_videoControllerMap[mapControllers[i]]){ + data.supportedMimeTypes.clear(); + } + m_videoControllerMap[mapControllers[i]].clear(); + } + m_videoControllerMap.clear(); + + // Resolve the supported video format and retrieve a list of controllers + CMMFControllerPluginSelectionParameters* pluginParameters = + CMMFControllerPluginSelectionParameters::NewLC(); + CMMFFormatSelectionParameters* format = + CMMFFormatSelectionParameters::NewLC(); + + // Set the play and record format selection parameters to be blank. + // Format support is only retrieved if requested. + pluginParameters->SetRequiredPlayFormatSupportL(*format); + pluginParameters->SetRequiredRecordFormatSupportL(*format); + + // Set the media IDs + RArray<TUid> mediaIds; + CleanupClosePushL(mediaIds); + + User::LeaveIfError(mediaIds.Append(KUidMediaTypeVideo)); + + // Get plugins that support at least video + pluginParameters->SetMediaIdsL(mediaIds, + CMMFPluginSelectionParameters::EAllowOtherMediaIds); + pluginParameters->SetPreferredSupplierL(KNullDesC, + CMMFPluginSelectionParameters::EPreferredSupplierPluginsFirstInList); + + // Array to hold all the controllers support the match data + RMMFControllerImplInfoArray controllers; + CleanupResetAndDestroyPushL(controllers); + pluginParameters->ListImplementationsL(controllers); + + // Find the first controller with at least one record format available + for (TInt index = 0; index < controllers.Count(); ++index) { + + m_videoControllerMap.insert(controllers[index]->Uid().iUid, QHash<TInt,VideoFormatData>()); + + const RMMFFormatImplInfoArray& recordFormats = controllers[index]->RecordFormats(); + for (TInt j = 0; j < recordFormats.Count(); ++j) { + VideoFormatData formatData; + formatData.description = QString::fromUtf16( + recordFormats[j]->DisplayName().Ptr(), + recordFormats[j]->DisplayName().Length()); + + const CDesC8Array& mimeTypes = recordFormats[j]->SupportedMimeTypes(); + for (int k = 0; k < mimeTypes.Count(); ++k) { + TPtrC8 mimeType = mimeTypes[k]; + QString type = QString::fromUtf8((char *)mimeType.Ptr(), + mimeType.Length()); + formatData.supportedMimeTypes.append(type); + } + + m_videoControllerMap[controllers[index]->Uid().iUid].insert(recordFormats[j]->Uid().iUid, formatData); + } + } + + CleanupStack::PopAndDestroy(&controllers); + CleanupStack::PopAndDestroy(&mediaIds); + CleanupStack::PopAndDestroy(format); + CleanupStack::PopAndDestroy(pluginParameters); +} + +/* + * This goes through the available controllers and selects proper one based + * on the format. Function sets proper UIDs to be used for controller and format. + */ +void S60VideoCaptureSession::selectController(const QString &format, + TUid &controllerUid, + TUid &formatUid) +{ + QList<TInt> controllers = m_videoControllerMap.keys(); + QList<TInt> formats; + + for (int i = 0; i < controllers.count(); ++i) { + formats = m_videoControllerMap[controllers[i]].keys(); + for (int j = 0; j < formats.count(); ++j) { + VideoFormatData formatData = m_videoControllerMap[controllers[i]][formats[j]]; + if (formatData.supportedMimeTypes.contains(format, Qt::CaseInsensitive)) { + controllerUid = TUid::Uid(controllers[i]); + formatUid = TUid::Uid(formats[j]); + } + } + } +} + +QStringList S60VideoCaptureSession::supportedVideoCaptureCodecs() +{ + return m_videoCodecList; +} + +QStringList S60VideoCaptureSession::supportedAudioCaptureCodecs() +{ + QStringList keys = m_audioCodecList.keys(); + keys.sort(); + return keys; +} + +QList<int> S60VideoCaptureSession::supportedSampleRates(const QAudioEncoderSettings &settings, bool *continuous) +{ + QList<int> rates; + + TRAPD(err, rates = doGetSupportedSampleRatesL(settings, continuous)); + if (err != KErrNotSupported) + setError(err, tr("Failed to query information of supported sample rates.")); + + return rates; +} + +QList<int> S60VideoCaptureSession::doGetSupportedSampleRatesL(const QAudioEncoderSettings &settings, bool *continuous) +{ + QList<int> sampleRates; + + if (m_captureState < EOpenComplete) + return sampleRates; + +#ifndef S60_31_PLATFORM + RArray<TUint> supportedSampleRates; + CleanupClosePushL(supportedSampleRates); + + if (!settings.codec().isEmpty()) { + + TFourCC currentAudioCodec; + currentAudioCodec = m_videoRecorder->AudioTypeL(); + + TFourCC requestedAudioCodec; + if (qstrcmp(settings.codec().toLocal8Bit().constData(), "audio/aac") == 0) + requestedAudioCodec.Set(KMMFFourCCCodeAAC); + else if (qstrcmp(settings.codec().toLocal8Bit().constData(), "audio/amr") == 0) + requestedAudioCodec.Set(KMMFFourCCCodeAMR); + m_videoRecorder->SetAudioTypeL(requestedAudioCodec); + + m_videoRecorder->GetSupportedAudioSampleRatesL(supportedSampleRates); + + m_videoRecorder->SetAudioTypeL(currentAudioCodec); + } + else + m_videoRecorder->GetSupportedAudioSampleRatesL(supportedSampleRates); + + for (int i = 0; i < supportedSampleRates.Count(); ++i) + sampleRates.append(int(supportedSampleRates[i])); + + CleanupStack::PopAndDestroy(); // RArray<TUint> supportedSampleRates +#else // S60 3.1 Platform + Q_UNUSED(settings); +#endif // S60_31_PLATFORM + + if (continuous) + *continuous = false; + + return sampleRates; +} + +void S60VideoCaptureSession::setAudioSampleRate(const int sampleRate) +{ + if (sampleRate != -1) + m_audioSettings.setSampleRate(sampleRate); + + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::setAudioBitRate(const int bitRate) +{ + if (bitRate != -1) + m_audioSettings.setBitRate(bitRate); + + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::setAudioChannelCount(const int channelCount) +{ + if (channelCount != -1) + m_audioSettings.setChannelCount(channelCount); + + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::setVideoCaptureCodec(const QString &codecName) +{ + if (codecName == m_videoSettings.codec()) + return; + + if (codecName.isEmpty()) + m_videoSettings.setCodec(KMimeTypeDefaultVideoCodec); // Use default + else + m_videoSettings.setCodec(codecName); + + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::setAudioCaptureCodec(const QString &codecName) +{ + if (codecName == m_audioSettings.codec()) + return; + + if (codecName.isEmpty()) { + m_audioSettings.setCodec(KMimeTypeDefaultAudioCodec); // Use default + } else { + // If information of supported codecs is already available check that + // given codec is supported + if (m_captureState >= EOpenComplete) { + if (m_audioCodecList.contains(codecName)) { + m_audioSettings.setCodec(codecName); + m_uncommittedSettings = true; + } else { + setError(KErrNotSupported, tr("Requested audio codec is not supported")); + } + } else { + m_audioSettings.setCodec(codecName); + m_uncommittedSettings = true; + } + } +} + +QString S60VideoCaptureSession::videoCaptureCodecDescription(const QString &codecName) +{ + QString codecDescription; + if (codecName.contains("video/H263-2000", Qt::CaseInsensitive)) + codecDescription.append("H.263 Video Codec"); + else if (codecName.contains("video/mp4v-es", Qt::CaseInsensitive)) + codecDescription.append("MPEG-4 Part 2 Video Codec"); + else if (codecName.contains("video/H264", Qt::CaseInsensitive)) + codecDescription.append("H.264 AVC (MPEG-4 Part 10) Video Codec"); + else + codecDescription.append("Video Codec"); + + return codecDescription; +} + +void S60VideoCaptureSession::doSetCodecsL() +{ + // Determine Profile and Level for the video codec if needed + // (MimeType/Profile-level-id contains "profile" if profile/level info is available) + if (!m_videoSettings.codec().contains(QString("profile"), Qt::CaseInsensitive)) + m_videoSettings.setCodec(determineProfileAndLevel()); + + if (m_videoRecorder) { + TPtrC16 str(reinterpret_cast<const TUint16*>(m_videoSettings.codec().utf16())); + HBufC8* videoCodec(0); + videoCodec = CnvUtfConverter::ConvertFromUnicodeToUtf8L(str); + CleanupStack::PushL(videoCodec); + + TFourCC audioCodec = m_audioCodecList[m_audioSettings.codec()]; + + TInt vErr = KErrNone; + TInt aErr = KErrNone; + TRAP(vErr, m_videoRecorder->SetVideoTypeL(*videoCodec)); + TRAP(aErr, m_videoRecorder->SetAudioTypeL(audioCodec)); + + User::LeaveIfError(vErr); + User::LeaveIfError(aErr); + + CleanupStack::PopAndDestroy(videoCodec); + } + else + setError(KErrNotReady, tr("Unexpected camera error.")); +} + +QString S60VideoCaptureSession::determineProfileAndLevel() +{ + QString determinedMimeType = m_videoSettings.codec(); + + // H.263 + if (determinedMimeType.contains(QString("video/H263-2000"), Qt::CaseInsensitive)) { + if ((m_videoSettings.resolution().width() * m_videoSettings.resolution().height()) > (176*144)) { + if (m_videoSettings.frameRate() > 15.0) + determinedMimeType.append("; profile=0; level=20"); + else + determinedMimeType.append("; profile=0; level=40"); + } else { + if (m_videoSettings.bitRate() > 64000) + determinedMimeType.append("; profile=0; level=45"); + else + determinedMimeType.append("; profile=0; level=10"); + } + + // MPEG-4 + } else if (determinedMimeType.contains(QString("video/mp4v-es"), Qt::CaseInsensitive)) { + if ((m_videoSettings.resolution().width() * m_videoSettings.resolution().height()) > (720*480)) { + determinedMimeType.append("; profile-level-id=6"); + } else if ((m_videoSettings.resolution().width() * m_videoSettings.resolution().height()) > (640*480)) { + determinedMimeType.append("; profile-level-id=5"); + } else if ((m_videoSettings.resolution().width() * m_videoSettings.resolution().height()) > (352*288)) { + determinedMimeType.append("; profile-level-id=4"); + } else if ((m_videoSettings.resolution().width() * m_videoSettings.resolution().height()) > (176*144)) { + if (m_videoSettings.frameRate() > 15.0) + determinedMimeType.append("; profile-level-id=3"); + else + determinedMimeType.append("; profile-level-id=2"); + } else { + if (m_videoSettings.bitRate() > 64000) + determinedMimeType.append("; profile-level-id=9"); + else + determinedMimeType.append("; profile-level-id=1"); + } + + // H.264 + } else if (determinedMimeType.contains(QString("video/H264"), Qt::CaseInsensitive)) { + if ((m_videoSettings.resolution().width() * m_videoSettings.resolution().height()) > (640*480)) { + determinedMimeType.append("; profile-level-id=42801F"); + } else if ((m_videoSettings.resolution().width() * m_videoSettings.resolution().height()) > (352*288)) { + determinedMimeType.append("; profile-level-id=42801E"); + } else if ((m_videoSettings.resolution().width() * m_videoSettings.resolution().height()) > (176*144)) { + if (m_videoSettings.frameRate() > 15.0) + determinedMimeType.append("; profile-level-id=428015"); + else + determinedMimeType.append("; profile-level-id=42800C"); + } else { + determinedMimeType.append("; profile-level-id=42900B"); + } + } + + return determinedMimeType; +} + +void S60VideoCaptureSession::setBitrate(const int bitrate) +{ + m_videoSettings.setBitRate(bitrate); + + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::doSetBitrate(const int &bitrate) +{ + if (bitrate != -1) { + if (m_videoRecorder) { + TRAPD(err, m_videoRecorder->SetVideoBitRateL(bitrate)); + if (err) { + if (err == KErrNotSupported || err == KErrArgument) { + setError(KErrNotSupported, tr("Requested video bitrate is not supported.")); + m_videoSettings.setBitRate(64000); // Reset + } else { + setError(err, tr("Failed to set video bitrate.")); + } + } + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } + } +} + +void S60VideoCaptureSession::setVideoResolution(const QSize &resolution) +{ + m_videoSettings.setResolution(resolution); + + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::doSetVideoResolution(const QSize &resolution) +{ + TSize size((TInt)resolution.width(), (TInt)resolution.height()); + + // Make sure resolution is not too big if main camera is not used + if (m_cameraEngine->CurrentCameraIndex() != 0) { + TCameraInfo *info = m_cameraEngine->CameraInfo(); + if (info) { + TInt videoResolutionCount = info->iNumVideoFrameSizesSupported; + TSize maxCameraVideoResolution = TSize(0,0); + CCamera *camera = m_cameraEngine->Camera(); + if (camera) { + for (TInt i = 0; i < videoResolutionCount; ++i) { + TSize checkedResolution; + // Use YUV video max frame size in the check (Through + // CVideoRecorderUtility/DevVideoRecord it is possible to + // query only encoder maximums) + camera->EnumerateVideoFrameSizes(checkedResolution, i, CCamera::EFormatYUV420Planar); + if ((checkedResolution.iWidth * checkedResolution.iHeight) > + (maxCameraVideoResolution.iWidth * maxCameraVideoResolution.iHeight)) + maxCameraVideoResolution = checkedResolution; + } + if ((maxCameraVideoResolution.iWidth * maxCameraVideoResolution.iHeight) < + (size.iWidth * size.iHeight)) { + size = maxCameraVideoResolution; + setError(KErrNotSupported, tr("Requested resolution is not supported for this camera.")); + } + } + else + setError(KErrGeneral, tr("Could not query supported video resolutions.")); + }else + setError(KErrGeneral, tr("Could not query supported video resolutions.")); + } + + if (resolution.width() != -1 && resolution.height() != -1) { + if (m_videoRecorder) { + TRAPD(err, m_videoRecorder->SetVideoFrameSizeL((TSize)size)); + if (err == KErrNotSupported || err == KErrArgument) { + setError(KErrNotSupported, tr("Requested video resolution is not supported.")); + TSize fallBack(640,480); + TRAPD(err, m_videoRecorder->SetVideoFrameSizeL(fallBack)); + if (err == KErrNone) { + m_videoSettings.setResolution(QSize(fallBack.iWidth,fallBack.iHeight)); + } else { + fallBack = TSize(176,144); + TRAPD(err, m_videoRecorder->SetVideoFrameSizeL(fallBack)); + if (err == KErrNone) + m_videoSettings.setResolution(QSize(fallBack.iWidth,fallBack.iHeight)); + } + } else { + setError(err, tr("Failed to set video resolution.")); + } + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } + } +} + +void S60VideoCaptureSession::setFrameRate(qreal rate) +{ + m_videoSettings.setFrameRate(rate); + + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::doSetFrameRate(qreal rate) +{ + if (rate != 0) { + if (m_videoRecorder) { + bool continuous = false; + QList<qreal> list = supportedVideoFrameRates(&continuous); + qreal maxRate = 0.0; + foreach (qreal fRate, list) + if (fRate > maxRate) + maxRate = fRate; + if (maxRate >= rate && rate > 0) { + TRAPD(err, m_videoRecorder->SetVideoFrameRateL((TReal32)rate)); + if (err == KErrNotSupported) { + setError(KErrNotSupported, tr("Requested framerate is not supported.")); + TReal32 fallBack = 15.0; + TRAPD(err, m_videoRecorder->SetVideoFrameRateL(fallBack)); + if (err == KErrNone) + m_videoSettings.setFrameRate((qreal)fallBack); + } else { + if (err == KErrArgument) { + setError(KErrNotSupported, tr("Requested framerate is not supported.")); + m_videoSettings.setFrameRate(15.0); // Reset + } else { + setError(err, tr("Failed to set video framerate.")); + } + } + } else { + setError(KErrNotSupported, tr("Requested framerate is not supported.")); + m_videoSettings.setFrameRate(15.0); // Reset + } + } else { + setError(KErrNotReady, tr("Unexpected camera error.")); + } + } +} + +void S60VideoCaptureSession::setVideoEncodingMode(const QtMultimediaKit::EncodingMode mode) +{ + // This has no effect as it has no support in Symbian + + if (mode == QtMultimediaKit::ConstantQualityEncoding) { + m_videoSettings.setEncodingMode(mode); + return; + } + + setError(KErrNotSupported, tr("Requested video encoding mode is not supported")); + + // m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::setAudioEncodingMode(const QtMultimediaKit::EncodingMode mode) +{ + // This has no effect as it has no support in Symbian + + if (mode == QtMultimediaKit::ConstantQualityEncoding) { + m_audioSettings.setEncodingMode(mode); + return; + } + + setError(KErrNotSupported, tr("Requested audio encoding mode is not supported")); + + // m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::initializeVideoCaptureSettings() +{ + // Check if user has already requested some settings + if (m_captureSettingsSet) + return; + + QSize resolution(-1, -1); + qreal frameRate(0); + int bitRate(-1); + + if (m_cameraEngine) { + + if (m_videoRecorder && m_captureState >= EInitialized) { + + // Resolution + QList<QSize> resos = supportedVideoResolutions(0); + foreach (QSize reso, resos) { + if ((reso.width() * reso.height()) > (resolution.width() * resolution.height())) + resolution = reso; + } + + // Needed to query supported framerates for this codec/resolution pair + m_videoSettings.setCodec(KMimeTypeDefaultVideoCodec); + m_videoSettings.setResolution(resolution); + + // FrameRate + QList<qreal> fRates = supportedVideoFrameRates(m_videoSettings, 0); + foreach (qreal rate, fRates) { + if (rate > frameRate) + frameRate = rate; + } + + // BitRate +#ifdef SYMBIAN_3_PLATFORM + if (m_cameraEngine->CurrentCameraIndex() == 0) + bitRate = KBiR_H264_PLID_42801F // 14Mbps + else + bitRate = KBiR_H264_PLID_428016 // 4Mbps +#else // Other platforms + if (m_cameraEngine->CurrentCameraIndex() == 0) + bitRate = KBiR_MPEG4_PLID_4 // 2/4Mbps + else + bitRate = KBiR_MPEG4_PLID_3 // 384kbps +#endif // SYMBIAN_3_PLATFORM + + } else { +#ifdef SYMBIAN_3_PLATFORM + if (m_cameraEngine->CurrentCameraIndex() == 0) { + // Primary camera + resolution = KResH264_PLID_42801F; // 1280x720 + frameRate = KFrR_H264_PLID_42801F; // 30fps + bitRate = KBiR_H264_PLID_42801F; // 14Mbps + } else { + // Other cameras + resolution = KResH264_PLID_42801E; // 640x480 + frameRate = KFrR_H264_PLID_428014; // 30fps + bitRate = KBiR_H264_PLID_428016; // 4Mbps + } +#else // Other platforms + if (m_cameraEngine->CurrentCameraIndex() == 0) { + // Primary camera + resolution = KResMPEG4_PLID_4; // 640x480 + frameRate = KFrR_MPEG4_PLID_4; // 15/30fps + bitRate = KBiR_MPEG4_PLID_4; // 2/4Mbps + } else { + // Other cameras + resolution = KResMPEG4_PLID_3; // 352x288 + frameRate = KFrR_MPEG4; // 15fps + bitRate = KBiR_MPEG4_PLID_3; // 384kbps + } +#endif // SYMBIAN_3_PLATFORM + } + } else { +#ifdef SYMBIAN_3_PLATFORM + resolution = KResH264_PLID_42801F; + frameRate = KFrR_H264_PLID_42801F; + bitRate = KBiR_H264_PLID_42801F; +#else // Pre-Symbian3 Platforms + resolution = KResMPEG4_PLID_4; + frameRate = KFrR_MPEG4_PLID_4; + bitRate = KBiR_MPEG4_PLID_4; +#endif // SYMBIAN_3_PLATFORM + } + + // Set specified settings (Resolution, FrameRate and BitRate) + m_videoSettings.setResolution(resolution); + m_videoSettings.setFrameRate(frameRate); + m_videoSettings.setBitRate(bitRate); + + // Video Settings: Codec, EncodingMode and Quality + m_videoSettings.setCodec(KMimeTypeDefaultVideoCodec); + m_videoSettings.setEncodingMode(QtMultimediaKit::ConstantQualityEncoding); + m_videoSettings.setQuality(QtMultimediaKit::VeryHighQuality); + + // Audio Settings + m_audioSettings.setCodec(KMimeTypeDefaultAudioCodec); + m_audioSettings.setBitRate(KDefaultBitRate); + m_audioSettings.setSampleRate(KDefaultSampleRate); + m_audioSettings.setChannelCount(KDefaultChannelCount); + m_audioSettings.setEncodingMode(QtMultimediaKit::ConstantQualityEncoding); + m_audioSettings.setQuality(QtMultimediaKit::VeryHighQuality); +} + +QSize S60VideoCaptureSession::pixelAspectRatio() +{ +#ifndef S60_31_PLATFORM + TVideoAspectRatio par; + TRAPD(err, m_videoRecorder->GetPixelAspectRatioL(par)); + if (err) + setError(err, tr("Failed to query current pixel aspect ratio.")); + return QSize(par.iNumerator, par.iDenominator); +#else // S60_31_PLATFORM + return QSize(); +#endif // !S60_31_PLATFORM +} + +void S60VideoCaptureSession::setPixelAspectRatio(const QSize par) +{ +#ifndef S60_31_PLATFORM + + const TVideoAspectRatio videoPar(par.width(), par.height()); + TRAPD(err, m_videoRecorder->SetPixelAspectRatioL(videoPar)); + if (err) + setError(err, tr("Failed to set pixel aspect ratio.")); +#else // S60_31_PLATFORM + Q_UNUSED(par); +#endif // !S60_31_PLATFORM + + m_uncommittedSettings = true; +} + +int S60VideoCaptureSession::gain() +{ + TInt gain = 0; + TRAPD(err, gain = m_videoRecorder->GainL()); + if (err) + setError(err, tr("Failed to query video gain.")); + return (int)gain; +} + +void S60VideoCaptureSession::setGain(const int gain) +{ + TRAPD(err, m_videoRecorder->SetGainL(gain)); + if (err) + setError(err, tr("Failed to set video gain.")); + + m_uncommittedSettings = true; +} + +int S60VideoCaptureSession::maxClipSizeInBytes() const +{ + return m_maxClipSize; +} + +void S60VideoCaptureSession::setMaxClipSizeInBytes(const int size) +{ + TRAPD(err, m_videoRecorder->SetMaxClipSizeL(size)); + if (err) { + setError(err, tr("Failed to set maximum video size.")); + } else + m_maxClipSize = size; + + m_uncommittedSettings = true; +} + +void S60VideoCaptureSession::MvruoOpenComplete(TInt aError) +{ + if (m_error) + return; + + if (aError == KErrNone && m_videoRecorder) { + if (m_captureState == EInitializing) { + // Dummy file open completed, initialize settings + TRAPD(err, doPopulateAudioCodecsL()); + setError(err, tr("Failed to gather information of supported audio codecs.")); + + // For DevVideoRecord codecs are populated during + // doPopulateVideoCodecsDataL() + TRAP(err, doPopulateVideoCodecsL()); + setError(err, tr("Failed to gather information of supported video codecs.")); +#ifndef S60_DEVVIDEO_RECORDING_SUPPORTED + // Max parameters needed to be populated, if not using DevVideoRecord + // Otherwise done already in constructor + doPopulateMaxVideoParameters(); +#endif // S60_DEVVIDEO_RECORDING_SUPPORTED + + m_captureState = EInitialized; + emit stateChanged(m_captureState); + + // Initialize settings if not already done + initializeVideoCaptureSettings(); + + // Validate codecs to be used + validateRequestedCodecs(); + + if (m_openWhenReady || m_prepareAfterOpenComplete || m_startAfterPrepareComplete) { + setOutputLocation(m_requestedSink); + m_openWhenReady = false; // Reset + } + if (m_commitSettingsWhenReady) { + applyAllSettings(); + m_commitSettingsWhenReady = false; // Reset + } + return; + + } else if (m_captureState == EOpening) { + // Actual file open completed + m_captureState = EOpenComplete; + emit stateChanged(m_captureState); + + // Prepare right away + if (m_startAfterPrepareComplete || m_prepareAfterOpenComplete) { + m_prepareAfterOpenComplete = false; // Reset + + // Commit settings and prepare with them + applyAllSettings(); + } + return; + + } else if (m_captureState == ENotInitialized) { + // Resources released while waiting OpenFileL to complete + m_videoRecorder->Close(); + return; + + } else { + setError(KErrGeneral, tr("Unexpected camera error.")); + return; + } + } + + m_videoRecorder->Close(); + if (aError == KErrNotFound || aError == KErrNotSupported || aError == KErrArgument) + setError(KErrGeneral, tr("Requested video container or controller is not supported.")); + else + setError(KErrGeneral, tr("Failure during video recorder initialization.")); +} + +void S60VideoCaptureSession::MvruoPrepareComplete(TInt aError) +{ + if (m_error) + return; + + if(aError == KErrNone) { + if (m_captureState == ENotInitialized) { + // Resources released while waiting for Prepare to complete + m_videoRecorder->Close(); + return; + } + + emit captureSizeChanged(m_videoSettings.resolution()); + + m_captureState = EPrepared; + emit stateChanged(EPrepared); + + // Check the actual active settings + queryAudioEncoderSettings(); + queryVideoEncoderSettings(); + + if (m_openWhenReady == true) { + setOutputLocation(m_requestedSink); + m_openWhenReady = false; // Reset + } + + if (m_commitSettingsWhenReady) { + applyAllSettings(); + m_commitSettingsWhenReady = false; // Reset + } + + if (m_startAfterPrepareComplete) { + m_startAfterPrepareComplete = false; // Reset + startRecording(); + } + } else { + m_videoRecorder->Close(); + if (aError == KErrNotSupported) + setError(aError, tr("Camera preparation for video recording failed because of unsupported setting.")); + else + setError(aError, tr("Failed to prepare camera for video recording.")); + } +} + +void S60VideoCaptureSession::MvruoRecordComplete(TInt aError) +{ + if (!m_videoRecorder) { + setError(KErrNotReady, tr("Unexpected camera error.")); + return; + } + + if((aError == KErrNone || aError == KErrCompletion)) { + m_videoRecorder->Stop(); + + // Reset state + if (m_captureState != ENotInitialized) { + m_captureState = ENotInitialized; + emit stateChanged(m_captureState); + if (m_durationTimer->isActive()) + m_durationTimer->stop(); + } + + if (m_cameraEngine->IsCameraReady()) + initializeVideoRecording(); + } + m_videoRecorder->Close(); + + // Notify muting is disabled if needed + if (m_muted) + emit mutedChanged(false); + + if (aError == KErrDiskFull) + setError(aError, tr("Not enough space for video, recording stopped.")); + else + setError(aError, tr("Recording stopped due to unexpected error.")); +} + +void S60VideoCaptureSession::MvruoEvent(const TMMFEvent& aEvent) +{ + Q_UNUSED(aEvent); +} + +#ifdef S60_DEVVIDEO_RECORDING_SUPPORTED +void S60VideoCaptureSession::MdvroReturnPicture(TVideoPicture *aPicture) +{ + // Not used + Q_UNUSED(aPicture); +} + +void S60VideoCaptureSession::MdvroSupplementalInfoSent() +{ + // Not used +} + +void S60VideoCaptureSession::MdvroNewBuffers() +{ + // Not used +} + +void S60VideoCaptureSession::MdvroFatalError(TInt aError) +{ + setError(aError, tr("Unexpected camera error.")); +} + +void S60VideoCaptureSession::MdvroInitializeComplete(TInt aError) +{ + // Not used + Q_UNUSED(aError); +} + +void S60VideoCaptureSession::MdvroStreamEnd() +{ + // Not used +} + +/* + * This populates video codec information (supported codecs, resolutions, + * framerates, etc.) using DevVideoRecord API. + */ +void S60VideoCaptureSession::doPopulateVideoCodecsDataL() +{ + RArray<TUid> encoders; + CleanupClosePushL(encoders); + + CMMFDevVideoRecord *mDevVideoRecord = CMMFDevVideoRecord::NewL(*this); + CleanupStack::PushL(mDevVideoRecord); + + // Retrieve list of all encoders provided by the platform + mDevVideoRecord->GetEncoderListL(encoders); + + for (int i = 0; i < encoders.Count(); ++i ) { + + CVideoEncoderInfo *encoderInfo = mDevVideoRecord->VideoEncoderInfoLC(encoders[i]); + + // Discard encoders that are not HW accelerated and do not support direct capture + if (encoderInfo->Accelerated() == false || encoderInfo->SupportsDirectCapture() == false) { + CleanupStack::Check(encoderInfo); + CleanupStack::PopAndDestroy(encoderInfo); + continue; + } + + m_videoParametersForEncoder.append(MaxResolutionRatesAndTypes()); + int newIndex = m_videoParametersForEncoder.count() - 1; + + m_videoParametersForEncoder[newIndex].bitRate = (int)encoderInfo->MaxBitrate(); + + // Get supported MIME Types + const RPointerArray<CCompressedVideoFormat> &videoFormats = encoderInfo->SupportedOutputFormats(); + for(int x = 0; x < videoFormats.Count(); ++x) { + QString codecMimeType = QString::fromUtf8((char *)videoFormats[x]->MimeType().Ptr(),videoFormats[x]->MimeType().Length()); + + m_videoParametersForEncoder[newIndex].mimeTypes.append(codecMimeType); + } + + // Get supported maximum Resolution/Framerate pairs + const RArray<TPictureRateAndSize> &ratesAndSizes = encoderInfo->MaxPictureRates(); + SupportedFrameRatePictureSize data; + for(int j = 0; j < ratesAndSizes.Count(); ++j) { + data.frameRate = ratesAndSizes[j].iPictureRate; + data.frameSize = QSize(ratesAndSizes[j].iPictureSize.iWidth, ratesAndSizes[j].iPictureSize.iHeight); + + // Save data to the hash + m_videoParametersForEncoder[newIndex].frameRatePictureSizePair.append(data); + } + + CleanupStack::Check(encoderInfo); + CleanupStack::PopAndDestroy(encoderInfo); + } + + CleanupStack::Check(mDevVideoRecord); + CleanupStack::PopAndDestroy(mDevVideoRecord); + CleanupStack::PopAndDestroy(); // RArray<TUid> encoders +} +#endif // S60_DEVVIDEO_RECORDING_SUPPORTED + +QStringList S60VideoCaptureSession::supportedVideoContainers() +{ + QStringList containers; + + QList<TInt> controllers = m_videoControllerMap.keys(); + for (int i = 0; i < controllers.count(); ++i) { + foreach (VideoFormatData formatData, m_videoControllerMap[controllers[i]]) { + for (int j = 0; j < formatData.supportedMimeTypes.count(); ++j) { + if (containers.contains(formatData.supportedMimeTypes[j], Qt::CaseInsensitive) == false) + containers.append(formatData.supportedMimeTypes[j]); + } + } + } + + return containers; +} + +bool S60VideoCaptureSession::isSupportedVideoContainer(const QString &containerName) +{ + return supportedVideoContainers().contains(containerName, Qt::CaseInsensitive); +} + +QString S60VideoCaptureSession::videoContainer() const +{ + return m_container; +} + +void S60VideoCaptureSession::setVideoContainer(const QString &containerName) +{ + if (containerName == m_requestedContainer) + return; + + if (containerName.isEmpty()) { + m_requestedContainer = KMimeTypeDefaultContainer; // Use default + } else { + if (supportedVideoContainers().contains(containerName)) { + m_requestedContainer = containerName; + } else { + setError(KErrNotSupported, tr("Requested video container is not supported.")); + m_requestedContainer = KMimeTypeDefaultContainer; // Reset to default + } + } + + m_uncommittedSettings = true; +} + +QString S60VideoCaptureSession::videoContainerDescription(const QString &containerName) +{ + QList<TInt> formats; + QList<TInt> encoders = m_videoControllerMap.keys(); + for (int i = 0; i < encoders.count(); ++i) { + formats = m_videoControllerMap[encoders[i]].keys(); + for (int j = 0; j < formats.count(); ++j) { + if (m_videoControllerMap[encoders[i]][formats[j]].supportedMimeTypes.contains(containerName, Qt::CaseInsensitive)) + return m_videoControllerMap[encoders[i]][formats[j]].description; + } + } + + return QString(); +} + +void S60VideoCaptureSession::cameraStatusChanged(QCamera::Status status) +{ + if (status == QCamera::ActiveStatus) { + m_cameraStarted = true; + + // Continue preparation or start recording if previously requested + if (m_captureState == EInitialized + && (m_openWhenReady || m_prepareAfterOpenComplete || m_startAfterPrepareComplete)) { + setOutputLocation(m_requestedSink); + m_openWhenReady = false; // Reset + } else if ((m_captureState == EOpenComplete || m_captureState == EPrepared) + && (m_prepareAfterOpenComplete || m_startAfterPrepareComplete)) { + startRecording(); + m_prepareAfterOpenComplete = false; // Reset + } + + } else if (status == QCamera::UnloadedStatus) { + m_cameraStarted = false; + releaseVideoRecording(); + } else { + m_cameraStarted = false; + } +} + +void S60VideoCaptureSession::durationTimerTriggered() +{ + // Update position only if recording is ongoing + if ((m_captureState == ERecording) && m_videoRecorder) { + // Signal will be automatically emitted of position changes + TRAPD(err, m_position = m_videoRecorder->DurationL().Int64() / 1000); + setError(err, tr("Cannot retrieve video position.")); + + emit positionChanged(m_position); + } +} + +void S60VideoCaptureSession::doPopulateAudioCodecsL() +{ + if (m_captureState == EInitializing) { + m_audioCodecList.clear(); + + RArray<TFourCC> audioTypes; + CleanupClosePushL(audioTypes); + + if (m_videoRecorder) + m_videoRecorder->GetSupportedAudioTypesL(audioTypes); + else + setError(KErrNotReady, tr("Unexpected camera error.")); + + for (TInt i = 0; i < audioTypes.Count(); i++) { + TUint32 codec = audioTypes[i].FourCC(); + + if (codec == KMMFFourCCCodeAMR) + m_audioCodecList.insert(QString("audio/amr"), KMMFFourCCCodeAMR); + if (codec == KMMFFourCCCodeAAC) + m_audioCodecList.insert(QString("audio/aac"), KMMFFourCCCodeAAC); + } + CleanupStack::PopAndDestroy(&audioTypes); + } +} + +void S60VideoCaptureSession::doPopulateVideoCodecsL() +{ + if (m_captureState == EInitializing) { + m_videoCodecList.clear(); + + CDesC8ArrayFlat* videoTypes = new (ELeave) CDesC8ArrayFlat(10); + CleanupStack::PushL(videoTypes); + + if (m_videoRecorder) + m_videoRecorder->GetSupportedVideoTypesL(*videoTypes); + else + setError(KErrNotReady, tr("Unexpected camera error.")); + + for (TInt i = 0; i < videoTypes->Count(); i++) { + TPtrC8 videoType = videoTypes->MdcaPoint(i); + QString codecMimeType = QString::fromUtf8((char *)videoType.Ptr(), videoType.Length()); +#ifdef S60_DEVVIDEO_RECORDING_SUPPORTED + for (int j = 0; j < m_videoParametersForEncoder.size(); ++j) { + if (m_videoParametersForEncoder[j].mimeTypes.contains(codecMimeType, Qt::CaseInsensitive)) { + m_videoCodecList << codecMimeType; + break; + } + } +#else // CVideoRecorderUtility + m_videoCodecList << codecMimeType; +#endif // S60_DEVVIDEO_RECORDING_SUPPORTED + } + CleanupStack::PopAndDestroy(videoTypes); + } +} + +#ifndef S60_DEVVIDEO_RECORDING_SUPPORTED +/* + * Maximum resolution, framerate and bitrate can not be queried via MMF or + * ECam, but needs to be set according to the definitions of the video + * standard in question. In video standards, the values often depend on each + * other, but the below function defines constant maximums. + */ +void S60VideoCaptureSession::doPopulateMaxVideoParameters() +{ + m_videoParametersForEncoder.append(MaxResolutionRatesAndTypes()); // For H.263 + m_videoParametersForEncoder.append(MaxResolutionRatesAndTypes()); // For MPEG-4 + m_videoParametersForEncoder.append(MaxResolutionRatesAndTypes()); // For H.264 + + for (int i = 0; i < m_videoCodecList.count(); ++i) { + + // Use all lower case for comparisons + QString codec = m_videoCodecList[i].toLower(); + + if (codec.contains("video/h263-2000", Qt::CaseInsensitive)) { + // H.263 + if (codec == "video/h263-2000" || + codec == "video/h263-2000; profile=0" || + codec == "video/h263-2000; profile=0; level=10" || + codec == "video/h263-2000; profile=3") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(176,144))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 64000) + m_videoParametersForEncoder[0].bitRate = 64000; + continue; + } else if (codec == "video/h263-2000; profile=0; level=20") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 128000) + m_videoParametersForEncoder[0].bitRate = 128000; + continue; + } else if (codec == "video/h263-2000; profile=0; level=30") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(30.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 384000) + m_videoParametersForEncoder[0].bitRate = 384000; + continue; + } else if (codec == "video/h263-2000; profile=0; level=40") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(30.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 2048000) + m_videoParametersForEncoder[0].bitRate = 2048000; + continue; + } else if (codec == "video/h263-2000; profile=0; level=45") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(176,144))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 128000) + m_videoParametersForEncoder[0].bitRate = 128000; + continue; + } else if (codec == "video/h263-2000; profile=0; level=50") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 4096000) + m_videoParametersForEncoder[0].bitRate = 4096000; + continue; + } + + } else if (codec.contains("video/mp4v-es", Qt::CaseInsensitive)) { + // Mpeg-4 + if (codec == "video/mp4v-es" || + codec == "video/mp4v-es; profile-level-id=1" || + codec == "video/mp4v-es; profile-level-id=8") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(176,144))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 64000) + m_videoParametersForEncoder[0].bitRate = 64000; + continue; + } else if (codec == "video/mp4v-es; profile-level-id=2" || + codec == "video/mp4v-es; profile-level-id=9") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 128000) + m_videoParametersForEncoder[0].bitRate = 128000; + continue; + } else if (codec == "video/mp4v-es; profile-level-id=3") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(30.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 384000) + m_videoParametersForEncoder[0].bitRate = 384000; + continue; + } else if (codec == "video/mp4v-es; profile-level-id=4") { +#if (defined(S60_31_PLATFORM) | defined(S60_32_PLATFORM)) + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(640,480))); +#else // S60 5.0 and later platforms + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(30.0, QSize(640,480))); +#endif + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 4000000) + m_videoParametersForEncoder[0].bitRate = 4000000; + continue; + } else if (codec == "video/mp4v-es; profile-level-id=5") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(25.0, QSize(720,576))); + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(30.0, QSize(720,480))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 8000000) + m_videoParametersForEncoder[0].bitRate = 8000000; + continue; + } else if (codec == "video/mp4v-es; profile-level-id=6") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(30.0, QSize(1280,720))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 12000000) + m_videoParametersForEncoder[0].bitRate = 12000000; + continue; + } + + } else if (codec.contains("video/h264", Qt::CaseInsensitive)) { + // H.264 + if (codec == "video/h264" || + codec == "video/h264; profile-level-id=42800a") { + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(176,144))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 64000) + m_videoParametersForEncoder[0].bitRate = 64000; + continue; + } else if (codec == "video/h264; profile-level-id=42900b") { // BP, L1b + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(176,144))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 128000) + m_videoParametersForEncoder[0].bitRate = 128000; + continue; + } else if (codec == "video/h264; profile-level-id=42800b") { // BP, L1.1 + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(7.5, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 192000) + m_videoParametersForEncoder[0].bitRate = 192000; + continue; + } else if (codec == "video/h264; profile-level-id=42800c") { // BP, L1.2 + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(15.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 384000) + m_videoParametersForEncoder[0].bitRate = 384000; + continue; + } else if (codec == "video/h264; profile-level-id=42800d") { // BP, L1.3 + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(30.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 768000) + m_videoParametersForEncoder[0].bitRate = 768000; + continue; + } else if (codec == "video/h264; profile-level-id=428014") { // BP, L2 + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(30.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 2000000) + m_videoParametersForEncoder[0].bitRate = 2000000; + continue; + } else if (codec == "video/h264; profile-level-id=428015") { // BP, L2.1 + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(50.0, QSize(352,288))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 4000000) + m_videoParametersForEncoder[0].bitRate = 4000000; + continue; + } else if (codec == "video/h264; profile-level-id=428016") { // BP, L2.2 + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(16.9, QSize(640,480))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 4000000) + m_videoParametersForEncoder[0].bitRate = 4000000; + continue; + } else if (codec == "video/h264; profile-level-id=42801e") { // BP, L3 + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(33.8, QSize(640,480))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 10000000) + m_videoParametersForEncoder[0].bitRate = 10000000; + continue; + } else if (codec == "video/h264; profile-level-id=42801f") { // BP, L3.1 + m_videoParametersForEncoder[0].frameRatePictureSizePair.append(SupportedFrameRatePictureSize(30.0, QSize(1280,720))); + m_videoParametersForEncoder[0].mimeTypes.append(codec); + if (m_videoParametersForEncoder[0].bitRate < 14000000) + m_videoParametersForEncoder[0].bitRate = 14000000; + continue; + } + } + } +} +#endif // S60_DEVVIDEO_RECORDING_SUPPORTED + +/* + * This function returns the maximum resolution defined by the video standards + * for different MIME Types. + */ +QSize S60VideoCaptureSession::maximumResolutionForMimeType(const QString &mimeType) const +{ + QSize maxSize(-1,-1); + // Use all lower case for comparisons + QString lowerMimeType = mimeType.toLower(); + + if (lowerMimeType == "video/h263-2000") { + maxSize = KResH263; + } else if (lowerMimeType == "video/h263-2000; profile=0") { + maxSize = KResH263_Profile0; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=10") { + maxSize = KResH263_Profile0_Level10; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=20") { + maxSize = KResH263_Profile0_Level20; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=30") { + maxSize = KResH263_Profile0_Level30; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=40") { + maxSize = KResH263_Profile0_Level40; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=45") { + maxSize = KResH263_Profile0_Level45; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=50") { + maxSize = KResH263_Profile0_Level50; + } else if (lowerMimeType == "video/h263-2000; profile=3") { + maxSize = KResH263_Profile3; + } else if (lowerMimeType == "video/mp4v-es") { + maxSize = KResMPEG4; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=1") { + maxSize = KResMPEG4_PLID_1; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=2") { + maxSize = KResMPEG4_PLID_2; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=3") { + maxSize = KResMPEG4_PLID_3; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=4") { + maxSize = KResMPEG4_PLID_4; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=5") { + maxSize = KResMPEG4_PLID_5; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=6") { + maxSize = KResMPEG4_PLID_6; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=8") { + maxSize = KResMPEG4_PLID_8; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=9") { + maxSize = KResMPEG4_PLID_9; + } else if (lowerMimeType == "video/h264") { + maxSize = KResH264; + } else if (lowerMimeType == "video/h264; profile-level-id=42800a" || + lowerMimeType == "video/h264; profile-level-id=4d400a" || + lowerMimeType == "video/h264; profile-level-id=64400a") { // L1 + maxSize = KResH264_PLID_42800A; + } else if (lowerMimeType == "video/h264; profile-level-id=42900b" || + lowerMimeType == "video/h264; profile-level-id=4d500b" || + lowerMimeType == "video/h264; profile-level-id=644009") { // L1.b + maxSize = KResH264_PLID_42900B; + } else if (lowerMimeType == "video/h264; profile-level-id=42800b" || + lowerMimeType == "video/h264; profile-level-id=4d400b" || + lowerMimeType == "video/h264; profile-level-id=64400b") { // L1.1 + maxSize = KResH264_PLID_42800B; + } else if (lowerMimeType == "video/h264; profile-level-id=42800c" || + lowerMimeType == "video/h264; profile-level-id=4d400c" || + lowerMimeType == "video/h264; profile-level-id=64400c") { // L1.2 + maxSize = KResH264_PLID_42800C; + } else if (lowerMimeType == "video/h264; profile-level-id=42800d" || + lowerMimeType == "video/h264; profile-level-id=4d400d" || + lowerMimeType == "video/h264; profile-level-id=64400d") { // L1.3 + maxSize = KResH264_PLID_42800D; + } else if (lowerMimeType == "video/h264; profile-level-id=428014" || + lowerMimeType == "video/h264; profile-level-id=4d4014" || + lowerMimeType == "video/h264; profile-level-id=644014") { // L2 + maxSize = KResH264_PLID_428014; + } else if (lowerMimeType == "video/h264; profile-level-id=428015" || + lowerMimeType == "video/h264; profile-level-id=4d4015" || + lowerMimeType == "video/h264; profile-level-id=644015") { // L2.1 + maxSize = KResH264_PLID_428015; + } else if (lowerMimeType == "video/h264; profile-level-id=428016" || + lowerMimeType == "video/h264; profile-level-id=4d4016" || + lowerMimeType == "video/h264; profile-level-id=644016") { // L2.2 + maxSize = KResH264_PLID_428016; + } else if (lowerMimeType == "video/h264; profile-level-id=42801e" || + lowerMimeType == "video/h264; profile-level-id=4d401e" || + lowerMimeType == "video/h264; profile-level-id=64401e") { // L3 + maxSize = KResH264_PLID_42801E; + } else if (lowerMimeType == "video/h264; profile-level-id=42801f" || + lowerMimeType == "video/h264; profile-level-id=4d401f" || + lowerMimeType == "video/h264; profile-level-id=64401f") { // L3.1 + maxSize = KResH264_PLID_42801F; + } else if (lowerMimeType == "video/h264; profile-level-id=428020" || + lowerMimeType == "video/h264; profile-level-id=4d4020" || + lowerMimeType == "video/h264; profile-level-id=644020") { // L3.2 + maxSize = KResH264_PLID_428020; + } else if (lowerMimeType == "video/h264; profile-level-id=428028" || + lowerMimeType == "video/h264; profile-level-id=4d4028" || + lowerMimeType == "video/h264; profile-level-id=644028") { // L4 + maxSize = KResH264_PLID_428028; + } + + return maxSize; +} + +/* + * This function returns the maximum framerate defined by the video standards + * for different MIME Types. + */ + +qreal S60VideoCaptureSession::maximumFrameRateForMimeType(const QString &mimeType) const +{ + qreal maxRate(-1.0); + // Use all lower case for comparisons + QString lowerMimeType = mimeType.toLower(); + + if (lowerMimeType == "video/h263-2000") { + maxRate = KFrR_H263; + } else if (lowerMimeType == "video/h263-2000; profile=0") { + maxRate = KFrR_H263_Profile0; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=10") { + maxRate = KFrR_H263_Profile0_Level10; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=20") { + maxRate = KFrR_H263_Profile0_Level20; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=30") { + maxRate = KFrR_H263_Profile0_Level30; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=40") { + maxRate = KFrR_H263_Profile0_Level40; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=45") { + maxRate = KFrR_H263_Profile0_Level45; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=50") { + maxRate = KFrR_H263_Profile0_Level50; + } else if (lowerMimeType == "video/h263-2000; profile=3") { + maxRate = KFrR_H263_Profile3; + } else if (lowerMimeType == "video/mp4v-es") { + maxRate = KFrR_MPEG4; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=1") { + maxRate = KFrR_MPEG4_PLID_1; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=2") { + maxRate = KFrR_MPEG4_PLID_2; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=3") { + maxRate = KFrR_MPEG4_PLID_3; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=4") { + maxRate = KFrR_MPEG4_PLID_4; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=5") { + maxRate = KFrR_MPEG4_PLID_5; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=6") { + maxRate = KFrR_MPEG4_PLID_6; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=8") { + maxRate = KFrR_MPEG4_PLID_8; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=9") { + maxRate = KFrR_MPEG4_PLID_9; + } else if (lowerMimeType == "video/h264") { + maxRate = KFrR_H264; + } else if (lowerMimeType == "video/h264; profile-level-id=42800a" || + lowerMimeType == "video/h264; profile-level-id=4d400a" || + lowerMimeType == "video/h264; profile-level-id=64400a") { // L1 + maxRate = KFrR_H264_PLID_42800A; + } else if (lowerMimeType == "video/h264; profile-level-id=42900b" || + lowerMimeType == "video/h264; profile-level-id=4d500b" || + lowerMimeType == "video/h264; profile-level-id=644009") { // L1.b + maxRate = KFrR_H264_PLID_42900B; + } else if (lowerMimeType == "video/h264; profile-level-id=42800b" || + lowerMimeType == "video/h264; profile-level-id=4d400b" || + lowerMimeType == "video/h264; profile-level-id=64400b") { // L1.1 + maxRate = KFrR_H264_PLID_42800B; + } else if (lowerMimeType == "video/h264; profile-level-id=42800c" || + lowerMimeType == "video/h264; profile-level-id=4d400c" || + lowerMimeType == "video/h264; profile-level-id=64400c") { // L1.2 + maxRate = KFrR_H264_PLID_42800C; + } else if (lowerMimeType == "video/h264; profile-level-id=42800d" || + lowerMimeType == "video/h264; profile-level-id=4d400d" || + lowerMimeType == "video/h264; profile-level-id=64400d") { // L1.3 + maxRate = KFrR_H264_PLID_42800D; + } else if (lowerMimeType == "video/h264; profile-level-id=428014" || + lowerMimeType == "video/h264; profile-level-id=4d4014" || + lowerMimeType == "video/h264; profile-level-id=644014") { // L2 + maxRate = KFrR_H264_PLID_428014; + } else if (lowerMimeType == "video/h264; profile-level-id=428015" || + lowerMimeType == "video/h264; profile-level-id=4d4015" || + lowerMimeType == "video/h264; profile-level-id=644015") { // L2.1 + maxRate = KFrR_H264_PLID_428015; + } else if (lowerMimeType == "video/h264; profile-level-id=428016" || + lowerMimeType == "video/h264; profile-level-id=4d4016" || + lowerMimeType == "video/h264; profile-level-id=644016") { // L2.2 + maxRate = KFrR_H264_PLID_428016; + } else if (lowerMimeType == "video/h264; profile-level-id=42801e" || + lowerMimeType == "video/h264; profile-level-id=4d401e" || + lowerMimeType == "video/h264; profile-level-id=64401e") { // L3 + maxRate = KFrR_H264_PLID_42801E; + } else if (lowerMimeType == "video/h264; profile-level-id=42801f" || + lowerMimeType == "video/h264; profile-level-id=4d401f" || + lowerMimeType == "video/h264; profile-level-id=64401f") { // L3.1 + maxRate = KFrR_H264_PLID_42801F; + } else if (lowerMimeType == "video/h264; profile-level-id=428020" || + lowerMimeType == "video/h264; profile-level-id=4d4020" || + lowerMimeType == "video/h264; profile-level-id=644020") { // L3.2 + maxRate = KFrR_H264_PLID_428020; + } else if (lowerMimeType == "video/h264; profile-level-id=428028" || + lowerMimeType == "video/h264; profile-level-id=4d4028" || + lowerMimeType == "video/h264; profile-level-id=644028") { // L4 + maxRate = KFrR_H264_PLID_428028; + } + + return maxRate; +} + +/* + * This function returns the maximum bitrate defined by the video standards + * for different MIME Types. + */ +int S60VideoCaptureSession::maximumBitRateForMimeType(const QString &mimeType) const +{ + int maxRate(-1.0); + // Use all lower case for comparisons + QString lowerMimeType = mimeType.toLower(); + + if (lowerMimeType == "video/h263-2000") { + maxRate = KBiR_H263; + } else if (lowerMimeType == "video/h263-2000; profile=0") { + maxRate = KBiR_H263_Profile0; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=10") { + maxRate = KBiR_H263_Profile0_Level10; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=20") { + maxRate = KBiR_H263_Profile0_Level20; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=30") { + maxRate = KBiR_H263_Profile0_Level30; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=40") { + maxRate = KBiR_H263_Profile0_Level40; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=45") { + maxRate = KBiR_H263_Profile0_Level45; + } else if (lowerMimeType == "video/h263-2000; profile=0; level=50") { + maxRate = KBiR_H263_Profile0_Level50; + } else if (lowerMimeType == "video/h263-2000; profile=3") { + maxRate = KBiR_H263_Profile3; + } else if (lowerMimeType == "video/mp4v-es") { + maxRate = KBiR_MPEG4; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=1") { + maxRate = KBiR_MPEG4_PLID_1; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=2") { + maxRate = KBiR_MPEG4_PLID_2; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=3") { + maxRate = KBiR_MPEG4_PLID_3; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=4") { + maxRate = KBiR_MPEG4_PLID_4; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=5") { + maxRate = KBiR_MPEG4_PLID_5; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=6") { + maxRate = KBiR_MPEG4_PLID_6; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=8") { + maxRate = KBiR_MPEG4_PLID_8; + } else if (lowerMimeType == "video/mp4v-es; profile-level-id=9") { + maxRate = KBiR_MPEG4_PLID_9; + } else if (lowerMimeType == "video/h264") { + maxRate = KBiR_H264; + } else if (lowerMimeType == "video/h264; profile-level-id=42800a" || + lowerMimeType == "video/h264; profile-level-id=4d400a" || + lowerMimeType == "video/h264; profile-level-id=64400a") { // L1 + maxRate = KBiR_H264_PLID_42800A; + } else if (lowerMimeType == "video/h264; profile-level-id=42900b" || + lowerMimeType == "video/h264; profile-level-id=4d500b" || + lowerMimeType == "video/h264; profile-level-id=644009") { // L1.b + maxRate = KBiR_H264_PLID_42900B; + } else if (lowerMimeType == "video/h264; profile-level-id=42800b" || + lowerMimeType == "video/h264; profile-level-id=4d400b" || + lowerMimeType == "video/h264; profile-level-id=64400b") { // L1.1 + maxRate = KBiR_H264_PLID_42800B; + } else if (lowerMimeType == "video/h264; profile-level-id=42800c" || + lowerMimeType == "video/h264; profile-level-id=4d400c" || + lowerMimeType == "video/h264; profile-level-id=64400c") { // L1.2 + maxRate = KBiR_H264_PLID_42800C; + } else if (lowerMimeType == "video/h264; profile-level-id=42800d" || + lowerMimeType == "video/h264; profile-level-id=4d400d" || + lowerMimeType == "video/h264; profile-level-id=64400d") { // L1.3 + maxRate = KBiR_H264_PLID_42800D; + } else if (lowerMimeType == "video/h264; profile-level-id=428014" || + lowerMimeType == "video/h264; profile-level-id=4d4014" || + lowerMimeType == "video/h264; profile-level-id=644014") { // L2 + maxRate = KBiR_H264_PLID_428014; + } else if (lowerMimeType == "video/h264; profile-level-id=428015" || + lowerMimeType == "video/h264; profile-level-id=4d4015" || + lowerMimeType == "video/h264; profile-level-id=644015") { // L2.1 + maxRate = KBiR_H264_PLID_428015; + } else if (lowerMimeType == "video/h264; profile-level-id=428016" || + lowerMimeType == "video/h264; profile-level-id=4d4016" || + lowerMimeType == "video/h264; profile-level-id=644016") { // L2.2 + maxRate = KBiR_H264_PLID_428016; + } else if (lowerMimeType == "video/h264; profile-level-id=42801e" || + lowerMimeType == "video/h264; profile-level-id=4d401e" || + lowerMimeType == "video/h264; profile-level-id=64401e") { // L3 + maxRate = KBiR_H264_PLID_42801E; + } else if (lowerMimeType == "video/h264; profile-level-id=42801f" || + lowerMimeType == "video/h264; profile-level-id=4d401f" || + lowerMimeType == "video/h264; profile-level-id=64401f") { // L3.1 + maxRate = KBiR_H264_PLID_42801F; + } else if (lowerMimeType == "video/h264; profile-level-id=428020" || + lowerMimeType == "video/h264; profile-level-id=4d4020" || + lowerMimeType == "video/h264; profile-level-id=644020") { // L3.2 + maxRate = KBiR_H264_PLID_428020; + } else if (lowerMimeType == "video/h264; profile-level-id=428028" || + lowerMimeType == "video/h264; profile-level-id=4d4028" || + lowerMimeType == "video/h264; profile-level-id=644028") { // L4 + maxRate = KBiR_H264_PLID_428028; + } + + return maxRate; +} + +// End of file |